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: cant 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 descriptors 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 + declarations 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 + declarations 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 Snchez and Bjrn 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 0000000..b7d1c5a Binary files /dev/null and b/src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_ecdh.lib differ 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 0000000..0a54917 Binary files /dev/null and b/src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_mesh_core.lib differ 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 0000000..beb3aef Binary files /dev/null and b/src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_mesh_models.lib differ diff --git a/src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_utils.lib b/src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_utils.lib new file mode 100644 index 0000000..b4000d9 Binary files /dev/null and b/src/components/ethermind/lib/meshlibs/phyos/keil/libethermind_utils.lib differ 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 (2s 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 Snchez and Bjrn 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 0000000..ac3e5a1 Binary files /dev/null and b/src/lib/aoxEst.lib differ 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 timefeatureҪ֧µĴҪ޸ + #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 0000000..83c683d Binary files /dev/null and b/src/lib/ble_host.lib differ 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 0000000..990feb3 Binary files /dev/null and b/src/lib/ble_host_multi5.lib differ diff --git a/src/lib/phy_font.lib b/src/lib/phy_font.lib new file mode 100644 index 0000000..d16639b Binary files /dev/null and b/src/lib/phy_font.lib differ diff --git a/src/lib/rf.lib b/src/lib/rf.lib new file mode 100644 index 0000000..1958b3b Binary files /dev/null and b/src/lib/rf.lib differ diff --git a/src/lib/rf/patch.c b/src/lib/rf/patch.c new file mode 100644 index 0000000..cc7cf12 --- /dev/null +++ b/src/lib/rf/patch.c @@ -0,0 +1,8706 @@ +/************************************************************************************************** + + 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. + +**************************************************************************************************/ + +#include +#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 0000000..f6a6f1a Binary files /dev/null and b/src/lib/rf_mst.lib differ diff --git a/src/lib/rflib.h b/src/lib/rflib.h new file mode 100644 index 0000000..c62bbb7 --- /dev/null +++ b/src/lib/rflib.h @@ -0,0 +1,22 @@ +/************************************************************************************************** +******* +**************************************************************************************************/ + + +#ifndef __RF_LIB_H +#define __RF_LIB_H +#include "hci.h" +#include "hci_tl.h" +#include "ll.h" +#include "ll_def.h" + +void rflib_vesion(uint8_t* major, uint8_t* minor, uint8_t* revision, char* test_build); +void check_PerStatsProcess(void); +int8 LL_PLUS_GetCurrentRSSI(void); + +hciStatus_t HCI_LE_SetHostChanClassificationCmd(uint8* chanMap); + +void LL_PLUS_GetCurrentPduDle(uint8_t connId, ll_pdu_length_ctrl_t* ppdu); + +#endif + diff --git a/src/lib/sec/aes.c b/src/lib/sec/aes.c new file mode 100644 index 0000000..5ebca77 --- /dev/null +++ b/src/lib/sec/aes.c @@ -0,0 +1,586 @@ +/************************************************************************************************** + + 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. + +**************************************************************************************************/ + +#include "aes.h" +#include "flash.h" +#include "ll_def.h" +#include "ll_enc.h" +//extern chipId_t g_chipId; +extern const char* s_company_id; + +unsigned char sBox[256] = +{ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, /*0*/ + 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, /*1*/ + 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, /*2*/ + 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, /*3*/ + 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, /*4*/ + 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, /*5*/ + 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, /*6*/ + 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, /*7*/ + 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, /*8*/ + 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, /*9*/ + 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, /*a*/ + 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, /*b*/ + 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, /*c*/ + 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, /*d*/ + 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, /*e*/ + 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16 /*f*/ +}; +unsigned char invsBox[256] = +{ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb, /*0*/ + 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb, /*1*/ + 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e, /*2*/ + 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25, /*3*/ + 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92, /*4*/ + 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84, /*5*/ + 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06, /*6*/ + 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b, /*7*/ + 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73, /*8*/ + 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e, /*9*/ + 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b, /*a*/ + 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4, /*b*/ + 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f, /*c*/ + 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef, /*d*/ + 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61, /*e*/ + 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d /*f*/ +}; + + +void getBit(unsigned char ci,int* b) +{ + for(int i=0; i<8; i++) + b[i]=(ci>>i)&0x01; +} + + +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 +