diff --git a/firmware/MedButton/.vscode/c_cpp_properties.json b/firmware/MedButton/.vscode/c_cpp_properties.json index 74b9f97..3a749e1 100644 --- a/firmware/MedButton/.vscode/c_cpp_properties.json +++ b/firmware/MedButton/.vscode/c_cpp_properties.json @@ -15,53 +15,70 @@ "-g", "-Wall" ], - "mtbGccDefaultIncludePath": [ + "mtbDefaultIncludePath": [ ".", "./OnethinxCore", "../mtb_shared/TARGET_CY8CKIT-062-BLE/latest-v2.X", - "../mtb_shared/capsense/latest-v2.X", - "../mtb_shared/core-lib/latest-v1.X", - "../mtb_shared/core-lib/latest-v1.X/include", - "../mtb_shared/freertos/latest-v10.X", - "../mtb_shared/freertos/latest-v10.X/Source", - "../mtb_shared/freertos/latest-v10.X/Source/include", - "../mtb_shared/freertos/latest-v10.X/Source/portable", - "../mtb_shared/freertos/latest-v10.X/Source/portable/TOOLCHAIN_GCC_ARM", - "../mtb_shared/freertos/latest-v10.X/Source/portable/TOOLCHAIN_GCC_ARM/CM4F", - "../mtb_shared/mtb-hal-cat1/latest-v1.X", - "../mtb_shared/mtb-hal-cat1/latest-v1.X/COMPONENT_PSOC6HAL", - "../mtb_shared/mtb-hal-cat1/latest-v1.X/COMPONENT_PSOC6HAL/include", - "../mtb_shared/mtb-hal-cat1/latest-v1.X/COMPONENT_PSOC6HAL/include/pin_packages", - "../mtb_shared/mtb-hal-cat1/latest-v1.X/COMPONENT_PSOC6HAL/include/triggers", - "../mtb_shared/mtb-hal-cat1/latest-v1.X/include", - "../mtb_shared/mtb-pdl-cat1/latest-v2.X", - "../mtb_shared/mtb-pdl-cat1/latest-v2.X/cmsis", - "../mtb_shared/mtb-pdl-cat1/latest-v2.X/cmsis/include", - "../mtb_shared/mtb-pdl-cat1/latest-v2.X/devices", - "../mtb_shared/mtb-pdl-cat1/latest-v2.X/devices/COMPONENT_CAT1A", - "../mtb_shared/mtb-pdl-cat1/latest-v2.X/devices/COMPONENT_CAT1A/include", - "../mtb_shared/mtb-pdl-cat1/latest-v2.X/devices/COMPONENT_CAT1A/include/ip", - "../mtb_shared/mtb-pdl-cat1/latest-v2.X/drivers", - "../mtb_shared/mtb-pdl-cat1/latest-v2.X/drivers/include", - "../mtb_shared/retarget-io/latest-v1.X", + "../mtb_shared/abstraction-rtos/release-v1.4.0", + "../mtb_shared/abstraction-rtos/release-v1.4.0/include", + "../mtb_shared/abstraction-rtos/release-v1.4.0/include/COMPONENT_FREERTOS", + "../mtb_shared/abstraction-rtos/release-v1.4.0/include/Template", + "../mtb_shared/bless/release-v3.50.0", + "../mtb_shared/bless/release-v3.50.0/common", + "../mtb_shared/capsense/release-v2.10.0", + "../mtb_shared/clib-support/release-v1.1.0", + "../mtb_shared/clib-support/release-v1.1.0/TOOLCHAIN_GCC_ARM", + "../mtb_shared/core-lib/release-v1.2.0", + "../mtb_shared/core-lib/release-v1.2.0/include", + "../mtb_shared/freertos/release-v10.3.1", + "../mtb_shared/freertos/release-v10.3.1/Source", + "../mtb_shared/freertos/release-v10.3.1/Source/include", + "../mtb_shared/freertos/release-v10.3.1/Source/portable", + "../mtb_shared/freertos/release-v10.3.1/Source/portable/COMPONENT_CM4", + "../mtb_shared/freertos/release-v10.3.1/Source/portable/COMPONENT_CM4/TOOLCHAIN_GCC_ARM", + "../mtb_shared/mtb-hal-cat1/release-v1.6.0", + "../mtb_shared/mtb-hal-cat1/release-v1.6.0/COMPONENT_PSOC6HAL", + "../mtb_shared/mtb-hal-cat1/release-v1.6.0/COMPONENT_PSOC6HAL/COMPONENT_CAT1A", + "../mtb_shared/mtb-hal-cat1/release-v1.6.0/COMPONENT_PSOC6HAL/COMPONENT_CAT1A/include", + "../mtb_shared/mtb-hal-cat1/release-v1.6.0/COMPONENT_PSOC6HAL/COMPONENT_CAT1A/include/pin_packages", + "../mtb_shared/mtb-hal-cat1/release-v1.6.0/COMPONENT_PSOC6HAL/COMPONENT_CAT1A/include/triggers", + "../mtb_shared/mtb-hal-cat1/release-v1.6.0/COMPONENT_PSOC6HAL/include", + "../mtb_shared/mtb-hal-cat1/release-v1.6.0/COMPONENT_PSOC6HAL/source", + "../mtb_shared/mtb-hal-cat1/release-v1.6.0/include", + "../mtb_shared/mtb-pdl-cat1/release-v2.2.0", + "../mtb_shared/mtb-pdl-cat1/release-v2.2.0/cmsis", + "../mtb_shared/mtb-pdl-cat1/release-v2.2.0/cmsis/include", + "../mtb_shared/mtb-pdl-cat1/release-v2.2.0/devices", + "../mtb_shared/mtb-pdl-cat1/release-v2.2.0/devices/COMPONENT_CAT1A", + "../mtb_shared/mtb-pdl-cat1/release-v2.2.0/devices/COMPONENT_CAT1A/include", + "../mtb_shared/mtb-pdl-cat1/release-v2.2.0/devices/COMPONENT_CAT1A/include/ip", + "../mtb_shared/mtb-pdl-cat1/release-v2.2.0/drivers", + "../mtb_shared/mtb-pdl-cat1/release-v2.2.0/drivers/include", + "../mtb_shared/retarget-io/release-v1.2.0", "${config:modustoolbox.toolsPath}/gcc/lib/gcc/arm-none-eabi/9.3.1/include", "${config:modustoolbox.toolsPath}/gcc/lib/gcc/arm-none-eabi/9.3.1/include-fixed", "${config:modustoolbox.toolsPath}/gcc/arm-none-eabi/include", "${config:modustoolbox.toolsPath}/gcc/arm-none-eabi/include/c++/9.3.1", - "${config:modustoolbox.toolsPath}/gcc/arm-none-eabi/include/c++/9.3.1/arm-none-eabi/thumb/v7e-m/fpv4-sp/hard", + "${config:modustoolbox.toolsPath}/gcc/arm-none-eabi/include/c++/9.3.1/arm-none-eabi/thumb/v7e-m/fpv4-sp/softfp", "${config:modustoolbox.toolsPath}/gcc/arm-none-eabi/include/c++/9.3.1/backward" ], - "mtbGccDefaultDefines": [ + "mtbDefaultDefines": [ "CY_USING_HAL", "CY_APPNAME_MedButton_First", "CY8C6347BZI_BLD53", "CY_TARGET_DEVICE=CY8C6347BZI_BLD53", "TARGET_CY8CKIT_062_BLE", "CY_TARGET_BOARD=CY8CKIT_062_BLE", + "COMPONENT_BLESS_CONTROLLER", + "COMPONENT_BLESS_HOST", + "COMPONENT_CAT1", "COMPONENT_CAT1A", "COMPONENT_CM0P_SLEEP", "COMPONENT_CM4", + "COMPONENT_CY8CKIT_062_BLE", + "COMPONENT_FREERTOS", "COMPONENT_PSOC6HAL", + "COMPONENT_RTOS_AWARE", "COMPONENT_SOFTFP", "DEBUG", "__GNUC__" @@ -79,14 +96,14 @@ "cStandard": "c99", "cppStandard": "c++11", "includePath": [ - "${mtbGccDefaultIncludePath}" + "${mtbDefaultIncludePath}" ], "browse": { "limitSymbolsToIncludedHeaders": true, "databaseFilename": "" }, "defines": [ - "${mtbGccDefaultDefines}" + "${mtbDefaultDefines}" ] } ] diff --git a/firmware/MedButton/.vscode/launch.json b/firmware/MedButton/.vscode/launch.json index 690cedb..71db460 100644 --- a/firmware/MedButton/.vscode/launch.json +++ b/firmware/MedButton/.vscode/launch.json @@ -40,7 +40,7 @@ "openOCDPreConfigLaunchCommands": [ "set PROGRAMMER kitprog3", "set ENABLE_ACQUIRE 0", - "set ENABLE_CM0 0", + "set ENABLE_CM0 0" ], "configFiles": [ "openocd.tcl" @@ -49,7 +49,6 @@ "set mem inaccessible-by-default off", "-enable-pretty-printing", "set remotetimeout 15", - "monitor reset init", // Comment this next line out if you don't want to reload program "monitor program {./build/CY8CKIT-062-BLE/Debug/MedButton_First.hex}", "monitor reset run", @@ -58,7 +57,8 @@ ], "numberOfProcessors": 1, "targetProcessor": 1, // Set to 0 for the CM0+, set to 1 for the CM4 - "postStartSessionCommands": [ // Needed if runToMain is false + "postStartSessionCommands": [ + // Needed if runToMain is false // Following two commands are needed to get gdb and openocd and HW all in sync. // Or, execution context (PC, stack, registers, etc.) look like they are from before reset. // The stepi, is a pretend instruction that does not actually do a stepi, but MUST be done @@ -108,8 +108,7 @@ ], "overrideAttachCommands": [ "set mem inaccessible-by-default off", - "-enable-pretty-printing", - "monitor halt" + "-enable-pretty-printing" ], "numberOfProcessors": 2, "targetProcessor": 1, // Set to 0 for the CM0+, set to 1 for the CM4 @@ -231,9 +230,9 @@ "servertype": "jlink", "device": "CY8C6xx7_CM0p_sect256KB_tm", "overrideLaunchCommands": [ - "monitor reset 2", // Reset via the reset pin - "monitor flash erase", "monitor reset 0", // Reset both core and the peripherals + "monitor flash erase", + "monitor reset 2", // Reset via the reset pin "quit" ], "showDevDebugOutput": false // When set to true, displays output of GDB. @@ -249,9 +248,9 @@ "servertype": "jlink", "device": "CY8C6xx7_CM0p_sect256KB_tm", "overrideLaunchCommands": [ - "monitor reset 2", // Reset via the reset pin - "-target-download", "monitor reset 0", // Reset both core and the peripherals + "-target-download", + "monitor reset 2", // Reset via the reset pin "monitor go", "quit" ], diff --git a/firmware/MedButton/.vscode/settings.json b/firmware/MedButton/.vscode/settings.json index fff1062..488df3a 100644 --- a/firmware/MedButton/.vscode/settings.json +++ b/firmware/MedButton/.vscode/settings.json @@ -10,7 +10,7 @@ //mtb// macOS : $HOME/Library/Application Support/Code/User/settings.json //mtb// Linux : $HOME/.config/Code/User/settings.json //mtb// - "modustoolbox.toolsPath": "C:/Users/maksy/ModusToolbox/tools_2.2", + "modustoolbox.toolsPath": "C:/Users/Deer/ModusToolbox/tools_2.3", "cortex-debug.armToolchainPath": "${config:modustoolbox.toolsPath}/gcc/bin", "cortex-debug.openocdPath": "${config:modustoolbox.toolsPath}/openocd/bin/openocd" } diff --git a/firmware/MedButton/FreeRTOSConfig.h b/firmware/MedButton/FreeRTOSConfig.h index c605aca..d060c78 100644 --- a/firmware/MedButton/FreeRTOSConfig.h +++ b/firmware/MedButton/FreeRTOSConfig.h @@ -71,7 +71,7 @@ #define configUSE_QUEUE_SETS 0 #define configUSE_TIME_SLICING 0 #define configENABLE_BACKWARD_COMPATIBILITY 0 -#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 3 /* Memory allocation related definitions. */ #define configSUPPORT_STATIC_ALLOCATION 1 @@ -188,7 +188,7 @@ standard names - or at least those used in the unmodified vector table. */ #define HEAP_ALLOCATION_TYPE5 (5) /* heap_5.c*/ #define NO_HEAP_ALLOCATION (0) -#define configHEAP_ALLOCATION_SCHEME (HEAP_ALLOCATION_TYPE3) +#define configHEAP_ALLOCATION_SCHEME (HEAP_ALLOCATION_TYPE4) /* Check if the ModusToolbox Device Configurator Power personality parameter * "System Idle Power Mode" is set to either "CPU Sleep" or "System Deep Sleep". diff --git a/firmware/MedButton/Makefile b/firmware/MedButton/Makefile index a60566e..82cdd11 100644 --- a/firmware/MedButton/Makefile +++ b/firmware/MedButton/Makefile @@ -79,10 +79,11 @@ VERBOSE= # ... then code in directories named COMPONENT_foo and COMPONENT_bar will be # added to the build # -COMPONENTS=FREERTOS RTOS_AWARE +COMPONENTS+=FREERTOS RTOS_AWARE BLESS_CONTROLLER BLESS_HOST # Like COMPONENTS, but disable optional code that was enabled by default. -DISABLE_COMPONENTS=BSP_DESIGN_MODUS +DISABLE_COMPONENTS= +#BSP_DESIGN_MODUS # By default the build system automatically looks in the Makefile's directory # tree for source code and builds it. The SOURCES variable can be used to diff --git a/firmware/MedButton/MedButton_First.code-workspace b/firmware/MedButton/MedButton_First.code-workspace index a19fa6c..d4e3dfc 100644 --- a/firmware/MedButton/MedButton_First.code-workspace +++ b/firmware/MedButton/MedButton_First.code-workspace @@ -17,13 +17,11 @@ //mtb// macOS : $HOME/Library/Application Support/Code/User/settings.json //mtb// Linux : $HOME/.config/Code/User/settings.json //mtb// - "modustoolbox.toolsPath": "C:/Users/maksy/ModusToolbox/tools_2.2", + "modustoolbox.toolsPath": "C:/Users/Deer/ModusToolbox/tools_2.3", "cortex-debug.armToolchainPath": "${config:modustoolbox.toolsPath}/gcc/bin", "cortex-debug.openocdPath": "${config:modustoolbox.toolsPath}/openocd/bin/openocd", - "workbench.colorCustomizations": { - "activityBar.background": "#482133", - "titleBar.activeBackground": "#642E47", - "titleBar.activeForeground": "#FCF9FA" + "files.associations": { + "onethinxcore01.h": "c" } } } \ No newline at end of file diff --git a/firmware/MedButton/OnethinxCore/LoRaWAN_keys.h b/firmware/MedButton/OnethinxCore/LoRaWAN_keys.h index 7169427..fcc2976 100644 --- a/firmware/MedButton/OnethinxCore/LoRaWAN_keys.h +++ b/firmware/MedButton/OnethinxCore/LoRaWAN_keys.h @@ -23,9 +23,9 @@ LoRaWAN_keys_t TTN_OTAAkeys = { .KeyType = OTAA_10x_key, .PublicNetwork = true, - .OTAA_10x.DevEui = {{ 0x00, 0xE3, 0x52, 0x07, 0xC8, 0x0A, 0x56, 0x90 }}, - .OTAA_10x.AppEui = {{ 0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x02, 0xB6, 0x3A }}, - .OTAA_10x.AppKey = {{ 0x8A, 0x9C, 0x9F, 0xAE, 0x12, 0xFE, 0x58, 0x1D, 0xFB, 0xA8, 0x41, 0x0E, 0xD9, 0x2B, 0xCC, 0x0C }} + .OTAA_10x.DevEui = {{ 0x00, 0x3A, 0xB1, 0x24, 0x7C, 0x87, 0x1A, 0x60 }}, + .OTAA_10x.AppEui = {{ 0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x03, 0x99, 0x3B }}, + .OTAA_10x.AppKey = {{ 0x3E, 0xB6, 0x2B, 0x9E, 0x19, 0x49, 0x7F, 0xFB, 0xAB, 0x85, 0xEF, 0x54, 0x10, 0xC9, 0x45, 0x85 }} }; #endif /* LORAWAN_KEYS_H */ diff --git a/firmware/MedButton/ble_task.c b/firmware/MedButton/ble_task.c new file mode 100644 index 0000000..f417497 --- /dev/null +++ b/firmware/MedButton/ble_task.c @@ -0,0 +1,1161 @@ +/****************************************************************************** +* File Name: ble_task.c +* +* Description: This file contains the task that initializes BLE and +* handles different BLE events. +* +* Related Document: README.md +* +******************************************************************************* +* Copyright (2020), Cypress Semiconductor Corporation. All rights reserved. +******************************************************************************* +* This software, including source code, documentation and related materials +* ("Software"), is owned by Cypress Semiconductor Corporation or one of its +* subsidiaries ("Cypress") and is protected by and subject to worldwide patent +* protection (United States and foreign), United States copyright laws and +* international treaty provisions. Therefore, you may use this Software only +* as provided in the license agreement accompanying the software package from +* which you obtained this Software ("EULA"). +* +* If no EULA applies, Cypress hereby grants you a personal, non-exclusive, +* non-transferable license to copy, modify, and compile the Software source +* code solely for use in connection with Cypress's integrated circuit products. +* Any reproduction, modification, translation, compilation, or representation +* of this Software except as specified above is prohibited without the express +* written permission of Cypress. +* +* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Cypress +* reserves the right to make changes to the Software without notice. Cypress +* does not assume any liability arising out of the application or use of the +* Software or any product or circuit described in the Software. Cypress does +* not authorize its products for use in any products where a malfunction or +* failure of the Cypress product may reasonably be expected to result in +* significant property damage, injury or death ("High Risk Product"). By +* including Cypress's product in a High Risk Product, the manufacturer of such +* system or application assumes all risk of such use and in doing so agrees to +* indemnify Cypress against all liability. +*******************************************************************************/ + +/****************************************************************************** + * Include header files + *****************************************************************************/ +#include "ble_task.h" +#include "cybsp.h" +#include "cyhal.h" +#include "cycfg_ble.h" +#include "string.h" +#include "data_struct.h" +#ifdef EINK_DISPLAY_SHIELD_PRESENT +#include "display_task.h" +#endif + +/****************************************************************************** + * Macros + *****************************************************************************/ +/* GATT parameters */ +#define NOTIFY_CCCD_UUID {0x02, 0x29} +#define NOTIFY_CCCD_SIZE (02u) +#define WRITEME_CHAR_UUID {0xC7u, 0x58u, 0xCFu, 0x70u, 0xB3u, 0xAFu,\ + 0xE4u,0xADu, 0x65u, 0x44u, 0xA3u, 0x85u, 0x26u,\ + 0x7Bu,0x70u, 0xD4u} +#define WRITEME_CHAR_UUID_SIZE (16u) +#define BLE_INTERRUPT_PRIORITY (1u) +#define ENABLE (1u) +#define DISABLE (0u) +#define CONN_INTERVAL_MULTIPLIER (1.25f) +#define TARGET_NAME_LENGTH (5u) +#define AD_TYPE_COMPLETE_LOCAL_NAME (9u) +/******************************************************************************* +* Global Variables +*******************************************************************************/ +/* Variables to hold GATT notification bytes count and GATT write bytes count */ +static uint32_t gatt_write_tx_bytes; +static uint32_t notif_rx_bytes; + +/* Variable to store latest connection interval for the BLE connection */ +static float conn_interval; + +/* CCCD value to enable/disable notification */ +static uint8_t CCCD_VALUE[NOTIFY_CCCD_SIZE] = {ENABLE,DISABLE}; + +/* Flags */ +/* Indication to start/stop GATT write */ +bool gatt_write_flag = false; +/* To ignore button press before the device is connected with peer */ +bool button_flag = false; +/* To scan only once, upon first button press by user */ +bool scan_flag = false; +/* To indicate if BLE stack is busy or free */ +static bool stack_free = true; +/* Flags used to indicate when to stop discovery procedure */ +static bool notify_cccd_uuid_found; +static bool writeme_char_uuid_found; +/* To indicate display task that the device has disconnected */ +bool device_disconnect_flag = false; + +/* Variable to store discovered attribute handles of the custom service */ +static cy_ble_gatt_db_attr_handle_t gatt_notify_cccd_attrHandle, gatt_write_val_attrHandle; + +/* Constant to store server name and use during scanning */ +static const char target_name[] = "Amazfit Bip Watch"; + +/* Variable to store user LED status */ +// static led_status_t led_status = {CYBSP_LED_STATE_OFF, CYBSP_LED_STATE_OFF}; + +/* Structure used for GATT writes */ +static cy_stc_ble_gattc_write_cmd_req_t write_param_characteristic; + +/* Variable to store TX and RX throughput values */ +throughput_val_t client_throughput = {0u, 0u}; + +/* Connection handle to identify the connected peer device */ +static cy_stc_ble_conn_handle_t conn_handle; + +/* Variable to keep track of the BLE API result */ +static cy_en_ble_api_result_t ble_api_result; + +/* Variable to hold the address of the peer device */ +static cy_stc_ble_gap_bd_addr_t peer_addr; + +/* Variable to store MTU size for active BLE connection */ +static uint16_t att_mtu_size = CY_BLE_GATT_MTU; + +#ifdef EINK_DISPLAY_SHIELD_PRESENT +/* Variable used to refresh the E-ink display every 5 seconds */ +static uint8_t count_five_sec; +#endif + +/******************************************************************************* +* Function Prototypes +*******************************************************************************/ +static void ble_init(void); +static void ble_stack_event_handler(uint32_t event, void *eventParam, message_struct *message_data); +static void ble_controller_interrupt_handler(void); +static void bless_interrupt_handler(void); +static void ble_initialize_gatt_write(cy_ble_gatt_db_attr_handle_t attribute_handle); +static cy_en_ble_api_result_t ble_enable_notification(cy_ble_gatt_db_attr_handle_t attribute_handle); +static cy_en_ble_api_result_t ble_disable_notification(cy_ble_gatt_db_attr_handle_t attribute_handle); +static uint8* adv_parser(uint16_t AD_type, cy_stc_ble_gapc_adv_report_param_t *scan_report, uint8 *adv_type_length); + +/******************************************************************************* +* Function Name: void task_BLE(void *pvParameters) +******************************************************************************** +* Summary: FreeRTOS task which handles the BLE activity of the application +* +* Parameters: +* void *pvParameters : Task parameter defined during task creation (unused) +* +* Return: +* None +* +*******************************************************************************/ +void task_BLE(void *pvParameters) +{ + /* Variable to store return value from FreeRTOS APIs */ + BaseType_t rtos_api_result; + + /* Variable to store BLE command received from queue */ + ble_command_type_t ble_cmd = BLE_PROCESS_EVENTS; + + /* Remove compiler warning for unused variable */ + message_struct *message_data = (message_struct*) pvParameters; + + /* Initialize BLE and process any stack events */ + ble_init(); + + /* Repeatedly running part of the task */ + for(;;) + { + /* Block until a BLE command has been received over bleCmdQ */ + rtos_api_result = xQueueReceive(ble_cmdQ, &ble_cmd, portMAX_DELAY); + + /* Command has been received from bleCmdQ */ + if(rtos_api_result == pdTRUE) + { + /* Process the BLE command */ + switch(ble_cmd) + { + /* Process BLE stack events */ + case BLE_PROCESS_EVENTS: + { + Cy_BLE_ProcessEvents(); + break; + } + + /* Enable BLE notifications on GATT server device */ + case BLE_ENABLE_NOTIFICATION: + { + /* Stop the 1 second timer */ + xTimerStop(timer_handle,(TickType_t)0); + + /* Send user LED2 status to the LED queue */ + // led_status.data_led = CYBSP_LED_STATE_OFF; + // xQueueSend(led_cmdQ, &led_status, (TickType_t)0); + + /* Enable the notifications */ + if(ble_enable_notification(gatt_notify_cccd_attrHandle) == CY_BLE_SUCCESS) + { + // tprintf("Notifications Enabled\r\n"); + /* Start 1 second timer to calculate throughput */ + xTimerStart(timer_handle, (TickType_t)0); +#ifdef EINK_DISPLAY_SHIELD_PRESENT + /* Notify the display task */ + xTaskNotifyGive(display_task_handle); +#endif + } + else + { + // tprintf("Failed to enable notifications\r\n"); + } + break; + } + + /* Disable BLE notifications on GATT server device */ + case BLE_DISABLE_NOTIFICATION: + { + /* Stop the 1 second timer */ + xTimerStop(timer_handle,(TickType_t)0); + + /* Disable the notifications */ + if(ble_disable_notification(gatt_notify_cccd_attrHandle) == CY_BLE_SUCCESS) + { + // tprintf("Notifications Disabled\r\n"); + /* Start 1 second timer to calculate throughput */ + xTimerStart(timer_handle, (TickType_t)0); +#ifdef EINK_DISPLAY_SHIELD_PRESENT + /* Notify the display task */ + xTaskNotifyGive(display_task_handle); +#endif + } + else + { + //tprintf("Failed to disable notifications\r\n"); + } + + /* Initialize the structure for GATT write */ + ble_initialize_gatt_write(gatt_write_val_attrHandle); + break; + } + + /* Invalid BLE command */ + default: + { + // //iprintf("Invalid BLE command!"); + break; + } + } + /* If notifications are disabled and GATT write is enabled */ + if(gatt_write_flag) + { + /* Check the BLE stack status */ + if(stack_free) + { + /* Write without response into server GATT Write characteristic */ + ble_api_result = Cy_BLE_GATTC_WriteWithoutResponse(&write_param_characteristic); + if(ble_api_result == CY_BLE_SUCCESS) + { + /* Increment bytes count only on successful operation */ + gatt_write_tx_bytes += write_param_characteristic.handleValPair.value.len; + + /* Switch ON LED2 to show data TX */ + // led_status.data_led = CYBSP_LED_STATE_ON; + // xQueueSend(led_cmdQ, &led_status, (TickType_t)0); + } + else + { + /* GATT write failed. Switch OFF LED2 to show there is no data TX */ + // led_status.data_led = CYBSP_LED_STATE_OFF; + // xQueueSend(led_cmdQ, &led_status, (TickType_t)0); + } + } + else + { + /* Stack is busy. Switch OFF LED2 to show data TX stopped */ + // led_status.data_led = CYBSP_LED_STATE_OFF; + // xQueueSend(led_cmdQ, &led_status, (TickType_t)0); + } + } + } + } +} + +/******************************************************************************* +* Function Name: static void ble_init(void) +******************************************************************************** +* Summary: +* This function initializes the BLE Host and Controller, configures BLE +* interrupt, and registers Application Host callbacks. +* +* Parameters: +* None +* +* Return: +* None +* +*******************************************************************************/ +static void ble_init(void) +{ + cy_en_ble_api_result_t ble_api_result = CY_BLE_SUCCESS; + + /* BLESS interrupt configuration structure */ + const cy_stc_sysint_t bless_isr_config = + { + /* The BLESS interrupt */ + .intrSrc = bless_interrupt_IRQn, + + /* The interrupt priority number */ + .intrPriority = BLE_INTERRUPT_PRIORITY + }; + + /* Store the pointer to blessIsrCfg in the BLE configuration structure */ + cy_ble_config.hw->blessIsrConfig = &bless_isr_config; + + /* Hook interrupt service routines for BLESS */ + (void) Cy_SysInt_Init(&bless_isr_config, bless_interrupt_handler); + + /* Register the generic callback functions */ + Cy_BLE_RegisterEventCallback(ble_stack_event_handler); + + /* Register the application Host callback */ + Cy_BLE_RegisterAppHostCallback(ble_controller_interrupt_handler); + + /* Initialize the BLE */ + ble_api_result = Cy_BLE_Init(&cy_ble_config); + if(ble_api_result != CY_BLE_SUCCESS) + { + /* BLE stack initialization failed, check configuration, notify error + * and halt CPU in debug mode + */ + // eprintf("Cy_BLE_Init API, errorcode = 0x%X ", ble_api_result); + vTaskSuspend(NULL); + } + + /* Enable BLE */ + ble_api_result = Cy_BLE_Enable(); + if(ble_api_result != CY_BLE_SUCCESS) + { + /* BLE stack initialization failed, check configuration, notify error + * and halt CPU in debug mode + */ + //eprintf("Cy_BLE_Enable API, errorcode = 0x%X ", ble_api_result); + vTaskSuspend(NULL); + } + /* Process BLE events after enabling BLE */ + Cy_BLE_ProcessEvents(); +} + +/******************************************************************************* +* Function Name: static void bless_interrupt_handler(void) +******************************************************************************** +* Summary: +* Wrapper function for BLESS interrupt +* +* Parameters: +* None +* +* Return: +* None +*******************************************************************************/ +static void bless_interrupt_handler(void) +{ + /* Process interrupt events generated by the BLE sub-system */ + Cy_BLE_BlessIsrHandler(); +} + + +/******************************************************************************* +* Function Name: static void ble_controller_interrupt_handler(void) +******************************************************************************** +* Summary: +* Call back event function to handle interrupts from BLE Controller +* +* Parameters: +* None +* +* Return: +* None +*******************************************************************************/ +static void ble_controller_interrupt_handler(void) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + /* Send command to process BLE events */ + ble_command_type_t bleCommand = BLE_PROCESS_EVENTS; + xQueueSendFromISR(ble_cmdQ, &bleCommand, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + +/************************************************************************************ +* Function Name: static void ble_stack_event_handler(uint32_t event, void *eventParam) +************************************************************************************* +* +* Summary: Call back event function to handle various events from the BLE stack. +* +* Parameters: +* uint32_t event : event from BLE stack +* void eventParam : Pointer to the value of event specific parameters +* +* Return: +* None +************************************************************************************/ +static void ble_stack_event_handler(uint32_t event, void *eventParam, message_struct *message_data) +{ + /* Take an action based on the current event */ + switch(event) + { + /*********************************************************************** + * General Events * + ***********************************************************************/ + /* This event is received when the BLE stack is Started */ + case CY_BLE_EVT_STACK_ON: + { + //iprintf("BLE Stack Event: CY_BLE_EVT_STACK_ON"); + //tprintf("Press button SW2 on your kit to start Scanning ...\r\n"); + + /* Wait till button press to start scanning */ + // ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + /* Start scanning for other BLE devices */ + ble_api_result = Cy_BLE_GAPC_StartScan(CY_BLE_SCANNING_FAST, CY_BLE_CENTRAL_CONFIGURATION_0_INDEX); + if( ble_api_result == CY_BLE_SUCCESS) + { + //tprintf("Scanning.....\r\n"); + //iprintf("BLE Start Scan API successfull"); + } + else + { + // eprintf("BLE Start Scan API, errorcode = 0x%X", ble_api_result); + } + break; + } + + /* This event indicates BLE stack status. This event is used to handle + * data throttling which may occur due to continuous GATT write being + * sent */ + case CY_BLE_EVT_STACK_BUSY_STATUS: + { + /* Variable to store status of the stack */ + cy_stc_ble_l2cap_state_info_t stack_status; + stack_status = *( cy_stc_ble_l2cap_state_info_t*)eventParam; + + if(stack_status.flowState == CY_BLE_STACK_STATE_BUSY) + { + /* If stack is busy, stop GATT write */ + stack_free = false; + } + else + { + /* If stack is free, start GATT write */ + stack_free = true; + } + break; + } + + /* This event is received when there is a timeout */ + case CY_BLE_EVT_TIMEOUT: + { + //iprintf("BLE Stack Event: CY_BLE_EVT_TIMEOUT"); + break; + } + + /*********************************************************************** + * Gap Events * + ***********************************************************************/ + /* This event indicates that the central device has started or stopped + * scanning */ + case CY_BLE_EVT_GAPC_SCAN_START_STOP: + { + //iprintf("BLE Stack Event: CY_BLE_EVT_GAPC_SCAN_START_STOP"); + break; + } + + /* This event is triggered every time a device is discovered */ + case CY_BLE_EVT_GAPC_SCAN_PROGRESS_RESULT: + { + cy_stc_ble_gapc_adv_report_param_t *scan_report; + scan_report = (cy_stc_ble_gapc_adv_report_param_t*)eventParam; + + /* Pointer to store return value from advertisement parser */ + char* peer_name = NULL; + uint8 name_length = 0u; + bool target_found = true; + + /* Process only for Advertisement packets, not on scan response + * packets */ + if(scan_report->eventType == CY_BLE_GAPC_SCAN_RSP) + { + /* Process the adv packets and get peer name if present in the + * packet */ + peer_name = (char*) adv_parser(AD_TYPE_COMPLETE_LOCAL_NAME, scan_report, &name_length); + if(peer_name == NULL) + { + target_found =false; + break; + } + /* Compare peer name with "TPUT" */ + else + { + peer_name[name_length]= '\0'; + //tprintf("Current device is: %c \r\n", peer_name); + target_found = ((strcmp(peer_name, target_name)) ? false : true); + } + + /* If target is found stop scanning and initiate connection */ + if (target_found) + { + Cy_BLE_GAPC_StopScan(); + + /* Get address and address type of the peer device to + * initiate connection */ + for(uint8 i = 0u; i < CY_BLE_BD_ADDR_SIZE; i++) + { + peer_addr.bdAddr[i] = scan_report->peerBdAddr[i]; + } + + //tprintf("Found Peer Device with address:"); + /* Print the peer bd address on UART terminal */ + for(uint8 i = (CY_BLE_BD_ADDR_SIZE); i > 0u; i--) + { + //tprintf(" %X", peer_addr.bdAddr[i - 1u]); + } + + /* Get the peer address type */ + peer_addr.type = scan_report->peerAddrType; + //tprintf("\r\nScan Completed\r\n"); + + /* Initiate connection with discovered peer device */ + ble_api_result = Cy_BLE_GAPC_ConnectDevice(&peer_addr, CY_BLE_CENTRAL_CONFIGURATION_0_INDEX); + if(ble_api_result == CY_BLE_SUCCESS) + { + //iprintf(" SUCCESS : Connection Initiation "); + } + else + { + //eprintf(" Connection Initiation API, errorcode = 0x%X", ble_api_result); + } + } + } + break; + } + + /* This event is generated at the GAP Peripheral end after connection + * is completed with peer Central device */ + case CY_BLE_EVT_GAP_DEVICE_CONNECTED: + { + //iprintf("BLE Stack Event: CY_BLE_EVT_GAP_DEVICE_CONNECTED"); + /* Variable to store connection parameters after GAP connection */ + cy_stc_ble_gap_connected_param_t* conn_param; + conn_param = (cy_stc_ble_gap_connected_param_t*)eventParam; + + /* Variable to store values to update PHY to 2M */ + cy_stc_ble_set_phy_info_t phy_pram; + phy_pram.allPhyMask = CY_BLE_PHY_NO_PREF_MASK_NONE; + phy_pram.bdHandle = conn_handle.bdHandle; + phy_pram.rxPhyMask = CY_BLE_PHY_MASK_LE_1M; + phy_pram.txPhyMask = CY_BLE_PHY_MASK_LE_1M; + + /* Reset the connection status flag upon reconnection */ + device_disconnect_flag = false; + + /* Reset the notify flag and stack_free flag after disconnection */ + gatt_write_flag = false; + stack_free = true; + + /* Store the connection interval value */ + conn_interval = (conn_param->connIntv) * CONN_INTERVAL_MULTIPLIER; + //tprintf("Connection Interval is: %f ms \r\n", conn_interval); + + /* Send user LED1 status to the LED queue */ + // led_status.conn_led = CYBSP_LED_STATE_ON; + // xQueueSend(led_cmdQ, &led_status, (TickType_t)0); + + /* Function call to set PHY to 2M */ + ble_api_result = Cy_BLE_SetPhy(&phy_pram); + if(ble_api_result == CY_BLE_SUCCESS) + { + //iprintf("Set PHY to 2M API successfull \r\n"); + //tprintf("Request sent to switch PHY to 2M \r\n"); + } + else + { + //eprintf("Set PHY API, errorcode = 0x%X", ble_api_result); + } + break; + } + + /* This event is generated when the device is disconnected from remote + * device or fails to establish connection */ + case CY_BLE_EVT_GAP_DEVICE_DISCONNECTED: + { + //iprintf("BLE Stack Event: CY_BLE_EVT_GAP_DEVICE_DISCONNECTED"); + + /* Stop the timer after device disconnection */ + xTimerStop(timer_handle,(TickType_t)0); + + /* Set the device disconnect flag */ + device_disconnect_flag = true; + + /* Reset the button flag to avoid any action due to button press + * after disconnection */ + button_flag = false; + + /* Change the mode flag value to GATT notifications */ + mode_flag = GATT_NOTIF_STOC; + + /* Reset the flags after disconnection */ + notify_cccd_uuid_found = false; + writeme_char_uuid_found =false; + gatt_write_flag = false; + + /* Send user LED1 and LED2 status to the LED queue */ + // led_status.conn_led = CYBSP_LED_STATE_OFF; + // led_status.data_led = CYBSP_LED_STATE_OFF; + // xQueueSend(led_cmdQ, &led_status, (TickType_t)0); + +#ifdef EINK_DISPLAY_SHIELD_PRESENT + /* Notify display task immediately to update E-ink display with + * appropriate message */ + count_five_sec = 0u; + xTaskNotifyGive(display_task_handle); +#endif + //tprintf("Device Disconnected!!!\r\n"); + //tprintf("Press button SW2 on your kit to start Scanning...\r\n"); + + /* Start scanning again after button press */ + scan_flag = false; + /* Wait till button press to start scanning */ + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + ble_api_result = Cy_BLE_GAPC_StartScan(CY_BLE_SCANNING_FAST, CY_BLE_CENTRAL_CONFIGURATION_0_INDEX); + if(ble_api_result == CY_BLE_SUCCESS) + { + //tprintf("Scanning.....\r\n"); + //iprintf("BLE Start Scan API successfull"); + } + else + { + //eprintf("BLE Start Scan API, errorcode = 0x%X", ble_api_result); + } + break; + } + + /* This event is generated when PHY is updated during an active + * connection */ + case CY_BLE_EVT_PHY_UPDATE_COMPLETE: + { + //iprintf("BLE Stack Event: CY_BLE_EVT_PHY_UPDATE_COMPLETE"); + + cy_stc_ble_events_param_generic_t *generic_param; + cy_stc_ble_phy_param_t *currentPHY; + generic_param = (cy_stc_ble_events_param_generic_t*)eventParam; + + /* Local variable to set MTU for the active connection */ + cy_stc_ble_gatt_xchg_mtu_param_t mtuParam = {conn_handle, CY_BLE_GATT_MTU}; + + /* GenericParam has to be cast to cy_stc_ble_phy_param_t to get + * TX and RX PHY */ + currentPHY = (cy_stc_ble_phy_param_t*)(generic_param->eventParams); + + /* Print the RX PHY selected on UART terminal */ + switch(currentPHY->rxPhyMask) + { + case CY_BLE_PHY_MASK_LE_1M: + //tprintf("Selected Rx PHY: 1M\r\n"); + break; + + case CY_BLE_PHY_MASK_LE_2M: + //tprintf("Selected Rx PHY: 2M\r\n"); + break; + + case CY_BLE_PHY_MASK_LE_CODED: + //tprintf("Selected Rx PHY: LE Coded\r\n"); + break; + } + + /* Print the TX PHY selected on UART terminal */ + switch(currentPHY->txPhyMask) + { + case CY_BLE_PHY_MASK_LE_1M: + //tprintf("Selected Tx PHY: 1M\r\n"); + break; + + case CY_BLE_PHY_MASK_LE_2M: + //tprintf("Selected Tx PHY: 2M\r\n"); + break; + + case CY_BLE_PHY_MASK_LE_CODED: + //tprintf("Selected Tx PHY: LE Coded\r\n"); + break; + } + + /* Initiate MTU exchange request */ + ble_api_result = Cy_BLE_GATTC_ExchangeMtuReq(&mtuParam); + if(ble_api_result == CY_BLE_SUCCESS) + { + //iprintf("GATT Exchange MTU Request successfull"); + } + else + { + //eprintf("GATT Exchange MTU Request API, errorcode = 0x%X", ble_api_result); + } + break; + } + + /* This event is generated when connection parameter update is + * requested. If the request is accepted by the Central, this event is + * generated on both the devices. If request is rejected, this event is + * not generated */ + case CY_BLE_EVT_GAP_CONNECTION_UPDATE_COMPLETE: + { + //iprintf("BLE Stack Event: CY_BLE_EVT_GAP_CONNECTION_UPDATE_COMPLETE"); + cy_stc_ble_gap_conn_param_updated_in_controller_t new_conn_params; + new_conn_params = *((cy_stc_ble_gap_conn_param_updated_in_controller_t*)eventParam); + + /* Store the new connection interval */ + conn_interval = (new_conn_params.connIntv) * CONN_INTERVAL_MULTIPLIER; + + //tprintf("Updated Connection interval : %f ms\r\n", conn_interval); + break; + } + + /*********************************************************************** + * GATT Events * + ***********************************************************************/ + /* This event is generated at the GAP Peripheral end after connection + * is completed with peer Central device + */ + case CY_BLE_EVT_GATT_CONNECT_IND: + { + conn_handle = *((cy_stc_ble_conn_handle_t*)eventParam); + //iprintf("BLE Stack Event: CY_BLE_EVT_GATT_CONNECT_IND"); + //tprintf("GATT connected\r\n"); + /* Start 1 second timer to calculate throughput */ + xTimerStart(timer_handle, (TickType_t)0); + break; + } + + /* This event indicates that the GATT is disconnected.*/ + case CY_BLE_EVT_GATT_DISCONNECT_IND: + { + //iprintf("BLE Stack Event: CY_BLE_EVT_GATT_DISCONNECT_IND"); + break; + } + + /* This event is generated when response is received from GATT Server + * for MTU exchange request */ + case CY_BLE_EVT_GATTC_XCHNG_MTU_RSP: + { + //iprintf("BLE Stack Event: CY_BLE_EVT_GATTC_XCHNG_MTU_RSP"); + cy_stc_ble_gatt_xchg_mtu_param_t *mtu_xchg_resp = + (cy_stc_ble_gatt_xchg_mtu_param_t*)eventParam; + + cy_stc_ble_gattc_find_info_req_t find_req_param; + find_req_param.connHandle = conn_handle; + /* 0x0001 - 0xFFFF is the range of attribute handles that can be present in a GATT database*/ + find_req_param.range.startHandle = 0x01; + find_req_param.range.endHandle = 0xFFFF; + + //tprintf("Negotiated MTU size: %d\r\n", mtu_xchg_resp->mtu); + if(mtu_xchg_resp->mtu > CY_BLE_GATT_MTU) + { + att_mtu_size = CY_BLE_GATT_MTU; + } + else + { + att_mtu_size = mtu_xchg_resp->mtu; + } + + cy_stc_ble_gattc_read_by_type_req_t param; + param.range.startHandle=0x0063; + param.range.endHandle=0x0064; + param.connHandle=conn_handle; + param.uuidFormat=CY_BLE_GATT_16_BIT_UUID_FORMAT; + param.uuid.uuid16=0x2A37; + ble_api_result= Cy_BLE_GATTC_DiscoverCharacteristicByUuid(¶m); + if(ble_api_result == CY_BLE_SUCCESS) + { + //tprintf("ReadCharacteristic value success \r\n"); + } + else + { + //tprintf("ReadCharacteristicValue, errorcode = 0x%X \r\n", ble_api_result); + } + break; + } + + /* This event indicates that the 'Find Information Response' is received + * from GATT Server device */ + case CY_BLE_EVT_GATTC_FIND_INFO_RSP: + { + //iprintf("BLE Stack Event: CY_BLE_EVT_GATTC_FIND_INFO_RSP"); + + cy_stc_ble_gattc_find_info_rsp_param_t find_info_param; + + find_info_param = *((cy_stc_ble_gattc_find_info_rsp_param_t*)eventParam); + int index = 0u; + uint8_t notify_cccd_uuid[NOTIFY_CCCD_SIZE] = NOTIFY_CCCD_UUID; + uint8_t writeme_char_uuid[WRITEME_CHAR_UUID_SIZE] = WRITEME_CHAR_UUID; + + /* Search for 'WriteMe' characteristic UUID and get the attribute + * handle */ + if(!writeme_char_uuid_found) + { + for (index = 0u; index < WRITEME_CHAR_UUID_SIZE; index++) + { + writeme_char_uuid_found =(find_info_param.handleValueList.list[index + 2] + != writeme_char_uuid[index]) ? false : true; + } + if(writeme_char_uuid_found) + { + gatt_write_val_attrHandle= find_info_param.handleValueList.list[0] + | (find_info_param.handleValueList.list[1] << 8 ); + //iprintf("Att Handle of Custom characteristic: 0x%X", gatt_write_val_attrHandle); + } + } + + /* Search for the CCCD UUID (0x2902) to identify the the CCCD + * attribute and get the handle */ + if(!notify_cccd_uuid_found) + { + for(index = 0u; index < NOTIFY_CCCD_SIZE; index++) + { + notify_cccd_uuid_found = (find_info_param.handleValueList.list[index + 2] != + notify_cccd_uuid[index]) ? false : true; + } + if(notify_cccd_uuid_found) + { + gatt_notify_cccd_attrHandle= find_info_param.handleValueList.list[0] + | (find_info_param.handleValueList.list[1] << 8 ); + //iprintf("Att Handle of Custom characteristic: 0x%X",gatt_notify_cccd_attrHandle); + } + } + + + /* If both the UUIDs are found, stop discovering characteristics */ + if((notify_cccd_uuid_found == true) && (writeme_char_uuid_found == true)) + { + cy_stc_ble_gattc_stop_cmd_param_t stop_cmd; + stop_cmd.connHandle = conn_handle; + Cy_BLE_GATTC_StopCmd(&stop_cmd); + } + break; + } + + case CY_BLE_EVT_GATTC_READ_RSP: + { + cy_stc_ble_gattc_read_rsp_param_t read_info_param; + read_info_param = *((cy_stc_ble_gattc_read_rsp_param_t*)eventParam); + message_data->pulse = read_info_param.value.val; + //tprintf("Characteristick value is = 0x%X \r\n", read_info_param.value.val); + break; + } + + case CY_BLE_EVT_GATTC_READ_BY_TYPE_RSP: + { + cy_stc_ble_gattc_read_by_type_rsp_param_t read_info_param; + read_info_param = *((cy_stc_ble_gattc_read_by_type_rsp_param_t*)eventParam); + //tprintf("Characteristick value is = 0x%X \r\n", read_info_param.attrData.attrValue); + break; + } + + /* This event indicates that the GATT long procedure has ended and the + * BLE Stack will not send any further requests to the peer */ + case CY_BLE_EVT_GATTC_LONG_PROCEDURE_END: + { + //iprintf("BLE Stack Event: CY_BLE_EVT_GATTC_LONG_PROCEDURE_END"); + break; + } + + /* This event is received by the GATT Client when the GATT Server cannot + * perform the requested operation and sends out an error response */ + case CY_BLE_EVT_GATTC_ERROR_RSP: + { + cy_stc_ble_gatt_err_param_t error_rsp; + error_rsp = *((cy_stc_ble_gatt_err_param_t*)eventParam); + //iprintf("BLE Stack Event: CY_BLE_EVT_GATTC_ERROR_RSP"); + /* To suppress compiler warning */ + (void)error_rsp; + break; + } + + /* This event indicates that a GATT group procedure has stopped or + * completed. This event occurs only if the application has called the + * Cy_BLE_GATTC_StopCmd() function. */ + case CY_BLE_EVT_GATTC_STOP_CMD_COMPLETE: + { + //iprintf("BLE Stack Event: CY_BLE_EVT_GATTC_STOP_CMD_COMPLETE"); + //tprintf("Attributes discovery complete\r\n"); + + /* Enable notification for the custom throughput service */ + ble_enable_notification(gatt_notify_cccd_attrHandle); +#ifdef EINK_DISPLAY_SHIELD_PRESENT + /* Notify the display task */ + xTaskNotifyGive(display_task_handle); +#endif + break; + } + + /* This event indicates that the 'Write Response' is received from GATT + * Server device. */ + case CY_BLE_EVT_GATTC_WRITE_RSP: + { + button_flag = true; + //iprintf("BLE Stack Event: CY_BLE_EVT_GATTC_WRITE_RSP"); + break; + } + + /* This event indicates that Notification data is received from GATT + * Server device. */ + case CY_BLE_EVT_GATTC_HANDLE_VALUE_NTF: + { + cy_stc_ble_gattc_handle_value_ntf_param_t *notif_parameter; + notif_parameter = (cy_stc_ble_gattc_handle_value_ntf_param_t*)eventParam; + + /* Increment the notification byte count */ + notif_rx_bytes += notif_parameter->handleValPair.value.len; + break; + } + + /*********************************************************************** + * L2CAP Events * + ***********************************************************************/ + /* This event indicates that the connection parameter update request + * is receivedfrom the remote device. */ + case CY_BLE_EVT_L2CAP_CONN_PARAM_UPDATE_REQ: + { + cy_stc_ble_gap_conn_update_param_info_t* conn_param; + conn_param = (cy_stc_ble_gap_conn_update_param_info_t*)eventParam; + + cy_stc_ble_l2cap_conn_update_param_rsp_info_t conn_param_update_rsp + = {true, conn_handle.bdHandle}; + + /* Check minimum and maximum connection interval requested by + * peripheral device */ + //tprintf("Connection Interval Update request received\r\n"); + if((conn_param->connIntvMin >= 54u) && (conn_param->connIntvMax <= 60u)) + { + conn_param_update_rsp.result = false; + //tprintf("Connection interval update request accepted\r\n"); + Cy_BLE_L2CAP_LeConnectionParamUpdateResponse(&conn_param_update_rsp); + } + else + { + conn_param_update_rsp.result = true; + //tprintf("Connection interval update request rejected\r\n"); + Cy_BLE_L2CAP_LeConnectionParamUpdateResponse(&conn_param_update_rsp); + } + break; + } + /*********************************************************************** + * Other Events * + ***********************************************************************/ + default: + { + //iprintf("Other BLE event: 0x%X", (uint32_t)event); + break; + } + } +} + +/*********************************************************************************************************** +* Function Name: cy_en_ble_api_result_t ble_enable_notification(cy_ble_gatt_db_attr_handle_t attribute_handle) +************************************************************************************************************ +* +* Summary: This function writes to the CCCD of custom characteristic +* 'GATT Notify' and enables notifications. +* +* Parameters: +* cy_ble_gatt_db_attr_handle_t attribute_handle : peer CCCD attribute details +* +* Return: +* cy_en_ble_api_result_t : error codes received as API result +* +***********************************************************************************************************/ +static cy_en_ble_api_result_t ble_enable_notification(cy_ble_gatt_db_attr_handle_t attribute_handle) +{ + cy_stc_ble_gattc_write_req_t write_param_notification; + + write_param_notification.connHandle = conn_handle; + write_param_notification.handleValPair.attrHandle = attribute_handle; + write_param_notification.handleValPair.value.val = CCCD_VALUE; + write_param_notification.handleValPair.value.len = NOTIFY_CCCD_SIZE; + + /* Clear TX/RX data byte count */ + gatt_write_tx_bytes = 0u; + notif_rx_bytes = 0u; + + /* Enable notification */ + ble_api_result = Cy_BLE_GATTC_WriteCharacteristicValue(&write_param_notification); + + return(ble_api_result); +} + +/************************************************************************************************************ +* Function Name: cy_en_ble_api_result_t ble_disable_notification(cy_ble_gatt_db_attr_handle_t attribute_handle) +************************************************************************************************************* +* +* Summary: This function writes to the CCCD of custom characteristic +* 'GATT Notify' and disables notifications. +* +* Parameters: +* cy_ble_gatt_db_attr_handle_t attribute_handle : peer CCCD attribute details +* +* Return: +* cy_en_ble_api_result_t : error codes received as API result +* +************************************************************************************************************/ +static cy_en_ble_api_result_t ble_disable_notification(cy_ble_gatt_db_attr_handle_t attribute_handle) +{ + cy_stc_ble_gattc_write_req_t write_param_notification; + + write_param_notification.connHandle = conn_handle; + write_param_notification.handleValPair.attrHandle = attribute_handle; + write_param_notification.handleValPair.value.val = &CCCD_VALUE[1]; + write_param_notification.handleValPair.value.len = NOTIFY_CCCD_SIZE; + + /* Clear TX/RX data byte count */ + gatt_write_tx_bytes = 0u; + notif_rx_bytes = 0u; + + /* Disable Notification */ + ble_api_result = Cy_BLE_GATTC_WriteCharacteristicValue(&write_param_notification); + + return(ble_api_result); +} + +/****************************************************************************************** +* Function Name: void ble_initialize_gatt_write(cy_ble_gatt_db_attr_handle_t attribute_handle) +******************************************************************************************* +* +* Summary: This function stores the attribute handle and custom data for GATT +* write. +* +* Parameters: +* cy_ble_gatt_db_attr_handle_t attribute_handle : peer attribute details +* +* Return: +* None +* +******************************************************************************************/ +static void ble_initialize_gatt_write(cy_ble_gatt_db_attr_handle_t attribute_handle) +{ + /* Variable to hold custom data to write into server GATT database. + * Size of the array is derived from MTU exchanged. + * Packet Length = (ATT_MTU - ATT_OPCODE(1 byte) - ATT_HANDLE(2 bytes)) */ + uint8_t custom_data_length = (att_mtu_size -3u); + uint8_t custom_write_data[CY_BLE_GATT_MTU] = {0}; + + cy_stc_ble_gatt_value_t writeValue = {custom_write_data, custom_data_length, custom_data_length}; + + write_param_characteristic.connHandle = conn_handle; + write_param_characteristic.handleValPair.attrHandle = attribute_handle; + write_param_characteristic.handleValPair.value = writeValue; +} + +/*************************************************************************************************************************** +* Function Name: uint8* adv_parser(uint16_t AD_type,cy_stc_ble_gapc_adv_report_param_t* scan_report, uint8* adv_type_length) +**************************************************************************************************************************** +* +* Summary: This function searches adv packets for the given type. +* +* Parameters: +* uint16_t AD_type : the type of value to be discovered +* cy_stc_ble_gapc_adv_report_param_t* scan_report : advertisement report +* parameter +* uint8* adv_type_length : length of discovered value +* +* Return: +* uint8* : Pointer to the value discovered in ADV packet +* +***************************************************************************************************************************/ +static uint8* adv_parser(uint16_t AD_type, cy_stc_ble_gapc_adv_report_param_t* + scan_report, uint8* adv_type_length) +{ + uint8 length =0u; + uint8* pName = NULL; + + for(uint8 i=0u; idataLen; i+=length+1) + { + length = scan_report->data[i]; + if(scan_report->data[i+1] == AD_type) + { + pName = & scan_report->data[i+2]; + *adv_type_length = length-1; + return pName; + } + } + return ((uint8*)NULL); +} + +/******************************************************************************* +* Function Name: void rtos_timer_cb(TimerHandle_t timer_handle) +******************************************************************************** +* Summary: This is a freeRTOS Software timer callback function. It calculates +* the throughput and displays the value over UART terminal. +* +* Parameters: +* TimerHandle_t timer_handle: parameter defined during timer creation (unused) +* +* Return: +* None +*******************************************************************************/ +void rtos_timer_cb(TimerHandle_t timer_handle) +{ + /* Avoid warning for unused parameter */ + (void)timer_handle; + + client_throughput.rx = 0u; + client_throughput.tx = 0u; + + /* Calculate TX and RX throughput + * + * throughput(kbps) = (number of bytes sent/received in 1 second) * 8(bits) + * ----------------------------------------------------- + * 1 second * 2^10 (kilo) + */ + + if(notif_rx_bytes != 0u) + { + /* Number of bytes */ + client_throughput.rx = (notif_rx_bytes) >> 7u; + notif_rx_bytes = 0u; + //tprintf("GATT NOTIFICATION: Client Throughput Rx = %lu kbps\r\n", client_throughput.rx); + } + + if(gatt_write_tx_bytes != 0u) + { + client_throughput.tx = (gatt_write_tx_bytes) >> 7u; + gatt_write_tx_bytes = 0u; + //tprintf("GATT WRITE: Client Throughput Tx = %lu kbps\r\n", client_throughput.tx); + + } + +#ifdef EINK_DISPLAY_SHIELD_PRESENT + count_five_sec++; + if(count_five_sec == 5u) + { + /* Notify the display task */ + xTaskNotifyGive(display_task_handle); + count_five_sec = 0u; + } +#endif +} + +/******************************************************************************* +* Function Name: throughput_val_t* get_throughput(void) +******************************************************************************** +* Summary: This function returns the pointer to the tx and rx throughput values. +* +* Parameters: +* None +* +* Return: +* throughput_val_t* gatt_throughput: BLE gatt throughput calculated in ble task. +*******************************************************************************/ +throughput_val_t* get_throughput(void) +{ + return(&client_throughput); +} +/* [] END OF FILE */ diff --git a/firmware/MedButton/ble_task.h b/firmware/MedButton/ble_task.h new file mode 100644 index 0000000..f088c2f --- /dev/null +++ b/firmware/MedButton/ble_task.h @@ -0,0 +1,99 @@ +/****************************************************************************** +* File Name: ble_task.h +* +* Description: This file is public interface of ble_task.c source file +* +* Related Document: Readme.md +* +******************************************************************************* +* Copyright (2020), Cypress Semiconductor Corporation. All rights reserved. +******************************************************************************* +* This software, including source code, documentation and related materials +* ("Software"), is owned by Cypress Semiconductor Corporation or one of its +* subsidiaries ("Cypress") and is protected by and subject to worldwide patent +* protection (United States and foreign), United States copyright laws and +* international treaty provisions. Therefore, you may use this Software only +* as provided in the license agreement accompanying the software package from +* which you obtained this Software ("EULA"). +* +* If no EULA applies, Cypress hereby grants you a personal, non-exclusive, +* non-transferable license to copy, modify, and compile the Software source +* code solely for use in connection with Cypress's integrated circuit products. +* Any reproduction, modification, translation, compilation, or representation +* of this Software except as specified above is prohibited without the express +* written permission of Cypress. +* +* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Cypress +* reserves the right to make changes to the Software without notice. Cypress +* does not assume any liability arising out of the application or use of the +* Software or any product or circuit described in the Software. Cypress does +* not authorize its products for use in any products where a malfunction or +* failure of the Cypress product may reasonably be expected to result in +* significant property damage, injury or death ("High Risk Product"). By +* including Cypress's product in a High Risk Product, the manufacturer of such +* system or application assumes all risk of such use and in doing so agrees to +* indemnify Cypress against all liability. +******************************************************************************/ + +/****************************************************************************** + * Include guard + *****************************************************************************/ +#ifndef RTOS_FILES_BLE_TASK_H_ +#define RTOS_FILES_BLE_TASK_H_ + +/****************************************************************************** + * Include header files + *****************************************************************************/ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "timers.h" + +/****************************************************************************** + * Structures and Enumerations + *****************************************************************************/ +/* Enumeration for BLE command types */ +typedef enum +{ + BLE_PROCESS_EVENTS, + BLE_ENABLE_NOTIFICATION, + BLE_DISABLE_NOTIFICATION +}ble_command_type_t; + +/* Enumeration for data transfer modes */ +typedef enum +{ + GATT_NOTIF_STOC =0, + GATT_WRITE_CTOS, + GATT_WRITE_AND_NOTIF +}tx_rx_mode; + +/* Structure to hold TX and RX throughput value */ +typedef struct +{ + uint32_t tx; + uint32_t rx; +}throughput_val_t; + +/****************************************************************************** + * External global references + *****************************************************************************/ +extern QueueHandle_t ble_cmdQ; +extern TaskHandle_t ble_task_handle; +extern TimerHandle_t timer_handle; +extern tx_rx_mode mode_flag; +extern bool gatt_write_flag; +extern bool button_flag; +extern bool scan_flag; +extern bool device_disconnect_flag; + +/****************************************************************************** + * Function prototypes + *****************************************************************************/ +void task_BLE(void *pvParameters); +void rtos_timer_cb(TimerHandle_t); +throughput_val_t* get_throughput(void); +#endif /* RTOS_FILES_BLE_TASK_H_ */ +/* [] END OF FILE */ diff --git a/firmware/MedButton/data_struct.h b/firmware/MedButton/data_struct.h new file mode 100644 index 0000000..54a99d6 --- /dev/null +++ b/firmware/MedButton/data_struct.h @@ -0,0 +1,19 @@ +#ifndef C_DATA_STRUCT_H +#define C_DATA_STRUCT_H + +#include "FreeRTOS.h" +#include "semphr.h" + +struct message_struct { + float latitude; + float longitude; + char resultTime[11]; + int pulse; + SemaphoreHandle_t mutex; + SemaphoreHandle_t semaphore_gprs; + SemaphoreHandle_t semaphore_lora; +}; + +typedef struct message_struct message_struct; + +#endif //C_DATA_STRUCT_H \ No newline at end of file diff --git a/firmware/MedButton/deps/bless.mtb b/firmware/MedButton/deps/bless.mtb new file mode 100644 index 0000000..f3b26c8 --- /dev/null +++ b/firmware/MedButton/deps/bless.mtb @@ -0,0 +1 @@ +https://github.com/cypresssemiconductorco/bless#release-v3.50.0#$$ASSET_REPO$$/bless/release-v3.50.0 diff --git a/firmware/MedButton/gprs_task.c b/firmware/MedButton/gprs_task.c new file mode 100644 index 0000000..2dd7aac --- /dev/null +++ b/firmware/MedButton/gprs_task.c @@ -0,0 +1,116 @@ +#include "gprs_task.h" + +#define LED_RED (P12_5) +#define GPRS_SETUP (P9_2) + +cyhal_uart_t gprs_uart; +uint8_t rx_buf[64]; + +const cyhal_uart_cfg_t uart_config_gprs = +{ + .data_bits = 8, + .stop_bits = 1, + .parity = CYHAL_UART_PARITY_NONE, + .rx_buffer = rx_buf, + .rx_buffer_size = 64, +}; + + +void wait_uart_free(cyhal_uart_t *uart_obj) +{ + while (cyhal_uart_is_rx_active(uart_obj)) { cyhal_system_delay_ms(1); } + while (cyhal_uart_is_tx_active(uart_obj)) { cyhal_system_delay_ms(1); } +} + +void uart_send_cmd_and_wait(char *cmd, size_t cmd_len, cyhal_uart_t *uart_obj) +{ + cy_rslt_t result; + wait_uart_free(uart_obj); + if (cmd_len > 1) + { + result = cyhal_uart_write_async(uart_obj, cmd, cmd_len); + } + else + { + result = cyhal_uart_putc(uart_obj, cmd[0]); + } + + if (CY_RSLT_SUCCESS != result) + { + while(1) + { + cyhal_gpio_toggle(LED_RED); + cyhal_system_delay_ms(100); + } + } + + wait_uart_free(uart_obj); + // bool data_received = false; + // while(cyhal_uart_readable(uart_obj) != 0) + // { + // data_received = true; + // uint8_t received_char; + // if (CY_RSLT_SUCCESS == cyhal_uart_getc(uart_obj, &received_char, 1)) + // { + // //printf("%c", received_char); + // } + // } + // if (data_received) + // { + // //printf("\n"); + // } + cyhal_system_delay_ms(3000); +} + +static void gprs_setup(void) { + cy_rslt_t rslt; + rslt = cyhal_gpio_init(GPRS_SETUP, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, false); + + if (rslt != CY_RSLT_SUCCESS) { + //printf("Not powered\r\n"); + } + + cyhal_gpio_write(GPRS_SETUP, false); + cyhal_system_delay_ms(1000); + cyhal_gpio_write(GPRS_SETUP, true); + cyhal_system_delay_ms(2000); + cyhal_gpio_write(GPRS_SETUP, false); + cyhal_system_delay_ms(3000); +} + +void task_gprs(void* param) { + /* uart GPRS */ + message_struct *message_data = (message_struct*) param; + + cy_rslt_t result; + + cyhal_uart_t gprs_uart; + + result = cyhal_uart_init(&gprs_uart, P9_1, P9_0, NULL, &uart_config_gprs); + + if (result == CY_RSLT_SUCCESS) + { + cyhal_uart_set_baud(&gprs_uart, 115200, NULL); + } + + gprs_setup(); + + char message[50]; + while (1) { + if (xSemaphoreTake(message_data->semaphore_gprs, 5000)) { + xSemaphoreTake(message_data->mutex, portMAX_DELAY); + sprintf(message, "%s-%f,%f", message_data->resultTime, message_data->latitude, message_data->longitude); + xSemaphoreGive(message_data->mutex); + char at_cmd[] = "AT\r"; + uart_send_cmd_and_wait(at_cmd, sizeof(at_cmd), &gprs_uart); + char sms_config_cmd[] = "AT+CMGF=1\r"; + uart_send_cmd_and_wait(sms_config_cmd, sizeof(sms_config_cmd), &gprs_uart); + char sms_prepare_cmd[] = "AT+CMGS=\"+380958957865\"\r"; + uart_send_cmd_and_wait(sms_prepare_cmd, sizeof(sms_prepare_cmd), &gprs_uart); + cyhal_uart_clear(&gprs_uart); + uart_send_cmd_and_wait(message, sizeof(message), &gprs_uart); + char sms_stop_cmd[] = { (char)26 }; + uart_send_cmd_and_wait(sms_stop_cmd, 1, &gprs_uart); + } + } +} \ No newline at end of file diff --git a/firmware/MedButton/gprs_task.h b/firmware/MedButton/gprs_task.h new file mode 100644 index 0000000..fc2bc35 --- /dev/null +++ b/firmware/MedButton/gprs_task.h @@ -0,0 +1,13 @@ +#ifndef C_GPRS_TASK_H +#define C_GPRS_TASK_H + +#include "cyhal.h" +#include "cybsp.h" +#include "cy_retarget_io.h" +#include "data_struct.h" + +void task_gprs(void* param); +void uart_send_cmd_and_wait(char *cmd, size_t cmd_len, cyhal_uart_t *uart_obj); +void wait_uart_free(cyhal_uart_t *uart_obj); + +#endif //C_GPRS_TASK_H \ No newline at end of file diff --git a/firmware/MedButton/gps_task.c b/firmware/MedButton/gps_task.c new file mode 100644 index 0000000..7386ada --- /dev/null +++ b/firmware/MedButton/gps_task.c @@ -0,0 +1,165 @@ +#include "gps_task.h" +#include + + +const cyhal_uart_cfg_t uart_config = +{ + .data_bits = 8, + .stop_bits = 1, + .parity = CYHAL_UART_PARITY_NONE, + .rx_buffer = NULL, + .rx_buffer_size = 0, +}; + +const char disable_nmea[10][30] = { + "$PUBX,40,GLL,0,0,0,0,0,0*5C\r\n", + "$PUBX,40,ZDA,0,0,0,0,0,0*44\r\n", + "PUBX,40,VTG,0,0,0,0,0,0*5E\r\n", + "PUBX,40,GSV,0,0,0,0,0,0*59\r\n", + "$PUBX,40,GSA,0,0,0,0,0,0*4E\r\n", + "$PUBX,40,RMC,0,0,0,0,0,0*47\r\n", + "$PUBX,40,GNS,0,0,0,0,0,0*41\r\n", + "$PUBX,40,GRS,0,0,0,0,0,0*5D\r\n", + "$PUBX,40,GST,0,0,0,0,0,0*5B\r\n", + "$PUBX,40,TXT,0,0,0,0,0,0*43\r\n", +}; + +void task_gps(void* param) { + /* uart GPS */ + message_struct *message_data = (message_struct*) param; + message_data->longitude = 0.0; + message_data->latitude = 0.0; + + cy_rslt_t result; + + cyhal_uart_t gps_uart; + + result = cyhal_uart_init(&gps_uart, P10_1, P10_0, NULL, &uart_config); + + if (result == CY_RSLT_SUCCESS) + { + result = cyhal_uart_set_baud(&gps_uart, 9600, NULL); + } + + // for (size_t i = 0; i < 10; i++) { + // uart_send_cmd_and_wait(disable_nmea[i], 30, &gps_uart); + // } + + /* GPS TASK */ + uint8_t c = 0; + int k, index; + char nmea[20], time[20]; + char lon[20], lat[20]; + int len; + float ignore; + + //read and parse raw NMEA sentences + + for (;;) + { + if (cyhal_uart_getc(&gps_uart, &c, 0) == CY_RSLT_SUCCESS) + { + if (c) + { + if (c == '$') + { + for (k = 0; k < 5; k++) + { + cyhal_uart_getc(&gps_uart, &c, 0); + while (!(c)) + { + cyhal_uart_getc(&gps_uart, &c, 0); + } + nmea[k] = c; // G + P + G + G + A + } + + if (strstr(nmea, "GPGGA")) + { + memset(lon, 0, sizeof lon); + memset(lat, 0, sizeof lat); + memset(time, 0, sizeof time); + index = 0; + cyhal_uart_getc(&gps_uart, &c, 0); + cyhal_uart_getc(&gps_uart, &c, 0); + while (!(c == ',')) + { + time[index] = c; + ++index; + cyhal_uart_getc(&gps_uart, &c, 0); + } + index = 0; + cyhal_uart_getc(&gps_uart, &c, 0); + while (!(c == ',')) + { + lat[index] = c; + ++index; + cyhal_uart_getc(&gps_uart, &c, 0); + } + cyhal_uart_getc(&gps_uart, &c, 0); + + index = 0; + cyhal_uart_getc(&gps_uart, &c, 0); + cyhal_uart_getc(&gps_uart, &c, 0); + while (!(c == ',')) + { + lon[index] = c; + ++index; + cyhal_uart_getc(&gps_uart, &c, 0); + } + cyhal_uart_getc(&gps_uart, &c, 0); + sscanf(lon, "%f %n", &ignore, &len); + + /// check if new longitude isn't empty + if (lon[0] != '\0') { + xSemaphoreTake(message_data->mutex, portMAX_DELAY); + message_data->longitude = NMEAtoDecimalDegrees(lon, c); + message_data->latitude = NMEAtoDecimalDegrees(lat, c); + UTCtoKyivTime(time, message_data); + xSemaphoreGive(message_data->mutex); + } + cyhal_system_delay_ms(5000); + } + } + } + } + } +} + + +float NMEAtoDecimalDegrees(const char *degree, char quadrant) +{ + // nmea format: "ddmm.mmmm" or "dddmm.mmmm" to decimal degrees + // D+M/60 + float result = 0; + if (strlen(degree) > 5) + { + char integerPart[3 + 1]; + int counter = (degree[4] == '.' ? 2 : 3); + memcpy(integerPart, degree, counter); + integerPart[counter] = 0; + degree += counter; + result = atoi(integerPart) + atof(degree) / 60.; + if (quadrant == 'W' || quadrant == 'S') + result = -result; + } + return result; +} + +char *UTCtoKyivTime(const char *utcTime, message_struct *message_data) +{ + // 172814.0 - hhmmss.ss + int i, digit, number = 0; + char c; + for (i = 0; i < 2; i++) + { + c = utcTime[i]; + if (c >= '0' && c <= '9') //to confirm it's a digit + { + digit = c - '0'; + number = number * 10 + digit; + } + } + number = (number + 2) % 24; + sprintf(message_data->resultTime, "%d:%c%c:%c%c", number, utcTime[2], utcTime[3], utcTime[4], utcTime[5]); + return 0; +} \ No newline at end of file diff --git a/firmware/MedButton/gps_task.h b/firmware/MedButton/gps_task.h new file mode 100644 index 0000000..0779b89 --- /dev/null +++ b/firmware/MedButton/gps_task.h @@ -0,0 +1,13 @@ +#ifndef C_GPS_TASK_H +#define C_GPS_TASK_H + +#include "cyhal.h" +#include "cybsp.h" +#include "cy_retarget_io.h" +#include "data_struct.h" + +void task_gps(void* param); +char *UTCtoKyivTime(const char *utcTime, message_struct *message_data); +float NMEAtoDecimalDegrees(const char *degree, char quadrant); + +#endif //C_GPS_TASK_H \ No newline at end of file diff --git a/firmware/MedButton/lora_task.c b/firmware/MedButton/lora_task.c new file mode 100644 index 0000000..353806e --- /dev/null +++ b/firmware/MedButton/lora_task.c @@ -0,0 +1,69 @@ +#include "lora_task.h" +#include "cyhal.h" +#include "cybsp.h" +#include "cy_retarget_io.h" +#include "OnethinxCore01.h" +#include "LoRaWAN_keys.h" +#include "data_struct.h" +#include + +#define LED_BLUE (P12_4) + +coreStatus_t coreStatus; +coreInfo_t coreInfo; + +uint8_t RXbuffer[64]; +uint8_t TXbuffer[64]; + + +coreConfiguration_t coreConfig = { + .Join.KeysPtr = &TTN_OTAAkeys, + .Join.DataRate = DR_AUTO, + .Join.Power = PWR_MAX, + .Join.MAXTries = 100, + .Join.SubBand_1st = EU_SUB_BANDS_DEFAULT, + .Join.SubBand_2nd = EU_SUB_BANDS_DEFAULT, + .TX.Confirmed = false, + .TX.DataRate = DR_0, + .TX.Power = PWR_MAX, + .TX.FPort = 1, +}; + +void lora_send(void* param) { + message_struct * message_data = (message_struct*) param; + + coreStatus = LoRaWAN_Init(&coreConfig); + // /* Check Onethinx Core info */ + LoRaWAN_GetInfo(&coreInfo); + /* send join using parameters in coreConfig, blocks until either success or MAXtries */ + coreStatus = LoRaWAN_Join(true); + + // /* check for successful join */ + if (!coreStatus.mac.isJoined){ + // while(1) { + cyhal_gpio_toggle(LED_BLUE); + cyhal_system_delay_ms(100); + // } + } else { + cyhal_gpio_write(LED_BLUE, true); + /*delay before first message will be sent */ + cyhal_system_delay_ms(1000); + } + + char message[50]; + while(1) { + if(xSemaphoreTake(message_data->semaphore_lora, 5000)) { + xSemaphoreTake(message_data->mutex, portMAX_DELAY); + sprintf(message, "%s-%f,%f", message_data->resultTime, message_data->latitude, message_data->longitude); + xSemaphoreGive(message_data->mutex); + coreStatus = LoRaWAN_Send((uint8_t *) message, 64, true); + cyhal_system_delay_ms(1000); // vTaskDelay + if( coreStatus.system.errorStatus == system_BusyError ){ + for(int i=0; i<10; i++){ + cyhal_gpio_toggle(LED_BLUE);; + cyhal_system_delay_ms(100); + } + } + } + } +} \ No newline at end of file diff --git a/firmware/MedButton/lora_task.h b/firmware/MedButton/lora_task.h new file mode 100644 index 0000000..f827bde --- /dev/null +++ b/firmware/MedButton/lora_task.h @@ -0,0 +1,6 @@ +#ifndef C_LORA_TASK_H +#define C_LORA_TASK_H + +void lora_send(void* param); + +#endif //C_LORA_TASK_H \ No newline at end of file diff --git a/firmware/MedButton/main.c b/firmware/MedButton/main.c index b82beea..4c503a6 100644 --- a/firmware/MedButton/main.c +++ b/firmware/MedButton/main.c @@ -1,32 +1,44 @@ #include "cyhal.h" #include "cybsp.h" +#include "cy_retarget_io.h" +#include "cy_pdl.h" +#include #include "FreeRTOS.h" #include "task.h" -#include "cy_retarget_io.h" -#include "OnethinxCore01.h" -#include "LoRaWAN_keys.h" +#include "queue.h" +#include "semphr.h" +#include "ble_task.h" +#include "gps_task.h" +#include "gprs_task.h" +#include "lora_task.h" -coreStatus_t coreStatus; -coreInfo_t coreInfo; +message_struct message_str; -uint8_t RXbuffer[64]; -uint8_t TXbuffer[64]; +cyhal_timer_t timer; #define LED_BLUE (P12_4) #define LED_RED (P12_5) -coreConfiguration_t coreConfig = { - .Join.KeysPtr = &TTN_OTAAkeys, - .Join.DataRate = DR_AUTO, - .Join.Power = PWR_MAX, - .Join.MAXTries = 100, - .Join.SubBand_1st = EU_SUB_BANDS_DEFAULT, - .Join.SubBand_2nd = EU_SUB_BANDS_DEFAULT, - .TX.Confirmed = false, - .TX.DataRate = DR_0, - .TX.Power = PWR_MAX, - .TX.FPort = 1, -}; +#define TASK (256u) +#define TASK_GPRS (512u) +#define TASK_BLE (configMINIMAL_STACK_SIZE * 4) + + +#define TIMER_CLOCK_HZ (10000) +#define TIMER_PERIOD (9999 * 60) + +#define BLE_CMD_Q_LEN (10u) + +static void gpio_interrupt_handler(void *handler_arg, cyhal_gpio_event_t event); +static void isr_timer(void *callback_arg, cyhal_timer_event_t event); +void lora_timer_init(void); + +/* FOR BLE */ +TaskHandle_t ble_task_handle; +QueueHandle_t ble_cmdQ; +TimerHandle_t timer_handle; +tx_rx_mode mode_flag = GATT_NOTIF_STOC; +/***************/ int main(void) { @@ -44,13 +56,21 @@ int main(void) /* Enable global interrupts */ __enable_irq(); - /* Initialize retarget-io to use the debug UART port */ - result = cy_retarget_io_init(P10_1, P10_0, CY_RETARGET_IO_BAUDRATE); + + /* Initialize the user button */ + result = cyhal_gpio_init(P0_4, CYHAL_GPIO_DIR_INPUT, CYHAL_GPIO_DRIVE_NONE, CYBSP_BTN_OFF); + if (result != CY_RSLT_SUCCESS) + { + // printf("Failed to init button!\n"); + } + + /* Configure GPIO interrupt */ + cyhal_gpio_register_callback(P0_4, gpio_interrupt_handler, NULL); + cyhal_gpio_enable_event(P0_4, CYHAL_GPIO_IRQ_RISE, CYHAL_ISR_PRIORITY_DEFAULT, true); CY_ASSERT(CY_RSLT_SUCCESS == cyhal_gpio_init(LED_BLUE, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, false)); CY_ASSERT(CY_RSLT_SUCCESS == cyhal_gpio_init(LED_RED, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, false)); - printf("Test printf\n"); /* retarget-io init failed. Stop program execution */ if (result != CY_RSLT_SUCCESS) @@ -58,59 +78,93 @@ int main(void) CY_ASSERT(0); } - coreStatus = LoRaWAN_Init(&coreConfig); - /* Check Onethinx Core info */ - LoRaWAN_GetInfo(&coreInfo); - /* send join using parameters in coreConfig, blocks until either success or MAXtries */ - coreStatus = LoRaWAN_Join(true); - - /* check for successful join */ - if (!coreStatus.mac.isJoined){ - while(1) { - cyhal_gpio_toggle(LED_BLUE); - CyDelay(100); - } - } else { - printf("Joined network successfully!\n"); - cyhal_gpio_write(LED_BLUE, false); - /*delay before first message will be sent */ - CyDelay(1000); - } - - /* main loop */ - for(;;) - { - cyhal_gpio_write(LED_BLUE, true); - - /* compose a message to send */ - uint8_t j=0; - TXbuffer[j++] = 0x48; /* H */ - TXbuffer[j++] = 0x45; /* E */ - TXbuffer[j++] = 0x4c; /* L */ - TXbuffer[j++] = 0x4c; /* L */ - TXbuffer[j++] = 0x4f; /* O */ - TXbuffer[j++] = 0x20; /* */ - TXbuffer[j++] = 0x57; /* W */ - TXbuffer[j++] = 0x4f; /* O */ - TXbuffer[j++] = 0x52; /* R */ - TXbuffer[j++] = 0x4c; /* L */ - TXbuffer[j++] = 0x44; /* D */ - coreStatus = LoRaWAN_Send((uint8_t *) TXbuffer, j, true); - CyDelay(1000); - if( coreStatus.system.errorStatus == system_BusyError ){ - for(int i=0; i<10; i++){ - cyhal_gpio_toggle(LED_BLUE);; - CyDelay(100); - } - } - else - { - printf("Sent a message!\n"); - } - cyhal_gpio_write(LED_BLUE, false); - - /* wait before sending next message */ - CyDelay( 10000 ); - } - -} \ No newline at end of file + /* FOR BLE */ + ble_cmdQ = xQueueCreate(BLE_CMD_Q_LEN, sizeof(ble_command_type_t)); + + timer_handle = xTimerCreate("Timer", pdMS_TO_TICKS(1000), pdTRUE, + NULL, rtos_timer_cb); + + + message_str.semaphore_lora = xSemaphoreCreateBinary(); + message_str.semaphore_gprs = xSemaphoreCreateBinary(); + message_str.mutex = xSemaphoreCreateMutex(); + + lora_timer_init(); + + xTaskCreate(task_gps, "GPS Task", TASK_GPRS, &message_str, 1, NULL); + xTaskCreate(task_BLE, "BLE Task", TASK_BLE, NULL, 1, &ble_task_handle); + xTaskCreate(lora_send, "LoRa", TASK , &message_str, 2, NULL); + xTaskCreate(task_gprs, "GPRS Task", TASK_GPRS , &message_str, 2, NULL); + + + vTaskStartScheduler(); + + CY_ASSERT(0); + +} + +/* + Interrupt by button. Wake up gprs task +*/ +static void gpio_interrupt_handler(void *handler_arg, cyhal_gpio_irq_event_t event) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE;; + xSemaphoreGiveFromISR(message_str.semaphore_gprs, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + + +void lora_timer_init(void) +{ + cy_rslt_t result; + + const cyhal_timer_cfg_t timer_cfg = + { + .compare_value = 0, /* Timer compare value, not used */ + .period = TIMER_PERIOD, /* Defines the timer period */ + .direction = CYHAL_TIMER_DIR_UP, /* Timer counts up */ + .is_compare = false, /* Don't use compare mode */ + .is_continuous = true, /* Run timer indefinitely */ + .value = 0 /* Initial value of counter */ + }; + + /* Initialize the timer object. Does not use input pin ('pin' is NC) and + * does not use a pre-configured clock source ('clk' is NULL). */ + result = cyhal_timer_init(&timer, NC, NULL); + + /* timer init failed. Stop program execution */ + if (result != CY_RSLT_SUCCESS) + { + CY_ASSERT(0); + } + + /* Configure timer period and operation mode such as count direction, + duration */ + cyhal_timer_configure(&timer, &timer_cfg); + + /* Set the frequency of timer's clock source */ + cyhal_timer_set_frequency(&timer, TIMER_CLOCK_HZ); + + /* Assign the ISR to execute on timer interrupt */ + cyhal_timer_register_callback(&timer, isr_timer, NULL); + + /* Set the event on which timer interrupt occurs and enable it */ + cyhal_timer_enable_event(&timer, CYHAL_TIMER_IRQ_TERMINAL_COUNT, + 7, true); + + /* Start the timer with the configured settings */ + cyhal_timer_start(&timer); +} + +/* + Interrupt by timer. Wake up lora task +*/ +static void isr_timer(void *callback_arg, cyhal_timer_event_t event) +{ + (void) callback_arg; + (void) event; + + BaseType_t xHigherPriorityTaskWoken = pdFALSE;; + xSemaphoreGiveFromISR(message_str.semaphore_lora, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} diff --git a/firmware/MedButton/openocd.tcl b/firmware/MedButton/openocd.tcl index b7f906c..d91fa73 100644 --- a/firmware/MedButton/openocd.tcl +++ b/firmware/MedButton/openocd.tcl @@ -2,4 +2,4 @@ source [find interface/kitprog3.cfg] source [find target/psoc6.cfg] kitprog3 power_config on 3300 ${TARGET}.cm4 configure -rtos auto -rtos-wipe-on-reset-halt 1 -psoc6 sflash_restrictions 1 +psoc6 sflash_restrictions 1 \ No newline at end of file diff --git a/software/Qt/Lora-MQTT-test/README.md b/software/Qt/Lora-MQTT-test/README.md new file mode 100644 index 0000000..5d9f49b --- /dev/null +++ b/software/Qt/Lora-MQTT-test/README.md @@ -0,0 +1,11 @@ +## LoRa uplink messages read from https://eu1.cloud.thethings.network/ server +This project reads most recent uplink LoRa packet for specified (in link) thethingsnetwork application. + +Items needed in order to start: +1. Activate storage integration for your application +![Storage Integration Screenshot](guidance_screenshots/storage.png) +2. Generate and copy to the code API key with "Read application traffic (uplink and downlink)" right. Copy key with help of "copy" button on generation window: +![API key generation](guidance_screenshots/api_key.png) +3. Place SSL libraries libeay32.dll and ssleay32.dll into target exe folder (D:\Git\MedButton\software\Qt\Lora-MQTT-test\build-mqtt-test-Desktop_Qt_5_12_3_MinGW_64_bit-Debug\debug in my case). This is needed for https GET request. I've found dlls in by next paths in my Qt installation folder: +* "D:\Qt\Tools\mingw730_64\opt\bin\libeay32.dll" +* "D:\Qt\Tools\mingw730_64\opt\bin\ssleay32.dll" diff --git a/software/Qt/Lora-MQTT-test/guidance_screenshots/api_key.png b/software/Qt/Lora-MQTT-test/guidance_screenshots/api_key.png new file mode 100644 index 0000000..4f78fc5 Binary files /dev/null and b/software/Qt/Lora-MQTT-test/guidance_screenshots/api_key.png differ diff --git a/software/Qt/Lora-MQTT-test/guidance_screenshots/storage.png b/software/Qt/Lora-MQTT-test/guidance_screenshots/storage.png new file mode 100644 index 0000000..f51895e Binary files /dev/null and b/software/Qt/Lora-MQTT-test/guidance_screenshots/storage.png differ diff --git a/software/Qt/Lora-MQTT-test/mqtt-test/.gitignore b/software/Qt/Lora-MQTT-test/mqtt-test/.gitignore new file mode 100644 index 0000000..fab7372 --- /dev/null +++ b/software/Qt/Lora-MQTT-test/mqtt-test/.gitignore @@ -0,0 +1,73 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + diff --git a/software/Qt/Lora-MQTT-test/mqtt-test/main.cpp b/software/Qt/Lora-MQTT-test/mqtt-test/main.cpp new file mode 100644 index 0000000..fd3e533 --- /dev/null +++ b/software/Qt/Lora-MQTT-test/mqtt-test/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/software/Qt/Lora-MQTT-test/mqtt-test/mainwindow.cpp b/software/Qt/Lora-MQTT-test/mqtt-test/mainwindow.cpp new file mode 100644 index 0000000..fa31ec3 --- /dev/null +++ b/software/Qt/Lora-MQTT-test/mqtt-test/mainwindow.cpp @@ -0,0 +1,50 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + ui->txt_box->setText("Test text!"); + + manager = new QNetworkAccessManager(); + QObject::connect(manager, SIGNAL(finished(QNetworkReply*)), + this, SLOT(managerFinished(QNetworkReply*))); + + // Example application name - "first-random-app" + // limit=1 - return only 1 (most recent) LoRa message + request.setUrl(QUrl("https://eu1.cloud.thethings.network/api/v3/as/applications/first-random-app/packages/storage/uplink_message?limit=1")); + // API Key goes after "Bearer" + request.setRawHeader("Authorization" , "Bearer NNSXS.DJBXJQNTIBAYD6LR5NVPUNP64EKDH54OLFKQGSI.OODUM6B6NVTPRDHJIDLUEWMU6IY3JG35Z34OWJ5EMMUVQS5XUQRA"); + request.setRawHeader("Accept" , "text/event-stream"); + request.setRawHeader("Content-Type" , "text/event-stream"); + + manager->get(request); +} + +void MainWindow::managerFinished(QNetworkReply *reply) +{ + QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + if (status_code.isValid()) + { + QString status = status_code.toString(); + QByteArray rawResponse = reply->readAll(); + QJsonDocument jsonResponse = QJsonDocument::fromJson(rawResponse); + QJsonObject jsonObject = jsonResponse.object(); + QString jsonData = jsonObject.value("result").toObject().value("uplink_message").toObject().value("frm_payload").toString(); + /* decoded from Base64 data will be stored in uplinkMsgText */ + QString uplinkMsgText = QByteArray::fromBase64(jsonData.toUtf8()); + qDebug() << "Received from server LoRa uplink_message: " << uplinkMsgText; + } +} + +MainWindow::~MainWindow() +{ + delete ui; +} + + +void MainWindow::on_btn_test_clicked() +{ +} diff --git a/software/Qt/Lora-MQTT-test/mqtt-test/mainwindow.h b/software/Qt/Lora-MQTT-test/mqtt-test/mainwindow.h new file mode 100644 index 0000000..41b389e --- /dev/null +++ b/software/Qt/Lora-MQTT-test/mqtt-test/mainwindow.h @@ -0,0 +1,28 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include "QtNetwork/QtNetwork" + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + QNetworkAccessManager *manager; + QNetworkRequest request; + +private slots: + void managerFinished(QNetworkReply *reply); + void on_btn_test_clicked(); + +private: + Ui::MainWindow *ui; +}; +#endif // MAINWINDOW_H diff --git a/software/Qt/Lora-MQTT-test/mqtt-test/mainwindow.ui b/software/Qt/Lora-MQTT-test/mqtt-test/mainwindow.ui new file mode 100644 index 0000000..f0a81bc --- /dev/null +++ b/software/Qt/Lora-MQTT-test/mqtt-test/mainwindow.ui @@ -0,0 +1,55 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + 10 + 10 + 771 + 501 + + + + + + + 10 + 520 + 75 + 23 + + + + Test Button + + + + + + + 0 + 0 + 800 + 21 + + + + + + + + diff --git a/software/Qt/Lora-MQTT-test/mqtt-test/mqtt-test.pro b/software/Qt/Lora-MQTT-test/mqtt-test/mqtt-test.pro new file mode 100644 index 0000000..01ad38e --- /dev/null +++ b/software/Qt/Lora-MQTT-test/mqtt-test/mqtt-test.pro @@ -0,0 +1,31 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets network + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + mainwindow.h + +FORMS += \ + mainwindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target