diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/LICENSE b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/LICENSE new file mode 100644 index 0000000000..97df0e645d --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/LICENSE @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, files are licensed +under the Apache 2.0 license, as can be found in: apache-2.0.txt \ No newline at end of file diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/README.md b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/README.md new file mode 100644 index 0000000000..4d9823e03a --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/README.md @@ -0,0 +1,6 @@ +# Example 802.15.4 RF driver for Silicon Labs EFR32 Wireless SoCs # + +Support for: + * EFR32MG1X + +This driver is used with the mbed 6LoWPAN stack. \ No newline at end of file diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/apache-2.0.txt b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/apache-2.0.txt new file mode 100644 index 0000000000..0e4cf3ee99 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/apache-2.0.txt @@ -0,0 +1,56 @@ + + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/buffer-pool-memory-manager/buffer_pool_allocator.c b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/buffer-pool-memory-manager/buffer_pool_allocator.c new file mode 100644 index 0000000000..78391c9c6f --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/buffer-pool-memory-manager/buffer_pool_allocator.c @@ -0,0 +1,102 @@ +/***************************************************************************//** + * @file buffer_pool_allocator.c + * @brief The source for a simple memory allocator that statically creates pools + * of fixed size buffers to allocate from. + * @copyright Copyright 2015 Silicon Laboratories, Inc. http://www.silabs.com + ******************************************************************************/ + +#include + +#include "buffer_pool_allocator.h" + +#include "em_int.h" + +#ifdef CONFIGURATION_HEADER +#include CONFIGURATION_HEADER +#endif + +// ----------------------------------------------------------------------------- +// Configuration Macros +// ----------------------------------------------------------------------------- + +// Default to a ping-pong buffer pool with a size of 128 (127 MTU + 1 length) bytes per buffer +#ifndef BUFFER_POOL_SIZE +#define BUFFER_POOL_SIZE 2 +#endif +#ifndef MAX_BUFFER_SIZE +#define MAX_BUFFER_SIZE 128 +#endif + +#define INVALID_BUFFER_OBJ ((void*)0xFFFFFFFF) + +typedef struct { + uint8_t refCount; + uint8_t data[MAX_BUFFER_SIZE]; +} BufferPoolObj_t; + +static BufferPoolObj_t memoryObjs[BUFFER_POOL_SIZE]; + +void* memoryAllocate(uint32_t size) +{ + uint32_t i = 0; + void *handle = INVALID_BUFFER_OBJ; + + // We can't support sizes greater than the maximum heap buffer size + if(size > MAX_BUFFER_SIZE) { + return INVALID_BUFFER_OBJ; + } + + INT_Disable(); + for(i = 0; i < BUFFER_POOL_SIZE; i++) + { + if(memoryObjs[i].refCount == 0) + { + memoryObjs[i].refCount = 1; + handle = (void*)i; + break; + } + } + INT_Enable(); + + return handle; +} + +void *memoryPtrFromHandle(void *handle) +{ + void *ptr = NULL; + + // Make sure we were given a valid handle + if((handle == INVALID_BUFFER_OBJ) || ((uint32_t)handle > BUFFER_POOL_SIZE)) + { + return NULL; + } + + INT_Disable(); + if(memoryObjs[(uint32_t)handle].refCount > 0) + { + ptr = memoryObjs[(uint32_t)handle].data; + } + INT_Enable(); + + return ptr; +} + +void memoryFree(void *handle) +{ + INT_Disable(); + if(memoryPtrFromHandle(handle) != NULL) + { + memoryObjs[(uint32_t)handle].refCount--; + } + INT_Enable(); +} + +void memoryTakeReference(void *handle) +{ + INT_Disable(); + if(memoryPtrFromHandle(handle) != NULL) + { + memoryObjs[(uint32_t)handle].refCount++; + } + INT_Enable(); +} diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/buffer-pool-memory-manager/buffer_pool_allocator.h b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/buffer-pool-memory-manager/buffer_pool_allocator.h new file mode 100644 index 0000000000..af311f91b9 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/buffer-pool-memory-manager/buffer_pool_allocator.h @@ -0,0 +1,51 @@ +/***************************************************************************//** + * @file buffer_pool_allocator.h + * @brief This is a simple memory allocator that uses a build time defined pool + * of constant sized buffers. It's a very simple allocator, but one that can + * be easily used in any application. + * + * @copyright Copyright 2015 Silicon Laboratories, Inc. http://www.silabs.com + ******************************************************************************/ + +#ifndef BUFFER_POOL_ALLOCATOR_H__ +#define BUFFER_POOL_ALLOCATOR_H__ + +// Get the standard include types +#include + +/** + * Allocate a buffer with at least the number of bytes specified. If there is + * not enough space then this function will return NULL. + * @param size The number of bytes to allocate for this buffer + * @return Returns a handle to a buffer at least size bytes long or NULL if no + * buffer could be allocated. + */ +void* memoryAllocate(uint32_t size); + +/** + * Free the buffer pointed to by handle. This will only decrement the reference + * counter for this buffer. The memory is not freed until the reference counter + * reaches zero. + * @param handle The handle to free. Must match the value returned by + * the memoryAllocate() function. + */ +void memoryFree(void *handle); + +/** + * Take a memory handle and get the data pointer associated with it. This will + * return NULL if passed an invalid or unallocated handle. + * @param handle The handle to get the pointer for. Must match the value + * returned by the memoryAllocate() function. + */ +void *memoryPtrFromHandle(void *handle); + +/** + * Increment the reference counter on the memory pointed to by handle. After + * doing this there will have to be an additional call to memoryFree() to + * release the memory. + * @param handle The handle to the object which needs its reference count + * increased. Must match the value returned by the memoryAllocate() function. + */ +void memoryTakeReference(void *handle); + +#endif // BUFFER_POOL_ALLOCATOR_H__ diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/buffer-pool-memory-manager/rail_integration.c b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/buffer-pool-memory-manager/rail_integration.c new file mode 100644 index 0000000000..f762e2ac0e --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/buffer-pool-memory-manager/rail_integration.c @@ -0,0 +1,35 @@ +/***************************************************************************//** + * @file rail_integration.c + * @brief Simple code to link this memory manager with a RAIL application by +* implementing the appropriate callbacks. + * @copyright Copyright 2015 Silicon Laboratories, Inc. http://www.silabs.com + ******************************************************************************/ + +#include +#include "rail.h" +#include "buffer_pool_allocator.h" + +/// Rely on the pool allocator's allocate function to get memory +void *RAILCb_AllocateMemory(uint32_t size) +{ + return memoryAllocate(size); +} + +/// Use the pool allocator's free function to return the memory to the pool +void RAILCb_FreeMemory(void *ptr) +{ + memoryFree(ptr); +} + +/// Get the memory pointer for this handle and offset into it as requested +void *RAILCb_BeginWriteMemory(void *handle, + uint32_t offset, + uint32_t *available) +{ + return ((uint8_t*)memoryPtrFromHandle(handle)) + offset; +} + +/// We don't need to track the completion of a memory write so do nothing +void RAILCb_EndWriteMemory(void *handle, uint32_t offset, uint32_t size) +{ +} diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/efr32-rf-driver/NanostackRfPhyEfr32.h b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/efr32-rf-driver/NanostackRfPhyEfr32.h new file mode 100644 index 0000000000..e06d761107 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/efr32-rf-driver/NanostackRfPhyEfr32.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016 Silicon Laboratories, Inc. http://www.silabs.com + * 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. + */ + +#ifndef NANOSTACK_PHY_EFR32_H_ +#define NANOSTACK_PHY_EFR32_H_ + +#include "mbed.h" +#include "NanostackRfPhy.h" + +class NanostackRfPhyEfr32 : public NanostackRfPhy { +public: + NanostackRfPhyEfr32(); + ~NanostackRfPhyEfr32(); + int8_t rf_register(); + void rf_unregister(); + void get_mac_address(uint8_t *mac); + void set_mac_address(uint8_t *mac); + uint32_t get_driver_version(); +}; + +#endif /* NANOSTACK_PHY_EFR32_H_ */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/ieee802154_efr32xg1_configurator_out.c b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/ieee802154_efr32xg1_configurator_out.c new file mode 100644 index 0000000000..213dac66fc --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/ieee802154_efr32xg1_configurator_out.c @@ -0,0 +1,103 @@ +/***************************************************************************//** + * @brief RAIL Configuration + * @copyright Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com + ******************************************************************************/ +//============================================================================= +// +// WARNING: Auto-Generated Radio Config - DO NOT EDIT +// +//============================================================================= +#include + +const uint32_t ieee802154_config_base[] = { + 0x01010FF4UL, 0x00000000UL, + 0x01010FF8UL, 0x0003C000UL, + 0x01010FFCUL, 0x0003C00EUL, + 0x00010004UL, 0x00157001UL, + 0x00010008UL, 0x0000007FUL, + 0x00010018UL, 0x00000000UL, + 0x0001001CUL, 0x00000000UL, + 0x00010028UL, 0x00000000UL, + 0x0001002CUL, 0x00000000UL, + 0x00010030UL, 0x00000000UL, + 0x00010034UL, 0x00000000UL, + 0x0001003CUL, 0x00000000UL, + 0x00010040UL, 0x000007A0UL, + 0x00010048UL, 0x00000000UL, + 0x00010054UL, 0x00000000UL, + 0x00010058UL, 0x00000000UL, + 0x000100A0UL, 0x00004000UL, + 0x000100A4UL, 0x00004CFFUL, + 0x000100A8UL, 0x00004100UL, + 0x000100ACUL, 0x00004DFFUL, + 0x00012000UL, 0x00000704UL, + 0x00012010UL, 0x00000000UL, + 0x00012018UL, 0x00008408UL, + 0x00013008UL, 0x0000AC3FUL, + 0x0001302CUL, 0x01F50AAAUL, + 0x00013030UL, 0x00104924UL, + 0x00013034UL, 0x00000001UL, + 0x0001303CUL, 0x00010AABUL, + 0x00013040UL, 0x00000000UL, + 0x000140A0UL, 0x0F00277AUL, + 0x000140F4UL, 0x00001020UL, + 0x00014134UL, 0x00000880UL, + 0x00014138UL, 0x000087E6UL, + 0x00014140UL, 0x0088006DUL, + 0x00014144UL, 0x1153E6C0UL, + 0x00016014UL, 0x00000010UL, + 0x00016018UL, 0x0413F920UL, + 0x0001601CUL, 0x0052C007UL, + 0x00016020UL, 0x000000C8UL, + 0x00016024UL, 0x00000000UL, + 0x00016028UL, 0x03000000UL, + 0x0001602CUL, 0x00000000UL, + 0x00016030UL, 0x00FF0264UL, + 0x00016034UL, 0x000008A2UL, + 0x00016038UL, 0x00000001UL, + 0x0001603CUL, 0x000807B0UL, + 0x00016040UL, 0x000000A7UL, + 0x00016044UL, 0x00000000UL, + 0x00016048UL, 0x0AC00141UL, + 0x0001604CUL, 0x744AC39BUL, + 0x00016050UL, 0x000003F0UL, + 0x00016054UL, 0x00000000UL, + 0x00016058UL, 0x00000000UL, + 0x0001605CUL, 0x30100101UL, + 0x00016060UL, 0x7F7F7050UL, + 0x00016064UL, 0x00000000UL, + 0x00017014UL, 0x000270FAUL, + 0x00017018UL, 0x00001800UL, + 0x0001701CUL, 0x82840000UL, + 0x00017028UL, 0x01800000UL, + 0x00017048UL, 0x00003D3CUL, + 0x0001704CUL, 0x000019BCUL, + 0x00017070UL, 0x00010103UL, + 0x00017074UL, 0x00000442UL, + 0x00017078UL, 0x00552300UL, + 0xFFFFFFFFUL, +}; + +const uint32_t ieee802154_config_base_min[] = { + 0x01010FFCUL, 0x0003C00EUL, + 0x0001303CUL, 0x00010AABUL, + 0x00016034UL, 0x000008A2UL, + 0x00016038UL, 0x00000001UL, + 0x00017078UL, 0x00552300UL, + 0xFFFFFFFFUL, +}; + +const uint32_t ieee802154_config_2415MHz_min[] = { + 0x01010FFCUL, 0x0003C00AUL, + 0x0001303CUL, 0x00003555UL, + 0xFFFFFFFFUL, +}; + +const uint32_t ieee802154_config_2420MHz_min[] = { + 0x0001303CUL, 0x00003555UL, + 0x00016034UL, 0x000004A1UL, + 0x00016038UL, 0x00000009UL, + 0x00017078UL, 0x0049E006UL, + 0xFFFFFFFFUL, +}; + diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/ieee802154_efr32xg1_configurator_out.h b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/ieee802154_efr32xg1_configurator_out.h new file mode 100644 index 0000000000..1474e7c214 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/ieee802154_efr32xg1_configurator_out.h @@ -0,0 +1,18 @@ + +/***************************************************************************//** + * @file ieee802154_config.h + * @brief IEEE802154 Configuration + * @copyright Copyright 2015 Silicon Laboratories, Inc. http://www.silabs.com + ******************************************************************************/ + +#ifndef __IEEE802154_EFR32XG1_CONFIGURATOR_OUT_H__ +#define __IEEE802154_EFR32XG1_CONFIGURATOR_OUT_H__ + +#include + +extern const uint32_t ieee802154_config_base[]; +extern const uint32_t ieee802154_config_base_min[]; +extern const uint32_t ieee802154_config_2415MHz_min[]; +extern const uint32_t ieee802154_config_2420MHz_min[]; + +#endif // __IEEE802154_EFR32XG1_CONFIGURATOR_OUT_H__ diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/ieee802154_subg_efr32xg1_configurator_out.c b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/ieee802154_subg_efr32xg1_configurator_out.c new file mode 100644 index 0000000000..8c35b66c61 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/ieee802154_subg_efr32xg1_configurator_out.c @@ -0,0 +1,155 @@ +/***************************************************************************//** + * @brief RAIL Configuration + * @copyright Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com + ******************************************************************************/ +//============================================================================= +// +// WARNING: Auto-Generated Radio Config - DO NOT EDIT +// +//============================================================================= +#include + +const uint32_t ieee802154_config_863[] = { +0x01010FF4UL, 0x00000000UL, +0x01010FF8UL, 0x0003C000UL, +0x01010FFCUL, 0x0003C008UL, +0x00010004UL, 0x00157001UL, +0x00010008UL, 0x0000007FUL, +0x00010018UL, 0x00000000UL, +0x0001001CUL, 0x00000000UL, +0x00010028UL, 0x00000000UL, +0x0001002CUL, 0x00000000UL, +0x00010030UL, 0x00000000UL, +0x00010034UL, 0x00000000UL, +0x0001003CUL, 0x00000000UL, +0x00010040UL, 0x000007A0UL, +0x00010048UL, 0x00000000UL, +0x00010054UL, 0x00000000UL, +0x00010058UL, 0x00000000UL, +0x000100A0UL, 0x00004000UL, +0x000100A4UL, 0x00004CFFUL, +0x000100A8UL, 0x00004100UL, +0x000100ACUL, 0x00004DFFUL, +0x00012000UL, 0x00000704UL, +0x00012010UL, 0x00000000UL, +0x00012018UL, 0x00008408UL, +0x00013008UL, 0x0000AC3FUL, +0x0001302CUL, 0x021EB000UL, +0x00013030UL, 0x00108000UL, +0x00013034UL, 0x00000003UL, +0x0001303CUL, 0x00014000UL, +0x00013040UL, 0x00000000UL, +0x000140A0UL, 0x0F00277AUL, +0x000140F4UL, 0x00001020UL, +0x00014134UL, 0x00000880UL, +0x00014138UL, 0x000087F6UL, +0x00014140UL, 0x00880048UL, +0x00014144UL, 0x1153E6C0UL, +0x00016014UL, 0x00000010UL, +0x00016018UL, 0x04127920UL, +0x0001601CUL, 0x0051C007UL, +0x00016020UL, 0x000000C2UL, +0x00016024UL, 0x00000000UL, +0x00016028UL, 0x03000000UL, +0x0001602CUL, 0x00000000UL, +0x00016030UL, 0x00FF0BF4UL, +0x00016034UL, 0x00000C20UL, +0x00016038UL, 0x0102000AUL, +0x0001603CUL, 0x00080430UL, +0x00016040UL, 0x000000A7UL, +0x00016044UL, 0x00000000UL, +0x00016048UL, 0x04602123UL, +0x0001604CUL, 0x0000A47CUL, +0x00016050UL, 0x00000018UL, +0x00016054UL, 0x00000000UL, +0x00016058UL, 0x00000000UL, +0x0001605CUL, 0x30100101UL, +0x00016060UL, 0x7F7F7050UL, +0x00016064UL, 0x00000000UL, +0x00017014UL, 0x000270F1UL, +0x00017018UL, 0x00001700UL, +0x0001701CUL, 0x82840000UL, +0x00017028UL, 0x00000000UL, +0x00017048UL, 0x0000383EUL, +0x0001704CUL, 0x000025BCUL, +0x00017070UL, 0x00010103UL, +0x00017074UL, 0x00000442UL, +0x00017078UL, 0x006D8480UL, +0xFFFFFFFFUL, +}; +const uint32_t ieee802154_config_863_min[] = { +0xFFFFFFFFUL, +}; + +const uint32_t ieee802154_config_915[] = { +0x01010FF4UL, 0x00000000UL, +0x01010FF8UL, 0x0003C000UL, +0x01010FFCUL, 0x0003C008UL, +0x00010004UL, 0x00157001UL, +0x00010008UL, 0x0000007FUL, +0x00010018UL, 0x00000000UL, +0x0001001CUL, 0x00000000UL, +0x00010028UL, 0x00000000UL, +0x0001002CUL, 0x00000000UL, +0x00010030UL, 0x00000000UL, +0x00010034UL, 0x00000000UL, +0x0001003CUL, 0x00000000UL, +0x00010040UL, 0x000007A0UL, +0x00010048UL, 0x00000000UL, +0x00010054UL, 0x00000000UL, +0x00010058UL, 0x00000000UL, +0x000100A0UL, 0x00004000UL, +0x000100A4UL, 0x00004CFFUL, +0x000100A8UL, 0x00004100UL, +0x000100ACUL, 0x00004DFFUL, +0x00012000UL, 0x00000704UL, +0x00012010UL, 0x00000000UL, +0x00012018UL, 0x00008408UL, +0x00013008UL, 0x0000AC3FUL, +0x0001302CUL, 0x02364000UL, +0x00013030UL, 0x00108000UL, +0x00013034UL, 0x00000003UL, +0x0001303CUL, 0x00014000UL, +0x00013040UL, 0x00000000UL, +0x000140A0UL, 0x0F00277AUL, +0x000140F4UL, 0x00001020UL, +0x00014134UL, 0x00000880UL, +0x00014138UL, 0x000087F6UL, +0x00014140UL, 0x00880048UL, +0x00014144UL, 0x1153E6C0UL, +0x00016014UL, 0x00000010UL, +0x00016018UL, 0x04127920UL, +0x0001601CUL, 0x0051C007UL, +0x00016020UL, 0x000000C2UL, +0x00016024UL, 0x00000000UL, +0x00016028UL, 0x03000000UL, +0x0001602CUL, 0x00000000UL, +0x00016030UL, 0x00FF04C8UL, +0x00016034UL, 0x000008A2UL, +0x00016038UL, 0x0100000AUL, +0x0001603CUL, 0x00080430UL, +0x00016040UL, 0x000000A7UL, +0x00016044UL, 0x00000000UL, +0x00016048UL, 0x0AC02123UL, +0x0001604CUL, 0x0000A47CUL, +0x00016050UL, 0x00000018UL, +0x00016054UL, 0x00000000UL, +0x00016058UL, 0x00000000UL, +0x0001605CUL, 0x30100101UL, +0x00016060UL, 0x7F7F7050UL, +0x00016064UL, 0x00000000UL, +0x00017014UL, 0x000270F1UL, +0x00017018UL, 0x00001700UL, +0x0001701CUL, 0x82840000UL, +0x00017028UL, 0x00000000UL, +0x00017048UL, 0x0000383EUL, +0x0001704CUL, 0x000025BCUL, +0x00017070UL, 0x00010103UL, +0x00017074UL, 0x00000442UL, +0x00017078UL, 0x006D8480UL, +0xFFFFFFFFUL, +}; +const uint32_t ieee802154_config_915_min[] = { +0xFFFFFFFFUL, +}; + diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/ieee802154_subg_efr32xg1_configurator_out.h b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/ieee802154_subg_efr32xg1_configurator_out.h new file mode 100644 index 0000000000..7933a489ce --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/ieee802154_subg_efr32xg1_configurator_out.h @@ -0,0 +1,31 @@ + +/***************************************************************************//** + * @file ieee802154_gb868_efr32xg1_configurator_out.h + * @brief IEEE802154 GB868_Configuration + * @copyright Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com + ******************************************************************************/ + +#ifndef __IEEE802154_GB868_EFR32XG1_CONFIGURATOR_OUT_H__ +#define __IEEE802154_GB868_EFR32XG1_CONFIGURATOR_OUT_H__ + +#include + +#define IEEE802154_863_RADIO_CONFIG_BASE_FREQUENCY 868300000UL +#define IEEE802154_863_RADIO_CONFIG_XTAL_FREQUENCY 38400000UL +#define IEEE802154_863_RADIO_CONFIG_BITRATE "100kbps" +#define IEEE802154_863_RADIO_CONFIG_MODULATION_TYPE "OQPSK" +#define IEEE802154_863_RADIO_CONFIG_DEVIATION "333.3kHz" + +extern const uint32_t ieee802154_config_863[]; +extern const uint32_t ieee802154_config_863_min[]; + +#define IEEE802154_915_RADIO_CONFIG_BASE_FREQUENCY 906000000UL +#define IEEE802154_915_RADIO_CONFIG_XTAL_FREQUENCY 38400000UL +#define IEEE802154_915_RADIO_CONFIG_BITRATE "250kbps" +#define IEEE802154_915_RADIO_CONFIG_MODULATION_TYPE "OQPSK" +#define IEEE802154_915_RADIO_CONFIG_DEVIATION "333.3kHz" + +extern const uint32_t ieee802154_config_915[]; +extern const uint32_t ieee802154_config_915_min[]; + +#endif // __IEEE802154_GB868_EFR32XG1_CONFIGURATOR_OUT_H__ diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/librail_efr32xg1.a b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/librail_efr32xg1.a new file mode 100644 index 0000000000..d505e1ccad Binary files /dev/null and b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_GCC_ARM/TARGET_EFR32MG1/librail_efr32xg1.a differ diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_IAR/TARGET_EFR32MG1/librail_efr32_iar_release.a b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_IAR/TARGET_EFR32MG1/librail_efr32_iar_release.a new file mode 100644 index 0000000000..a089e35b1d Binary files /dev/null and b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TOOLCHAIN_IAR/TARGET_EFR32MG1/librail_efr32_iar_release.a differ diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/ieee802154/rail_ieee802154.h b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/ieee802154/rail_ieee802154.h new file mode 100644 index 0000000000..612c6ddc72 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/ieee802154/rail_ieee802154.h @@ -0,0 +1,374 @@ +/***************************************************************************//** + * @file rail_ieee802154.h + * @brief The IEEE 802.15.4 specific header file for the RAIL library. + * @copyright Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com + ******************************************************************************/ + +#ifndef __RAIL_IEEE802154_H__ +#define __RAIL_IEEE802154_H__ + +/** + * @addtogroup Protocol_Specific + * @{ + */ + +/** + * @addtogroup IEEE802_15_4 + * @brief IEEE 802.15.4 configuration routines + * + * The functions in this group configure RAIL IEEE 802.15.4 hardware + * acceleration. To configure 802.15.4 functionality, call + * RAIL_IEEE802154_Init(). Make note that this function calls many other RAIL + * functions; the application is advised to not reconfigure any of these + * functions. When using 802.15.4 functionality in the 2.4 GHz band, consider + * using RAIL_IEEE802154_2p4GHzRadioConfig() instead of RAIL_RadioConfig() and + * RAIL_ChannelConfig(). + * + * @code{.c} + * RAIL_IEEE802154_Config_t config = { false, false, + * RAIL_IEEE802154_ACCEPT_STANDARD_FRAMES, + * RAIL_RF_STATE_RX, 100, 192, 894, NULL }; + * RAIL_IEEE802154_2p4GHzRadioConfig(); + * RAIL_IEEE802154_Init(&config); + * @endcode + * + * The application can configure the node's address by using + * RAIL_IEEE802154_SetAddresses(). Inidividual members can be changed with + * RAIL_IEEE802154_SetPanId(), RAIL_IEEE802154_SetShortAddress(), + * RAIL_IEEE802154_SetLongAddress(). RAIL only supports one set of addresses at + * a time. Beacon addresses are supported by default, without additional + * configuration. + * + * @code{.c} + * uint8_t longAddress[8] = { 0x11, 0x22, 0x33, 0x44, + * 0x55, 0x66, 0x77, 0x88}; + * // PanID OTA value of 0x34 0x12 + * // Short Address OTA byte order of 0x78 0x56 + * // Long address with OTA byte order of 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 + * RAIL_IEEE802154_AddrConfig_t nodeAddress = { 0x1234, 0x5678, + * &longAddress[0] }; + * + * bool status = RAIL_IEEE802154_SetAddresses(&nodeAddress); + * + * // Alternative methods: + * status = RAIL_IEEE802154_SetPanId(nodeAddress.panId); + * status = RAIL_IEEE802154_SetShortAddress(nodeAddress.shortAddr); + * status = RAIL_IEEE802154_SetLongAddress(nodeAddress.longAddr); + * @endcode + * + * Auto ack is initialized through RAIL_IEEE802154_Init(). It is not advised + * to call RAIL_AutoAckConfig() while 802.15.4 hardware acceleration is + * enabled. The default IEEE 802.15.4 ack will have a 5 byte length. The frame + * type will be an ack. The frame pending bit will be set based on the + * RAIL_IEEE802154_SetFramePending() function. The sequence number will be set to + * match the packet being acknowledged. All other frame control fields will be + * set to 0, in compliance with IEEE Std 802.15.4-2011 section 5.2.2.3. + * However, the auto ack modification function can be used to control auto + * acking. Documentation for these functions can be found in \ref Auto_Ack. + * @{ + */ + +/** + * @enum RAIL_IEEE802154_AddressLength_t + * @brief Different lengths that an 802.15.4 address can have + */ +typedef enum RAIL_IEEE802154_AddressLength +{ + RAIL_IEEE802154_ShortAddress = 2, /**< 2 byte short address. */ + RAIL_IEEE802154_LongAddress = 3, /**< 8 byte extended address. */ +} RAIL_IEEE802154_AddressLength_t; + +/** + * @struct RAIL_IEEE802154_Address_t + * @brief Representation of 802.15.4 address + * This structure is only used for a received address, which needs to be parsed + * to discover the type. + */ +typedef struct RAIL_IEEE802154_Address +{ + /** + * Enum of the received address length + */ + RAIL_IEEE802154_AddressLength_t length; + union + { + uint16_t shortAddress; /**< Present for 2 byte addresses. */ + uint8_t longAddress[8]; /**< Present for 8 byte addresses. */ + }; +} RAIL_IEEE802154_Address_t; + +/** + * @struct RAIL_IEEE802154_AddrConfig_t + * @brief Configuration structure for IEEE 802.15.4 Address Filtering. The + * broadcast addresses are handled separately, and do not need to be specified + * here. Any address which is NULL will be ignored. + */ +typedef struct RAIL_IEEE802154_AddrConfig +{ + uint16_t panId; /**< PAN ID for destination filtering. */ + uint16_t shortAddr; /**< Network address for destination filtering. */ + uint8_t *longAddr; /**< 64 bit address for destination filtering. In OTA byte order.*/ +} RAIL_IEEE802154_AddrConfig_t; + +/** + * @struct RAIL_IEEE802154_Config_t + * @brief Configuration structure for IEEE 802.15.4 in RAIL + */ +typedef struct RAIL_IEEE802154_Config { + /** + * Enable promiscuous mode during configuration. This can be overridden via + * RAIL_IEEE802154_SetPromiscuousMode() afterwards. + */ + bool promiscuousMode; + /** + * Set whether the device is a PAN Coordinator during configuration. This can + * be overridden via RAIL_IEEE802154_SetPanCoordinator() afterwards. + */ + bool isPanCoordinator; + /** + * Set which 802.15.4 frame types will be received, of Beacon, Data, Ack, and + * Command. This setting can be overridden via RAIL_IEEE802154_AcceptFrames(). + */ + uint8_t framesMask; + /** + * Defines the default radio state after a transmit operation (transmit + * packet, wait for ack) or a receive operation (receive packet, transmit + * ack) finishes. + */ + RAIL_RadioState_t defaultState; + /** + * Define the idleToRx and idleToTx time + * This defines the time it takes for the radio to go into RX or TX from an + * idle radio state + */ + uint16_t idleTime; + /** + * Define the turnaround time after receiving a packet and transmitting an + * ack and vice versa + */ + uint16_t turnaroundTime; + /** + * Define the ack timeout time in microseconds + */ + uint16_t ackTimeout; + /** + * Configure the RAIL Address Filter to allow the given destination + * addresses. If addresses is NULL, defer destination address configuration. + * If a member of addresses is NULL, defer configuration of just that member. + * This can be overridden via RAIL_IEEE802154_SetAddresses(), or the + * individual members can be changed via RAIL_IEEE802154_SetPanId(), + * RAIL_IEEE802154_SetShortAddress(), and RAIL_IEEE802154_SetLongAddress(). + */ + RAIL_IEEE802154_AddrConfig_t *addresses; +} RAIL_IEEE802154_Config_t; + +/** + * Initialize RAIL for IEEE802.15.4 features + * + * @param[in] config IEEE802154 configuration struct + * @return \ref RAIL_STATUS_NO_ERROR if successfully configured. + * + * This function calls the following RAIL functions to configure the radio for + * IEEE802.15.4 features. + * + * Initializes the following: + * - Enables IEEE802154 hardware acceleration + * - Configures RAIL Auto Ack functionality + * - Configures RAIL Address Filter for 802.15.4 address filtering + * + * It calls the following functions: + * - RAIL_AutoAckConfig() + * - RAIL_SetRxTransitions() + * - RAIL_SetTxTransitions() + * - RAIL_SetStateTiming() + * - RAIL_AddressFilterConfig() + * - RAIL_AddressFilterEnable() + */ +RAIL_Status_t RAIL_IEEE802154_Init(RAIL_IEEE802154_Config_t *config); + +/** + * Configures the radio for 2.4GHz 802.15.4 operation + * + * @return \ref RAIL_STATUS_NO_ERROR if successfully configured. + * + * This initializes the radio for 2.4GHz operation. It takes the place of + * calling \ref RAIL_RadioConfig and \ref RAIL_ChannelConfig. After this call, + * channels 11-26 will be available, giving the frequencies of those channels + * on channel page 0, as defined by IEEE 802.15.4-2011 section 8.1.2.2. + */ +RAIL_Status_t RAIL_IEEE802154_2p4GHzRadioConfig(void); + +/** + * De-initializes IEEE802.15.4 hardware acceleration + * + * @return 0 if IEEE802.15.4 hardware acceleration is successfully + * deinitialized. Error code on failure + * + * Disables and resets all IEE802.15.4 hardware acceleration features. This + * function should only be called when the radio is IDLE. This calls the + * following: + * - RAIL_AutoAckDisable(), which resets the state transitions to IDLE + * - RAIL_SetStateTiming(), to reset all timings to 100 us + * - RAIL_AddressFilterDisable() + * - RAIL_AddressFilterReset() + */ +RAIL_Status_t RAIL_IEEE802154_Deinit(void); + +/** + * Return whether IEEE802.15.4 hardware accelertion is currently enabled. + * + * @return True if IEEE802.15.4 hardware acceleration was enabled to start with + * and false otherwise + */ +bool RAIL_IEEE802154_IsEnabled(void); + +/** + * Configure the RAIL Address Filter for 802.15.4 filtering + * + * @param[in] addresses The address information that should be used + * @return True if addresses were successfully set, false otherwise + * + * Set up the 802.15.4 address filter to accept messages to the given + * addresses. This will return true if at least one address was successfully + * stored to be used. + */ +bool RAIL_IEEE802154_SetAddresses(RAIL_IEEE802154_AddrConfig_t *addresses); + +/** + * Set a PAN ID for 802.15.4 address filtering + * + * @param[in] panId The 16-bit PAN ID information. + * This will be matched against the destination PAN ID of incoming messages. + * The PAN ID is sent little endian over the air meaning panId[7:0] is first in + * the payload followed by panId[15:8]. + * @return True if the PAN ID was successfully set, false otherwise + * + * Set up the 802.15.4 address filter to accept messages to the given PAN ID. + */ +bool RAIL_IEEE802154_SetPanId(uint16_t panId); + +/** + * Set a short address for 802.15.4 address filtering + * + * @param[in] shortAddr 16 bit short address value. This will be matched against the + * destination short address of incoming messages. The short address is sent + * little endian over the air meaning shortAddr[7:0] is first in the payload + * followed by shortAddr[15:8]. + * @return True if the short address was successfully set, false otherwise + * + * Set up the 802.15.4 address filter to accept messages to the given short + * address. + */ +bool RAIL_IEEE802154_SetShortAddress(uint16_t shortAddr); + +/** + * Set a long address for 802.15.4 address filtering + * + * @param[in] longAddr Pointer to a 8 byte array containing the long address + * information. The long address must be in over the air byte order. This will + * be matched against the destination long address of incoming messages. + * @return True if the long address was successfully set, false otherwise + * + * Set up the 802.15.4 address filter to accept messages to the given long + * address. + */ +bool RAIL_IEEE802154_SetLongAddress(uint8_t *longAddr); + +/** + * Set whether the current node is a PAN coordinator + * + * @param[in] isPanCoordinator True if this device is a PAN coordinator + * @return Returns zero on success and an error code on error + * + * If the device is a PAN Coordinator, then it will accept data and command + * frames with no destination address. This function will fail if 802.15.4 + * hardware acceleration is not currently enabled. This setting may be changed + * at any time when 802.15.4 hardwarea acceleration is enabled. + */ +RAIL_Status_t RAIL_IEEE802154_SetPanCoordinator(bool isPanCoordinator); + +/** + * Set whether to enable 802.15.4 promiscuous mode + * + * @param[in] enable True if all frames and addresses should be accepted + * @return Returns zero on success and an error code on error + * + * If promiscuous mode is enabled, then no frame or address filtering steps + * will be performed, other than checking the CRC. This function will fail if + * 802.15.4 hardware acceleration is not currently enabled. This setting may be + * changed at any time when 802.15.4 hardware acceleration is enabled. + */ +RAIL_Status_t RAIL_IEEE802154_SetPromiscuousMode(bool enable); + +/// When receiving packets, accept 802.15.4 BEACON frame types +#define RAIL_IEEE802154_ACCEPT_BEACON_FRAMES (0x01) +/// When receiving packets, accept 802.15.4 DATA frame types +#define RAIL_IEEE802154_ACCEPT_DATA_FRAMES (0x02) +/// When receiving packets, accept 802.15.4 ACK frame types +/// If this is not enabled, ACK frame types will only be accepted while waiting +/// for an ack +#define RAIL_IEEE802154_ACCEPT_ACK_FRAMES (0x04) +/// When receiving packets, accept 802.15.4 COMMAND frame types +#define RAIL_IEEE802154_ACCEPT_COMMAND_FRAMES (0x08) + +/// In standard operation, accept BEACON, DATA and COMMAND frames. +/// Only receive ACK frames while waiting for ack +#define RAIL_IEEE802154_ACCEPT_STANDARD_FRAMES (RAIL_IEEE802154_ACCEPT_BEACON_FRAMES | \ + RAIL_IEEE802154_ACCEPT_DATA_FRAMES | \ + RAIL_IEEE802154_ACCEPT_COMMAND_FRAMES) + +/** + * Set which 802.15.4 frame types to accept + * + * @param[in] framesMask Mask containing which 802.15.4 frame types to receive + * @return Returns zero on success and an error code on error + * + * This function will fail if 802.15.4 hardware acceleration is not currently + * enabled. This setting may be changed at any time when 802.15.4 hardware + * acceleration is enabled. Only Beacon, Data, Ack, and Command frames may + * be received. The RAIL_IEEE802154_ACCEPT_XXX_FRAMES defines may be combined + * to create a bitmask to pass into this function. + * + * \ref RAIL_IEEE802154_ACCEPT_ACK_FRAMES behaves slightly different than the + * other defines. If \ref RAIL_IEEE802154_ACCEPT_ACK_FRAMES is set, the radio + * will accept an ACK frame during normal packet reception. If \ref + * RAIL_IEEE802154_ACCEPT_ACK_FRAMES is not set, ACK frames will be filtered + * unless the radio is waiting for an ACK. + */ +RAIL_Status_t RAIL_IEEE802154_AcceptFrames(uint8_t framesMask); + +/** + * Callback for when a Data Request is being received + * + * @param address The source address of the data request command + * + * This function is called when the command byte of an incoming frame is for a + * data request, which requests an ACK. This callback will be called before the + * packet is fully received, to allow the node to have more time to decide + * whether to set frame pending in the outgoing ACK. + */ +void RAILCb_IEEE802154_DataRequestCommand(RAIL_IEEE802154_Address_t *address); + +/** + * Set the frame pending bit on the outgoing ACK + * + * @return Returns zero on success and an error code on error + * + * This function should be called after receiving + * RAILCb_IEEE802154_DataRequestCommand(), if the given source address has a + * pending frame. This will return \ref RAIL_STATUS_INVALID_STATE if it is too + * late to modify the ACK. + */ +RAIL_Status_t RAIL_IEEE802154_SetFramePending(void); + +/** + * @} + * end of IEEE802.15.4 + */ + +/** + * @} + * end of Protocol_Specific + */ + +#endif // __RAIL_IEEE802154_H__ diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/pa.h b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/pa.h new file mode 100644 index 0000000000..faeefeca14 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/pa.h @@ -0,0 +1,115 @@ +/***************************************************************************//** + * @file pa.h + * @brief RADIO PA API + ******************************************************************************* + * @section License + * (C) Copyright 2015 Silicon Labs, http://www.silabs.com + ******************************************************************************* + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no + * obligation to support this Software. Silicon Labs is providing the + * Software "AS IS", with no express or implied warranties of any kind, + * including, but not limited to, any implied warranties of merchantability + * or fitness for any particular purpose or warranties against infringement + * of any proprietary rights of a third party. + * + * Silicon Labs will not be liable for any consequential, incidental, or + * special damages, or any other relief, or for any claim by any third party, + * arising from your use of this Software. + * + ******************************************************************************/ +#ifndef __RADIO_PA_H +#define __RADIO_PA_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * @addtogroup RF_Library + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup PA + * @{ + ******************************************************************************/ + +/******************************************************************************* + **************************** CONFIGURATION ******************************** + ******************************************************************************/ +#define PA_SCALING_FACTOR 10 + +/** + * @struct RADIO_PASel_t + * @brief Selection of the rf power amplifier (PA) to use + */ +typedef enum RADIO_PASel +{ + /** High power PA */ + PA_SEL_2P4_HP, + /** Low power PA */ + PA_SEL_2P4_LP, + /** SubGig PA*/ + PA_SEL_SUBGIG +} RADIO_PASel_t; + +typedef enum RADIO_PAVoltMode +{ + /** Vpa = Vbat = 3.3V */ + PA_VOLTMODE_VBAT, + /** Vpa = DCDC Vout = 1.8V */ + PA_VOLTMODE_DCDC +} RADIO_PAVoltMode_t; + +/** + * @struct RADIO_PAInit_t + * @brief Configuration structure for the rf power amplifier (PA) + */ +typedef struct RADIO_PAInit { + /** Power Amplifier mode */ + RADIO_PASel_t paSel; + /** Power Amplifier vPA Voltage mode */ + RADIO_PAVoltMode_t voltMode; + /** Desired output power in dBm * 10 */ + int16_t power; + /** Output power offset in dBm * 10 */ + int16_t offset; + /** Desired ramp time in us */ + uint16_t rampTime; +} RADIO_PAInit_t; + +/******************************************************************************* + ****************************** PROTOTYPES ********************************* + ******************************************************************************/ + +bool RADIO_PA_Init(RADIO_PAInit_t * paInit); +int32_t PA_OutputPowerGet(void); +int32_t PA_OutputPowerSet(int32_t power); +int32_t PA_MaxOutputPowerSet(void); +uint32_t PA_RampTimeGet(void); +uint32_t PA_RampTimeSet(uint32_t ramptime); +void PA_CTuneSet(uint8_t txPaCtuneValue, uint8_t rxPaCtuneValue); + +/** @} (end addtogroup PA) */ +/** @} (end addtogroup RF_Library) */ + +#ifdef __cplusplus +} +#endif + + +#endif /* __RADIO_PA_H */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/pti.h b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/pti.h new file mode 100644 index 0000000000..93697e14dd --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/pti.h @@ -0,0 +1,75 @@ +/***************************************************************************//** + * @file pti.h + * @brief This header file contains information for working with the packet + * trace APIs. + * @copyright Copyright 2015 Silicon Laboratories, Inc. http://www.silabs.com + ******************************************************************************/ + +#ifndef __RADIO_PTI_H +#define __RADIO_PTI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "em_gpio.h" + +/******************************** TYPEDEFS *********************************/ + +/** Channel type enumeration. */ +typedef enum RADIO_PTIMode +{ + /** SPI mode. */ + RADIO_PTI_MODE_SPI = 0U, + /** UART mode. */ + RADIO_PTI_MODE_UART = 1U, + /** 9bit UART mode. */ + RADIO_PTI_MODE_UART_ONEWIRE = 2U, + /** Turn PTI off entirely */ + RADIO_PTI_MODE_DISABLED = 3U, +} RADIO_PTIMode_t; + +/** + * @struct RADIO_PTIInit_t + * @brief Configuration structure for the packet trace interface (PTI) + */ +typedef struct RADIO_PTIInit { + /** Packet Trace mode (UART or SPI) */ + RADIO_PTIMode_t mode; + + /** Output baudrate for PTI in Hz */ + uint32_t baud; + + /** Data output (DOUT) location for pin/port */ + uint8_t doutLoc; + /** Data output (DOUT) GPIO port */ + GPIO_Port_TypeDef doutPort; + /** Data output (DOUT) GPIO pin */ + uint8_t doutPin; + + /** Data clock (DCLK) location for pin/port. Only used in SPI mode */ + uint8_t dclkLoc; + /** Data clock (DCLK) GPIO port. Only used in SPI mode */ + GPIO_Port_TypeDef dclkPort; + /** Data clock (DCLK) GPIO pin. Only used in SPI mode */ + uint8_t dclkPin; + + /** Data frame (DFRAME) location for pin/port. Only used for */ + uint8_t dframeLoc; + /** Data frame (DFRAME) GPIO port */ + GPIO_Port_TypeDef dframePort; + /** Data frame (DFRAME) GPIO pin */ + uint8_t dframePin; +} RADIO_PTIInit_t; + +/************************* FUNCTION PROTOTYPES *****************************/ +void RADIO_PTI_Init(RADIO_PTIInit_t *pitInit); +void RADIO_PTI_Enable(void); +void RADIO_PTI_Disable(void); + +#ifdef __cplusplus +} +#endif + +#endif //__RADIO_PTI_H diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/rail.h b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/rail.h new file mode 100644 index 0000000000..af1fb40699 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/rail.h @@ -0,0 +1,1698 @@ +/***************************************************************************//** + * @file rail.h + * @brief The main header file for the RAIL library. It describes the external + * APIs available to a RAIL user + * @copyright Copyright 2015 Silicon Laboratories, Inc. http://www.silabs.com + ******************************************************************************/ + +#ifndef __RAIL_H__ +#define __RAIL_H__ + +// Get the standard include types +#include +#include + +// Get the RAIL specific structures and types +#include "rail/rail_types.h" + +/** + * @addtogroup RAIL_API + * @brief This is the primary API layer for the Radio Abstraction Interface + * Layer (RAIL) + * @{ + */ + +/****************************************************************************** + * General Radio Operation + *****************************************************************************/ +/** + * @addtogroup General + * @brief Basic APIs for setting up and interacting with the RAIL library + * @{ + */ + +/** + * Get the version information for the compiled RAIL library. + * + * @param[in] version Pointer to \ref RAIL_Version_t struct to populate with version + * information. + * @param[in] verbose Populate \ref RAIL_Version_t struct with verbose information + * + * Version information contains a major version number, a minor version number, + * and a rev (revision) number. + */ +void RAIL_VersionGet(RAIL_Version_t * version, bool verbose); + +/** + * Initialize RAIL + * + * @param[in] railInit The initialization structure to be used for setting up + * the library. This will contain memory and other options needed by RAIL. + * @return Returns zero on success and an error code on error. + * + * RF initialization sets the overall maximum packet length, the xtal frequency + * of the radio, and the calibrations to perform. + */ +uint8_t RAIL_RfInit(const RAIL_Init_t *railInit); + +/** + * Set protocol that RAIL outputs on PTI + * + * @param protocol The enum representing which protocol the node is using + * @return Returns zero on success and an error code on error. + * + * The protocol is output via the Packet Trace Interface (PTI) for each packet. + * Before any protocol is set, the default value is \ref RAIL_PTI_PROTOCOL_CUSTOM. + * A custom value may be used if it does not conflict with one of the available + * \ref RAIL_PtiProtocol_t enum values, though values may only go up to \ref + * RAIL_PTI_PROTOCOL_MAX. + */ +RAIL_Status_t RAIL_SetPtiProtocol(RAIL_PtiProtocol_t protocol); + +/** + * Callback for when the radio is finished initializing from \ref RAIL_RfInit + * and is ready to be configured + * + * @return void + * + * Callback that notifies the application when the radio is finished + * initializing and is ready for further configuration. This is callback is + * useful for potential transceiver products that require a power up sequence + * before further configuration is available. After this callback fires, the + * radio is ready for additional configuration before transmit and receive + * operations. + */ +void RAILCb_RfReady(void); + +/** + * Get the current radio state + * + * @return An enumeration for current radio state + * + * Returns the state of the radio as either TX, RX, or IDLE. There are + * intermediate states that the radio can transistion through which are not + * reported, but are instead bucketed into the state being transitioned + * into. (Example: When the transmitter is in the process of shutting down, + * this function will return TX, as if the shutdown process hadn't started yet) + */ +RAIL_RadioState_t RAIL_RfStateGet(void); + +/** + * Configure RAIL automatic state transitions after RX + * + * @param[in] success The next radio state to enter after a successful packet + * reception. + * @param[in] error The next radio state to enter after an error during packet + * reception. + * @param[in] ignoreErrors Define errors during packet handling to be ignored + * @return Returns zero on success and an error code on error. + * + * This function fails if unsupported transitions are passed in, or if the + * radio is currently in the RX state. Success can transition to TX, RX, or + * IDLE, while error can transition to RX or IDLE. The full list of options for + * the ignoreErrors parameter is any define that starts with RAIL_IGNORE_. + */ +RAIL_Status_t RAIL_SetRxTransitions(RAIL_RadioState_t success, + RAIL_RadioState_t error, + uint8_t ignoreErrors); + +/** + * Configure RAIL automatic state transitions after TX + * + * @param[in] success The next radio state to enter after a successful packet + * transmission. + * @param[in] error The next radio state to enter after an error during packet + * transmission. + * @return Returns zero on success and an error code on error. + * + * This function fails if unsupported transitions are passed in, or if the + * radio is currently the TX state. Success and error can each transition to RX + * or IDLE. + */ +RAIL_Status_t RAIL_SetTxTransitions(RAIL_RadioState_t success, + RAIL_RadioState_t error); + +/** + * Configure RAIL automatic state transition timing + * + * @param[in] timings The timings used to configure the RAIL state machine. This + * structure will be overwritten with the actual times that were set, in the + * case of an input timing that is invalid. + * @return Returns zero on success and an error code on error. + * + * The timings given will be close to the actual transition time, but there is + * some software overhead that is not yet characterized. Also, timings are not + * always adhered to when using an automatic transition after an error, due to + * the cleanup required to recover from the error. + */ +RAIL_Status_t RAIL_SetStateTiming(RAIL_StateTiming_t *timings); + +/** + * Place the radio into an idle state + * + * @return void + * + * This function is used to remove the radio from TX and RX states. + */ +void RAIL_RfIdle(void); + +/** + * Extended radio idle API + * + * @param[in] mode The method to use for shutting down the radio. + * @param[in] wait Whether this function should wait for the radio to reach idle + * before returning. + * + * This is an extended version of the simple RAIL_RfIdle() API which lets the + * application specify how it reaches idle state and if the function should + * busy wait. + */ +void RAIL_RfIdleExt(RAIL_RfIdleMode_t mode, bool wait); + +/** + * Start/Stop RF Sense functionality for use during low-energy sleep modes. + * + * @param[in] band The frequency band(s) on which to sense RF energy. + * To stop Rf Sense, specify \ref RAIL_RFSENSE_OFF. + * @param[in] senseTime The time (in microseconds) RF energy must be + * continually detected to be considered "sensed". + * @param[in] enableCb Set true to enable \ref RAILCb_RxRadioStatus() callback + * with status \ref RAIL_RX_CONFIG_RF_SENSED when Rf is sensed. Set false if + * prefer to poll via \ref RAIL_RfSensed(). + * + * @return The actual senseTime utilized, which may be different than + * requested due to limitations of the hardware. If 0, RF sense was + * disabled or it could not be enabled (no callback will be issued). + * + * The EFR32 has the ability to sense the presence of RF Energy above -20 dBm + * within either or both the 2.4 GHz and Sub-GHz bands, and trigger an event + * if that energy is continuously present for certain durations of time. + * + * @note After RF energy has been sensed, RF Sense is automatically disabled, + * and RAIL_RfSense() must be called again to reactivate it. + * + * @warning RF Sense functionality is only guaranteed from 0 to + * 85 degrees Celsius. RF Sense should be disabled + * outside this Temperature range. + */ +uint32_t RAIL_RfSense(RAIL_RfSenseBand_t band, uint32_t senseTime, bool enableCb); + +/** + * Check if RF was sensed. + * + * @return true if RF was sensed since last call to \ref RAIL_RfSense; false + * otherwise. + * + * This function is useful if \ref RAIL_RfSense has been called with enableCb + * set to false. It is generally used after EM4 reboot, but can be used any + * time. + */ +bool RAIL_RfSensed(void); + +/***************************************************************************//** + * Collect entropy from the radio if available. + * + * @param buffer The buffer to write the collected entropy to. + * @param bytes The number of bytes to fill in in the input buffer + * @return Returns the number of bytes of entropy we were able to collect. For + * chips that don't support entropy collection this will return 0. Values less + * than the requested amount may also be returned on platforms that use entropy + * pools to collect random data periodically. + * + * Attempts to fill up the provided buffer with the requested number of bytes of + * entropy. If we cannot provide as many bytes as requested then we will fill in + * whatever we can and return the number of bytes we were able to get. For chips + * that do not support this function we will always return 0 bytes. For + * information about the specific mechanism for gathering entropy consult the + * documentation for the chip family you're using. + ******************************************************************************/ +uint16_t RAIL_GetRadioEntropy(uint8_t *buffer, uint16_t bytes); + +/** + * @} + */ + +/** + * @addtogroup Memory_Management + * @brief Application callbacks to provide memory for RAIL actions. + * + * The RAIL library does not want to dictate how upper layers handle memory + * allocation for packet receive data. At the same time we need to put the + * packets somewhere to give them to the upper layers. To abstract this we + * require the user application to implement the RAILCb_AllocateMemory(), + * RAILCb_FreeMemory(), RAILCb_BeginWriteMemory(), and RAILCb_EndWriteMemory() + * callbacks. These callbacks will be called from interrupt context to interact + * with whatever memory allocation system your application uses. + * + * Memory will be allocated for receiving a packet whenever we think we need + * it. This depends on the chip you're using and possibly the size of your + * maximum packet. We will never ask for more memory than `MAX_PACKET_SIZE + + * sizeof(\ref RAIL_RxPacketInfo_t)` where MAX_PACKET_SIZE is the maximum + * packet your PHY is configured to receive over the air. Once you give us the + * handle to this memory it must stay valid until we tell you we are done with + * it using the RAILCb_FreeMemory() callback. Generally this will happen + * immediately after we call the RAILCb_RxPacketReceived() function with that + * handle. RAIL has no concept of an invalid handle so we will attempt to use + * whatever you pass to us. This means that you will still receive all + * callbacks for invalid handles even if we are forced to drop receive packet + * bytes because they don't fit anywhere. + * + * If the handle is invalid you must make sure your callbacks do not + * crash and that RAILCb_BeginWriteMemory() returns a NULL pointer or 0 bytes + * available so that we do not try to write to this memory. In this case, the + * packet data will be dropped. + * + * To actually write data to the handle you provide us we need to convert it + * into an actual memory pointer. We will do this each time we need to access + * the memory by calling RAILCb_BeginWriteMemory(). This function must return + * a pointer to the requested offset in the memory buffer allocated. If you are + * using non-contiguous memory buffers you can also return the number of bytes + * available before we need to re-request a pointer with a new offset. Once the + * access is complete we will call RAILCb_EndWriteMemory() with information + * about exactly how many bytes were written at the specified offset. After this + * call we will always call RAILCb_BeginWriteMemory() again before trying to + * write any more data. In the event that you receive an invalid handle these + * APIs must return NULL or set available bytes to 0 so that we do not attempt + * to write packet data to the buffer. + * + * This system is fairly flexible and can tie into many higher level memory + * allocation APIs. A simple example using one static buffer for memory + * allocation is shown below. You will probably want a more advanced system + * that can handle receiving multiple packets simultaneously. + * + * @code{.c} + * static uint8_t buffer[MAX_PACKET_SIZE + sizeof(RAIL_RxPacketInfo_t)]; + * static bool isAllocated = false; + * + * void *RAILCb_AllocateMemory(uint32_t size) + * { + * int i = 0; + * void *ptr = NULL; + * + * // We can't support sizes greater than the maximum buffer size + * if(size > (MAX_PACKET_SIZE + sizeof(RAIL_RxPacketInfo_t))) { + * return NULL; + * } + * + * // Disable interrupts and attempt to grab the buffer + * INT_Disable(); + * if (isAllocated) { + * ptr = NULL; + * } else { + * isAllocated = true; + * ptr = buffer; + * } + * INT_Enable(); + * + * return ptr; + * } + * + * void RAILCb_FreeMemory(void *ptr) + * { + * INT_Disable(); + * isAllocated = false; + * INT_Enable(); + * } + * + * void *RAILCb_BeginWriteMemory(void *handle, + * uint32_t offset, + * uint32_t *available) + * { + * return ((uint8_t*)handle) + offset; + * } + * + * void RAILCb_EndWriteMemory(void *handle, uint32_t offset, uint32_t size) + * { + * // Do nothing + * } + * @endcode + * + * @{ + */ + +/** + * Callback function used by RAIL to request memory. + * + * @param[in] size The amount of memory in bytes that we need for this packet + * @return A handle to memory in your storage system. + * + * This is used to allocate memory for receive packets and must be implemented + * by the application. + */ +void *RAILCb_AllocateMemory(uint32_t size); + +/** + * Callback function used by RAIL to free memory. + * + * @param[in] handle A handle to a memory block allocated with the + * RAILCb_AllocateMemory() API above. + * + * This is used to free memory that was allocated with the + * RAILCb_AllocateMemory() function when RAIL is done using it. + */ +void RAILCb_FreeMemory(void *handle); + +/** + * Called to begin copying received data into the current memory handle. + * + * @param[in] handle A handle to the current memory block for packet data. + * @param[in] offset The offset in bytes from the start of the handle that we + * need a pointer for. + * @param[out] available The number of bytes available to be written to this + * return pointer. If this is zero the receive will terminate. This parameter + * will default to all spaces allocated to handle contiguous allocators. If your + * allocator is different you *must* set this appropriately. + * @return A pointer to the address to write data for this handle. + * + * This function is called before every memory write to a handle so that we can + * get the actual address this handle references in the system. When we're done + * writing there will be a corresponding call to RAILCb_EndWriteMemory(). + * + * @note You must have at least `sizeof(RAIL_RxPacketInfo_t)` contiguous bytes at + * offset 0 or the appended info will not be written. + */ +void *RAILCb_BeginWriteMemory(void *handle, + uint32_t offset, + uint32_t *available); + +/** + * Called to complete the write memory transaction. + * + * @param handle The handle to the current memory block we're modifying. + * @param offset The offset in bytes from the start of the handle that this data + * was written to. + * @param size The number of bytes that were written. + * + * This callback indicates the completeion of a write memory transaction. It + * can be used to store information about how many bytes were written or + * anything else needed. Once this is called the pointer returned by + * RAILCb_BeginWriteMemory() will no longer be assumed to be valid and we will + * call that function again for any future writes. + */ +void RAILCb_EndWriteMemory(void *handle, uint32_t offset, uint32_t size); + +/** + * @} + */ + +/****************************************************************************** + * Timing Information + *****************************************************************************/ +/** + * @addtogroup System_Timing + * @brief Functionality related to the RAIL timer and general system time. + * + * These functions can be used to get information about the current system time + * or to manipulate the RAIL timer. + * + * The system time returned by RAIL_GetTime() is in the same timebase that is + * used throughout RAIL. Any callbacks that return a timestamp (like + * RAILCb_RxPacketReceived()) will use this same timebase as will any APIs that + * accept an absolute time for scheduling their action. Throughout this + * documentation the timebase used for this will be referred to as the RAIL + * timebase. This is currently a value in microseconds from chip boot time. This + * means that it will wrap every 1.19 hours + * (`(2^32 - 1) / (3600 sec/hr * 1000000 us/sec)`). + * + * The provided timer is hardware backed and interrupt driven. It can be used + * for timing any event in your system, but will be especially helpful for + * timing protocol based state machines and other systems that interact with + * the radio. If you do not want to process the expiration in interrupt context + * you can leave the RAILCb_TimerExpired() callback empty and poll for + * expiration with the RAIL_TimerExpired() function. + * + * @{ + */ + +/** + * Get the current RAIL time + * + * @return Returns the RAIL timebase in microseconds. Note that this wraps after + * around 1.19 hours since it's stored in a 32bit value. + * + * Return the current time in the RAIL timebase (microseconds). This can be + * used to compare with packet timestamps or to schedule transmits. + */ +uint32_t RAIL_GetTime(void); + +/** + * Set the current RAIL time + * + * @param[in] time Set the RAIL timebase to this value in microseconds. + * @return Returns RAIL_STATUS_NO_ERROR on success and + * RAIL_STATUS_INVALID_STATE if the time could not be set. + * + * Set the current time in the RAIL timebase in microseconds. + */ +RAIL_Status_t RAIL_SetTime(uint32_t time); + +/** + * Set a timer via the RAIL timebase + * + * @param[in] time The time to delay for in the RAIL timebase. + * @param[in] mode The timer mode can be relative to now or an absolute time. + * @return Returns RAIL_STATUS_NO_ERROR on success and + * RAIL_STATUS_INVALID_PARAMETER if the timer could not be scheduled. + * + * Configure a timer to fire after some period in the RAIL timebase. This timer + * can be used to implement low level protocol features. + */ +RAIL_Status_t RAIL_TimerSet(uint32_t time, RAIL_TimeMode_t mode); + +/** + * Return the absolute time that the RAIL timer is configured to fire at. + * + * @return The absolute time that this timer is set to go off at. + * + * This will give the absolute time regardless of the \ref RAIL_TimeMode_t that + * was passed into \ref RAIL_TimerSet. The return value is undefined if the + * timer was never set. + */ +uint32_t RAIL_TimerGet(void); + +/** + * Stop the currently scheduled RAIL timer. + * + * @return void + * + * Cancels the timer. If this is called before the timer fires, then + * RAILCb_TimerExpired will never be called. + */ +void RAIL_TimerCancel(void); + +/** + * Check to see if the RAIL timer has expired + * + * @return True if the previously scheduled timer has fired and false otherwise. + * + * This is cleared on RAIL_TimerSet() and will be set when the delay expires. + * This function can be used as an alternative to RAILCb_TimerExpired using + * polling. If this is the case, implement RAILCb_TimerExpired as a stub. + */ +bool RAIL_TimerExpired(void); + +/** + * See if the RAIL timer is currently running + * + * @return Returns true if the timer is running and false otherwise + * + * Will return false if the timer was never set or has expired. + */ +bool RAIL_TimerIsRunning(void); + +/** + * This function is called when the RAIL timer expires + * + * @return void + * + * You must implement a stub for this in your RAIL application even if you + * don't use the timer. You can use this callback for low-level protocol + * features. + */ +void RAILCb_TimerExpired(void); + +/** + * @} + */ + +/****************************************************************************** + * Radio Configuration + *****************************************************************************/ +/** + * @addtogroup Radio_Configuration + * @brief Routines for setting up and querying radio configuration information. + * + * All of these routines allow for runtime flexibility in your radio + * configuration. Some of the parameters, however, are meant to be generated + * from the radio calculator in Simplicity Studio. The basic code to configure + * the radio from this calculator output looks like the example below. + * + * @code{.c} + * // Apply the selected RADIO configuration + * if (RAIL_RadioConfig((void*)configList[0])) { + * // Error: Could not apply the radio configuration + * while(1); + * } + * + * // Configure the packet configuration for this PHY + * RAIL_PacketLengthConfigFrameType(frameTypeConfigList[0]); + * + * // Set up the channel configuration for this PHY + * RAIL_ChannelConfig(channelConfigs[0]); + * @endcode + * + * For more information about the types of parameters that can be changed in + * the other functions and how to use them see their individual documentation. + * + * @{ + */ + +/** + * Load a static radio configuration + * + * @param[in] radioConfig Pointer to a radio configuration array + * @return A non-zero value on failure and zero on success + * + * The radioConfig passed into this function should be generated for you, and + * not created or edited by hand. + */ +uint8_t RAIL_RadioConfig(void *radioConfig); + +/** + * Configure the length to use for received packets to be variable based on an + * implicit length field in payload bytes + * + * @param[in] frameType Frame type configuration structure. + * + * Currently the frame type passed in only handles packet length decoding. + */ +void RAIL_PacketLengthConfigFrameType(const RAIL_FrameType_t *frameType); + +/** + * Configure the channels supported by this device + * + * @param[in] config A pointer to the channel configuration for your device. + * This pointer will be cached in the library so it must be something that + * will exist for the runtime of the application. Typically this should be + * what is stored in Flash by the configuration tool. + * @return Returns first available channel in config. + * + * When configuring channels on the EFR32, the Synth will be reconfigured based + * on the frequency and channel spacing in config. +*/ +uint8_t RAIL_ChannelConfig(const RAIL_ChannelConfig_t * config); + +/** + * Check to see if the channel exists in RAIL + * + * @param[in] channel Channel number to check + * @return Returns 1 on failure, returns 0 on channel exists + * + * Will return 1 if the given channel does not exist in the channel config + * currently being used, and 0 if the channel is valid. + */ +RAIL_Status_t RAIL_ChannelExists(uint8_t channel); + +/** + * Return the symbol rate for the current PHY + * + * @return The symbol rate in symbols per second + * + * The symbol rate is the number of symbol changes over the air. For non DSSS + * PHYs this is the same as the baudrate. For DSSS PHYs it is the baudrate + * divided by the length of a chipping sequence. For more information on this + * consult the modem calculator documentation. + */ +uint32_t RAIL_SymbolRateGet(void); + +/** + * Return the bit rate for the current PHY + * + * @return The bit rate in bits per second + * + * The bit rate is the effective over the air data rate. It does not account + * for extra spreading you may do for things like forward error correction, but + * will account for modulation schemes, DSSS, and other configurations. For more + * information on this consult the modem calculator documentation. + */ +uint32_t RAIL_BitRateGet(void); + +/** + * Set the PA capacitor tune value for transmit and receive + * + * @param[in] txPaCtuneValue PA Ctune value for TX mode + * @param[in] rxPaCtuneValue PA Ctune value for RX mode + * + * @return returns RAIL_STATUS_NO_ERROR if successful + * + * Provides the ability to tune the impedance of the transmit + * and receive modes by changing the amount of capacitance at + * the PA output. + */ +RAIL_Status_t RAIL_PaCtuneSet(uint8_t txPaCtuneValue, uint8_t rxPaCtuneValue); + +/** + * @} + */ + +/****************************************************************************** + * Transmit + *****************************************************************************/ +/** + * @addtogroup Transmit + * @brief APIs related to transmitting data packets + * @{ + */ + +/** + * Set the radio transmit power level + * + * @param[in] powerLevel TX Power Level defined in deci dBm (0.0 dBm) + * @return TX Power Level in deci dBm (0.0 dBm) + * + * Not all values of powerLevel are achievable, but this function will set the + * power output to be close to the given powerLevel, and return the value that + * was set as the power. + */ +int32_t RAIL_TxPowerSet(int32_t powerLevel); + +/** + * Get the radio transmit power level + * + * @return TX Power Level defined in deci dBm (0.0 dBm) + * + * This will return what the power output was actually set to, not just the + * value passed into RAIL_TxPowerSet. + */ +int32_t RAIL_TxPowerGet(void); + +/** + * Load payload to send. + * + * @param[in] txData Pointer to a RAIL_TxData_t structure which defines the + * payload bytes and length to transmit. If the fields are configured for + * fixed length. + * @return Returns 0 on success and an error code on fail. + * + * This function may overwrite current TX data held by RAIL, and should not be + * called repetitively or during TX. The recommended way to use this is to call + * RAIL_TxDataLoad() and RAIL_TxStart() almost immediately in succession. + * + * Will return \ref RAIL_STATUS_INVALID_CALL if the Tx buffer is in use by the + * radio and cannot be updated. + */ +uint8_t RAIL_TxDataLoad(RAIL_TxData_t *txData); + +/** + * Non-blocking Transmit + * + * @param[in] channel Define the channel to transmit on. + * @param[in] preTxOp Function to use for any pre-transmit operation (e.g. for + * scheduled transmit, CSMA, LBT, etc.), or NULL for an immediate transmit. + * @param[in] preTxOpParams Pointer to the pre-transmit operation's + * configuration parameters, or NULL if none. + * @return Returns 0 on successfully initiating the transmit process, or an + * error code on failure. If successfully initiated, transmit completion + * or failure will be reported by later callbacks RAILCb_TxPacketSent() + * (success) or RAILCb_TxRadioStatus() (failure). + * + * Begins transmission of the payload previously loaded via RAIL_TxDataLoad(). + * Return error if currently transmitting or receiving. + */ +uint8_t RAIL_TxStart(uint8_t channel, + RAIL_PreTxOp_t preTxOp, + void *preTxOpParams); + +/** + * Non-blocking Transmit with options + * + * @param[in] channel Define the channel to transmit on. + * @param[in] options Defines options that apply for this transmit + * @param[in] preTxOp Function to use for any pre-transmit operation (e.g. for + * scheduled transmit, CSMA, LBT, etc.), or NULL for an immediate transmit. + * @param[in] preTxOpParams Pointer to the pre-transmit operation's + * configuration parameters, or NULL if none. + * @return Returns 0 on successfully initiating the transmit process, or an + * error code on failure. If successfully initiated, transmit completion + * or failure will be reported by later callbacks RAILCb_TxPacketSent() + * (success) or RAILCb_TxRadioStatus() (failure). + * + * This is an extension of RAIL_TxStart where the transmit is modified by the + * options defined in RAIL_TxOptions_t. If using a pre-tx operation, the + * transmit options will only be configured if the preTxOp is successful. + * + * Begins transmission of the payload previously loaded via RAIL_TxDataLoad(). + * Return error if currently transmitting or receiving. + */ +uint8_t RAIL_TxStartWithOptions(uint8_t channel, + RAIL_TxOptions_t *options, + RAIL_PreTxOp_t preTxOp, + void *preTxOpParams); + +/** + * Interrupt level callback to signify when the packet was sent + * + * @param txPacketInfo Information about the packet that was transmitted. + * @note that this structure is only valid during the timeframe of the + * callback. + * + * Currently the RAIL_TxPacketInfo_t only contains the time when the packet + * was transmitted. + */ +void RAILCb_TxPacketSent(RAIL_TxPacketInfo_t *txPacketInfo); + +/** + * Callback to indicate an error with a transmission + * + * @param[in] status A bit field that defines what event caused the callback + * + * This interrupt level callback allows the user finer granularity in handling + * TX radio errors. + * + * Radio Statuses: + * - \ref RAIL_TX_CONFIG_BUFFER_UNDERFLOW + * - \ref RAIL_TX_CONFIG_CHANNEL_BUSY + * - \ref RAIL_TX_CONFIG_TX_ABORTED + * - \ref RAIL_TX_CONFIG_TX_BLOCKED + */ +void RAILCb_TxRadioStatus(uint8_t status); + + +/****************************************************************************** + * Pre-Transmit Operations + *****************************************************************************/ +/** + * @addtogroup Pre-Transmit + * @brief APIs for pre-transmit operations (Scheduling, CSMA, LBT, ...) + * + * There are many operation that you can want to happen before a transmit. In + * RAIL these are configurable via Pre-Transmit hooks. You are free to use your + * own custom hooks, but there are several provided hooks to help with common + * use cases. The provided hooks will use the hardware as efficiently as + * possible which typically means that they do not introduce any software + * time overhead. + * + * Here's a simple example of how to use a scheduled transmit to send a packet + * 1 ms after right now. + * + * @code{.c} + * RAIL_ScheduleTxConfig_t nextPacketTxTime = { 1000, RAIL_TIME_DELAY }; + * txStatus = RAIL_TxStart(channel, &RAIL_ScheduleTx, &nextPacketTxTime); + * @endcode + * + * @{ + */ + +/** + * Send a packet on a schedule, instead of immediately + * + * @param[in] params A pointer to the RAIL_ScheduleTxConfig_t + * structure containing when the transmit should occur. + * @return - Returns 0 on success and anything else on error. + * + * A RAIL_PreTxOp_t function that schedules the transmit to occur at the + * specified absolute or relative time within a RAIL_TxStart() transmit + * operation. + */ +uint8_t RAIL_ScheduleTx(void *params); + +/** + * Use CSMA instead of ignoring current usage of the channel + * + * @param[in] params A pointer to the RAIL_CsmaConfig_t structure containing + * the CSMA parameters to use. + * @return - Returns 0 on success and anything else on error. + * + * A RAIL_PreTxOp_t function that performs the CSMA algorithm when specified + * within a RAIL_TxStart() transmit operation. + */ +uint8_t RAIL_CcaCsma(void *params); + +/** + * Listen to the channel before sending a message + * + * @param[in] params A pointer to the RAIL_LbtConfig_t structure containing + * the LBT parameters to use. + * @return Returns 0 on success and anything else on error. + * + * A RAIL_PreTxOp_t function that performs the LBT algorithm when specified + * within a RAIL_TxStart() transmit operation. + */ +uint8_t RAIL_CcaLbt(void *params); + +/** + * end of group Pre-Transmit + * @} + */ + +/** + * end of group Transmit + * @} + */ + +/****************************************************************************** + * Receive + *****************************************************************************/ +/** + * @addtogroup Receive + * @brief APIs related to packet receive + * @{ + */ + +/** + * Configure radio receive actions + * + * @param[in] cbToEnable Define which callbacks to trigger for receive events. + * The full list of available callabcks can be found by looking at the + * RAIL_RX_CONFIG_* set of defines. + * @param[in] appendedInfoEnable Enable/Disable appended info (not implemented) + * @return Return 0 for success or an error code + * + * Setup which receive interrupts will generate a RAILCb_RxRadioStatus() + * callback. The full list of options is any define that starts with + * RAIL_RX_CONFIG_. This function cannot be called while receiving. + */ +uint8_t RAIL_RxConfig(uint32_t cbToEnable, bool appendedInfoEnable); + +/** + * Listen on a channel for a packet + * + * @param[in] channel Channel to listen on + * @return Return 0 for success or an error code + * + * This is a non-blocking function. RAILCb_RxPacketReceived() will be called + * when a packet has been received. Returns an error is currently transmitting + * or receiving. + */ +uint8_t RAIL_RxStart(uint8_t channel); + +/** + * Schedule a receive window for some time in the future. + * + * @param[in] channel Channel to listen on + * @param[in] cfg The configuation struct to define the receive window. + * @return Return 0 on success or an error code + * + * This API will immediately change your channel and schedule receive to start + * at the specified time and end at the given end time. If you do not specify an + * end time then you may call this API later with an end time as long as you set + * the start time to disabled. You can also terminate the whole receive + * operation immediately using the RAIL_RfIdle() function. Note that relative + * end times are always relative to the start unless there is not start + * specified. + */ +uint8_t RAIL_ScheduleRx(uint8_t channel, RAIL_ScheduleRxConfig_t *cfg); + +/** + * Return the current raw RSSI + * + * @return Return \ref RAIL_RSSI_INVALID if the receiver is disabled and we are + * unable to get an RSSI value, otherwise, return the RSSI in quarter dBm, + * dbm*4. + * + * Get the current RSSI value. This value represents the current energy of the + * channel, so it can change rapidly, and will be low if there is no RF energy + * in your current channel. The function from the value reported to dBm is an + * offset dependent on the PHY and the PCB layout. Users should characterize the + * RSSI received on their hardware and apply an offset in the application to + * account for board and PHY parameters. + */ +int16_t RAIL_RxGetRSSI(void); + +/** + * Receive packet callback. + * + * @param[in] rxPacketHandle Contains a handle that points to the memory that + * the packet was stored in. This handle will be the same as something + * returned by the RAILCb_AllocateMemory() API. This handle will hold a + * RAIL_RxPacketInfo_t structure starting at offset 0 in the buffer. + * + * This function is called whenever a packet is received and returns to you the + * memory handle for where this received packet and its appended information was + * stored. After this callback is done we will release the memory handle so you + * must somehow increment a reference count or copy the data out within this + * function. + */ +void RAILCb_RxPacketReceived(void *rxPacketHandle); + +/** + * Called whenever an enabled radio status event occurs + * + * @param[in] status The event that triggered this callback + * + * The triggers that cause this function to be called can be enabled using the + * RAIL_RxConfig() function. + * + * @note This function will return only the first 8 of all possible triggers. + * For accessing all triggers see the new RAILCb_RxRadioStatusExt() API. If you + * implement RAILCb_RxRadioStatusExt() this callback will no longer be used by + * the RAIL library. In RAIL 2.0 this API will be merged with the + * RAILCb_RxRadioStatusExt() for one clean interface. + * + * Triggers: + * - \ref RAIL_RX_CONFIG_PREAMBLE_DETECT + * - \ref RAIL_RX_CONFIG_SYNC1_DETECT + * - \ref RAIL_RX_CONFIG_SYNC2_DETECT + * - \ref RAIL_RX_CONFIG_FRAME_ERROR + * - \ref RAIL_RX_CONFIG_BUFFER_OVERFLOW + * - \ref RAIL_RX_CONFIG_ADDRESS_FILTERED + * - \ref RAIL_RX_CONFIG_RF_SENSED + */ +void RAILCb_RxRadioStatus(uint8_t status); + +/** + * Called whenever an enabled radio status event occurs + * + * @param[in] status The event or events that triggered this callback + * + * The triggers that cause this function to be called can be enabled using the + * RAIL_RxConfig() function. This function is the same as RAILCb_RxRadioStatus() + * with an extended set of triggers. For backwards compatibility this function + * is weakly defined in the RAIL library to call RAILCb_RxRadioStatus() with the + * subset of valid events. If you need more events you must implement this + * version which will stop the old one from being called. + * + * @note In RAIL 2.0 this API will be merged with the RAILCb_RxRadioStatus() for + * one clean interface. + * + * Triggers: + * - \ref RAIL_RX_CONFIG_PREAMBLE_DETECT + * - \ref RAIL_RX_CONFIG_SYNC1_DETECT + * - \ref RAIL_RX_CONFIG_SYNC2_DETECT + * - \ref RAIL_RX_CONFIG_FRAME_ERROR + * - \ref RAIL_RX_CONFIG_BUFFER_OVERFLOW + * - \ref RAIL_RX_CONFIG_ADDRESS_FILTERED + * - \ref RAIL_RX_CONFIG_RF_SENSED + * - \ref RAIL_RX_CONFIG_TIMEOUT + * - \ref RAIL_RX_CONFIG_SCHEDULED_RX_END + */ +void RAILCb_RxRadioStatusExt(uint32_t status); + +/****************************************************************************** + * Address Filtering (Rx) + *****************************************************************************/ +/** + * @addtogroup Address_Filtering + * @brief Configuration APIs for receive packet address filtering. + * + * The address filtering code examines the packet as follows. + * + * | `Bytes: 0 - 255` | `0 - 8` | `0 - 255` | `0 - 8` | `Variable` | + * |:----------------:|---------:|----------:|---------:|:----------:| + * | `Data0` | `Field0` | `Data1` | `Field1` | `Data2` | + * + * In the above structure, anything listed as DataN is an optional section of + * bytes that RAIL will not process for address filtering. The FieldN segments + * reference the specific sections in the packet that will each be interpreted + * as an address during address filtering. The application may submit up to four + * addresses to attempt to match each field segment and each address may have a + * size of up to 8 bytes. To setup + * address filtering you must first configure where the addresses are in your + * packet and how long they are. Next, you need to configure what combinations + * of matches in Field0 and Field1 should constitute an address match. Lastly, + * you need to enter addresses into the tables for each field and enable them. + * The first two of these are part of the RAIL_AddrConfig_t structure while the + * second part is configured at runtime using the RAIL_AddressFilterSetAddress() + * API. A brief description of each of these configurations is listed below. + * + * For the first piece of configuration, the offsets and sizes of the fields are + * assumed to be fixed for the RAIL address filter. To set them you must specify + * arrays for these values in the sizes and offsets entries in the + * RAIL_AddrConfig_t struct. A size of zero will indicate that a field is + * disabled. The start offset for a field is relative to the previous start + * offset and if you're using FrameType decoding the first start offset is + * relative to the end of the byte containing the frame type. + * + * Configuring which combinations of Field0 and Field1 constitute a match is the + * most complex portion of the address filter. The easiest way to think about + * this is with a truth table. If you consider each of the four possible address + * entries in a field then you can have a match on any one of those or a match + * for none of them. We can represent this as a 4 bit mask where a 1 indicates a + * match and a 0 indicates no match. If we then show the Field0 match options as + * rows and the Field1 options as columns we get a truth table like the one + * shown below. + * + * | | 0000 | 0001 | 0010 | 0100 | 1000 | + * |----------|------|------|------|------|------| + * | __0000__ | bit0 | bit1 | bit2 | bit3 | bit4 | + * | __0001__ | bit5 | bit6 | bit7 | bit8 | bit9 | + * | __0010__ | bit10| bit11| bit12| bit13| bit14| + * | __0100__ | bit15| bit16| bit17| bit18| bit19| + * | __1000__ | bit20| bit21| bit22| bit23| bit24| + * + * Since this is only 25 bits it can be represented in one 32bit integer where a + * 1 indicates filter pass and a 0 indicates filter fail. This is the matchTable + * parameter in the configuration struct and it is what's used during filtering. + * For common simple configurations we provide two defines, the truth tables for + * which are shown below. The first is \ref + * ADDRCONFIG_MATCH_TABLE_SINGLE_FIELD and it can be used if you're only using + * one address field (either field). If you're using two fields and want to + * force in the same address entry in each field you can use second define: \ref + * ADDRCONFIG_MATCH_TABLE_DOUBLE_FIELD. For more complex systems you'll have to + * create a valid table on your own. + * + * @note When using a 38.4 MHz crystal, address filtering will not function with + * any data rate greater than 1Mbps. + * + * @{ + */ + +/** + * Configure address filtering. + * + * @param addrConfig The configuration structure which defines how addresses + * are setup in your packets. + * @return True if we were able to configure address filtering and false + * otherwise. + * + * This function must be called to setup address filtering. You may call this + * multiple times, but all previous information is wiped out each time you call + * it so any configured addresses must be reset. + */ +bool RAIL_AddressFilterConfig(RAIL_AddrConfig_t *addrConfig); + +/** + * Enable address filtering. + * + * @return True if address filtering was enabled to start with and false + * otherwise + * + * Only allow packets through that pass the current address filtering + * configuration. This will not reset or change the configuration so you can + * set that up before turning this feature on. + */ +bool RAIL_AddressFilterEnable(void); + +/** + * Disable address filtering. + * + * @return True if address filtering was enabled to start with and false + * otherwise + * + * Allow all packets through regardless of addressing information. This will not + * reset or change the current configuration. + */ +bool RAIL_AddressFilterDisable(void); + +/** + * Return whether address filtering is currently enabled. + * + * @return True if address filtering is enabled and false otherwise + */ +bool RAIL_AddressFilterIsEnabled(void); + +/** + * Reset the address filtering configuration. + * + * Reset all structures related to address filtering. This will not disable + * address fitlering. It will leave the radio in a state where no packets will + * pass filtering. + */ +void RAIL_AddressFilterReset(void); + +/** + * Set an address for filtering in hardware. + * + * @param field Which address field you want to use for this address + * @param index Which match entry you want to place this address in for the + * given field. + * @param value A pointer to the address data. This must be at least as long + * as the size specified in RAIL_AddressFilterConfig(). + * @param enable A boolean to indicate whether this address should be enabled + * immediately. + * @return True if we were able to set this address and false otherwise. + * + * This function will load the given address into hardware for filtering and + * start filtering on it if you set the enable parameter to true. Otherwise, + * you must call RAIL_AddressFilterEnableAddress() to turn it on later. + */ +bool RAIL_AddressFilterSetAddress(uint8_t field, + uint8_t index, + uint8_t *value, + bool enable); + +/** + * Enable address filtering for the specified address + * + * @param field Which address field you want to enable the address within + * @param index Which match entry in the given field you want to enable + * @return True if we were able to enable filtering for this address and false + * otherwise. + */ +bool RAIL_AddressFilterEnableAddress(uint8_t field, uint8_t index); + +/** + * Disable address filtering for the specified address + * + * @param field Which address field you want to disable the address within + * @param index Which match entry in the given field you want to disable + * @return True if this address disabled successfully and false otherwise. + * + * This will clear the matchMask set in the RAIL_AddressFilterEnableAddress() + * function and make sure that this address is marked as valid. To use it in + * filtering again you must enable this address again. + */ +bool RAIL_AddressFilterDisableAddress(uint8_t field, uint8_t index); + +/** + * Configure address filtering based on frame type + * + * @param validFrames The frames on which to enable address filtering. Each bit + * corresponds to a frame, where a 1 means to enable address filtering during + * that frame, and a 0 means to ignore addresses during that frame.. The least + * significant bit corresponds to frame 0, and the most significant bit to + * frame 7. + * @return True if configuration was set properly, false otherwise + * + * This function only takes effect if frame type length decoding and address + * filtering are both being used. In that case, this function gives the ability + * to only enable address filtering on certain types of frames. + * + * @note This function must be called after RAIL_AddressFilterConfig for it to + * take effect. + */ +bool RAIL_AddressFilterByFrameType(uint8_t validFrames); + +/** + * end of group Address_Filtering + * @} + */ + +/** + * end of group Receive + * @} + */ + +/****************************************************************************** + * Auto Acking + *****************************************************************************/ +/** + * @addtogroup Auto_Ack + * @brief APIs for configuring Auto-Ack functionality + * + * These APIs are used to configure the radio for auto acknowledgement + * features. Auto ack inherently changes how the underlying state machine + * behaves so users should not modify RAIL_SetRxTransitions() and + * RAIL_SetTxTransitions() while using auto ack features. + * + * @code{.c} + * // Go to RX after ack operation, 100 us idle->rx/tx, + * // 192 us rx->tx/tx->rx, 1000 us ack timeout + * RAIL_AutoAckConfig_t autoAckConfig = { RAIL_RF_STATE_RX, 100, 192, 1000}; + * + * RAIL_Status_t status = RAIL_AutoAckConfig(&autoAckConfig); + * + * uint8_t ackPayload[] = {0x05, 0x02, 0x10, 0x00}; + * RAIL_AutoAckData_t ackData = {ackPayload, sizeof(ackPayload)}; + * + * RAIL_Status_t status = RAIL_AutoAckLoadBuffer(&ackData); + * @endcode + * + * The acknowledgement will transmit based on the frame format configured via + * the Radio Configurator. For example, if the frame format is using a variable + * length scheme, the ack will be sent according to that scheme. If a 10 byte + * packet is loaded into the ack, but the variable length field of the ack + * payload specifies a length of 5, only 5 bytes will transmit for the ack. + * The converse is also true, if the frame length is configured to be a fixed + * 10 byte packet but only 5 bytes are loaded into the ack buffer then a TX + * underflow will occur during the ack transmit. + * + * When auto ack is enabled, the default operation is to transmit the ack after + * a receive and wait for an ack after a transmit. After the ack operation + * completes, the radio will transition to the configured defaultState. If + * there is a desire to not auto acknowledge a series of packets after transmit + * or receive, call RAIL_AutoAckTxPause() and RAIL_AutoAckRxPause(). When + * auto acking is paused, after successfully receiving or transmitting a + * packet, the radio will transition to the defaultState. To get out of a + * paused state and resume auto acking, call RAIL_AutoAckTxResume() or + * RAIL_AutoAckRxResume(). + * + * Applications can cancel the transmission of an ack with + * RAIL_AutoAckCancelAck(). Conversly, applications can control if a transmit + * operation should wait for an ack after transmitting by using + * RAIL_TxStartWithOptions() and populating the waitForAck field in + * \ref RAIL_TxOptions_t. + * + * @code{.c} + * void RAILCb_RxPacketReceived(void *rxPacketHandle) + * { + * // If we have just received an ACK, don't respond with an ACK + * if (rxPacketInfo->dataPtr[2] == 0xF1) + * { + * RAIL_AutoAckCancelAck(); + * } + * } + * + * void transmitAndWaitForAck (void) + * { + * RAIL_TxOptions_t txOption; + * txOption.waitForAck = true; + * RAIL_Status_t status = RAIL_TxStartWithOptions(0, &txOption, NULL, NULL); + * } + * @endcode + * + * If the ack payload is dynamic, the application must call + * RAIL_AutoAckLoadBuffer() with the appropriate ack payload after the + * application processes the receive. RAIL can auto ack from the normal + * transmit buffer if RAIL_AutoAckUseTxBuffer() is called before the radio + * transmits the ack. Make sure the transmit buffer contains data loaded by + * RAIL_TxDataLoad(). + * + * Standards based protocols that contain auto ack functionality are normally + * configured in the protocol specific config function. For example, + * RAIL_IEEE802154_Init() provides auto ack configuration parameters in \ref + * RAIL_IEEE802154_Config_t and should only be configured through that + * function. It is unadvised to call both RAIL_IEEE802154_Init() and + * RAIL_AutoAckConfig(). However, ack modification functions are still valid to + * use with protocol specific acks. To cancel a IEEE 802.15.4 ack transmit, use + * RAIL_AutoAckCancelAck(). + * + * @{ + */ + +/** + * Disable Automatic Acknowledgement + * + * @return if function successfully disabled auto acking + * + * Disable auto ack functionality. All state transitions are reverted to IDLE, + * IDLE. + */ +RAIL_Status_t RAIL_AutoAckDisable(void); + +/** + * Return the enable status of the auto ack feature + * + * @return true if Auto Ack is enabled, false if disabled + */ +bool RAIL_AutoAckIsEnabled(void); + +/** + * Configure and enable Auto Acknowledgement + * + * @param[in] config Auto ack config structure + * @return If autoack is successfully enabled + * + * Configures the RAIL state machine to for hardware accelerated auto + * acknowledgement. Ack timing parameters are defined in the configuration + * structure. + * + * While auto acking is enabled do not call the following RAIL functions: + * - RAIL_SetRxTransitions() + * - RAIL_SetTxTransitions() + * - RAIL_SetStateTiming() + */ +RAIL_Status_t RAIL_AutoAckConfig(RAIL_AutoAckConfig_t *config); + +/** + * Load Auto Ack buffer with ack data + * + * @param[in] ackData Pointer to ack data to transmit + * @return \ref RAIL_STATUS_INVALID_CALL if called while ACK buffer is being + * used by the radio + * + * If the ack buffer is available to be updated, load the ack buffer with data. + */ +RAIL_Status_t RAIL_AutoAckLoadBuffer(RAIL_AutoAckData_t *ackData); + +/** + * Pause RX Auto Ack functionality. + * + * @return void + * + * When RX Auto Acking is paused, the radio will transition to the defaultState + * after receiving a packet and will not transmit an ack. + * + */ +void RAIL_AutoAckRxPause(void); + +/** + * Resume Rx Auto Ack functionality. + * + * @return void + * + * When Rx Auto Ack is resumed, the radio will resume automatically acking + * every successfully received packet. + */ +void RAIL_AutoAckRxResume(void); + +/** + * Return if Rx Auto Ack is paused + * + * @return true if Rx Auto Ack is paused, false if not paused + */ +bool RAIL_AutoAckRxIsPaused(void); + +/** + * Resume Tx Auto Ack functionality. + * + * @return void + * + * When Tx Auto Ack is resumed, the radio will resume automatically waiting for + * an ack after a successful transmit. + */ +void RAIL_AutoAckTxResume(void); + +/** + * Pause TX Auto Ack functionality. + * + * @return void + * + * When TX Auto Acking is paused, the radio will transition to the defaultState + * after transmitting a packet and will not wait for an ack. + * + */ +void RAIL_AutoAckTxPause(void); + +/** + * Return if Tx Auto Ack is paused + * + * @return true if Tx Auto Ack is paused, false if not paused + */ +bool RAIL_AutoAckTxIsPaused(void); + +/** + * Modify the upcoming ack to use the TX Buffer + * + * @return True if the ack is modified to send from TX buffer, false if it is + * too late to switch to tx buffer or if the function call is not valid + * + * This function allows the application to use the normal TX buffer as the data + * source for the upcoming ack. The ack modification to use the TX buffer only + * applies to one ack transmission. + * + * This function will only return true if the following conditions are met: + * - Radio has not already decided to use the ack buffer AND + * - Radio is either looking for sync, receiving the packet after sync or in + * the Rx2Tx turnaround before the ack is sent. + */ +bool RAIL_AutoAckUseTxBuffer(void); + +/** + * Cancel the upcoming ack + * + * @return True if the ack is successfully cancelled, false if it is + * too late to cancel the ack or if the function call is not valid + * + * This function allows the application to use cancel the upcoming automatic + * acknowledgement. + * + * This function will only return true if the following conditions are met: + * - Radio has not already decided to transmit the ack AND + * - Radio is either looking for sync, receiving the packet after sync or in + * the Rx2Tx turnaround before the ack is sent. + */ +bool RAIL_AutoAckCancelAck(void); + +/** + * Return if the radio is currently waiting for an ack + * + * @return True if radio is waiting for ack, False if radio is not waiting for + * an ack + * + * This function allows the application to query if the radio is currently + * waiting for an ack after a transmit operation. + */ +bool RAIL_AutoAckWaitingForAck(void); + +/** + * Callback that notifies the application when searching for an ACK has timed + * out. + * + * @return void + * + * This callback function is called whenever the timeout for searching for an + * ack is exceeded. + */ +void RAILCb_RxAckTimeout(void); + +/** + * @} endof Auto_Acking + */ + +/****************************************************************************** + * Calibration + *****************************************************************************/ +/** + * @addtogroup Calibration + * @brief APIs for calibrating the radio + * @{ + * + * These APIs can be used to calibrate the radio. The RAIL library will + * determine what calibrations are necessary to be performed. Calibrations can + * be enabled/disabled in RAIL_Init_t.calEnable. + * + * Some calibrations produce values that can be saved and reapplied to + * save repetition of the calibration process. RAIL_CalValues_t is the + * structure to communicate this value between RAIL and the application. + */ + +/** + * Initialize RAIL Calibration + * + * @param[in] railCalInit The initialization structure to be used for setting + * up calibration procedures. + * @return Returns zero on success and an error code on error. + * + * Calibration initialization provides the calibration settings that + * correspond to the current radio configuration. + */ +uint8_t RAIL_CalInit(const RAIL_CalInit_t *railCalInit); + +/** + * Start the calibration process + * + * @param[in] calValues Calibration Values to apply. To force the calibration + * algorithm to run set the value to \ref RAIL_CAL_INVALID_VALUE. + * @param[in] calForce Mask to force certain calibration(s) to execute. These + * will run even if not enabled during initialization. If specified, only forced + * calibrations will be run. + * @param[in] calSave If true, we will update any invalid values in calValues + * with their computed value. You can use this to save calibrations across runs. + * + * This function begins the calibration process while determining which + * calibrations should be performed. The possible list of calibration options + * are configured in RAIL_Init_t.calEnable parameter. + * + * If the calibration was performed previously and the application saves off + * the calibration value, it can be passed into function and applied to the + * chip. If the calibration value provided is \ref RAIL_CAL_INVALID_VALUE then + * the calibration will be performed to set this value. If calSave is set, the + * calibration output will update the pointer's value. If a NULL pointer is + * passed in all calibrations requested/required will be performed and the + * results will not be saved regardless of the calSave parameter. + * + * @note Some calibrations should only be executed when the radio is IDLE. See + * chip-specific documentation for more detail. + */ +void RAIL_CalStart(RAIL_CalValues_t *calValues, RAIL_CalMask_t calForce, bool calSave); + +/** + * Returns the current set of pending calibrations + * + * @return A mask of all pending calibrations that the user has been asked to + * perform. + * + * This function will return a full set of pending calibrations. The only way + * to clear pending calibrations is to perform them using the \ref RAIL_CalStart() + * API with the appropriate list of calibrations. + */ +RAIL_CalMask_t RAIL_CalPendingGet(void); + +/** + * Callback that notifies the application that a calibration is needed. + * + * @return void + * + * This callback function is called whenever the RAIL library detects that a + * calibration is needed. It is up to the application to determine a valid + * window to call \ref RAIL_CalStart(). + */ +void RAILCb_CalNeeded(void); + +/** + * @} + */ + +/****************************************************************************** + * Diagnostic + *****************************************************************************/ +/** + * @addtogroup Diagnostic + * @brief APIs for diagnostic and test chip modes + * @{ + */ + +/** + * Enable or disable direct mode for RAIL. + * + * @param[in] enable Whether to turn direct mode on or off. At some point this + * will include a configuration structure. + * @warning This API configures fixed pins for tx data in, rx data out, rx clock + * out. There should be more control over these pins in the future but they are + * currently fixed. + * + * In this mode packets will be output and input directly to the radio via GPIO + * and RAIL packet handling will be ignored. On the EFR32, the DIN pin in TX is + * EFR32_PC10, which corresponds to EXP_HEADER15/WSTKP12, and the DOUT pin in + * RX is EFR32_PC11, which corresponds to EXP_HEADER16/WSTKP13. + */ +void RAIL_DirectModeConfig(bool enable); + +/** + * Set the crystal tuning + * + * @param[in] tune Chip dependent crystal capacitor bank tuning parameter + * + * Tune the crystal that the radio depends on, to change the location of the + * center frequency for transmitting and receiving. + */ +void RAIL_SetTune(uint32_t tune); + +/** + * Get the crystal tuning + * + * @return Chip dependent crystal capacitor bank tuning parameter + * + * Retrieve the current tuning value used by the crystal that the radio + * depends on. + */ +uint32_t RAIL_GetTune(void); + +/** + * Starts transmitting a tone on a certain channel + * + * @param[in] channel Define the channel to emit a tone + * @return Returns 0 on success and 1 on error + * + * Transmits a continuous wave, or tone, at the given channel, as defined by + * the channel configuration passed to RAIL_ChannelConfig(). + */ +uint8_t RAIL_TxToneStart(uint8_t channel); + +/** + * Stop tone transmission + * + * @return Returns 0 on success and 1 on error + * + * Halt the transmission started by RAIL_TxToneStart(). + */ +uint8_t RAIL_TxToneStop(void); + +/** + * Start transmitting a stream on a certain channel + * + * @param[in] channel Channel on which to emit a stream + * @param[in] mode Choose the stream mode (PN9, etc) + * @return Returns 0 on success and 1 on error + * + * Emits an encoded stream of bits on the given channel, from either a PN9 or + * pseudo-random source. + */ +uint8_t RAIL_TxStreamStart(uint8_t channel, RAIL_StreamMode_t mode); + +/** + * Stop stream transmission + * + * @return Returns 0 on success and 1 on error + * + * Halt the transmission started by RAIL_TxStreamStart(). + */ +uint8_t RAIL_TxStreamStop(void); + +/** + * Configure BER test + * + * @param[in] berConfig BER test parameters to apply. + * + * Configure settings specific to bit error rate (BER) testing. + * During BER test mode, this device will expect to receive a standard PN9 + * signal (x^9 + x^5 + 1). In order to use this BER test, the selection + * for BER mode should be enabled from the radio configurator. + */ +void RAIL_BerConfigSet(RAIL_BerConfig_t *berConfig); + +/** + * Start BER test + * + * @return void + * + * Enter BER receive with the settings specified by RAIL_BerConfigSet(). + * This also resets the BER status. + */ +void RAIL_BerRxStart(void); + +/** + * Stop BER test + * + * @return void + * + * Halt a test early, or exit infinite BER receive mode. + */ +void RAIL_BerRxStop(void); + +/** + * Get BER test status + * + * @param[out] status Statistics pertaining to the latest BER test. + * @return void + * + * Get status of latest BER test. + */ +void RAIL_BerStatusGet(RAIL_BerStatus_t *status); + +/** + * @} + */ + + +/****************************************************************************** + * Debug + *****************************************************************************/ +/** + * @addtogroup Debug + * @brief APIs for debugging + * @{ + */ + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +/** + * Configure Debug callbacks (all are optional) + * + * @param[in] cbToEnable Define statuses that force TxRadioStatus callback + */ +void RAIL_DebugCbConfig(uint32_t cbToEnable); + +/** + * Configure the debug mode for the radio library. Do not use this function + * unless instructed to by Silicon Labs. + * @param debugMode The debug mode to enter + * @return Whether this command ran successfully or not. + */ +RAIL_Status_t RAIL_DebugModeSet(uint32_t debugMode); + +uint32_t RAIL_DebugModeGet(void); + +/** + * Override the radio base frequency + * + * @param[in] freq Desired frequency in Hz + * + * Sets the radio to transmit at a the frequency given. This function can only + * be used while in RAIL_DEBUG_MODE_FREQ_OVERRIDE. The given frequency needs + * to be close to the base frequency of the current PHY. + */ +RAIL_Status_t RAIL_DebugFrequencyOverride(uint32_t freq); +#endif + +/** + * Interrupt level callback to signify when the radio changes state. This is + * for debug and __NOT__ for application use. It is not called by default but + * is required for the linking process. + * + * Create an empty function for this callback. + * + * @code{.c} + * RAILCb_RadioStateChanged(uint8_t state) { + * } + * @endcode + */ +#ifndef DOXYGEN_SHOULD_SKIP_THIS +/** + * @param[in] state Current state of the radio, as defined by EFR32 data sheet + * TODO: Unify these states with the RAIL_RadioState_t type? (There are much + * more than just TX, RX, and IDLE) + */ +#endif +void RAILCb_RadioStateChanged(uint8_t state); + +/** + * @} + */ + +/** + * end of RAIL_API + * @} + */ + +#endif // __RAIL_H__ diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/rail_chip_specific.h b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/rail_chip_specific.h new file mode 100644 index 0000000000..fad46dab6c --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/rail_chip_specific.h @@ -0,0 +1,92 @@ +/***************************************************************************//** + * @file rail_chip_specific.h + * @brief This file contains the type definitions for EFR32 chip specific + * aspects of RAIL. + * @copyright Copyright 2015 Silicon Laboratories, Inc. http://www.silabs.com + ******************************************************************************/ + +#ifndef __RAIL_CHIP_SPECIFIC_H_ +#define __RAIL_CHIP_SPECIFIC_H_ + +// Include standard type headers to help define structures +#include +#include +#include + +// ----------------------------------------------------------------------------- +// Calibration +// ----------------------------------------------------------------------------- +/** + * @addtogroup Calibration + * @{ + */ + +/** + * @addtogroup EFR32 + * @{ + * @brief EFR32 Specific Calibrations + * + * The EFR32 has two supported calibrations. There is the Image Rejection (IR) + * calibration and a temperature dependent calibration. The IR calibration is + * something that can be computed once and stored off or computed each time at + * startup. It is PHY specific and provides sensitivity improvements so we + * highly recommend using it. The IR calibration should only be run when the + * radio is IDLE. The temperature dependent calibrations are used to + * recalibrate the synth if the temperature falls below 0 or changes by a + * certain amount while sitting in receive. We will do this automatically upon + * entering the receive state so you may omit this calibration if you feel that + * your stack will turn receive on and off frequently enough. If you do not + * calibrate for temperature it's possible to miss receive packets due to drift + * in the carrier frequency. + */ + +/** + * @struct RAIL_CalValues_t + * @brief Calibration value structure + * + * This structure contains the set of persistent calibration values for the + * EFR32. You can set these before hand and apply them at startup to save the + * time required to compute them. Any of these values may be set to + * RAIL_CAL_INVALID_VALUE to force the code to compute that calibration value. + */ +typedef struct RAIL_CalValues { + uint32_t imageRejection; /**< Image Rejection (IR) calibration value */ +} RAIL_CalValues_t; + +/** Invalid calibration value */ +#define RAIL_CAL_INVALID_VALUE (0xFFFFFFFF) + +/** + * A define to set all RAIL_CalValues_t values to uninitialized. + * + * This define can be used when you have no data to pass to the calibration + * routines but wish to compute and save all possible calibrations. + */ +#define RAIL_CALVALUES_UNINIT { \ + RAIL_CAL_INVALID_VALUE, \ +} + +/** EFR32 specific temperature calibration bit */ +#define RAIL_CAL_TEMP_VCO (0x00000001) +/** EFR32 specific IR calibration bit */ +#define RAIL_CAL_ONETIME_IRCAL (0x00010000) + +/** Mask to run temperature dependent calibrations */ +#define RAIL_CAL_TEMP (RAIL_CAL_TEMP_VCO) +/** Mask to run one time calibrations */ +#define RAIL_CAL_ONETIME (RAIL_CAL_ONETIME_IRCAL) +/** Mask to run optional performance calibrations */ +#define RAIL_CAL_PERF () +/** Mask for calibrations that require the radio to be off */ +#define RAIL_CAL_OFFLINE (RAIL_CAL_ONETIME_IRCAL) +/** Mask to run all possible calibrations for this chip */ +#define RAIL_CAL_ALL (RAIL_CAL_TEMP | RAIL_CAL_ONETIME) +/** Mask to run all pending calibrations */ +#define RAIL_CAL_ALL_PENDING (0x00000000) + +/** + * @} + * @} + */ + +#endif diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/rail_types.h b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/rail_types.h new file mode 100644 index 0000000000..75de9d0e98 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/rail_types.h @@ -0,0 +1,855 @@ +/***************************************************************************//** + * @file rail_types.h + * @brief This file contains the type definitions for RAIL structures, enums, + * and other types. + * @copyright Copyright 2015 Silicon Laboratories, Inc. http://www.silabs.com + ******************************************************************************/ + +#ifndef __RAIL_TYPES_H__ +#define __RAIL_TYPES_H__ + +// Include standard type headers to help define structures +#include +#include +#include + +#include "rail/rail_chip_specific.h" + +/** + * @addtogroup RAIL_API + * @{ + */ + +// ----------------------------------------------------------------------------- +// Calibration Structures +// ----------------------------------------------------------------------------- +/** + * @addtogroup Calibration + * @{ + */ + +/** + * @typedef RAIL_CalMask_t + * @brief Calibration mask type + * + * This type is a bitmask of different RAIL calibration values. The exact + * meaning of these bits depends on what your particular chip supports. + */ +typedef uint32_t RAIL_CalMask_t; + +/** + * @struct RAIL_CalInit_t + * @brief Initialization structure for RAIL calibrations. + */ +typedef struct RAIL_CalInit { + RAIL_CalMask_t calEnable; /**< Mask that defines calibrations to perform in RAIL. */ + const uint8_t *irCalSettings; /**< Pointer to image rejection calibration settings. */ +} RAIL_CalInit_t; + +/** + * @} + */ + +// ----------------------------------------------------------------------------- +// Radio Configuration Structures +// ----------------------------------------------------------------------------- + +/** + * @addtogroup General + * @{ + */ + +/** + * @struct RAIL_Version_t + * @brief Contains RAIL Library Version Information + */ +typedef struct RAIL_Version { + uint32_t hash; /**< Git hash */ + uint8_t major; /**< Major number */ + uint8_t minor; /**< Minor number */ + uint8_t rev; /**< Revision number */ + uint8_t build; /**< Build number */ + uint8_t flags; /**< Build flags */ +} RAIL_Version_t; + +/** + * @struct RAIL_Init_t + * @brief Initialization structure for the RAIL library. + */ +typedef struct RAIL_Init { + uint16_t maxPacketLength; /**< The maximum number of bytes in a packet. */ + const uint32_t rfXtalFreq; /**< The xtal frequency of the radio. */ + RAIL_CalMask_t calEnable; /**< Mask that defines calibrations to perform in RAIL. */ +} RAIL_Init_t; + +/** + * @enum RAIL_PtiProtocol_t + * @brief The protocol that RAIL outputs via the Packet Trace Interface (PTI) + */ +typedef enum RAIL_PtiProtocol { + RAIL_PTI_PROTOCOL_CUSTOM = 0, /**< PTI output for a custom protocol */ + RAIL_PTI_PROTOCOL_ZIGBEE = 1, /**< PTI output for the Zigbee protocol */ + RAIL_PTI_PROTOCOL_THREAD = 2, /**< PTI output for the Thread protocol */ + RAIL_PTI_PROTOCOL_BLE = 3, /**< PTI output for the Bluetooth Smart protocol */ + RAIL_PTI_PROTOCOL_CONNECT = 4, /**< PTI output for the Connect protocol */ + RAIL_PTI_PROTOCOL_MAX = 0xF /**< Maximum possible protocol value for PTI */ +} RAIL_PtiProtocol_t; + +/** + * @enum RAIL_RadioState_t + * @brief The current state of the radio + */ +typedef enum RAIL_RadioState { + RAIL_RF_STATE_IDLE, /**< Radio is idle */ + RAIL_RF_STATE_RX, /**< Radio is in receive */ + RAIL_RF_STATE_TX, /**< Radio is in transmit */ +} RAIL_RadioState_t; + +/** + * @enum RAIL_Status_t + * @brief The available status options + */ +typedef enum RAIL_Status { + RAIL_STATUS_NO_ERROR, /**< RAIL function reports no error */ + RAIL_STATUS_INVALID_PARAMETER, /**< Call to RAIL function errored because of an invalid parameter */ + RAIL_STATUS_INVALID_STATE, /**< Call to RAIL function errored because called during an invalid radio state */ + RAIL_STATUS_INVALID_CALL, /**< The function is called in an invalid order */ +} RAIL_Status_t; + +/** + * @enum RAIL_RfSenseBand_t + * @brief Enumeration for specifying Rf Sense frequency band. + */ +typedef enum { + RAIL_RFSENSE_OFF, /**< RFSense is disabled */ + RAIL_RFSENSE_2_4GHZ, /**< RFSense is in 2.4G band */ + RAIL_RFSENSE_SUBGHZ, /**< RFSense is in subgig band */ + RAIL_RFSENSE_ANY, /**< RfSense is in both bands */ + RAIL_RFSENSE_MAX // Must be last +} RAIL_RfSenseBand_t; + +/** + * @enum RAIL_RfIdleMode_t + * @brief Enumeration for the different types of idle modes we support. These + * vary how quickly and destructively we will put the radio into idle. + */ +typedef enum { + /** + * Idle the radio by turning off receive and canceling any future scheduled + * receive or transmit operations. This will not abort a receive or + * transmit that is in progress. + */ + RAIL_IDLE, + /** + * Idle the radio by turning off receive and any scheduled events. This will + * also abort any receive, transmit, or scheduled events in progress. + */ + RAIL_IDLE_ABORT, + /** + * Force the radio into a shutdown mode as quickly as possible. This will + * abort all current operations and cancel any pending scheduled operations. + * It may also corrupt receive or transmit buffers and end up clearing them. + */ + RAIL_IDLE_FORCE_SHUTDOWN +} RAIL_RfIdleMode_t; + +/** + * @} + */ + +// ----------------------------------------------------------------------------- +// PHY Configuration Structures +// ----------------------------------------------------------------------------- + +/** + * @addtogroup Radio_Configuration + * @{ + */ + +/** + * @struct RAIL_StateTiming_t + * @brief Timing configuration structure for the RAIL State Machine + * + * This is used to configure the timings of the radio state transitions for + * common situations. All of the listed timings are in us. Timing values cannot + * exceed 13ms. Transitions to IDLE always happen as fast as possible. + */ +typedef struct RAIL_StateTiming { + uint16_t idleToRx; /**RX + * and RX->TX, and finally the total amount of time to look for an ack. All of + * these timing parameters are in microseconds. + */ +typedef struct RAIL_AutoAckConfig { + /** + * Default state once auto ack sequence completes or errors. Can only be + * RAIL_RF_STATE_RX or RAIL_RF_STATE_IDLE. + */ + RAIL_RadioState_t defaultState; + /** + * Define the time from idleToTx and idleToRx in us. Limited to a max of + * 13ms. + */ + uint16_t idleTiming; + /** + * Define the ack turnaround time in us. Limited to a max of 13ms. + */ + uint16_t turnaroundTime; + /** + * Define the rx ack timeout duration in us. Limited to a max of 65.535ms. + */ + uint16_t ackTimeout; +} RAIL_AutoAckConfig_t; + +/** + * @struct RAIL_AutoAckData_t + * @brief This structure is used to define the data to use during auto + * acknowledgement. The data is copied into an RAIL space buffer so after + * RAIL_AutoAckLoadBuffer returns, the pointer can be deallocated or reused. + * + * Size limited to \ref RAIL_AUTOACK_MAX_LENGTH. + */ +typedef struct RAIL_AutoAckData { + uint8_t *dataPtr; /**< Pointer to ack data to transmit */ + uint8_t dataLength; /**< Number of ack bytes to transmit */ +} RAIL_AutoAckData_t; + +/// Acknowledgement packets cannot be longer than 64 bytes. +#define RAIL_AUTOACK_MAX_LENGTH 64 +/** + * @} + * endofgroup AutoAck + */ +/****************************************************************************** + * Version + *****************************************************************************/ +/** + * @addtogroup Diagnostic + * @{ + */ + +/** + * @enum RAIL_StreamMode_t + * @brief Possible stream output modes. + */ +typedef enum RAIL_StreamMode { + PSEUDO_RANDOM_STREAM, /**< Pseudo random stream of bytes */ + PN9_STREAM /**< PN9 byte sequence */ +} RAIL_StreamMode_t; + +/** + * @struct RAIL_BerConfig_t + * @brief BER test parameters. + */ +typedef struct RAIL_BerConfig +{ + uint32_t bytesToTest; /**< Number of bytes to test */ +} RAIL_BerConfig_t; + +/** + * @struct RAIL_BerStatus_t + * @brief The status of the latest bit error rate (BER) test. + */ +typedef struct RAIL_BerStatus +{ + uint32_t bitsTotal; /**< Number of bits to receive */ + uint32_t bitsTested; /**< Number of bits currently tested */ + uint32_t bitErrors; /**< Number of bits errors detected */ + int8_t rssi; /**< Latched RSSI value at pattern detect */ +} RAIL_BerStatus_t; + +/** + * @} + */ + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +/****************************************************************************** + * Debug + *****************************************************************************/ +/** + * @addtogroup Debug + * @{ + */ + +// Debug Config Callback Defines +/** Callback for radio state change */ +#define RAIL_DEBUG_CONFIG_STATE_CHANGE (0x01 << 1) + +/** + * @def RAIL_DEBUG_MODE_FREQ_OVERRIDE + * @brief A bitmask to enable the frequency override debug mode where you can + * manually tune to a specified frequency. Note that this should only be used + * for testing and is not as tuned as frequencies from the calculator. + */ +#define RAIL_DEBUG_MODE_FREQ_OVERRIDE 0x00000001UL +/** + * @def RAIL_DEBUG_MODE_VALID_MASK + * @brief Any debug mode bits outside of this mask are invalid and ignored. + */ +#define RAIL_DEBUG_MODE_VALID_MASK (!(RAIL_DEBUG_MODE_FREQ_OVERRIDE)) + +/** + * @} + */ +#endif + +/** + * @} + * end of RAIL_API + */ + +#endif // __RAIL_TYPES_H__ diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/source/NanostackRfPhyEfr32.cpp b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/source/NanostackRfPhyEfr32.cpp new file mode 100644 index 0000000000..16a350367c --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/source/NanostackRfPhyEfr32.cpp @@ -0,0 +1,827 @@ +/* + * Copyright (c) 2016 Silicon Laboratories, Inc. http://www.silabs.com + * 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. + */ +#include "NanostackRfPhyEfr32.h" +#include "ns_types.h" +#include "platform/arm_hal_interrupt.h" +#include "nanostack/platform/arm_hal_phy.h" +#include "toolchain.h" +#include + +#include "mbed-trace/mbed_trace.h" +#define TRACE_GROUP "SLRF" + +/* Silicon Labs headers */ +extern "C" { + #include "rail/rail.h" + #include "rail/pa.h" + #include "rail/pti.h" + #include "rail/ieee802154/rail_ieee802154.h" + #include "buffer-pool-memory-manager/buffer_pool_allocator.h" +} + +/* RF driver data */ +static phy_device_driver_s device_driver; +static int8_t rf_radio_driver_id = -1; +static uint8_t MAC_address[8]; +static uint16_t PAN_address; +static uint16_t short_address; + +/* Driver instance handle */ +static NanostackRfPhyEfr32 *rf = NULL; + +/* Channel configurations */ +static const phy_rf_channel_configuration_s phy_24ghz = {2405000000U, 5000000U, 250000U, 16U, M_OQPSK}; +static const phy_rf_channel_configuration_s phy_subghz = {868300000U, 2000000U, 250000U, 11U, M_OQPSK}; + +static const phy_device_channel_page_s phy_channel_pages[] = { + { CHANNEL_PAGE_0, &phy_24ghz}, + { CHANNEL_PAGE_2, &phy_subghz}, + { CHANNEL_PAGE_0, NULL} +}; + +/* Driver structures */ +typedef enum { + RADIO_UNINIT, + RADIO_INITING, + RADIO_IDLE, + RADIO_TX, + RADIO_RX, + RADIO_CALIBRATION +} siliconlabs_modem_state_t; + +static const RAIL_CsmaConfig_t csma_config = RAIL_CSMA_CONFIG_802_15_4_2003_2p4_GHz_OQPSK_CSMA; + +#if defined(TARGET_EFR32MG1) +#include "ieee802154_subg_efr32xg1_configurator_out.h" +#include "ieee802154_efr32xg1_configurator_out.h" +#else +#error "Not a valid target." +#endif + +static const RAIL_ChannelConfigEntry_t entry[] = { + {0U, 0U, 600000U, 868300000U}, + {1U, 10U, 2000000U, 906000000U}, + {11U, 26U, 5000000U, 2405000000U} +}; + +#if MBED_CONF_SL_RAIL_BAND == 868 +#ifndef DEVICE_RF_SUBGHZ +#error "Sub-Gigahertz band is not supported on this target." +#endif +static const RAIL_ChannelConfig_t channels = { + (RAIL_ChannelConfigEntry_t *) &entry[0], + 1 +}; +#elif MBED_CONF_SL_RAIL_BAND == 915 +#ifndef DEVICE_RF_SUBGHZ +#error "Sub-Gigahertz band is not supported on this target." +#endif +static const RAIL_ChannelConfig_t channels = { + (RAIL_ChannelConfigEntry_t *) &entry[1], + 1 +}; +#elif MBED_CONF_SL_RAIL_BAND == 2400 +#ifndef DEVICE_RF_2P4GHZ +#error "2.4GHz band is not supported on this target." +#endif +static const RAIL_ChannelConfig_t channels = { + (RAIL_ChannelConfigEntry_t *) &entry[2], + 1 +}; +#else +#error "sl-rail.band is not correctly defined" +#endif + +static const RAIL_IEEE802154_Config_t config = { false, false, + RAIL_IEEE802154_ACCEPT_STANDARD_FRAMES, + RAIL_RF_STATE_RX, 100, 192, 894, NULL }; + +static const RAIL_Init_t railInitParams = { 140, 38400000, RAIL_CAL_ALL_PENDING }; + +#if defined (DEVICE_RF_2P4GHZ) + // Set up the PA for 2.4 GHz operation +static const RADIO_PAInit_t paInit2p4 = { + PA_SEL_2P4_HP, /* Power Amplifier mode */ + PA_VOLTMODE_DCDC, /* Power Amplifier vPA Voltage mode */ + 100, /* Desired output power in dBm * 10 */ + 0, /* Output power offset in dBm * 10 */ + 10 /* Desired ramp time in us */ + }; +#endif + +#if defined (DEVICE_RF_SUBGHZ) + // Set up the PA for sub-GHz operation +static const RADIO_PAInit_t paInitSubGhz = { + PA_SEL_SUBGIG, /* Power Amplifier mode */ + PA_VOLTMODE_DCDC, /* Power Amplifier vPA Voltage mode */ + 100, /* Desired output power in dBm * 10 */ + 0, /* Output power offset in dBm * 10 */ + 10 /* Desired ramp time in us */ + }; +#endif + +static volatile siliconlabs_modem_state_t radio_state = RADIO_UNINIT; +static volatile int8_t channel = -1; +static volatile uint8_t current_tx_handle = 0; +static volatile uint8_t current_tx_sequence = 0; +static volatile bool waiting_for_ack = false; +static volatile bool data_pending = false, last_ack_pending_bit = false; +static volatile uint32_t last_tx = 0; + +/* ARM_NWK_HAL prototypes */ +static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr); +static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel); +static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr); +static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol ); + +/* Local function prototypes */ +static bool rail_checkAndSwitchChannel(uint8_t channel); + +/*============ CODE =========*/ + +/* + * \brief Function initialises and registers the RF driver. + * + * \param none + * + * \return rf_radio_driver_id Driver ID given by NET library + */ +static int8_t rf_device_register(void) +{ + // If we already exist, bail. + if(radio_state != RADIO_UNINIT) { + return -1; + } + +#if MBED_CONF_SL_RAIL_BAND == 2400 + RADIO_PA_Init((RADIO_PAInit_t*)&paInit2p4); +#elif (MBED_CONF_SL_RAIL_BAND == 915) || (MBED_CONF_SL_RAIL_BAND == 868) + RADIO_PA_Init((RADIO_PAInit_t*)&paInitSubGhz); +#endif + + // Set up PTI since it makes life so much easier +#if defined(DEVICE_SL_PTI) + RADIO_PTIInit_t ptiInit = { + RADIO_PTI_MODE_UART, + 1600000, + 6, + // TODO: Configure PTI pinout using config system. + // Not very urgent, since all boards use the same pins now. + gpioPortB, + 12, + 6, + gpioPortB, + 11, + 6, + gpioPortB, + 13, + }; + + RADIO_PTI_Init(&ptiInit); +#endif + + // Set up RAIL + RAIL_RfInit(&railInitParams); + RAIL_ChannelConfig(&channels); +#if MBED_CONF_SL_RAIL_BAND == 2400 + RAIL_RadioConfig((void*) ieee802154_config_base); + channel = 11; +#elif (MBED_CONF_SL_RAIL_BAND == 915) + RAIL_RadioConfig((void*) ieee802154_config_915); + channel = 1; +#elif MBED_CONF_SL_RAIL_BAND == 868 + RAIL_RadioConfig((void*) ieee802154_config_863); + channel = 0; +#endif + RAIL_IEEE802154_Init((RAIL_IEEE802154_Config_t*)&config); + + /* Get real MAC address */ + /* MAC is stored MSB first */ + memcpy(MAC_address, (const void*)&DEVINFO->UNIQUEH, 4); + memcpy(&MAC_address[4], (const void*)&DEVINFO->UNIQUEL, 4); + + /*Set pointer to MAC address*/ + device_driver.PHY_MAC = MAC_address; + device_driver.driver_description = (char*)"EFR32_154"; + + /*Type of RF PHY*/ +#if MBED_CONF_SL_RAIL_BAND == 2400 + device_driver.link_type = PHY_LINK_15_4_2_4GHZ_TYPE; +#elif (MBED_CONF_SL_RAIL_BAND == 915) || (MBED_CONF_SL_RAIL_BAND == 868) + device_driver.link_type = PHY_LINK_15_4_SUBGHZ_TYPE; +#endif + + device_driver.phy_channel_pages = phy_channel_pages; + /*Maximum size of payload is 127*/ + device_driver.phy_MTU = 127; + /*1 byte header in PHY layer (length)*/ + device_driver.phy_header_length = 1; + /*No tail in PHY layer*/ + device_driver.phy_tail_length = 0; + /*Set address write function*/ + device_driver.address_write = &rf_address_write; + /*Set RF extension function*/ + device_driver.extension = &rf_extension; + /*Set RF state control function*/ + device_driver.state_control = &rf_interface_state_control; + /*Set transmit function*/ + device_driver.tx = &rf_start_cca; + /*Upper layer callbacks init to NULL, get populated by arm_net_phy_register*/ + device_driver.phy_rx_cb = NULL; + device_driver.phy_tx_done_cb = NULL; + /*Virtual upper data callback init to NULL*/ + device_driver.arm_net_virtual_rx_cb = NULL; + device_driver.arm_net_virtual_tx_cb = NULL; + + /*Register device driver*/ + rf_radio_driver_id = arm_net_phy_register(&device_driver); + + // If the radio hasn't called the ready callback by now, place it in the initing state + if(radio_state == RADIO_UNINIT) { + radio_state = RADIO_INITING; + } + + return rf_radio_driver_id; +} + +/* + * \brief Function unregisters the RF driver. + * + * \param none + * + * \return none + */ +static void rf_device_unregister(void) +{ + arm_net_phy_unregister(rf_radio_driver_id); +} + +/* + * \brief Function starts the CCA process before starting data transmission and copies the data to RF TX FIFO. + * + * \param data_ptr Pointer to TX data + * \param data_length Length of the TX data + * \param tx_handle Handle to transmission + * \return 0 Success + * \return -1 Busy + */ +static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol ) +{ + + RAIL_TxData_t txData = { + data_ptr, + data_length + 3 + }; + + tr_debug("Called TX, len %d, chan %d\n", data_length, channel); + + switch(radio_state) { + case RADIO_UNINIT: + tr_debug("Radio uninit\n"); + return -1; + case RADIO_INITING: + tr_debug("Radio initing\n"); + return -1; + case RADIO_CALIBRATION: + tr_debug("Radio calibrating\n"); + return -1; + case RADIO_TX: + tr_debug("Radio in TX mode\n"); + return -1; + case RADIO_IDLE: + case RADIO_RX: + // If we're still waiting for an ACK, don't mess up the internal state + if(waiting_for_ack || RAIL_RfStateGet() == RAIL_RF_STATE_TX) { + if((RAIL_GetTime() - last_tx) < 30000) { + tr_debug("Still waiting on previous ACK\n"); + return -1; + } else { + tr_debug("TXerr\n"); + } + } + + data_ptr[0] = data_length + 2; + RAIL_RfIdleExt(RAIL_IDLE_ABORT , true); + RAIL_TxDataLoad(&txData); + radio_state = RADIO_TX; + + RAIL_TxOptions_t txOpt; + //Check to see whether we'll be waiting for an ACK + if(data_ptr[1] & (1 << 5)) { + txOpt.waitForAck = true; + waiting_for_ack = true; + } else { + txOpt.waitForAck = false; + } + + if(RAIL_TxStartWithOptions(channel, &txOpt, &RAIL_CcaCsma, (RAIL_CsmaConfig_t*) &csma_config) == 0) { + //Save packet number and sequence + current_tx_handle = tx_handle; + current_tx_sequence = data_ptr[3]; + return 0; + } else { + RAIL_RfIdle(); + RAIL_RxStart(channel); + radio_state = RADIO_RX; + return -1; + } + } + //Should never get here... + return -1; +} + +/* + * \brief Function gives the control of RF states to MAC. + * + * \param new_state RF state + * \param rf_channel RF channel + * + * \return 0 Success + */ +static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel) +{ + int8_t ret_val = 0; + switch (new_state) + { + /* Reset PHY driver and set to idle */ + case PHY_INTERFACE_RESET: + RAIL_RfIdle(); + radio_state = RADIO_IDLE; + break; + /* Disable PHY Interface driver */ + case PHY_INTERFACE_DOWN: + RAIL_RfIdle(); + radio_state = RADIO_IDLE; + break; + /* Enable RX */ + case PHY_INTERFACE_UP: + if(rail_checkAndSwitchChannel(rf_channel)) { + RAIL_IEEE802154_SetPromiscuousMode(false); + RAIL_RxStart(channel); + radio_state = RADIO_RX; + } else { + ret_val = -1; + } + break; + /* Enable wireless interface ED scan mode */ + case PHY_INTERFACE_RX_ENERGY_STATE: + tr_debug("Energy det req\n"); + // TODO: implement energy detection + break; + /* Enable RX in promiscuous mode (aka no address filtering) */ + case PHY_INTERFACE_SNIFFER_STATE: + if(rail_checkAndSwitchChannel(rf_channel)) { + RAIL_IEEE802154_SetPromiscuousMode(true); + RAIL_RxStart(channel); + radio_state = RADIO_RX; + } else { + ret_val = -1; + } + break; + } + return ret_val; +} + +/* + * \brief Function controls the ACK pending, channel setting and energy detection. + * + * \param extension_type Type of control + * \param data_ptr Data from NET library + * + * \return 0 Success + */ +static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr) +{ + switch (extension_type) + { + /* Control MAC pending bit for Indirect data transmission */ + case PHY_EXTENSION_CTRL_PENDING_BIT: + if(*data_ptr) { + data_pending = true; + } else { + data_pending = false; + } + break; + /* Return frame pending bit from last received ACK */ + case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS: + if(last_ack_pending_bit) { + *data_ptr = 0xFF; + } else { + *data_ptr = 0; + } + break; + /* Set channel */ + case PHY_EXTENSION_SET_CHANNEL: + channel = *data_ptr; + break; + /* Read energy on the channel */ + case PHY_EXTENSION_READ_CHANNEL_ENERGY: + // TODO: implement energy detection + *data_ptr = 0; + break; + /* Read status of the link */ + case PHY_EXTENSION_READ_LINK_STATUS: + // TODO: return accurate value here + tr_debug("Trying to read link status\n"); + break; + /* Convert between LQI and RSSI */ + case PHY_EXTENSION_CONVERT_SIGNAL_INFO: + // TODO: return accurate value here + tr_debug("Trying to read signal info\n"); + break; + } + return 0; +} + +/* + * \brief Function sets the addresses to RF address filters. + * + * \param address_type Type of address + * \param address_ptr Pointer to given address + * + * \return 0 Success + */ +static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr) +{ + int8_t ret_val = 0; + switch (address_type) + { + /*Set 48-bit address*/ + case PHY_MAC_48BIT: + // 15.4 does not support 48-bit addressing + ret_val = -1; + break; + /*Set 64-bit MAC address*/ + case PHY_MAC_64BIT: + /* Store MAC in MSB order */ + memcpy(MAC_address, address_ptr, 8); + tr_debug("MACw "); + for(unsigned int i = 0; i < sizeof(MAC_address); i ++) { + tr_debug("%02x:", MAC_address[i]); + } + tr_debug("\n"); + /* Pass MAC to the RF driver in LSB order */ + uint8_t MAC_reversed[8]; + for(unsigned int i = 0; i < sizeof(MAC_address); i ++) { + MAC_reversed[i] = MAC_address[sizeof(MAC_address) - 1 - i]; + } + RAIL_IEEE802154_SetLongAddress(MAC_reversed); + break; + /*Set 16-bit address*/ + case PHY_MAC_16BIT: + short_address = address_ptr[0] << 8 | address_ptr[1]; + tr_debug("Filter EUI16 %04x\n", short_address); + RAIL_IEEE802154_SetShortAddress(short_address); + break; + /*Set PAN Id*/ + case PHY_MAC_PANID: + PAN_address = address_ptr[0] << 8 | address_ptr[1]; + tr_debug("Filter PAN %04x\n", PAN_address); + RAIL_IEEE802154_SetPanId(PAN_address); + break; + } + return ret_val; +} + +/*****************************************************************************/ +/*****************************************************************************/ + +static void rf_if_lock(void) +{ + platform_enter_critical(); +} + +static void rf_if_unlock(void) +{ + platform_exit_critical(); +} + +NanostackRfPhyEfr32::NanostackRfPhyEfr32() : NanostackRfPhy() +{ + // Do nothing +} + +NanostackRfPhyEfr32::~NanostackRfPhyEfr32() +{ + rf_unregister(); +} + +int8_t NanostackRfPhyEfr32::rf_register() +{ + + rf_if_lock(); + + if (rf != NULL) { + rf_if_unlock(); + error("Multiple registrations of NanostackRfPhyEfr32 not supported"); + return -1; + } + + int8_t radio_id = rf_device_register(); + if (radio_id < 0) { + rf = NULL; + } else { + rf = this; + } + + rf_if_unlock(); + return radio_id; +} + +void NanostackRfPhyEfr32::rf_unregister() +{ + rf_if_lock(); + + if (rf != this) { + rf_if_unlock(); + return; + } + + rf_device_unregister(); + rf = NULL; + + rf_if_unlock(); +} + +void NanostackRfPhyEfr32::get_mac_address(uint8_t *mac) +{ + rf_if_lock(); + + memcpy(mac, MAC_address, sizeof(MAC_address)); + + rf_if_unlock(); +} + +void NanostackRfPhyEfr32::set_mac_address(uint8_t *mac) +{ + rf_if_lock(); + + if (NULL != rf) { + error("NanostackRfPhyEfr32 cannot change mac address when running"); + rf_if_unlock(); + return; + } + + memcpy(MAC_address, mac, sizeof(MAC_address)); + + rf_if_unlock(); +} + +uint32_t NanostackRfPhyEfr32::get_driver_version() +{ + RAIL_Version_t railversion; + RAIL_VersionGet(&railversion, true); + + return (railversion.major << 24) | + (railversion.minor << 16) | + (railversion.rev << 8) | + (railversion.build); +} + + +//====================== RAIL-defined callbacks ========================= +/** + * Callback that lets the app know when the radio has finished init + * and is ready. + */ +void RAILCb_RfReady(void) { + radio_state = RADIO_IDLE; +} + +/** + * Interrupt level callback + * Allows the user finer granularity in tx radio events. + * + * Radio Statuses: + * RAIL_TX_CONFIG_BUFFER_UNDERFLOW + * RAIL_TX_CONFIG_CHANNEL_BUSY + * + * @param[in] status A bit field that defines what event caused the callback + */ +void RAILCb_TxRadioStatus(uint8_t status) { + tr_debug("Packet TX error %d\n", status); + if(device_driver.phy_tx_done_cb != NULL) { + if(status == RAIL_TX_CONFIG_BUFFER_UNDERFLOW || + status == RAIL_TX_CONFIG_CHANNEL_BUSY || + status == RAIL_TX_CONFIG_TX_ABORTED || + status == RAIL_TX_CONFIG_TX_BLOCKED) { + waiting_for_ack = false; + device_driver.phy_tx_done_cb( rf_radio_driver_id, + current_tx_handle, + PHY_LINK_CCA_FAIL, + 8, + 1); + } + } + radio_state = RADIO_RX; +} + +/** + * Called whenever an enabled radio status event occurs + * + * Triggers: + * RAIL_RX_CONFIG_PREAMBLE_DETECT + * RAIL_RX_CONFIG_SYNC1_DETECT + * RAIL_RX_CONFIG_SYNC2_DETECT + * RAIL_RX_CONFIG_INVALID_CRC + * RAIL_RX_CONFIG_BUFFER_OVERFLOW + * RAIL_RX_CONFIG_ADDRESS_FILTERED + * + * @param[in] status The event that triggered this callback + */ +void RAILCb_RxRadioStatus(uint8_t status) { + tr_debug("RXE %d\n", status); +} + +/** + * Callback that notifies the application that a calibration is needed. + * + * This callback function is called whenever the RAIL library detects that a + * calibration is needed. It is up to the application to determine a valid + * window to call RAIL_CalStart(). + * + */ +void RAILCb_CalNeeded(void) { + // TODO: Implement on-the-fly recalibration + tr_debug("!!!! Calling for calibration\n"); +} + +/** + * Interrupt level callback to signify when the radio changes state. + * + * @param[in] state Current state of the radio, as defined by EFR32 data sheet + */ +void RAILCb_RadioStateChanged(uint8_t state) { + return; +} + +/** + * This function is called when the RAIL timer expires + * + * You must implement a stub for this in your RAIL application even if you + * don't use the timer. + */ +void RAILCb_TimerExpired(void) { +} + +/** + * Interrupt level callback to signify when the packet was sent + * @param txPacketInfo Information about the packet that was transmitted. + * @note that this structure is only valid during the timeframe of the + * callback. + */ +void RAILCb_TxPacketSent(RAIL_TxPacketInfo_t *txPacketInfo) { + if(device_driver.phy_tx_done_cb != NULL) { + device_driver.phy_tx_done_cb( rf_radio_driver_id, + current_tx_handle, + // Normally we'd switch on ACK requested here, but Nanostack does that for us. + PHY_LINK_TX_SUCCESS, + // Succeeded, so how many times we tried is really not relevant. + 1, + 1); + } + last_tx = RAIL_GetTime(); + radio_state = RADIO_RX; +} + +/** + * Receive packet callback. + * + * @param[in] rxPacketHandle Contains a handle that points to the memory that + * the packet was stored in. This handle will be the same as something + * returned by the RAILCb_AllocateMemory() API. To convert this into a receive + * packet info struct use the *** function. + * + * This function is called whenever a packet is received and returns to you the + * memory handle for where this received packet and its appended information was + * stored. After this callback is done we will release the memory handle so you + * must somehow increment a reference count or copy the data out within this + * function. + */ +void RAILCb_RxPacketReceived(void *rxPacketHandle) { + RAIL_RxPacketInfo_t* rxPacketInfo = (RAIL_RxPacketInfo_t*) memoryPtrFromHandle(rxPacketHandle); + if(rxPacketInfo->appendedInfo.crcStatus) { + /* If this is an ACK, deal with it */ + if( rxPacketInfo->dataLength == 4 && + rxPacketInfo->dataPtr[3] == (current_tx_sequence) && + waiting_for_ack) { + /* Tell the radio to not ACK an ACK */ + RAIL_AutoAckCancelAck(); + waiting_for_ack = false; + /* Save the pending bit */ + last_ack_pending_bit = (rxPacketInfo->dataPtr[1] & (1 << 4)) != 0; + /* Tell the stack we got an ACK */ + tr_debug("rACK\n"); + device_driver.phy_tx_done_cb( rf_radio_driver_id, + current_tx_handle, + PHY_LINK_TX_DONE, + 1, + 1); + } else { + /* Figure out whether we want to not ACK this packet */ + + /* + * dataPtr[0] = length + * dataLength = length w/o length byte + * dataptr[1:2] = 0x61C9 -> 0b01100001 0b1100 1001 (version 1, dest 3, src 2, ACKreq, type = 1) + * [1] => b[0:2] frame type, b[3] = security enabled, b[4] = frame pending, b[5] = ACKreq, b[6] = intrapan + * [2] => b[2:3] destmode, b[4:5] version, b[6:7] srcmode + */ + if( (rxPacketInfo->dataPtr[1] & (1 << 5)) == 0 ) { + /* Cancel the ACK if the sender did not request one */ + RAIL_AutoAckCancelAck(); + } + + tr_debug("rPKT %d\n", rxPacketInfo->dataLength); + /* Feed the received packet into the stack */ + device_driver.phy_rx_cb(rxPacketInfo->dataPtr + 1, + rxPacketInfo->dataLength - 1, + //TODO: take a new RAIL release that exposes LQI, or have LQI as function of RSSI + 255, + rxPacketInfo->appendedInfo.rssiLatch, + rf_radio_driver_id); + } + } +} + + +/** + * Callback for when a Data Request is being received + * + * @param address The source address of the data request command + * + * This function is called when the command byte of an incoming frame is for a + * data request, which requests an ACK. This callback will be called before the + * packet is fully received, to allow the node to have more time to decide + * whether to set frame pending in the outgoing ACK. + */ +void RAILCb_IEEE802154_DataRequestCommand(RAIL_IEEE802154_Address_t *address) { + if(data_pending) { + RAIL_IEEE802154_SetFramePending(); + } +} + +/** + * Callback that notifies the application when searching for an ACK has timed + * out. + * + * @return void + * + * This callback function is called whenever the timeout for searching for an + * ack is exceeded. + */ +void RAILCb_RxAckTimeout(void) { + if(waiting_for_ack) { + waiting_for_ack = false; + device_driver.phy_tx_done_cb( rf_radio_driver_id, + current_tx_handle, + PHY_LINK_TX_FAIL, + 1, + 1); + } +} + +/** + * Function to check the requested channel against the current channel, + * and change the radio configuration if necessary. + * + * @param channel The new channel number requested + * @return bool True if able to switch to the requested channel + * + */ +static bool rail_checkAndSwitchChannel(uint8_t newChannel) { + if(channel == newChannel) { + return true; + } + + if(newChannel > 0 && newChannel < 11) { + if(MBED_CONF_SL_RAIL_BAND == 915) { + channel = newChannel; + return true; + } else { + return false; + } + } else if(newChannel >= 11 && newChannel <= 26) { + if(MBED_CONF_SL_RAIL_BAND == 2400) { + channel = newChannel; + return true; + } else { + return false; + } + } else { + return false; + } +} \ No newline at end of file diff --git a/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/mbed_lib.json b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/mbed_lib.json new file mode 100644 index 0000000000..fc7c7e0822 --- /dev/null +++ b/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/mbed_lib.json @@ -0,0 +1,6 @@ +{ + "name": "sl-rail", + "config": { + "band": 2400 + } +}