├── .cproject ├── .gitignore ├── .project ├── LICENSE ├── README.md ├── doc ├── LMiC-v1.5.pdf ├── README.txt └── release-notes.txt ├── examples ├── beacon │ └── main.c ├── hello │ └── main.c ├── interrupt │ ├── main.c │ └── sensor.c ├── join │ └── main.c ├── periodic │ ├── main.c │ └── sensor.c ├── ping │ └── main.c └── transmit │ └── main.c ├── hal ├── debug.c ├── debug.h └── hal.c └── lmic ├── aes.c ├── hal.h ├── lmic.c ├── lmic.h ├── lorabase.h ├── oslmic.c ├── oslmic.h └── radio.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | 45 | 46 | 47 | 48 | 49 | # Compiled binaries 50 | *.bin 51 | *.elf 52 | *.hex 53 | *.map 54 | 55 | # Trash 56 | *.bak 57 | 58 | # IAR project "Debug" directory 59 | Debug/ 60 | 61 | # IAR project "Release" directory 62 | Release/ 63 | 64 | # IAR project settings directory 65 | settings/ 66 | 67 | # IAR backup files 68 | Backup* 69 | 70 | # IAR .dep files 71 | *.dep 72 | 73 | Exe/ 74 | List/ 75 | Obj/ 76 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | lmic 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | 16 | org.eclipse.cdt.core.cnature 17 | com.silabs.ide.project.core.SLSProjectNature 18 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 19 | 20 | 21 | 22 | emlib/em_acmp.c 23 | 1 24 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_acmp.c 25 | 26 | 27 | emlib/em_adc.c 28 | 1 29 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_adc.c 30 | 31 | 32 | emlib/em_aes.c 33 | 1 34 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_aes.c 35 | 36 | 37 | emlib/em_assert.c 38 | 1 39 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_assert.c 40 | 41 | 42 | emlib/em_burtc.c 43 | 1 44 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_burtc.c 45 | 46 | 47 | emlib/em_cmu.c 48 | 1 49 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_cmu.c 50 | 51 | 52 | emlib/em_dac.c 53 | 1 54 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_dac.c 55 | 56 | 57 | emlib/em_dbg.c 58 | 1 59 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_dbg.c 60 | 61 | 62 | emlib/em_dma.c 63 | 1 64 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_dma.c 65 | 66 | 67 | emlib/em_ebi.c 68 | 1 69 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_ebi.c 70 | 71 | 72 | emlib/em_emu.c 73 | 1 74 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_emu.c 75 | 76 | 77 | emlib/em_gpio.c 78 | 1 79 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_gpio.c 80 | 81 | 82 | emlib/em_i2c.c 83 | 1 84 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_i2c.c 85 | 86 | 87 | emlib/em_idac.c 88 | 1 89 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_idac.c 90 | 91 | 92 | emlib/em_int.c 93 | 1 94 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_int.c 95 | 96 | 97 | emlib/em_lcd.c 98 | 1 99 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_lcd.c 100 | 101 | 102 | emlib/em_lesense.c 103 | 1 104 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_lesense.c 105 | 106 | 107 | emlib/em_letimer.c 108 | 1 109 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_letimer.c 110 | 111 | 112 | emlib/em_leuart.c 113 | 1 114 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_leuart.c 115 | 116 | 117 | emlib/em_mpu.c 118 | 1 119 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_mpu.c 120 | 121 | 122 | emlib/em_msc.c 123 | 1 124 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_msc.c 125 | 126 | 127 | emlib/em_opamp.c 128 | 1 129 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_opamp.c 130 | 131 | 132 | emlib/em_pcnt.c 133 | 1 134 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_pcnt.c 135 | 136 | 137 | emlib/em_prs.c 138 | 1 139 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_prs.c 140 | 141 | 142 | emlib/em_rmu.c 143 | 1 144 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_rmu.c 145 | 146 | 147 | emlib/em_rtc.c 148 | 1 149 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_rtc.c 150 | 151 | 152 | emlib/em_system.c 153 | 1 154 | STUDIO_SDK_LOC/emlib/src/em_system.c 155 | 156 | 157 | emlib/em_timer.c 158 | 1 159 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_timer.c 160 | 161 | 162 | emlib/em_usart.c 163 | 1 164 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_usart.c 165 | 166 | 167 | emlib/em_vcmp.c 168 | 1 169 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_vcmp.c 170 | 171 | 172 | emlib/em_wdog.c 173 | 1 174 | PARENT-5-PROJECT_LOC/SiliconLabs/SimplicityStudio/v3/developer/sdks/efm32/v2/emlib/src/em_wdog.c 175 | 176 | 177 | CMSIS/efm32g/startup_gcc_efm32g.s 178 | 1 179 | STUDIO_SDK_LOC/Device/SiliconLabs/EFM32G/Source/GCC/startup_efm32g.S 180 | 181 | 182 | CMSIS/efm32g/system_efm32g.c 183 | 1 184 | STUDIO_SDK_LOC/Device/SiliconLabs/EFM32G/Source/system_efm32g.c 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Eclipse Public License - v 1.0 2 | 3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 4 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 5 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 6 | 7 | 1. DEFINITIONS 8 | 9 | "Contribution" means: 10 | 11 | a) in the case of the initial Contributor, the initial code and documentation 12 | distributed under this Agreement, and 13 | b) in the case of each subsequent Contributor: 14 | i) changes to the Program, and 15 | ii) additions to the Program; 16 | 17 | where such changes and/or additions to the Program originate from and are 18 | distributed by that particular Contributor. A Contribution 'originates' 19 | from a Contributor if it was added to the Program by such Contributor 20 | itself or anyone acting on such Contributor's behalf. Contributions do not 21 | include additions to the Program which: (i) are separate modules of 22 | software distributed in conjunction with the Program under their own 23 | license agreement, and (ii) are not derivative works of the Program. 24 | 25 | "Contributor" means any person or entity that distributes the Program. 26 | 27 | "Licensed Patents" mean patent claims licensable by a Contributor which are 28 | necessarily infringed by the use or sale of its Contribution alone or when 29 | combined with the Program. 30 | 31 | "Program" means the Contributions distributed in accordance with this 32 | Agreement. 33 | 34 | "Recipient" means anyone who receives the Program under this Agreement, 35 | including all Contributors. 36 | 37 | 2. GRANT OF RIGHTS 38 | a) Subject to the terms of this Agreement, each Contributor hereby grants 39 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 40 | reproduce, prepare derivative works of, publicly display, publicly 41 | perform, distribute and sublicense the Contribution of such Contributor, 42 | if any, and such derivative works, in source code and object code form. 43 | b) Subject to the terms of this Agreement, each Contributor hereby grants 44 | Recipient a non-exclusive, worldwide, royalty-free patent license under 45 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 46 | transfer the Contribution of such Contributor, if any, in source code and 47 | object code form. This patent license shall apply to the combination of 48 | the Contribution and the Program if, at the time the Contribution is 49 | added by the Contributor, such addition of the Contribution causes such 50 | combination to be covered by the Licensed Patents. The patent license 51 | shall not apply to any other combinations which include the Contribution. 52 | No hardware per se is licensed hereunder. 53 | c) Recipient understands that although each Contributor grants the licenses 54 | to its Contributions set forth herein, no assurances are provided by any 55 | Contributor that the Program does not infringe the patent or other 56 | intellectual property rights of any other entity. Each Contributor 57 | disclaims any liability to Recipient for claims brought by any other 58 | entity based on infringement of intellectual property rights or 59 | otherwise. As a condition to exercising the rights and licenses granted 60 | hereunder, each Recipient hereby assumes sole responsibility to secure 61 | any other intellectual property rights needed, if any. For example, if a 62 | third party patent license is required to allow Recipient to distribute 63 | the Program, it is Recipient's responsibility to acquire that license 64 | before distributing the Program. 65 | d) Each Contributor represents that to its knowledge it has sufficient 66 | copyright rights in its Contribution, if any, to grant the copyright 67 | license set forth in this Agreement. 68 | 69 | 3. REQUIREMENTS 70 | 71 | A Contributor may choose to distribute the Program in object code form under 72 | its own license agreement, provided that: 73 | 74 | a) it complies with the terms and conditions of this Agreement; and 75 | b) its license agreement: 76 | i) effectively disclaims on behalf of all Contributors all warranties 77 | and conditions, express and implied, including warranties or 78 | conditions of title and non-infringement, and implied warranties or 79 | conditions of merchantability and fitness for a particular purpose; 80 | ii) effectively excludes on behalf of all Contributors all liability for 81 | damages, including direct, indirect, special, incidental and 82 | consequential damages, such as lost profits; 83 | iii) states that any provisions which differ from this Agreement are 84 | offered by that Contributor alone and not by any other party; and 85 | iv) states that source code for the Program is available from such 86 | Contributor, and informs licensees how to obtain it in a reasonable 87 | manner on or through a medium customarily used for software exchange. 88 | 89 | When the Program is made available in source code form: 90 | 91 | a) it must be made available under this Agreement; and 92 | b) a copy of this Agreement must be included with each copy of the Program. 93 | Contributors may not remove or alter any copyright notices contained 94 | within the Program. 95 | 96 | Each Contributor must identify itself as the originator of its Contribution, 97 | if 98 | any, in a manner that reasonably allows subsequent Recipients to identify the 99 | originator of the Contribution. 100 | 101 | 4. COMMERCIAL DISTRIBUTION 102 | 103 | Commercial distributors of software may accept certain responsibilities with 104 | respect to end users, business partners and the like. While this license is 105 | intended to facilitate the commercial use of the Program, the Contributor who 106 | includes the Program in a commercial product offering should do so in a manner 107 | which does not create potential liability for other Contributors. Therefore, 108 | if a Contributor includes the Program in a commercial product offering, such 109 | Contributor ("Commercial Contributor") hereby agrees to defend and indemnify 110 | every other Contributor ("Indemnified Contributor") against any losses, 111 | damages and costs (collectively "Losses") arising from claims, lawsuits and 112 | other legal actions brought by a third party against the Indemnified 113 | Contributor to the extent caused by the acts or omissions of such Commercial 114 | Contributor in connection with its distribution of the Program in a commercial 115 | product offering. The obligations in this section do not apply to any claims 116 | or Losses relating to any actual or alleged intellectual property 117 | infringement. In order to qualify, an Indemnified Contributor must: 118 | a) promptly notify the Commercial Contributor in writing of such claim, and 119 | b) allow the Commercial Contributor to control, and cooperate with the 120 | Commercial Contributor in, the defense and any related settlement 121 | negotiations. The Indemnified Contributor may participate in any such claim at 122 | its own expense. 123 | 124 | For example, a Contributor might include the Program in a commercial product 125 | offering, Product X. That Contributor is then a Commercial Contributor. If 126 | that Commercial Contributor then makes performance claims, or offers 127 | warranties related to Product X, those performance claims and warranties are 128 | such Commercial Contributor's responsibility alone. Under this section, the 129 | Commercial Contributor would have to defend claims against the other 130 | Contributors related to those performance claims and warranties, and if a 131 | court requires any other Contributor to pay any damages as a result, the 132 | Commercial Contributor must pay those damages. 133 | 134 | 5. NO WARRANTY 135 | 136 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN 137 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR 138 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each 140 | Recipient is solely responsible for determining the appropriateness of using 141 | and distributing the Program and assumes all risks associated with its 142 | exercise of rights under this Agreement , including but not limited to the 143 | risks and costs of program errors, compliance with applicable laws, damage to 144 | or loss of data, programs or equipment, and unavailability or interruption of 145 | operations. 146 | 147 | 6. DISCLAIMER OF LIABILITY 148 | 149 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 150 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 151 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 152 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 153 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 154 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 155 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 156 | OF SUCH DAMAGES. 157 | 158 | 7. GENERAL 159 | 160 | If any provision of this Agreement is invalid or unenforceable under 161 | applicable law, it shall not affect the validity or enforceability of the 162 | remainder of the terms of this Agreement, and without further action by the 163 | parties hereto, such provision shall be reformed to the minimum extent 164 | necessary to make such provision valid and enforceable. 165 | 166 | If Recipient institutes patent litigation against any entity (including a 167 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 168 | (excluding combinations of the Program with other software or hardware) 169 | infringes such Recipient's patent(s), then such Recipient's rights granted 170 | under Section 2(b) shall terminate as of the date such litigation is filed. 171 | 172 | All Recipient's rights under this Agreement shall terminate if it fails to 173 | comply with any of the material terms or conditions of this Agreement and does 174 | not cure such failure in a reasonable period of time after becoming aware of 175 | such noncompliance. If all Recipient's rights under this Agreement terminate, 176 | Recipient agrees to cease use and distribution of the Program as soon as 177 | reasonably practicable. However, Recipient's obligations under this Agreement 178 | and any licenses granted by Recipient relating to the Program shall continue 179 | and survive. 180 | 181 | Everyone is permitted to copy and distribute copies of this Agreement, but in 182 | order to avoid inconsistency the Agreement is copyrighted and may only be 183 | modified in the following manner. The Agreement Steward reserves the right to 184 | publish new versions (including revisions) of this Agreement from time to 185 | time. No one other than the Agreement Steward has the right to modify this 186 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 187 | Eclipse Foundation may assign the responsibility to serve as the Agreement 188 | Steward to a suitable separate entity. Each new version of the Agreement will 189 | be given a distinguishing version number. The Program (including 190 | Contributions) may always be distributed subject to the version of the 191 | Agreement under which it was received. In addition, after a new version of the 192 | Agreement is published, Contributor may elect to distribute the Program 193 | (including its Contributions) under the new version. Except as expressly 194 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 195 | licenses to the intellectual property of any Contributor under this Agreement, 196 | whether expressly, by implication, estoppel or otherwise. All rights in the 197 | Program not expressly granted under this Agreement are reserved. 198 | 199 | This Agreement is governed by the laws of the State of New York and the 200 | intellectual property laws of the United States of America. No party to this 201 | Agreement will bring a legal action under this Agreement more than one year 202 | after the cause of action arose. Each party waives its rights to a jury trial in 203 | any resulting litigation. 204 | 205 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Attention 2 | This is a port of the original lmic HAL for STM32 microcontroller to EFM32. 3 | 4 | Original IAR projects are also ported to Eclipse + GNU compiler. 5 | 6 | # lmic 7 | IBM “LoRa WAN in C” is the LoRa WAN implementation of choice, and a perfect match to the IBM LRSC on the end device. It is provided as open source under the Eclipse Public License (EPL). 8 | http://www.research.ibm.com/labs/zurich/ics/lrsc/lmic.html 9 | -------------------------------------------------------------------------------- /doc/LMiC-v1.5.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirakonta/lmic/cc9b4134379b056f03fe7629756e4c2adbe0453a/doc/LMiC-v1.5.pdf -------------------------------------------------------------------------------- /doc/README.txt: -------------------------------------------------------------------------------- 1 | DISCLAIMER: 2 | Please note that the software is provided AS IS and we cannot 3 | provide support for optimizations, adaptations, integration, 4 | ports to other platforms or device drivers! 5 | -------------------------------------------------------------------------------- /doc/release-notes.txt: -------------------------------------------------------------------------------- 1 | ============================================================================== 2 | LMIC VERSION 1.4 (17-Mar-2015) 3 | ------------------------------- 4 | 5 | - changed API: inverted port indicator flag in LMIC.txrxFlags 6 | (now TXRX_PORT, previously TXRX_NOPORT) 7 | 8 | - fixed offset OFF_CFLIST constant 9 | 10 | - changed CRC-16 algorithm for beacons to CCITT(XMODEM) polynomial 11 | 12 | - fixed radio driver (low data rate optimization for SF11+SF12 only for BW125) 13 | 14 | - fixed timer rollover handling in job queue 15 | 16 | ============================================================================== 17 | LMIC VERSION 1.5 (8-May-2015) 18 | ------------------------------ 19 | 20 | - fixed condition in convFreq() 21 | 22 | - fixed freq*100 bug and freq==0 bug for CFList 23 | 24 | - fixed TX scheduling bug 25 | 26 | - better support for GNU compiler toolchain 27 | 28 | ============================================================================== 29 | -------------------------------------------------------------------------------- /examples/beacon/main.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | #include "../../lmic/lmic.h" 13 | #include "../../hal/debug.h" 14 | 15 | ////////////////////////////////////////////////// 16 | // CONFIGURATION (FOR APPLICATION CALLBACKS BELOW) 17 | ////////////////////////////////////////////////// 18 | 19 | // application router ID (LSBF) 20 | static const u1_t APPEUI[8] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xFF, 0xC0 }; 21 | 22 | // unique device ID (LSBF) 23 | static const u1_t DEVEUI[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; 24 | 25 | // device-specific AES key (derived from device EUI) 26 | static const u1_t DEVKEY[16] = { 0xE7, 0x63, 0x2E, 0x1C, 0xF3, 0x61, 0x7E, 0xAD, 0xF5, 0xC0, 0xBC, 0x7E, 0x38, 0xEA, 0x09, 0xA8 }; 27 | 28 | static const u1_t nwkKey[16] = { 0xE7, 0x63, 0x2E, 0x1C, 0xF3, 0x61, 0x7E, 0xAD, 0xF5, 0xC0, 0xBC, 0x7E, 0x38, 0xEA, 0x09, 0xA8 }; 29 | 30 | static const u1_t artKey[16] = { 0xE7, 0x63, 0x2E, 0x1C, 0xF3, 0x61, 0x7E, 0xAD, 0xF5, 0xC0, 0xBC, 0x7E, 0x38, 0xEA, 0x09, 0xA8 }; 31 | 32 | 33 | ////////////////////////////////////////////////// 34 | // APPLICATION CALLBACKS 35 | ////////////////////////////////////////////////// 36 | 37 | // provide application router ID (8 bytes, LSBF) 38 | void os_getArtEui (u1_t* buf) { 39 | memcpy(buf, APPEUI, 8); 40 | } 41 | 42 | // provide device ID (8 bytes, LSBF) 43 | void os_getDevEui (u1_t* buf) { 44 | memcpy(buf, DEVEUI, 8); 45 | } 46 | 47 | // provide device key (16 bytes) 48 | void os_getDevKey (u1_t* buf) { 49 | memcpy(buf, DEVKEY, 16); 50 | } 51 | 52 | 53 | ////////////////////////////////////////////////// 54 | // MAIN - INITIALIZATION AND STARTUP 55 | ////////////////////////////////////////////////// 56 | 57 | // initial job 58 | static void initfunc (osjob_t* j) { 59 | // reset MAC state 60 | LMIC_reset(); 61 | // start joining 62 | LMIC_setSession(0x12345678, 0xB710566C, nwkKey, artKey); 63 | // enable tracking mode, start scanning... 64 | LMIC_enableTracking(0); 65 | debug_str("SCANNING...\r\n"); 66 | 67 | //LMIC_startJoining(); 68 | // init done - onEvent() callback will be invoked... 69 | } 70 | 71 | 72 | // application entry point 73 | int main () { 74 | osjob_t initjob; 75 | 76 | // initialize runtime env 77 | os_init(); 78 | // initialize debug library 79 | debug_init(); 80 | // setup initial job 81 | os_setCallback(&initjob, initfunc); 82 | // execute scheduled jobs and events 83 | os_runloop(); 84 | // (not reached) 85 | return 0; 86 | } 87 | 88 | 89 | ////////////////////////////////////////////////// 90 | // LMIC EVENT CALLBACK 91 | ////////////////////////////////////////////////// 92 | 93 | void onEvent (ev_t ev) { 94 | debug_event(ev); 95 | 96 | switch(ev) { 97 | 98 | // network joined, session established 99 | case EV_JOINED: 100 | // enable tracking mode, start scanning... 101 | LMIC_enableTracking(0); 102 | debug_str("SCANNING...\r\n"); 103 | break; 104 | 105 | // beacon found by scanning 106 | case EV_BEACON_FOUND: 107 | // switch LEN on 108 | debug_led(1); 109 | break; 110 | 111 | // beacon tracked at expected time 112 | case EV_BEACON_TRACKED: 113 | debug_val("GPS time = ", LMIC.bcninfo.time); 114 | // switch LEN on 115 | debug_led(1); 116 | break; 117 | 118 | // beacon missed at expected time 119 | case EV_BEACON_MISSED: 120 | // switch LEN off 121 | debug_led(0); 122 | break; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /examples/hello/main.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | #include "../../lmic/lmic.h" 13 | #include "../../hal/debug.h" 14 | 15 | // LMIC application callbacks not used in his example 16 | void os_getArtEui (u1_t* buf) { 17 | } 18 | 19 | void os_getDevEui (u1_t* buf) { 20 | } 21 | 22 | void os_getDevKey (u1_t* buf) { 23 | } 24 | 25 | void onEvent (ev_t ev) { 26 | } 27 | 28 | // counter 29 | static int cnt = 0; 30 | 31 | // log text to USART and toggle LED 32 | static void initfunc (osjob_t* job) { 33 | // say hello 34 | debug_str("Hello World!\r\n"); 35 | // log counter 36 | debug_val("cnt = ", cnt); 37 | // toggle LED 38 | debug_led(++cnt & 1); 39 | // reschedule job every second 40 | os_setTimedCallback(job, os_getTime()+sec2osticks(1), initfunc); 41 | } 42 | 43 | // application entry point 44 | int main () 45 | { 46 | osjob_t initjob; 47 | u4_t time; 48 | 49 | debug_init(); // initialize debug library 50 | 51 | /*hal_init(); 52 | while(1) 53 | { 54 | debug_str("\r\nT="); 55 | time = hal_ticks(); 56 | debug_hex(time>>24); 57 | debug_hex(time>>16); 58 | debug_hex(time>>8); 59 | debug_hex(time>>0); 60 | }*/ 61 | 62 | os_init(); // initialize runtime env 63 | 64 | os_setCallback(&initjob, initfunc); // setup initial job 65 | 66 | os_runloop(); // execute scheduled jobs and events 67 | 68 | 69 | return 0; // (not reached) 70 | } 71 | -------------------------------------------------------------------------------- /examples/interrupt/main.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | #include "../../lmic/lmic.h" 13 | #include "../../hal/debug.h" 14 | 15 | // sensor functions 16 | extern void initsensor(osjobcb_t callback); 17 | extern u2_t readsensor(void); 18 | 19 | 20 | ////////////////////////////////////////////////// 21 | // CONFIGURATION (FOR APPLICATION CALLBACKS BELOW) 22 | ////////////////////////////////////////////////// 23 | 24 | // application router ID (LSBF) 25 | static const u1_t APPEUI[8] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xFF, 0xC0 }; 26 | 27 | // unique device ID (LSBF) 28 | static const u1_t DEVEUI[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; 29 | 30 | // device-specific AES key (derived from device EUI) 31 | static const u1_t DEVKEY[16] = { 0xE7, 0x63, 0x2E, 0x1C, 0xF3, 0x61, 0x7E, 0xAD, 0xF5, 0xC0, 0xBC, 0x7E, 0x38, 0xEA, 0x09, 0xA8 }; 32 | 33 | static const u1_t nwkKey[16] = { 0xE7, 0x63, 0x2E, 0x1C, 0xF3, 0x61, 0x7E, 0xAD, 0xF5, 0xC0, 0xBC, 0x7E, 0x38, 0xEA, 0x09, 0xA8 }; 34 | 35 | static const u1_t artKey[16] = { 0xE7, 0x63, 0x2E, 0x1C, 0xF3, 0x61, 0x7E, 0xAD, 0xF5, 0xC0, 0xBC, 0x7E, 0x38, 0xEA, 0x09, 0xA8 }; 36 | 37 | 38 | ////////////////////////////////////////////////// 39 | // APPLICATION CALLBACKS 40 | ////////////////////////////////////////////////// 41 | 42 | // provide application router ID (8 bytes, LSBF) 43 | void os_getArtEui (u1_t* buf) { 44 | memcpy(buf, APPEUI, 8); 45 | } 46 | 47 | // provide device ID (8 bytes, LSBF) 48 | void os_getDevEui (u1_t* buf) { 49 | memcpy(buf, DEVEUI, 8); 50 | } 51 | 52 | // provide device key (16 bytes) 53 | void os_getDevKey (u1_t* buf) { 54 | memcpy(buf, DEVKEY, 16); 55 | } 56 | 57 | 58 | ////////////////////////////////////////////////// 59 | // SENSOR CALLBACK (run by sensor IRQ job) 60 | ////////////////////////////////////////////////// 61 | 62 | // report sensor value when change was detected 63 | static void sensorfunc (osjob_t* j) { 64 | // read sensor 65 | u2_t val = readsensor(); 66 | debug_val("val = ", val); 67 | // prepare and schedule data for transmission 68 | LMIC.frame[0] = val << 8; 69 | LMIC.frame[1] = val; 70 | LMIC_setTxData2(1, LMIC.frame, 2, 0); // (port 1, 2 bytes, unconfirmed) 71 | } 72 | 73 | 74 | ////////////////////////////////////////////////// 75 | // MAIN - INITIALIZATION AND STARTUP 76 | ////////////////////////////////////////////////// 77 | 78 | // initial job 79 | static void initfunc (osjob_t* j) { 80 | // intialize sensor hardware 81 | initsensor(sensorfunc); 82 | // reset MAC state 83 | LMIC_reset(); 84 | // start joining 85 | LMIC_startJoining(); 86 | // init done - onEvent() callback will be invoked... 87 | } 88 | 89 | 90 | // application entry point 91 | int main () { 92 | osjob_t initjob; 93 | 94 | // initialize runtime env 95 | os_init(); 96 | // initialize debug library 97 | debug_init(); 98 | // setup initial job 99 | os_setCallback(&initjob, initfunc); 100 | // execute scheduled jobs and events 101 | os_runloop(); 102 | // (not reached) 103 | return 0; 104 | } 105 | 106 | 107 | ////////////////////////////////////////////////// 108 | // LMIC EVENT CALLBACK 109 | ////////////////////////////////////////////////// 110 | 111 | void onEvent (ev_t ev) { 112 | debug_event(ev); 113 | 114 | switch(ev) { 115 | 116 | // network joined, session established 117 | case EV_JOINED: 118 | // switch on LED 119 | debug_led(1); 120 | // (further actions will be interrupt-driven) 121 | break; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /examples/interrupt/sensor.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | #include "../../lmic/lmic.h" 13 | 14 | // use PB12 (DIP switch 1) 15 | #define INP_PORT 1 16 | #define INP_PIN 12 17 | 18 | static osjob_t irqjob; 19 | 20 | // use DIP1 as sensor value 21 | void initsensor (osjobcb_t callback) { 22 | // configure input 23 | //RCC->AHBENR |= RCC_AHBENR_GPIOBEN; // clock enable port B 24 | //hw_cfg_pin(GPIOx(INP_PORT), INP_PIN, GPIOCFG_MODE_INP | GPIOCFG_OSPEED_40MHz | GPIOCFG_OTYPE_OPEN); 25 | //hw_cfg_extirq(INP_PORT, INP_PIN, GPIO_IRQ_CHANGE); 26 | // save application callback 27 | irqjob.func = callback; 28 | } 29 | 30 | // read PB12 31 | u2_t readsensor () 32 | { 33 | return 0; 34 | // return ((GPIOB->IDR & (1 << INP_PIN)) != 0); 35 | } 36 | 37 | // called by EXTI_IRQHandler 38 | // (set preprocessor option CFG_EXTI_IRQ_HANDLER=sensorirq) 39 | void sensorirq () 40 | { 41 | // if((EXTI->PR & (1<PR = (1<AHBENR |= RCC_AHBENR_GPIOBEN; // clock enable port B 19 | // hw_cfg_pin(GPIOB, 12, GPIOCFG_MODE_INP | GPIOCFG_OSPEED_40MHz | GPIOCFG_OTYPE_OPEN); // PB12 20 | } 21 | 22 | // read PB12 23 | u2_t readsensor () 24 | { 25 | return 0; 26 | // return ((GPIOB->IDR & (1 << 12)) != 0); 27 | } 28 | -------------------------------------------------------------------------------- /examples/ping/main.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | #include "../../lmic/lmic.h" 13 | #include "../../hal/debug.h" 14 | 15 | ////////////////////////////////////////////////// 16 | // CONFIGURATION (FOR APPLICATION CALLBACKS BELOW) 17 | ////////////////////////////////////////////////// 18 | 19 | // application router ID (LSBF) 20 | static const u1_t APPEUI[8] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xFF, 0xC0 }; 21 | 22 | // unique device ID (LSBF) 23 | static const u1_t DEVEUI[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; 24 | 25 | // device-specific AES key (derived from device EUI) 26 | static const u1_t DEVKEY[16] = { 0xE7, 0x63, 0x2E, 0x1C, 0xF3, 0x61, 0x7E, 0xAD, 0xF5, 0xC0, 0xBC, 0x7E, 0x38, 0xEA, 0x09, 0xA8 }; 27 | 28 | static const u1_t nwkKey[16] = { 0xE7, 0x63, 0x2E, 0x1C, 0xF3, 0x61, 0x7E, 0xAD, 0xF5, 0xC0, 0xBC, 0x7E, 0x38, 0xEA, 0x09, 0xA8 }; 29 | 30 | static const u1_t artKey[16] = { 0xE7, 0x63, 0x2E, 0x1C, 0xF3, 0x61, 0x7E, 0xAD, 0xF5, 0xC0, 0xBC, 0x7E, 0x38, 0xEA, 0x09, 0xA8 }; 31 | 32 | 33 | ////////////////////////////////////////////////// 34 | // APPLICATION CALLBACKS 35 | ////////////////////////////////////////////////// 36 | 37 | // provide application router ID (8 bytes, LSBF) 38 | void os_getArtEui (u1_t* buf) { 39 | memcpy(buf, APPEUI, 8); 40 | } 41 | 42 | // provide device ID (8 bytes, LSBF) 43 | void os_getDevEui (u1_t* buf) { 44 | memcpy(buf, DEVEUI, 8); 45 | } 46 | 47 | // provide device key (16 bytes) 48 | void os_getDevKey (u1_t* buf) { 49 | memcpy(buf, DEVKEY, 16); 50 | } 51 | 52 | 53 | ////////////////////////////////////////////////// 54 | // MAIN - INITIALIZATION AND STARTUP 55 | ////////////////////////////////////////////////// 56 | 57 | // initial job 58 | static void initfunc (osjob_t* j) { 59 | // reset MAC state 60 | LMIC_reset(); 61 | // start joining 62 | LMIC_setSession(0x12345678, 0xB710566C, nwkKey, artKey); 63 | // enable pinging mode, start scanning... 64 | // (set local ping interval configuration to 2^1 == 2 sec) 65 | LMIC_setPingable(1); 66 | debug_str("SCANNING...\r\n"); 67 | 68 | LMIC_sendAlive(); 69 | //LMIC_startJoining(); 70 | // init done - onEvent() callback will be invoked... 71 | } 72 | 73 | 74 | // application entry point 75 | int main () { 76 | osjob_t initjob; 77 | 78 | // initialize runtime env 79 | os_init(); 80 | // initialize debug library 81 | debug_init(); 82 | // setup initial job 83 | os_setCallback(&initjob, initfunc); 84 | // execute scheduled jobs and events 85 | os_runloop(); 86 | // (not reached) 87 | return 0; 88 | } 89 | 90 | 91 | ////////////////////////////////////////////////// 92 | // LMIC EVENT CALLBACK 93 | ////////////////////////////////////////////////// 94 | 95 | void onEvent (ev_t ev) { 96 | debug_event(ev); 97 | 98 | switch(ev) { 99 | 100 | // network joined, session established 101 | case EV_JOINED: 102 | // enable pinging mode, start scanning... 103 | // (set local ping interval configuration to 2^1 == 2 sec) 104 | LMIC_setPingable(1); 105 | debug_str("SCANNING...\r\n"); 106 | break; 107 | 108 | // beacon found by scanning 109 | case EV_BEACON_FOUND: 110 | // send empty frame up to notify server of ping mode and interval! 111 | LMIC_sendAlive(); 112 | break; 113 | 114 | // data frame received in ping slot 115 | case EV_RXCOMPLETE: 116 | // log frame data 117 | debug_buf(LMIC.frame+LMIC.dataBeg, LMIC.dataLen); 118 | if(LMIC.dataLen == 1) { 119 | // set LED state if exactly one byte is received 120 | debug_led(LMIC.frame[LMIC.dataBeg] & 0x01); 121 | } 122 | break; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /examples/transmit/main.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | #include "../../lmic/lmic.h" 13 | #include "../../hal/debug.h" 14 | 15 | ////////////////////////////////////////////////// 16 | // CONFIGURATION (FOR APPLICATION CALLBACKS BELOW) 17 | ////////////////////////////////////////////////// 18 | 19 | // application router ID (LSBF) 20 | static const u1_t APPEUI[8] = { 0xBE, 0x7A, 0x00, 0x0B, 0xE7, 0xA0, 0x00, 0x40 };//0x02, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xFF, 0xC0 }; 21 | 22 | // unique device ID (LSBF) 23 | static const u1_t DEVEUI[8] = { 0xBE, 0x7A, 0x00, 0x0B, 0xE7, 0xA0, 0x00, 0x45 };//0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; 24 | 25 | // device-specific AES key (derived from device EUI) 26 | static const u1_t DEVKEY[16] = { 0xE7, 0x63, 0x2E, 0x1C, 0xF3, 0x61, 0x7E, 0xAD, 0xF5, 0xC0, 0xBC, 0x7E, 0x38, 0xEA, 0x09, 0xA8 }; 27 | 28 | static const u1_t nwkKey[16] = { 0xE7, 0x63, 0x2E, 0x1C, 0xF3, 0x61, 0x7E, 0xAD, 0xF5, 0xC0, 0xBC, 0x7E, 0x38, 0xEA, 0x09, 0xA8 }; 29 | 30 | static const u1_t artKey[16] = { 0xE7, 0x63, 0x2E, 0x1C, 0xF3, 0x61, 0x7E, 0xAD, 0xF5, 0xC0, 0xBC, 0x7E, 0x38, 0xEA, 0x09, 0xA8 }; 31 | 32 | ////////////////////////////////////////////////// 33 | // APPLICATION CALLBACKS 34 | ////////////////////////////////////////////////// 35 | 36 | // provide application router ID (8 bytes, LSBF) 37 | void os_getArtEui (u1_t* buf) { 38 | memcpy(buf, APPEUI, 8); 39 | } 40 | 41 | // provide device ID (8 bytes, LSBF) 42 | void os_getDevEui (u1_t* buf) { 43 | memcpy(buf, DEVEUI, 8); 44 | } 45 | 46 | // provide device key (16 bytes) 47 | void os_getDevKey (u1_t* buf) { 48 | memcpy(buf, DEVKEY, 16); 49 | } 50 | 51 | 52 | ////////////////////////////////////////////////// 53 | // MAIN - INITIALIZATION AND STARTUP 54 | ////////////////////////////////////////////////// 55 | 56 | // initial job 57 | static void initfunc (osjob_t* j) { 58 | 59 | LMIC_reset(); // reset MAC state 60 | 61 | LMIC_setSession(0x12345678, 0xB710566C, nwkKey, artKey); 62 | 63 | //LMIC_startJoining(); // start joining 64 | // init done - onEvent() callback will be invoked... 65 | 66 | /*void LMIC_setSession (u4_t netid, devaddr_t(u4_t) devaddr, xref2u1_t nwkKey, xref2u1_t artKey) { 67 | LMIC.netid = netid; 68 | LMIC.devaddr = devaddr; 69 | if( nwkKey != (xref2u1_t)0 ) 70 | os_copyMem(LMIC.nwkKey, nwkKey, 16); 71 | if( artKey != (xref2u1_t)0 ) 72 | os_copyMem(LMIC.artKey, artKey, 16);*/ 73 | 74 | debug_str("\r\nSending"); 75 | // immediately prepare next transmission 76 | LMIC.frame[0] = LMIC.snr; 77 | // schedule transmission (port 1, datalen 1, no ack requested) 78 | LMIC_setTxData2(1, LMIC.frame, 1, 0); 79 | // (will be sent as soon as duty cycle permits) 80 | 81 | LMIC_sendAlive(); 82 | } 83 | 84 | 85 | // application entry point 86 | int main () { 87 | osjob_t initjob; 88 | 89 | // initialize runtime env 90 | os_init(); 91 | // initialize debug library 92 | debug_init(); 93 | // setup initial job 94 | os_setCallback(&initjob, initfunc); 95 | // execute scheduled jobs and events 96 | os_runloop(); 97 | // (not reached) 98 | return 0; 99 | } 100 | 101 | 102 | ////////////////////////////////////////////////// 103 | // LMIC EVENT CALLBACK 104 | ////////////////////////////////////////////////// 105 | 106 | void onEvent (ev_t ev) 107 | { 108 | debug_event(ev); 109 | 110 | switch(ev) 111 | { 112 | 113 | // network joined, session established 114 | case EV_JOINED: 115 | debug_val("\r\nnetid = ", LMIC.netid); 116 | 117 | // immediately prepare next transmission 118 | debug_str("\r\nSending"); 119 | LMIC.frame[0] = LMIC.snr; 120 | LMIC_setTxData2(1, LMIC.frame, 1, 0); // schedule transmission (port 1, datalen 1, no ack requested) 121 | break; 122 | 123 | // scheduled data sent (optionally data received) 124 | case EV_TXCOMPLETE: 125 | if(LMIC.dataLen) { // data received in rx slot after tx 126 | debug_str("\r\nReceived:"); 127 | debug_buf(LMIC.frame+LMIC.dataBeg, LMIC.dataLen); 128 | } 129 | // immediately prepare next transmission 130 | LMIC.frame[0] = LMIC.snr; 131 | debug_val("\r\nSending:", LMIC.frame[0]); 132 | // schedule transmission (port 1, datalen 1, no ack requested) 133 | LMIC_setTxData2(1, LMIC.frame, 1, 0); 134 | break; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /hal/debug.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | 13 | #include "debug.h" 14 | #include "../lmic/lmic.h" 15 | #include "em_gpio.h" 16 | #include "em_cmu.h" 17 | #include "em_leuart.h" 18 | 19 | #if defined PA52 20 | #define PORT_TXD gpioPortD //TXD = PD4 21 | #define PIN_TXD 4U 22 | #define PORT_RXD gpioPortD //RXD = PD5 23 | #define PIN_RXD 5U 24 | 25 | #define PORT_SPK gpioPortC //REED3 = PC15 TILT = SPK 26 | #define PIN_SPK 15U 27 | #elif defined PA53 28 | #define PORT_TXD gpioPortD //TXD = PD4 29 | #define PIN_TXD 4U 30 | #define PORT_RXD gpioPortD //RXD = PD5 31 | #define PIN_RXD 5U 32 | 33 | #define PORT_SPK gpioPortC //REED3 = PC15 TILT = SPK 34 | #define PIN_SPK 15U 35 | #endif 36 | 37 | void debug_init () 38 | { 39 | GPIO_PinModeSet(PORT_SPK, PIN_SPK, gpioModePushPull, 0); 40 | 41 | LEUART_Init_TypeDef init = LEUART_INIT_DEFAULT; 42 | 43 | CMU_ClockEnable(cmuClock_HFPER, true); 44 | CMU_ClockEnable(cmuClock_GPIO, true); 45 | 46 | CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO); 47 | CMU_ClockDivSet(cmuClock_LEUART0, cmuClkDiv_1); 48 | CMU_ClockEnable(cmuClock_LEUART0, true); 49 | 50 | init.refFreq = 0; //14MHz / 2 pre-scaled by 4 = 1750000; 51 | init.enable = leuartDisable; 52 | init.baudrate = 9600; 53 | init.databits = leuartDatabits8; 54 | init.parity = leuartNoParity; 55 | init.stopbits = leuartStopbits1; 56 | 57 | // Reseting and initializing LEUART0 58 | LEUART_Reset(LEUART0); 59 | LEUART_Init(LEUART0, &init); 60 | 61 | GPIO_PinModeSet(PORT_TXD, PIN_TXD, gpioModePushPull, 1); 62 | GPIO_PinModeSet(PORT_RXD, PIN_RXD, gpioModeInput, 0); 63 | 64 | LEUART0->ROUTE = LEUART_ROUTE_TXPEN | LEUART_ROUTE_RXPEN | LEUART_ROUTE_LOCATION_LOC0; 65 | LEUART0->CMD = LEUART_CMD_TXDIS | LEUART_CMD_RXDIS | LEUART_CMD_CLEARTX | LEUART_CMD_CLEARRX; 66 | LEUART0->CMD = LEUART_CMD_TXEN | LEUART_CMD_RXEN; 67 | 68 | // Eventually enable UART 69 | LEUART_Enable(LEUART0, leuartEnable); 70 | 71 | // print banner 72 | debug_str("\r\n============= DEBUG STARTED =============\r\n"); 73 | } 74 | 75 | void debug_led (u1_t val) 76 | { 77 | if (val) 78 | GPIO_PinOutSet(PORT_SPK, PIN_SPK); 79 | else 80 | GPIO_PinOutClear(PORT_SPK, PIN_SPK); 81 | } 82 | 83 | void debug_char (u1_t c) 84 | { 85 | LEUART_Tx(LEUART0, c); 86 | } 87 | 88 | void debug_hex (u1_t b) { 89 | debug_char("0123456789ABCDEF"[b>>4]); 90 | debug_char("0123456789ABCDEF"[b&0xF]); 91 | } 92 | 93 | void debug_buf (const u1_t* buf, u2_t len) { 94 | while(len--) { 95 | debug_hex(*buf++); 96 | debug_char(' '); 97 | } 98 | debug_char('\r'); 99 | debug_char('\n'); 100 | } 101 | 102 | void debug_uint (u4_t v) { 103 | for(s1_t n=24; n>=0; n-=8) { 104 | debug_hex(v>>n); 105 | } 106 | } 107 | 108 | void debug_str (const u1_t* str) { 109 | while(*str) { 110 | debug_char(*str++); 111 | } 112 | } 113 | 114 | void debug_val (const u1_t* label, u4_t val) { 115 | debug_str(label); 116 | debug_uint(val); 117 | debug_char('\r'); 118 | debug_char('\n'); 119 | } 120 | 121 | void debug_event (int ev) { 122 | static const u1_t* evnames[] = { 123 | [EV_SCAN_TIMEOUT] = "SCAN_TIMEOUT", 124 | [EV_BEACON_FOUND] = "BEACON_FOUND", 125 | [EV_BEACON_MISSED] = "BEACON_MISSED", 126 | [EV_BEACON_TRACKED] = "BEACON_TRACKED", 127 | [EV_JOINING] = "JOINING", 128 | [EV_JOINED] = "JOINED", 129 | [EV_RFU1] = "RFU1", 130 | [EV_JOIN_FAILED] = "JOIN_FAILED", 131 | [EV_REJOIN_FAILED] = "REJOIN_FAILED", 132 | [EV_TXCOMPLETE] = "TXCOMPLETE", 133 | [EV_LOST_TSYNC] = "LOST_TSYNC", 134 | [EV_RESET] = "RESET", 135 | [EV_RXCOMPLETE] = "RXCOMPLETE", 136 | [EV_LINK_DEAD] = "LINK_DEAD", 137 | [EV_LINK_ALIVE] = "LINK_ALIVE", 138 | }; 139 | debug_str(evnames[ev]); 140 | debug_char('\r'); 141 | debug_char('\n'); 142 | } 143 | -------------------------------------------------------------------------------- /hal/debug.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | #include "../lmic/oslmic.h" 12 | 13 | // intialize debug library 14 | void debug_init (void); 15 | 16 | // set LED state 17 | void debug_led (u1_t val); 18 | 19 | // write character to USART 20 | void debug_char (u1_t c); 21 | 22 | // write byte as two hex digits to USART 23 | void debug_hex (u1_t b); 24 | 25 | // write buffer as hex dump to USART 26 | void debug_buf (const u1_t* buf, u2_t len); 27 | 28 | // write 32-bit integer as eight hex digits to USART 29 | void debug_uint (u4_t v); 30 | 31 | // write nul-terminated string to USART 32 | void debug_str (const u1_t* str); 33 | 34 | // write LMiC event name to USART 35 | void debug_event (int ev); 36 | 37 | // write label and 32-bit value as hex to USART 38 | void debug_val (const u1_t* label, u4_t val); 39 | -------------------------------------------------------------------------------- /hal/hal.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | #include "../lmic/lmic.h" 13 | 14 | #include "em_chip.h" 15 | #include "em_device.h" 16 | #include "em_cmu.h" 17 | #include "em_gpio.h" 18 | #include "em_int.h" 19 | #include "em_emu.h" 20 | #include "em_rtc.h" 21 | #include "em_usart.h" 22 | 23 | // ----------------------------------------------------------------------------- 24 | // I/O 25 | #if defined PA52 26 | #define PORT_DIO0 gpioPortB //DIO0 = PB11 27 | #define PIN_DIO0 11 28 | #define PORT_DIO1 gpioPortC //DIO1 = PC1 29 | #define PIN_DIO1 1 30 | #define PORT_DIO2 gpioPortC //DIO2 = PC0 31 | #define PIN_DIO2 0 32 | #define PORT_DIO3 gpioPortA //DIO3 = PA2 33 | #define PIN_DIO3 2 34 | #define PORT_DIO4 gpioPortA //DIO4 = PA1 35 | #define PIN_DIO4 1 36 | #define PORT_DIO5 gpioPortA //DIO5 = PA0 37 | #define PIN_DIO5 0 38 | #define USART_USED USART0 39 | #define USART_LOCATION USART_ROUTE_LOCATION_LOC0 40 | #define USART_CLK cmuClock_USART0 41 | #define PIN_SPI_TX 10 //MOSI = PE10 42 | #define PORT_SPI_TX gpioPortE 43 | #define PIN_SPI_RX 11 //MISO = PE11 44 | #define PORT_SPI_RX gpioPortE 45 | #define PIN_SPI_CLK 12 //SCK = PE12 46 | #define PORT_SPI_CLK gpioPortE 47 | #define PIN_SPI_CS 13 //CSN = PE13 48 | #define PORT_SPI_CS gpioPortE 49 | #elif defined PA53 50 | #define PORT_DIO0 gpioPortC //DIO0 = PC1 51 | #define PIN_DIO0 1U 52 | #define PORT_DIO1 gpioPortC //DIO1 = PC0 53 | #define PIN_DIO1 0U 54 | #define PORT_DIO2 gpioPortA //DIO2 = PA2 55 | #define PIN_DIO2 2U 56 | #define PORT_DIO4 gpioPortA //DIO4 = PA1 57 | #define PIN_DIO4 1U 58 | #define PORT_DIO5 gpioPortA //DIO5 = PA0 59 | #define PIN_DIO5 0U 60 | #define USART_USED USART0 61 | #define USART_LOCATION USART_ROUTE_LOCATION_LOC0 62 | #define USART_CLK cmuClock_USART0 63 | #define PIN_SPI_TX 10 //MOSI = PE10 64 | #define PORT_SPI_TX gpioPortE 65 | #define PIN_SPI_RX 11 //MISO = PE11 66 | #define PORT_SPI_RX gpioPortE 67 | #define PIN_SPI_CLK 12 //SCK = PE12 68 | #define PORT_SPI_CLK gpioPortE 69 | #define PIN_SPI_CS 13 //CSN = PE13 70 | #define PORT_SPI_CS gpioPortE 71 | #else 72 | #error Missing board! 73 | #endif 74 | 75 | // HAL state 76 | static struct 77 | { 78 | //int irqlevel; 79 | u4_t ticks; 80 | } HAL; 81 | 82 | // ----------------------------------------------------------------------------- 83 | // I/O 84 | 85 | static void hal_io_init () 86 | { 87 | //Enable module clocks 88 | CMU_ClockEnable(cmuClock_HFPER, true); 89 | CMU_ClockEnable(cmuClock_GPIO, true); 90 | 91 | GPIO_PinModeSet(PORT_DIO0, PIN_DIO0, gpioModeInputPull, 0); //DIO0=PayLoadReady 92 | GPIO_PinModeSet(PORT_DIO1, PIN_DIO1, gpioModeInputPull, 0); //DIO1=FifoLevel 93 | GPIO_PinModeSet(PORT_DIO2, PIN_DIO2, gpioModeInputPull, 0); //DIO2=SyncAddr 94 | #if !defined PA53 95 | GPIO_PinModeSet(PORT_DIO3, PIN_DIO3, gpioModeInputPull, 0); //DIO3=FifoEmpty 96 | #endif 97 | GPIO_PinModeSet(PORT_DIO4, PIN_DIO4, gpioModeInputPull, 0); //DIO4=PreambleDetect/RSSI 98 | GPIO_PinModeSet(PORT_DIO5, PIN_DIO5, gpioModeInputPull, 0); //DIO5=ModeReady 99 | 100 | GPIO_IntConfig(PORT_DIO0, PIN_DIO0, true, false, true); 101 | GPIO_IntConfig(PORT_DIO1, PIN_DIO1, true, false, true); 102 | GPIO_IntConfig(PORT_DIO2, PIN_DIO2, true, false, true); 103 | NVIC_EnableIRQ(GPIO_ODD_IRQn); 104 | NVIC_EnableIRQ(GPIO_EVEN_IRQn); 105 | } 106 | 107 | // val ==1 => tx 1, rx 0 ; val == 0 => tx 0, rx 1 108 | void hal_pin_rxtx (u1_t val) 109 | { 110 | //not used in PA52 nor PA53 111 | } 112 | 113 | 114 | // set radio NSS pin to given value 115 | void hal_pin_nss (u1_t val) 116 | { 117 | if (val) 118 | GPIO_PinOutSet(PORT_SPI_CS, PIN_SPI_CS); // SPI Disable 119 | else 120 | GPIO_PinOutClear(PORT_SPI_CS, PIN_SPI_CS); // SPI Enable (Active Low) 121 | } 122 | 123 | // set radio RST pin to given value (or keep floating!) 124 | void hal_pin_rst (u1_t val) 125 | { 126 | #if defined PA52 127 | //not used in PA52 128 | #elif defined PA53 129 | if(val == 0 || val == 1) { // drive pin 130 | hw_cfg_pin(GPIOx(RST_PORT), RST_PIN, GPIOCFG_MODE_OUT | GPIOCFG_OSPEED_40MHz | GPIOCFG_OTYPE_PUPD | GPIOCFG_PUPD_PUP); 131 | hw_set_pin(GPIOx(RST_PORT), RST_PIN, val); 132 | } else { // keep pin floating 133 | hw_cfg_pin(GPIOx(RST_PORT), RST_PIN, GPIOCFG_MODE_INP | GPIOCFG_OSPEED_40MHz | GPIOCFG_OTYPE_OPEN); 134 | } 135 | #endif 136 | } 137 | 138 | extern void radio_irq_handler(u1_t dio); 139 | 140 | void GPIO_ODD_IRQHandler(void) //impar 141 | { 142 | u4_t i = GPIO_IntGet(); 143 | if (i & 1<ROUTE = USART_ROUTE_TXPEN | USART_ROUTE_RXPEN | USART_ROUTE_CLKPEN | USART_LOCATION; 186 | } 187 | 188 | // perform SPI transaction with radio 189 | u1_t hal_spi (u1_t out) 190 | { 191 | /* For every byte sent, one is received */ 192 | USART_Tx(USART_USED, out); 193 | return USART_Rx(USART_USED); 194 | } 195 | 196 | 197 | // ----------------------------------------------------------------------------- 198 | // TIME 199 | static uint8_t rtcInitialized = 0; /**< 1 if rtc is initialized */ 200 | static uint32_t rtcFreq; /**< RTC Frequence. 32.768 kHz */ 201 | 202 | /***************************************************************************//** 203 | * @brief RTC Interrupt Handler, invoke callback function if defined. 204 | ******************************************************************************/ 205 | void RTC_IRQHandler(void) 206 | { 207 | if (RTC_IntGet() & RTC_IF_OF) 208 | { 209 | HAL.ticks ++; 210 | } 211 | 212 | if(RTC_IntGet() & RTC_IF_COMP0) // expired 213 | { 214 | // do nothing, only wake up cpu 215 | } 216 | RTC_IntClear(_RTC_IF_MASK); // clear IRQ flags 217 | } 218 | 219 | 220 | static void hal_time_init () 221 | { 222 | RTC_Init_TypeDef init; 223 | 224 | rtcInitialized = 1; 225 | 226 | /* Ensure LE modules are accessible */ 227 | CMU_ClockEnable(cmuClock_CORELE, true); 228 | 229 | /* Enable LFACLK in CMU (will also enable oscillator if not enabled) */ 230 | CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO); 231 | 232 | /* Use the prescaler to reduce power consumption. */ 233 | CMU_ClockDivSet(cmuClock_RTC, cmuClkDiv_1); 234 | 235 | rtcFreq = CMU_ClockFreqGet(cmuClock_RTC); 236 | 237 | /* Enable clock to RTC module */ 238 | CMU_ClockEnable(cmuClock_RTC, true); 239 | 240 | init.enable = false; 241 | init.debugRun = false; 242 | init.comp0Top = false; 243 | //init.comp0Top = true; /* Count to max before wrapping */ 244 | RTC_Init(&init); 245 | 246 | /* Disable interrupt generation from RTC0 */ 247 | RTC_IntDisable(_RTC_IF_MASK); 248 | 249 | /* Enable interrupts */ 250 | NVIC_ClearPendingIRQ(RTC_IRQn); 251 | NVIC_EnableIRQ(RTC_IRQn); 252 | 253 | /* Enable RTC */ 254 | RTC_Enable(true); 255 | 256 | RTC_IntEnable(RTC_IF_OF); //Enable interrupt on overflow 257 | } 258 | 259 | u4_t hal_ticks () 260 | { 261 | hal_disableIRQs(); 262 | u4_t t = HAL.ticks; 263 | u4_t cnt = RTC_CounterGet(); 264 | if (RTC_IntGet() & RTC_IF_OF) // Overflow before we read CNT? 265 | { 266 | cnt = RTC_CounterGet(); 267 | t ++; // Include overflow in evaluation but leave update of state to ISR once interrupts enabled again 268 | } 269 | hal_enableIRQs(); 270 | return (t<<24)|cnt; 271 | } 272 | 273 | // return modified delta ticks from now to specified ticktime (0 for past, FFFF for far future) 274 | static u2_t deltaticks (u4_t time) 275 | { 276 | u4_t t = hal_ticks(); 277 | s4_t d = time - t; 278 | if( d<=0 ) return 0; // in the past 279 | if( (d>>16)!=0 ) return 0xFFFF; // far ahead 280 | return (u2_t)d; 281 | } 282 | 283 | void hal_waitUntil (u4_t time) 284 | { 285 | while( deltaticks(time) != 0 ); // busy wait until timestamp is reached 286 | } 287 | 288 | // check and rewind for target time 289 | u1_t hal_checkTimer (u4_t time) 290 | { 291 | u2_t dt; 292 | RTC_IntClear(RTC_IF_COMP0); //clear any pending interrupts 293 | if((dt = deltaticks(time)) < 5) // event is now (a few ticks ahead) 294 | { 295 | RTC_IntDisable(RTC_IF_COMP0); // disable IE 296 | return 1; 297 | } 298 | else // rewind timer (fully or to exact time)) 299 | { 300 | RTC_CompareSet(0, RTC_CounterGet() + dt); // set comparator 301 | RTC_IntEnable(RTC_IF_COMP0); // enable IE 302 | return 0; 303 | } 304 | } 305 | 306 | 307 | 308 | // ----------------------------------------------------------------------------- 309 | // IRQ 310 | 311 | void hal_disableIRQs () 312 | { 313 | INT_Disable(); 314 | } 315 | 316 | void hal_enableIRQs () 317 | { 318 | INT_Enable(); 319 | } 320 | 321 | void hal_sleep () 322 | { 323 | EMU_EnterEM2(false); 324 | } 325 | 326 | // ----------------------------------------------------------------------------- 327 | 328 | void hal_init () 329 | { 330 | CHIP_Init(); 331 | 332 | memset(&HAL, 0x00, sizeof(HAL)); 333 | hal_disableIRQs(); 334 | 335 | hal_io_init(); // configure radio I/O and interrupt handler 336 | 337 | hal_spi_init(); // configure radio SPI 338 | 339 | hal_time_init(); // configure timer and interrupt handler 340 | 341 | hal_enableIRQs(); 342 | } 343 | 344 | void hal_failed () 345 | { 346 | debug_led(1); 347 | // HALT... 348 | hal_disableIRQs(); 349 | hal_sleep(); 350 | while(1); 351 | } 352 | 353 | -------------------------------------------------------------------------------- /lmic/aes.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | #include "oslmic.h" 13 | 14 | #define AES_MICSUB 0x30 // internal use only 15 | 16 | static const u4_t AES_RCON[10] = { 17 | 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 18 | 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000 19 | }; 20 | 21 | static const u1_t AES_S[256] = { 22 | 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 23 | 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 24 | 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 25 | 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 26 | 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 27 | 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 28 | 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 29 | 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 30 | 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 31 | 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 32 | 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 33 | 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 34 | 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 35 | 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 36 | 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 37 | 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16, 38 | }; 39 | 40 | static const u4_t AES_E1[256] = { 41 | 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554, 42 | 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, 43 | 0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, 44 | 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, 0xE4727296, 0x9BC0C05B, 45 | 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, 46 | 0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F, 47 | 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, 0x0A05050F, 0x2F9A9AB5, 48 | 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, 49 | 0x1209091B, 0x1D83839E, 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB, 50 | 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497, 51 | 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, 52 | 0xD46A6ABE, 0x8DCBCB46, 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A, 53 | 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, 0x66333355, 0x11858594, 54 | 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, 55 | 0xA25151F3, 0x5DA3A3FE, 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504, 56 | 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, 0xFDF3F30E, 0xBFD2D26D, 57 | 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, 58 | 0x93C4C457, 0x55A7A7F2, 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395, 59 | 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, 0x3B9090AB, 0x0B888883, 60 | 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, 61 | 0xDBE0E03B, 0x64323256, 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4, 62 | 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, 0xD3E4E437, 0xF279798B, 63 | 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, 64 | 0xD86C6CB4, 0xAC5656FA, 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818, 65 | 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, 0x73B4B4C7, 0x97C6C651, 66 | 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, 67 | 0xE0707090, 0x7C3E3E42, 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12, 68 | 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, 0x3A1D1D27, 0x279E9EB9, 69 | 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, 70 | 0x2D9B9BB6, 0x3C1E1E22, 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A, 71 | 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, 0x844242C6, 0xD06868B8, 72 | 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A, 73 | }; 74 | 75 | static const u4_t AES_E2[256] = { 76 | 0xA5C66363, 0x84F87C7C, 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5, 77 | 0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, 0xE64DABAB, 0x9AEC7676, 78 | 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0, 79 | 0xEC41ADAD, 0x67B3D4D4, 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0, 80 | 0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, 0x02F5F7F7, 0x4F83CCCC, 81 | 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515, 82 | 0x0C080404, 0x5295C7C7, 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A, 83 | 0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727, 0xCD7FB2B2, 0x9FEA7575, 84 | 0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0, 85 | 0xF6A45252, 0x4D763B3B, 0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484, 86 | 0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC, 0xC879B1B1, 0xEDB65B5B, 87 | 0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF, 88 | 0x6BBBD0D0, 0x2AC5EFEF, 0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585, 89 | 0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, 0xBA259F9F, 0xE34BA8A8, 90 | 0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5, 91 | 0xDF63BCBC, 0xC177B6B6, 0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2, 92 | 0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, 0xCC884444, 0x392E1717, 93 | 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373, 94 | 0xA0C06060, 0x98198181, 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888, 95 | 0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, 0x1D160B0B, 0x76ADDBDB, 96 | 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C, 97 | 0x5D9FC2C2, 0x6EBDD3D3, 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979, 98 | 0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5, 0xD29C4E4E, 0xE049A9A9, 99 | 0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808, 100 | 0xD56FBABA, 0x88F07878, 0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6, 101 | 0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD, 0x860D8B8B, 0x850F8A8A, 102 | 0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E, 103 | 0xA3C26161, 0x5F6A3535, 0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E, 104 | 0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, 0x89078E8E, 0xA7339494, 105 | 0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF, 106 | 0x8F038C8C, 0xF859A1A1, 0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868, 107 | 0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, 0x3A2C1616, 108 | }; 109 | 110 | static const u4_t AES_E3[256] = { 111 | 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5, 112 | 0x30506030, 0x01030201, 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76, 113 | 0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259, 0x47C98E47, 0xF00BFBF0, 114 | 0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0, 115 | 0xB7C275B7, 0xFD1CE1FD, 0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC, 116 | 0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8, 0x31536231, 0x153F2A15, 117 | 0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A, 118 | 0x07090E07, 0x12362412, 0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75, 119 | 0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, 0x5AEEB45A, 0xA0FB5BA0, 120 | 0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384, 121 | 0x53F5A653, 0xD168B9D1, 0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B, 122 | 0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, 0x58E8B058, 0xCF4A85CF, 123 | 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185, 124 | 0x45CF8A45, 0xF910E9F9, 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8, 125 | 0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, 0x38487038, 0xF504F1F5, 126 | 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2, 127 | 0xCD4C81CD, 0x0C14180C, 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17, 128 | 0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D, 0x192B3219, 0x7395E673, 129 | 0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88, 130 | 0x46CA8C46, 0xEE29C7EE, 0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB, 131 | 0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06, 0x246C4824, 0x5CE4B85C, 132 | 0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279, 133 | 0xE732D5E7, 0xC8438BC8, 0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9, 134 | 0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, 0xAEE947AE, 0x08181008, 135 | 0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6, 136 | 0xE823CBE8, 0xDD7CA1DD, 0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A, 137 | 0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, 0xF601F7F6, 0x0E121C0E, 138 | 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E, 139 | 0xE138D9E1, 0xF813EBF8, 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394, 140 | 0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, 0x28785028, 0xDF7AA5DF, 141 | 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068, 142 | 0x41C38241, 0x99B02999, 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16, 143 | }; 144 | 145 | static const u4_t AES_E4[256] = { 146 | 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, 147 | 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, 148 | 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, 149 | 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, 150 | 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, 151 | 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, 152 | 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, 153 | 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, 154 | 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, 155 | 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, 156 | 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, 157 | 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, 158 | 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, 159 | 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, 160 | 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, 161 | 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, 162 | 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, 163 | 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, 164 | 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, 165 | 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, 166 | 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, 167 | 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, 168 | 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, 169 | 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, 170 | 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, 171 | 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, 172 | 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, 173 | 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, 174 | 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, 175 | 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, 176 | 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, 177 | 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C, 178 | }; 179 | 180 | #define msbf4_read(p) ((p)[0]<<24 | (p)[1]<<16 | (p)[2]<<8 | (p)[3]) 181 | #define msbf4_write(p,v) (p)[0]=(v)>>24,(p)[1]=(v)>>16,(p)[2]=(v)>>8,(p)[3]=(v) 182 | #define swapmsbf(x) ( (x&0xFF)<<24 | (x&0xFF00)<<8 | (x&0xFF0000)>>8 | (x>>24) ) 183 | 184 | #define u1(v) ((u1_t)(v)) 185 | 186 | #define AES_key4(r1,r2,r3,r0,i) r1 = ki[i+1]; \ 187 | r2 = ki[i+2]; \ 188 | r3 = ki[i+3]; \ 189 | r0 = ki[i] 190 | 191 | #define AES_expr4(r1,r2,r3,r0,i) r1 ^= AES_E4[u1(i)]; \ 192 | r2 ^= AES_E3[u1(i>>8)]; \ 193 | r3 ^= AES_E2[u1(i>>16)]; \ 194 | r0 ^= AES_E1[ (i>>24)] 195 | 196 | #define AES_expr(a,r0,r1,r2,r3,i) a = ki[i]; \ 197 | a ^= (AES_S[ r0>>24 ]<<24); \ 198 | a ^= (AES_S[u1(r1>>16)]<<16); \ 199 | a ^= (AES_S[u1(r2>> 8)]<< 8); \ 200 | a ^= AES_S[u1(r3) ] 201 | 202 | // global area for passing parameters (aux, key) and for storing round keys 203 | u4_t AESAUX[16/sizeof(u4_t)]; 204 | u4_t AESKEY[11*16/sizeof(u4_t)]; 205 | 206 | // generate 1+10 roundkeys for encryption with 128-bit key 207 | // read 128-bit key from AESKEY in MSBF, generate roundkey words in place 208 | static void aesroundkeys () { 209 | int i; 210 | u4_t b; 211 | 212 | for( i=0; i<4; i++) { 213 | AESKEY[i] = swapmsbf(AESKEY[i]); 214 | } 215 | 216 | b = AESKEY[3]; 217 | for( ; i<44; i++ ) { 218 | if( i%4==0 ) { 219 | // b = SubWord(RotWord(b)) xor Rcon[i/4] 220 | b = (AES_S[u1(b >> 16)] << 24) ^ 221 | (AES_S[u1(b >> 8)] << 16) ^ 222 | (AES_S[u1(b) ] << 8) ^ 223 | (AES_S[ b >> 24 ] ) ^ 224 | AES_RCON[(i-4)/4]; 225 | } 226 | AESKEY[i] = b ^= AESKEY[i-4]; 227 | } 228 | } 229 | 230 | u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len) { 231 | 232 | aesroundkeys(); 233 | 234 | if( mode & AES_MICNOAUX ) { 235 | AESAUX[0] = AESAUX[1] = AESAUX[2] = AESAUX[3] = 0; 236 | } else { 237 | AESAUX[0] = swapmsbf(AESAUX[0]); 238 | AESAUX[1] = swapmsbf(AESAUX[1]); 239 | AESAUX[2] = swapmsbf(AESAUX[2]); 240 | AESAUX[3] = swapmsbf(AESAUX[3]); 241 | } 242 | 243 | while( (signed char)len > 0 ) { 244 | u4_t a0, a1, a2, a3; 245 | u4_t t0, t1, t2, t3; 246 | u4_t *ki, *ke; 247 | 248 | // load input block 249 | if( (mode & AES_CTR) || ((mode & AES_MIC) && (mode & AES_MICNOAUX)==0) ) { // load CTR block or first MIC block 250 | a0 = AESAUX[0]; 251 | a1 = AESAUX[1]; 252 | a2 = AESAUX[2]; 253 | a3 = AESAUX[3]; 254 | } 255 | else if( (mode & AES_MIC) && len <= 16 ) { // last MIC block 256 | a0 = a1 = a2 = a3 = 0; // load null block 257 | mode |= ((len == 16) ? 1 : 2) << 4; // set MICSUB: CMAC subkey K1 or K2 258 | } else 259 | LOADDATA: { // load data block (partially) 260 | for(t0=0; t0<16; t0++) { 261 | t1 = (t1<<8) | ((t0> 4) != 0 ) { // last block 312 | do { 313 | // compute CMAC subkey K1 and K2 314 | t0 = a0 >> 31; // save MSB 315 | a0 = (a0 << 1) | (a1 >> 31); 316 | a1 = (a1 << 1) | (a2 >> 31); 317 | a2 = (a2 << 1) | (a3 >> 31); 318 | a3 = (a3 << 1); 319 | if( t0 ) a3 ^= 0x87; 320 | } while( --t1 ); 321 | 322 | AESAUX[0] ^= a0; 323 | AESAUX[1] ^= a1; 324 | AESAUX[2] ^= a2; 325 | AESAUX[3] ^= a3; 326 | mode &= ~AES_MICSUB; 327 | goto LOADDATA; 328 | } else { 329 | // save cipher block as new iv 330 | AESAUX[0] = a0; 331 | AESAUX[1] = a1; 332 | AESAUX[2] = a2; 333 | AESAUX[3] = a3; 334 | } 335 | } else { // CIPHER 336 | if( mode & AES_CTR ) { // xor block (partially) 337 | t0 = (len > 16) ? 16: len; 338 | for(t1=0; t1>24); 340 | a0 <<= 8; 341 | if((t1&3)==3) { 342 | a0 = a1; 343 | a1 = a2; 344 | a2 = a3; 345 | } 346 | } 347 | // update counter 348 | AESAUX[3]++; 349 | } else { // ECB 350 | // store block 351 | msbf4_write(buf+0, a0); 352 | msbf4_write(buf+4, a1); 353 | msbf4_write(buf+8, a2); 354 | msbf4_write(buf+12, a3); 355 | } 356 | } 357 | 358 | // update block state 359 | if( (mode & AES_MIC)==0 || (mode & AES_MICNOAUX) ) { 360 | buf += 16; 361 | len -= 16; 362 | } 363 | mode |= AES_MICNOAUX; 364 | } 365 | return AESAUX[0]; 366 | } 367 | 368 | -------------------------------------------------------------------------------- /lmic/hal.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | #ifndef _hal_hpp_ 13 | #define _hal_hpp_ 14 | 15 | /* 16 | * initialize hardware (IO, SPI, TIMER, IRQ). 17 | */ 18 | void hal_init (void); 19 | 20 | /* 21 | * drive radio NSS pin (0=low, 1=high). 22 | */ 23 | void hal_pin_nss (u1_t val); 24 | 25 | /* 26 | * drive radio RX/TX pins (0=rx, 1=tx). 27 | */ 28 | void hal_pin_rxtx (u1_t val); 29 | 30 | /* 31 | * control radio RST pin (0=low, 1=high, 2=floating) 32 | */ 33 | void hal_pin_rst (u1_t val); 34 | 35 | /* 36 | * perform 8-bit SPI transaction with radio. 37 | * - write given byte 'outval' 38 | * - read byte and return value 39 | */ 40 | u1_t hal_spi (u1_t outval); 41 | 42 | /* 43 | * disable all CPU interrupts. 44 | * - might be invoked nested 45 | * - will be followed by matching call to hal_enableIRQs() 46 | */ 47 | void hal_disableIRQs (void); 48 | 49 | /* 50 | * enable CPU interrupts. 51 | */ 52 | void hal_enableIRQs (void); 53 | 54 | /* 55 | * put system and CPU in low-power mode, sleep until interrupt. 56 | */ 57 | void hal_sleep (void); 58 | 59 | /* 60 | * return 32-bit system time in ticks. 61 | */ 62 | u4_t hal_ticks (void); 63 | 64 | /* 65 | * busy-wait until specified timestamp (in ticks) is reached. 66 | */ 67 | void hal_waitUntil (u4_t time); 68 | 69 | /* 70 | * check and rewind timer for target time. 71 | * - return 1 if target time is close 72 | * - otherwise rewind timer for target time or full period and return 0 73 | */ 74 | u1_t hal_checkTimer (u4_t targettime); 75 | 76 | /* 77 | * perform fatal failure action. 78 | * - called by assertions 79 | * - action could be HALT or reboot 80 | */ 81 | void hal_failed (void); 82 | 83 | #endif // _hal_hpp_ 84 | -------------------------------------------------------------------------------- /lmic/lmic.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | //! @file 13 | //! @brief LMIC API 14 | 15 | #ifndef _lmic_h_ 16 | #define _lmic_h_ 17 | 18 | #include "oslmic.h" 19 | #include "lorabase.h" 20 | 21 | // LMIC version 22 | #define LMIC_VERSION_MAJOR 1 23 | #define LMIC_VERSION_MINOR 5 24 | #define LMIC_VERSION_BUILD 1431528305 25 | 26 | enum { MAX_FRAME_LEN = 64 }; //!< Library cap on max frame length 27 | enum { TXCONF_ATTEMPTS = 8 }; //!< Transmit attempts for confirmed frames 28 | enum { MAX_MISSED_BCNS = 20 }; // threshold for triggering rejoin requests 29 | enum { MAX_RXSYMS = 100 }; // stop tracking beacon beyond this 30 | 31 | enum { LINK_CHECK_CONT = 12 , // continue with this after reported dead link 32 | LINK_CHECK_DEAD = 24 , // after this UP frames and no response from NWK assume link is dead 33 | LINK_CHECK_INIT = -12 , // UP frame count until we inc datarate 34 | LINK_CHECK_OFF =-128 }; // link check disabled 35 | 36 | enum { TIME_RESYNC = 6*128 }; // secs 37 | enum { TXRX_GUARD_ms = 6000 }; // msecs - don't start TX-RX transaction before beacon 38 | enum { JOIN_GUARD_ms = 9000 }; // msecs - don't start Join Req/Acc transaction before beacon 39 | enum { TXRX_BCNEXT_secs = 2 }; // secs - earliest start after beacon time 40 | enum { RETRY_PERIOD_secs = 3 }; // secs - random period for retrying a confirmed send 41 | 42 | #if defined(CFG_eu868) // EU868 spectrum ==================================================== 43 | 44 | enum { MAX_CHANNELS = 16 }; //!< Max supported channels 45 | enum { MAX_BANDS = 4 }; 46 | 47 | enum { LIMIT_CHANNELS = (1<<4) }; // EU868 will never have more channels 48 | //! \internal 49 | struct band_t { 50 | u2_t txcap; // duty cycle limitation: 1/txcap 51 | s1_t txpow; // maximum TX power 52 | u1_t lastchnl; // last used channel 53 | ostime_t avail; // channel is blocked until this time 54 | }; 55 | TYPEDEF_xref2band_t; //!< \internal 56 | 57 | #elif defined(CFG_us915) // US915 spectrum ================================================= 58 | 59 | enum { MAX_XCHANNELS = 2 }; // extra channels in RAM, channels 0-71 are immutable 60 | enum { MAX_TXPOW_125kHz = 30 }; 61 | 62 | #endif // ========================================================================== 63 | 64 | // Keep in sync with evdefs.hpp::drChange 65 | enum { DRCHG_SET, DRCHG_NOJACC, DRCHG_NOACK, DRCHG_NOADRACK, DRCHG_NWKCMD }; 66 | enum { KEEP_TXPOW = -128 }; 67 | 68 | 69 | //! \internal 70 | struct rxsched_t { 71 | u1_t dr; 72 | u1_t intvExp; // 0..7 73 | u1_t slot; // runs from 0 to 128 74 | u1_t rxsyms; 75 | ostime_t rxbase; 76 | ostime_t rxtime; // start of next spot 77 | u4_t freq; 78 | }; 79 | TYPEDEF_xref2rxsched_t; //!< \internal 80 | 81 | 82 | //! Parsing and tracking states of beacons. 83 | enum { BCN_NONE = 0x00, //!< No beacon received 84 | BCN_PARTIAL = 0x01, //!< Only first (common) part could be decoded (info,lat,lon invalid/previous) 85 | BCN_FULL = 0x02, //!< Full beacon decoded 86 | BCN_NODRIFT = 0x04, //!< No drift value measured yet 87 | BCN_NODDIFF = 0x08 }; //!< No differential drift measured yet 88 | //! Information about the last and previous beacons. 89 | struct bcninfo_t { 90 | ostime_t txtime; //!< Time when the beacon was sent 91 | s1_t rssi; //!< Adjusted RSSI value of last received beacon 92 | s1_t snr; //!< Scaled SNR value of last received beacon 93 | u1_t flags; //!< Last beacon reception and tracking states. See BCN_* values. 94 | u4_t time; //!< GPS time in seconds of last beacon (received or surrogate) 95 | // 96 | u1_t info; //!< Info field of last beacon (valid only if BCN_FULL set) 97 | s4_t lat; //!< Lat field of last beacon (valid only if BCN_FULL set) 98 | s4_t lon; //!< Lon field of last beacon (valid only if BCN_FULL set) 99 | }; 100 | 101 | // purpose of receive window - lmic_t.rxState 102 | enum { RADIO_RST=0, RADIO_TX=1, RADIO_RX=2, RADIO_RXON=3 }; 103 | // Netid values / lmic_t.netid 104 | enum { NETID_NONE=(int)~0U, NETID_MASK=(int)0xFFFFFF }; 105 | // MAC operation modes (lmic_t.opmode). 106 | enum { OP_NONE = 0x0000, 107 | OP_SCAN = 0x0001, // radio scan to find a beacon 108 | OP_TRACK = 0x0002, // track my networks beacon (netid) 109 | OP_JOINING = 0x0004, // device joining in progress (blocks other activities) 110 | OP_TXDATA = 0x0008, // TX user data (buffered in pendTxData) 111 | OP_POLL = 0x0010, // send empty UP frame to ACK confirmed DN/fetch more DN data 112 | OP_REJOIN = 0x0020, // occasionally send JOIN REQUEST 113 | OP_SHUTDOWN = 0x0040, // prevent MAC from doing anything 114 | OP_TXRXPEND = 0x0080, // TX/RX transaction pending 115 | OP_RNDTX = 0x0100, // prevent TX lining up after a beacon 116 | OP_PINGINI = 0x0200, // pingable is initialized and scheduling active 117 | OP_PINGABLE = 0x0400, // we're pingable 118 | OP_NEXTCHNL = 0x0800, // find a new channel 119 | OP_LINKDEAD = 0x1000, // link was reported as dead 120 | OP_TESTMODE = 0x2000, // developer test mode 121 | }; 122 | // TX-RX transaction flags - report back to user 123 | enum { TXRX_ACK = 0x80, // confirmed UP frame was acked 124 | TXRX_NACK = 0x40, // confirmed UP frame was not acked 125 | TXRX_NOPORT = 0x20, // set if a frame with a port was RXed, clr if no frame/no port 126 | TXRX_PORT = 0x10, // set if a frame with a port was RXed, LMIC.frame[LMIC.dataBeg-1] => port 127 | TXRX_DNW1 = 0x01, // received in 1st DN slot 128 | TXRX_DNW2 = 0x02, // received in 2dn DN slot 129 | TXRX_PING = 0x04 }; // received in a scheduled RX slot 130 | // Event types for event callback 131 | enum _ev_t { EV_SCAN_TIMEOUT=1, EV_BEACON_FOUND, 132 | EV_BEACON_MISSED, EV_BEACON_TRACKED, EV_JOINING, 133 | EV_JOINED, EV_RFU1, EV_JOIN_FAILED, EV_REJOIN_FAILED, 134 | EV_TXCOMPLETE, EV_LOST_TSYNC, EV_RESET, 135 | EV_RXCOMPLETE, EV_LINK_DEAD, EV_LINK_ALIVE }; 136 | typedef enum _ev_t ev_t; 137 | 138 | 139 | struct lmic_t { 140 | // Radio settings TX/RX (also accessed by HAL) 141 | ostime_t txend; 142 | ostime_t rxtime; 143 | u4_t freq; 144 | s1_t rssi; 145 | s1_t snr; 146 | rps_t rps; 147 | u1_t rxsyms; 148 | u1_t dndr; 149 | s1_t txpow; // dBm 150 | 151 | osjob_t osjob; 152 | 153 | // Channel scheduling 154 | #if defined(CFG_eu868) 155 | band_t bands[MAX_BANDS]; 156 | u4_t channelFreq[MAX_CHANNELS]; 157 | u2_t channelDrMap[MAX_CHANNELS]; 158 | u2_t channelMap; 159 | #elif defined(CFG_us915) 160 | u4_t xchFreq[MAX_XCHANNELS]; // extra channel frequencies (if device is behind a repeater) 161 | u2_t xchDrMap[MAX_XCHANNELS]; // extra channel datarate ranges ---XXX: ditto 162 | u2_t channelMap[(72+MAX_XCHANNELS+15)/16]; // enabled bits 163 | u2_t chRnd; // channel randomizer 164 | #endif 165 | u1_t txChnl; // channel for next TX 166 | u1_t globalDutyRate; // max rate: 1/2^k 167 | ostime_t globalDutyAvail; // time device can send again 168 | 169 | u4_t netid; // current network id (~0 - none) 170 | u2_t opmode; 171 | u1_t upRepeat; // configured up repeat 172 | s1_t adrTxPow; // ADR adjusted TX power 173 | u1_t datarate; // current data rate 174 | u1_t errcr; // error coding rate (used for TX only) 175 | u1_t rejoinCnt; // adjustment for rejoin datarate 176 | s2_t drift; // last measured drift 177 | s2_t lastDriftDiff; 178 | s2_t maxDriftDiff; 179 | 180 | u1_t pendTxPort; 181 | u1_t pendTxConf; // confirmed data 182 | u1_t pendTxLen; // +0x80 = confirmed 183 | u1_t pendTxData[MAX_LEN_PAYLOAD]; 184 | 185 | u2_t devNonce; // last generated nonce 186 | u1_t nwkKey[16]; // network session key 187 | u1_t artKey[16]; // application router session key 188 | devaddr_t devaddr; 189 | u4_t seqnoDn; // device level down stream seqno 190 | u4_t seqnoUp; 191 | 192 | u1_t dnConf; // dn frame confirm pending: LORA::FCT_ACK or 0 193 | s1_t adrAckReq; // counter until we reset data rate (0=off) 194 | u1_t adrChanged; 195 | 196 | u1_t margin; 197 | bit_t ladrAns; // link adr adapt answer pending 198 | bit_t devsAns; // device status answer pending 199 | u1_t adrEnabled; 200 | u1_t moreData; // NWK has more data pending 201 | bit_t dutyCapAns; // have to ACK duty cycle settings 202 | u1_t snchAns; // answer set new channel 203 | // 2nd RX window (after up stream) 204 | u1_t dn2Dr; 205 | u4_t dn2Freq; 206 | u1_t dn2Ans; // 0=no answer pend, 0x80+ACKs 207 | #if defined CLASS_B 208 | // Class B state 209 | u1_t missedBcns; // unable to track last N beacons 210 | u1_t bcninfoTries; // how often to try (scan mode only) 211 | u1_t pingSetAns; // answer set cmd and ACK bits 212 | rxsched_t ping; // pingable setup 213 | #endif 214 | // Public part of MAC state 215 | u1_t txCnt; 216 | u1_t txrxFlags; // transaction flags (TX-RX combo) 217 | u1_t dataBeg; // 0 or start of data (dataBeg-1 is port) 218 | u1_t dataLen; // 0 no data or zero length data, >0 byte count of data 219 | u1_t frame[MAX_LEN_FRAME]; 220 | 221 | u1_t bcnChnl; 222 | u1_t bcnRxsyms; // 223 | ostime_t bcnRxtime; 224 | bcninfo_t bcninfo; // Last received beacon info 225 | }; 226 | //! \var struct lmic_t LMIC 227 | //! The state of LMIC MAC layer is encapsulated in this variable. 228 | DECLARE_LMIC; //!< \internal 229 | 230 | //! Construct a bit map of allowed datarates from drlo to drhi (both included). 231 | #define DR_RANGE_MAP(drlo,drhi) (((u2_t)0xFFFF<<(drlo)) & ((u2_t)0xFFFF>>(15-(drhi)))) 232 | #if defined(CFG_eu868) 233 | enum { BAND_MILLI=0, BAND_CENTI=1, BAND_DECI=2, BAND_AUX=3 }; 234 | bit_t LMIC_setupBand (u1_t bandidx, s1_t txpow, u2_t txcap); 235 | #endif 236 | bit_t LMIC_setupChannel (u1_t channel, u4_t freq, u2_t drmap, s1_t band); 237 | void LMIC_disableChannel (u1_t channel); 238 | 239 | void LMIC_setDrTxpow (dr_t dr, s1_t txpow); // set default/start DR/txpow 240 | void LMIC_setAdrMode (bit_t enabled); // set ADR mode (if mobile turn off) 241 | bit_t LMIC_startJoining (void); 242 | 243 | void LMIC_shutdown (void); 244 | void LMIC_init (void); 245 | void LMIC_reset (void); 246 | void LMIC_restart (void); //restart after a LMIC_shutdown without reset 247 | void LMIC_clrTxData (void); 248 | void LMIC_setTxData (void); 249 | int LMIC_setTxData2 (u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed); 250 | void LMIC_sendAlive (void); 251 | 252 | bit_t LMIC_enableTracking (u1_t tryBcnInfo); 253 | void LMIC_disableTracking (void); 254 | 255 | void LMIC_stopPingable (void); 256 | void LMIC_setPingable (u1_t intvExp); 257 | void LMIC_tryRejoin (void); 258 | 259 | void LMIC_setSession (u4_t netid, devaddr_t devaddr, xref2u1_t nwkKey, xref2u1_t artKey); 260 | void LMIC_setLinkCheckMode (bit_t enabled); 261 | 262 | // Special APIs - for development or testing 263 | // !!!See implementation for caveats!!! 264 | 265 | #endif // _lmic_h_ 266 | -------------------------------------------------------------------------------- /lmic/lorabase.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | #ifndef _lorabase_h_ 13 | #define _lorabase_h_ 14 | 15 | // ================================================================================ 16 | // BEG: Keep in sync with lorabase.hpp 17 | // 18 | 19 | enum _cr_t { CR_4_5=0, CR_4_6, CR_4_7, CR_4_8 }; 20 | enum _sf_t { FSK=0, SF7, SF8, SF9, SF10, SF11, SF12, SFrfu }; 21 | enum _bw_t { BW125=0, BW250, BW500, BWrfu }; 22 | typedef u1_t cr_t; 23 | typedef u1_t sf_t; 24 | typedef u1_t bw_t; 25 | typedef u1_t dr_t; 26 | // Radio parameter set (encodes SF/BW/CR/IH/NOCRC) 27 | typedef u2_t rps_t; 28 | TYPEDEF_xref2rps_t; 29 | 30 | enum { ILLEGAL_RPS = 0xFF }; 31 | enum { DR_PAGE_EU868 = 0x00 }; 32 | enum { DR_PAGE_US915 = 0x10 }; 33 | 34 | // Global maximum frame length 35 | enum { STD_PREAMBLE_LEN = 8 }; 36 | enum { MAX_LEN_FRAME = 64 }; 37 | enum { LEN_DEVNONCE = 2 }; 38 | enum { LEN_ARTNONCE = 3 }; 39 | enum { LEN_NETID = 3 }; 40 | enum { DELAY_JACC1 = 5 }; // in secs 41 | enum { DELAY_DNW1 = 1 }; // in secs down window #1 42 | enum { DELAY_EXTDNW2 = 1 }; // in secs 43 | enum { DELAY_JACC2 = DELAY_JACC1+(int)DELAY_EXTDNW2 }; // in secs 44 | enum { DELAY_DNW2 = DELAY_DNW1 +(int)DELAY_EXTDNW2 }; // in secs down window #1 45 | enum { BCN_INTV_exp = 7 }; 46 | enum { BCN_INTV_sec = 1<> 3) & 0x3); } 346 | inline rps_t setBw (rps_t params, bw_t cr) { return (rps_t)((params & ~0x18) | (cr<<3)); } 347 | inline cr_t getCr (rps_t params) { return (cr_t)((params >> 5) & 0x3); } 348 | inline rps_t setCr (rps_t params, cr_t cr) { return (rps_t)((params & ~0x60) | (cr<<5)); } 349 | inline int getNocrc(rps_t params) { return ((params >> 7) & 0x1); } 350 | inline rps_t setNocrc(rps_t params, int nocrc) { return (rps_t)((params & ~0x80) | (nocrc<<7)); } 351 | inline int getIh (rps_t params) { return ((params >> 8) & 0xFF); } 352 | inline rps_t setIh (rps_t params, int ih) { return (rps_t)((params & ~0xFF00) | (ih<<8)); } 353 | inline rps_t makeRps (sf_t sf, bw_t bw, cr_t cr, int ih, int nocrc) { 354 | return sf | (bw<<3) | (cr<<5) | (nocrc?(1<<7):0) | ((ih&0xFF)<<8); 355 | } 356 | #define MAKERPS(sf,bw,cr,ih,nocrc) ((rps_t)((sf) | ((bw)<<3) | ((cr)<<5) | ((nocrc)?(1<<7):0) | ((ih&0xFF)<<8))) 357 | // Two frames with params r1/r2 would interfere on air: same SFx + BWx 358 | inline int sameSfBw(rps_t r1, rps_t r2) { return ((r1^r2)&0x1F) == 0; } 359 | 360 | extern const u1_t _DR2RPS_CRC[]; 361 | inline rps_t updr2rps (dr_t dr) { return (rps_t)_DR2RPS_CRC[dr+1]; } 362 | inline rps_t dndr2rps (dr_t dr) { return setNocrc(updr2rps(dr),1); } 363 | inline int isFasterDR (dr_t dr1, dr_t dr2) { return dr1 > dr2; } 364 | inline int isSlowerDR (dr_t dr1, dr_t dr2) { return dr1 < dr2; } 365 | inline dr_t incDR (dr_t dr) { return _DR2RPS_CRC[dr+2]==ILLEGAL_RPS ? dr : (dr_t)(dr+1); } // increase data rate 366 | inline dr_t decDR (dr_t dr) { return _DR2RPS_CRC[dr ]==ILLEGAL_RPS ? dr : (dr_t)(dr-1); } // decrease data rate 367 | inline dr_t assertDR (dr_t dr) { return _DR2RPS_CRC[dr+1]==ILLEGAL_RPS ? DR_DFLTMIN : dr; } // force into a valid DR 368 | inline bit_t validDR (dr_t dr) { return _DR2RPS_CRC[dr+1]!=ILLEGAL_RPS; } // in range 369 | inline dr_t lowerDR (dr_t dr, u1_t n) { while(n--){dr=decDR(dr);} return dr; } // decrease data rate by n steps 370 | 371 | // 372 | // BEG: Keep in sync with lorabase.hpp 373 | // ================================================================================ 374 | 375 | 376 | // Convert between dBm values and power codes (MCMD_LADR_XdBm) 377 | s1_t pow2dBm (u1_t mcmd_ladr_p1); 378 | // Calculate airtime 379 | ostime_t calcAirTime (rps_t rps, u1_t plen); 380 | // Sensitivity at given SF/BW 381 | int getSensitivity (rps_t rps); 382 | 383 | 384 | #endif // _lorabase_h_ 385 | -------------------------------------------------------------------------------- /lmic/oslmic.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | #include "lmic.h" 13 | 14 | // RUNTIME STATE 15 | static struct { 16 | osjob_t* scheduledjobs; 17 | osjob_t* runnablejobs; 18 | } OS; 19 | 20 | void os_init () { 21 | memset(&OS, 0x00, sizeof(OS)); 22 | hal_init(); 23 | radio_init(); 24 | LMIC_init(); 25 | } 26 | 27 | ostime_t os_getTime () { 28 | return hal_ticks(); 29 | } 30 | 31 | static u1_t unlinkjob (osjob_t** pnext, osjob_t* job) { 32 | for( ; *pnext; pnext = &((*pnext)->next)) { 33 | if(*pnext == job) { // unlink 34 | *pnext = job->next; 35 | return 1; 36 | } 37 | } 38 | return 0; 39 | } 40 | 41 | // clear scheduled job 42 | void os_clearCallback (osjob_t* job) { 43 | hal_disableIRQs(); 44 | unlinkjob(&OS.scheduledjobs, job) || unlinkjob(&OS.runnablejobs, job); 45 | hal_enableIRQs(); 46 | } 47 | 48 | // schedule immediately runnable job 49 | void os_setCallback (osjob_t* job, osjobcb_t cb) { 50 | osjob_t** pnext; 51 | hal_disableIRQs(); 52 | // remove if job was already queued 53 | os_clearCallback(job); 54 | // fill-in job 55 | job->func = cb; 56 | job->next = NULL; 57 | // add to end of run queue 58 | for(pnext=&OS.runnablejobs; *pnext; pnext=&((*pnext)->next)); 59 | *pnext = job; 60 | hal_enableIRQs(); 61 | } 62 | 63 | // schedule timed job 64 | void os_setTimedCallback (osjob_t* job, ostime_t time, osjobcb_t cb) { 65 | osjob_t** pnext; 66 | hal_disableIRQs(); 67 | // remove if job was already queued 68 | os_clearCallback(job); 69 | // fill-in job 70 | job->deadline = time; 71 | job->func = cb; 72 | job->next = NULL; 73 | // insert into schedule 74 | for(pnext=&OS.scheduledjobs; *pnext; pnext=&((*pnext)->next)) { 75 | if((*pnext)->deadline - time > 0) { // (cmp diff, not abs!) 76 | // enqueue before next element and stop 77 | job->next = *pnext; 78 | break; 79 | } 80 | } 81 | *pnext = job; 82 | hal_enableIRQs(); 83 | } 84 | 85 | // execute jobs from timer and from run queue 86 | void os_runloop () { 87 | while(1) { 88 | osjob_t* j = NULL; 89 | hal_disableIRQs(); 90 | // check for runnable jobs 91 | if(OS.runnablejobs) { 92 | j = OS.runnablejobs; 93 | OS.runnablejobs = j->next; 94 | } else if(OS.scheduledjobs && hal_checkTimer(OS.scheduledjobs->deadline)) { // check for expired timed jobs 95 | j = OS.scheduledjobs; 96 | OS.scheduledjobs = j->next; 97 | } else { // nothing pending 98 | hal_sleep(); // wake by irq (timer already restarted) 99 | } 100 | hal_enableIRQs(); 101 | if(j) { // run job callback 102 | j->func(j); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lmic/oslmic.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | //! \file 13 | #ifndef _oslmic_h_ 14 | #define _oslmic_h_ 15 | 16 | // Dependencies required for the LoRa MAC in C to run. 17 | // These settings can be adapted to the underlying system. 18 | // You should not, however, change the lmic.[hc] 19 | 20 | 21 | 22 | //================================================================================ 23 | //================================================================================ 24 | // Target platform as C library 25 | typedef unsigned char bit_t; 26 | typedef unsigned char u1_t; 27 | typedef signed char s1_t; 28 | typedef unsigned short u2_t; 29 | typedef short s2_t; 30 | typedef unsigned int u4_t; 31 | typedef int s4_t; 32 | typedef unsigned long long u8_t; 33 | typedef long long s8_t; 34 | typedef unsigned int uint; 35 | typedef const char* str_t; 36 | 37 | #include 38 | #include "hal.h" 39 | #define EV(a,b,c) /**/ 40 | #define DO_DEVDB(field1,field2) /**/ 41 | #if !defined(CFG_noassert) 42 | #define ASSERT(cond) if(!(cond)) hal_failed() 43 | #else 44 | #define ASSERT(cond) /**/ 45 | #endif 46 | 47 | #define os_clearMem(a,b) memset(a,0,b) 48 | #define os_copyMem(a,b,c) memcpy(a,b,c) 49 | 50 | typedef struct osjob_t osjob_t; 51 | typedef struct band_t band_t; 52 | typedef struct chnldef_t chnldef_t; 53 | typedef struct rxsched_t rxsched_t; 54 | typedef struct bcninfo_t bcninfo_t; 55 | typedef const u1_t* xref2cu1_t; 56 | typedef u1_t* xref2u1_t; 57 | #define TYPEDEF_xref2rps_t typedef rps_t* xref2rps_t 58 | #define TYPEDEF_xref2rxsched_t typedef rxsched_t* xref2rxsched_t 59 | #define TYPEDEF_xref2chnldef_t typedef chnldef_t* xref2chnldef_t 60 | #define TYPEDEF_xref2band_t typedef band_t* xref2band_t 61 | #define TYPEDEF_xref2osjob_t typedef osjob_t* xref2osjob_t 62 | 63 | #define SIZEOFEXPR(x) sizeof(x) 64 | 65 | #define ON_LMIC_EVENT(ev) onEvent(ev) 66 | #define DECL_ON_LMIC_EVENT void onEvent(ev_t e) 67 | 68 | extern u4_t AESAUX[]; 69 | extern u4_t AESKEY[]; 70 | #define AESkey ((u1_t*)AESKEY) 71 | #define AESaux ((u1_t*)AESAUX) 72 | #define FUNC_ADDR(func) (&(func)) 73 | 74 | u1_t radio_rand1 (void); 75 | #define os_getRndU1() radio_rand1() 76 | 77 | #define DEFINE_LMIC struct lmic_t LMIC 78 | #define DECLARE_LMIC extern struct lmic_t LMIC 79 | 80 | void radio_init (void); 81 | void radio_irq_handler (u1_t dio); 82 | void os_init (void); 83 | void os_runloop (void); 84 | 85 | //================================================================================ 86 | 87 | 88 | #ifndef RX_RAMPUP 89 | #define RX_RAMPUP (us2osticks(2000)) 90 | #endif 91 | #ifndef TX_RAMPUP 92 | #define TX_RAMPUP (us2osticks(2000)) 93 | #endif 94 | 95 | #ifndef OSTICKS_PER_SEC 96 | #define OSTICKS_PER_SEC 32768 97 | #elif OSTICKS_PER_SEC < 10000 || OSTICKS_PER_SEC > 64516 98 | #error Illegal OSTICKS_PER_SEC - must be in range [10000:64516]. One tick must be 15.5us .. 100us long. 99 | #endif 100 | 101 | typedef s4_t ostime_t; 102 | 103 | #if !HAS_ostick_conv 104 | #define us2osticks(us) ((ostime_t)( ((s8_t)(us) * OSTICKS_PER_SEC) / 1000000)) 105 | #define ms2osticks(ms) ((ostime_t)( ((s8_t)(ms) * OSTICKS_PER_SEC) / 1000)) 106 | #define sec2osticks(sec) ((ostime_t)( (s8_t)(sec) * OSTICKS_PER_SEC)) 107 | #define osticks2ms(os) ((s4_t)(((os)*(s8_t)1000 ) / OSTICKS_PER_SEC)) 108 | #define osticks2us(os) ((s4_t)(((os)*(s8_t)1000000 ) / OSTICKS_PER_SEC)) 109 | // Special versions 110 | #define us2osticksCeil(us) ((ostime_t)( ((s8_t)(us) * OSTICKS_PER_SEC + 999999) / 1000000)) 111 | #define us2osticksRound(us) ((ostime_t)( ((s8_t)(us) * OSTICKS_PER_SEC + 500000) / 1000000)) 112 | #define ms2osticksCeil(ms) ((ostime_t)( ((s8_t)(ms) * OSTICKS_PER_SEC + 999) / 1000)) 113 | #define ms2osticksRound(ms) ((ostime_t)( ((s8_t)(ms) * OSTICKS_PER_SEC + 500) / 1000)) 114 | #endif 115 | 116 | 117 | struct osjob_t; // fwd decl. 118 | typedef void (*osjobcb_t) (struct osjob_t*); 119 | struct osjob_t { 120 | struct osjob_t* next; 121 | ostime_t deadline; 122 | osjobcb_t func; 123 | }; 124 | TYPEDEF_xref2osjob_t; 125 | 126 | 127 | #ifndef HAS_os_calls 128 | 129 | #ifndef os_getDevKey 130 | void os_getDevKey (xref2u1_t buf); 131 | #endif 132 | #ifndef os_getArtEui 133 | void os_getArtEui (xref2u1_t buf); 134 | #endif 135 | #ifndef os_getDevEui 136 | void os_getDevEui (xref2u1_t buf); 137 | #endif 138 | #ifndef os_setCallback 139 | void os_setCallback (xref2osjob_t job, osjobcb_t cb); 140 | #endif 141 | #ifndef os_setTimedCallback 142 | void os_setTimedCallback (xref2osjob_t job, ostime_t time, osjobcb_t cb); 143 | #endif 144 | #ifndef os_clearCallback 145 | void os_clearCallback (xref2osjob_t job); 146 | #endif 147 | #ifndef os_getTime 148 | ostime_t os_getTime (void); 149 | #endif 150 | #ifndef os_getTimeSecs 151 | uint os_getTimeSecs (void); 152 | #endif 153 | #ifndef os_radio 154 | void os_radio (u1_t mode); 155 | #endif 156 | #ifndef os_getBattLevel 157 | u1_t os_getBattLevel (void); 158 | #endif 159 | 160 | #ifndef os_rlsbf4 161 | //! Read 32-bit quantity from given pointer in little endian byte order. 162 | u4_t os_rlsbf4 (xref2cu1_t buf); 163 | #endif 164 | #ifndef os_wlsbf4 165 | //! Write 32-bit quntity into buffer in little endian byte order. 166 | void os_wlsbf4 (xref2u1_t buf, u4_t value); 167 | #endif 168 | #ifndef os_rmsbf4 169 | //! Read 32-bit quantity from given pointer in big endian byte order. 170 | u4_t os_rmsbf4 (xref2cu1_t buf); 171 | #endif 172 | #ifndef os_wmsbf4 173 | //! Write 32-bit quntity into buffer in big endian byte order. 174 | void os_wmsbf4 (xref2u1_t buf, u4_t value); 175 | #endif 176 | #ifndef os_rlsbf2 177 | //! Read 16-bit quantity from given pointer in little endian byte order. 178 | u2_t os_rlsbf2 (xref2cu1_t buf); 179 | #endif 180 | #ifndef os_wlsbf2 181 | //! Write 16-bit quntity into buffer in little endian byte order. 182 | void os_wlsbf2 (xref2u1_t buf, u2_t value); 183 | #endif 184 | 185 | //! Get random number (default impl for u2_t). 186 | #ifndef os_getRndU2 187 | #define os_getRndU2() ((u2_t)((os_getRndU1()<<8)|os_getRndU1())) 188 | #endif 189 | #ifndef os_crc16 190 | u2_t os_crc16 (xref2u1_t d, uint len); 191 | #endif 192 | 193 | #endif // !HAS_os_calls 194 | 195 | // ====================================================================== 196 | // AES support 197 | // !!Keep in sync with lorabase.hpp!! 198 | 199 | #ifndef AES_ENC // if AES_ENC is defined as macro all other values must be too 200 | #define AES_ENC 0x00 201 | #define AES_DEC 0x01 202 | #define AES_MIC 0x02 203 | #define AES_CTR 0x04 204 | #define AES_MICNOAUX 0x08 205 | #endif 206 | #ifndef AESkey // if AESkey is defined as macro all other values must be too 207 | extern xref2u1_t AESkey; 208 | extern xref2u1_t AESaux; 209 | #endif 210 | #ifndef os_aes 211 | u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len); 212 | #endif 213 | 214 | 215 | 216 | #endif // _oslmic_h_ 217 | -------------------------------------------------------------------------------- /lmic/radio.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014-2015 IBM Corporation. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * IBM Zurich Research Lab - initial API, implementation and documentation 10 | *******************************************************************************/ 11 | 12 | #include "lmic.h" 13 | 14 | // ---------------------------------------- 15 | // Registers Mapping 16 | #define RegFifo 0x00 // common 17 | #define RegOpMode 0x01 // common 18 | #define FSKRegBitrateMsb 0x02 19 | #define FSKRegBitrateLsb 0x03 20 | #define FSKRegFdevMsb 0x04 21 | #define FSKRegFdevLsb 0x05 22 | #define RegFrfMsb 0x06 // common 23 | #define RegFrfMid 0x07 // common 24 | #define RegFrfLsb 0x08 // common 25 | #define RegPaConfig 0x09 // common 26 | #define RegPaRamp 0x0A // common 27 | #define RegOcp 0x0B // common 28 | #define RegLna 0x0C // common 29 | #define FSKRegRxConfig 0x0D 30 | #define LORARegFifoAddrPtr 0x0D 31 | #define FSKRegRssiConfig 0x0E 32 | #define LORARegFifoTxBaseAddr 0x0E 33 | #define FSKRegRssiCollision 0x0F 34 | #define LORARegFifoRxBaseAddr 0x0F 35 | #define FSKRegRssiThresh 0x10 36 | #define LORARegFifoRxCurrentAddr 0x10 37 | #define FSKRegRssiValue 0x11 38 | #define LORARegIrqFlagsMask 0x11 39 | #define FSKRegRxBw 0x12 40 | #define LORARegIrqFlags 0x12 41 | #define FSKRegAfcBw 0x13 42 | #define LORARegRxNbBytes 0x13 43 | #define FSKRegOokPeak 0x14 44 | #define LORARegRxHeaderCntValueMsb 0x14 45 | #define FSKRegOokFix 0x15 46 | #define LORARegRxHeaderCntValueLsb 0x15 47 | #define FSKRegOokAvg 0x16 48 | #define LORARegRxPacketCntValueMsb 0x16 49 | #define LORARegRxpacketCntValueLsb 0x17 50 | #define LORARegModemStat 0x18 51 | #define LORARegPktSnrValue 0x19 52 | #define FSKRegAfcFei 0x1A 53 | #define LORARegPktRssiValue 0x1A 54 | #define FSKRegAfcMsb 0x1B 55 | #define LORARegRssiValue 0x1B 56 | #define FSKRegAfcLsb 0x1C 57 | #define LORARegHopChannel 0x1C 58 | #define FSKRegFeiMsb 0x1D 59 | #define LORARegModemConfig1 0x1D 60 | #define FSKRegFeiLsb 0x1E 61 | #define LORARegModemConfig2 0x1E 62 | #define FSKRegPreambleDetect 0x1F 63 | #define LORARegSymbTimeoutLsb 0x1F 64 | #define FSKRegRxTimeout1 0x20 65 | #define LORARegPreambleMsb 0x20 66 | #define FSKRegRxTimeout2 0x21 67 | #define LORARegPreambleLsb 0x21 68 | #define FSKRegRxTimeout3 0x22 69 | #define LORARegPayloadLength 0x22 70 | #define FSKRegRxDelay 0x23 71 | #define LORARegPayloadMaxLength 0x23 72 | #define FSKRegOsc 0x24 73 | #define LORARegHopPeriod 0x24 74 | #define FSKRegPreambleMsb 0x25 75 | #define LORARegFifoRxByteAddr 0x25 76 | #define LORARegModemConfig3 0x26 77 | #define FSKRegPreambleLsb 0x26 78 | #define FSKRegSyncConfig 0x27 79 | #define LORARegFeiMsb 0x28 80 | #define FSKRegSyncValue1 0x28 81 | #define LORAFeiMib 0x29 82 | #define FSKRegSyncValue2 0x29 83 | #define LORARegFeiLsb 0x2A 84 | #define FSKRegSyncValue3 0x2A 85 | #define FSKRegSyncValue4 0x2B 86 | #define LORARegRssiWideband 0x2C 87 | #define FSKRegSyncValue5 0x2C 88 | #define FSKRegSyncValue6 0x2D 89 | #define FSKRegSyncValue7 0x2E 90 | #define FSKRegSyncValue8 0x2F 91 | #define FSKRegPacketConfig1 0x30 92 | #define FSKRegPacketConfig2 0x31 93 | #define LORARegDetectOptimize 0x31 94 | #define FSKRegPayloadLength 0x32 95 | #define FSKRegNodeAdrs 0x33 96 | #define LORARegInvertIQ 0x33 97 | #define FSKRegBroadcastAdrs 0x34 98 | #define FSKRegFifoThresh 0x35 99 | #define FSKRegSeqConfig1 0x36 100 | #define FSKRegSeqConfig2 0x37 101 | #define LORARegDetectionThreshold 0x37 102 | #define FSKRegTimerResol 0x38 103 | #define FSKRegTimer1Coef 0x39 104 | #define LORARegSyncWord 0x39 105 | #define FSKRegTimer2Coef 0x3A 106 | #define FSKRegImageCal 0x3B 107 | #define FSKRegTemp 0x3C 108 | #define FSKRegLowBat 0x3D 109 | #define FSKRegIrqFlags1 0x3E 110 | #define FSKRegIrqFlags2 0x3F 111 | #define RegDioMapping1 0x40 // common 112 | #define RegDioMapping2 0x41 // common 113 | #define RegVersion 0x42 // common 114 | // #define RegAgcRef 0x43 // common 115 | // #define RegAgcThresh1 0x44 // common 116 | // #define RegAgcThresh2 0x45 // common 117 | // #define RegAgcThresh3 0x46 // common 118 | // #define RegPllHop 0x4B // common 119 | // #define RegTcxo 0x58 // common 120 | #define RegPaDac 0x5A // common 121 | // #define RegPll 0x5C // common 122 | // #define RegPllLowPn 0x5E // common 123 | // #define RegFormerTemp 0x6C // common 124 | // #define RegBitRateFrac 0x70 // common 125 | 126 | // ---------------------------------------- 127 | // spread factors and mode for RegModemConfig2 128 | #define SX1272_MC2_FSK 0x00 129 | #define SX1272_MC2_SF7 0x70 130 | #define SX1272_MC2_SF8 0x80 131 | #define SX1272_MC2_SF9 0x90 132 | #define SX1272_MC2_SF10 0xA0 133 | #define SX1272_MC2_SF11 0xB0 134 | #define SX1272_MC2_SF12 0xC0 135 | // bandwidth for RegModemConfig1 136 | #define SX1272_MC1_BW_125 0x00 137 | #define SX1272_MC1_BW_250 0x40 138 | #define SX1272_MC1_BW_500 0x80 139 | // coding rate for RegModemConfig1 140 | #define SX1272_MC1_CR_4_5 0x08 141 | #define SX1272_MC1_CR_4_6 0x10 142 | #define SX1272_MC1_CR_4_7 0x18 143 | #define SX1272_MC1_CR_4_8 0x20 144 | #define SX1272_MC1_IMPLICIT_HEADER_MODE_ON 0x04 // required for receive 145 | #define SX1272_MC1_RX_PAYLOAD_CRCON 0x02 146 | #define SX1272_MC1_LOW_DATA_RATE_OPTIMIZE 0x01 // mandated for SF11 and SF12 147 | // transmit power configuration for RegPaConfig 148 | #define SX1272_PAC_PA_SELECT_PA_BOOST 0x80 149 | #define SX1272_PAC_PA_SELECT_RFIO_PIN 0x00 150 | 151 | 152 | // sx1276 RegModemConfig1 153 | #define SX1276_MC1_BW_125 0x70 154 | #define SX1276_MC1_BW_250 0x80 155 | #define SX1276_MC1_BW_500 0x90 156 | #define SX1276_MC1_CR_4_5 0x02 157 | #define SX1276_MC1_CR_4_6 0x04 158 | #define SX1276_MC1_CR_4_7 0x06 159 | #define SX1276_MC1_CR_4_8 0x08 160 | 161 | #define SX1276_MC1_IMPLICIT_HEADER_MODE_ON 0x01 162 | 163 | // sx1276 RegModemConfig2 164 | #define SX1276_MC2_RX_PAYLOAD_CRCON 0x04 165 | 166 | // sx1276 RegModemConfig3 167 | #define SX1276_MC3_LOW_DATA_RATE_OPTIMIZE 0x08 168 | #define SX1276_MC3_AGCAUTO 0x04 169 | 170 | // preamble for lora networks (nibbles swapped) 171 | #define LORA_MAC_PREAMBLE 0x34 172 | 173 | #define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG1 0x0A 174 | #ifdef CFG_sx1276_radio 175 | #define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x70 176 | #elif CFG_sx1272_radio 177 | #define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x74 178 | #endif 179 | 180 | 181 | 182 | // ---------------------------------------- 183 | // Constants for radio registers 184 | #define OPMODE_LORA 0x80 185 | #define OPMODE_MASK 0x07 186 | #define OPMODE_SLEEP 0x00 187 | #define OPMODE_STANDBY 0x01 188 | #define OPMODE_FSTX 0x02 189 | #define OPMODE_TX 0x03 190 | #define OPMODE_FSRX 0x04 191 | #define OPMODE_RX 0x05 192 | #define OPMODE_RX_SINGLE 0x06 193 | #define OPMODE_CAD 0x07 194 | 195 | // ---------------------------------------- 196 | // Bits masking the corresponding IRQs from the radio 197 | #define IRQ_LORA_RXTOUT_MASK 0x80 198 | #define IRQ_LORA_RXDONE_MASK 0x40 199 | #define IRQ_LORA_CRCERR_MASK 0x20 200 | #define IRQ_LORA_HEADER_MASK 0x10 201 | #define IRQ_LORA_TXDONE_MASK 0x08 202 | #define IRQ_LORA_CDDONE_MASK 0x04 203 | #define IRQ_LORA_FHSSCH_MASK 0x02 204 | #define IRQ_LORA_CDDETD_MASK 0x01 205 | 206 | #define IRQ_FSK1_MODEREADY_MASK 0x80 207 | #define IRQ_FSK1_RXREADY_MASK 0x40 208 | #define IRQ_FSK1_TXREADY_MASK 0x20 209 | #define IRQ_FSK1_PLLLOCK_MASK 0x10 210 | #define IRQ_FSK1_RSSI_MASK 0x08 211 | #define IRQ_FSK1_TIMEOUT_MASK 0x04 212 | #define IRQ_FSK1_PREAMBLEDETECT_MASK 0x02 213 | #define IRQ_FSK1_SYNCADDRESSMATCH_MASK 0x01 214 | #define IRQ_FSK2_FIFOFULL_MASK 0x80 215 | #define IRQ_FSK2_FIFOEMPTY_MASK 0x40 216 | #define IRQ_FSK2_FIFOLEVEL_MASK 0x20 217 | #define IRQ_FSK2_FIFOOVERRUN_MASK 0x10 218 | #define IRQ_FSK2_PACKETSENT_MASK 0x08 219 | #define IRQ_FSK2_PAYLOADREADY_MASK 0x04 220 | #define IRQ_FSK2_CRCOK_MASK 0x02 221 | #define IRQ_FSK2_LOWBAT_MASK 0x01 222 | 223 | // ---------------------------------------- 224 | // DIO function mappings D0D1D2D3 225 | #define MAP_DIO0_LORA_RXDONE 0x00 // 00------ 226 | #define MAP_DIO0_LORA_TXDONE 0x40 // 01------ 227 | #define MAP_DIO1_LORA_RXTOUT 0x00 // --00---- 228 | #define MAP_DIO1_LORA_NOP 0x30 // --11---- 229 | #define MAP_DIO2_LORA_NOP 0xC0 // ----11-- 230 | 231 | #define MAP_DIO0_FSK_READY 0x00 // 00------ (packet sent / payload ready) 232 | #define MAP_DIO1_FSK_NOP 0x30 // --11---- 233 | #define MAP_DIO2_FSK_TXNOP 0x04 // ----01-- 234 | #define MAP_DIO2_FSK_TIMEOUT 0x08 // ----10-- 235 | 236 | 237 | // FSK IMAGECAL defines 238 | #define RF_IMAGECAL_AUTOIMAGECAL_MASK 0x7F 239 | #define RF_IMAGECAL_AUTOIMAGECAL_ON 0x80 240 | #define RF_IMAGECAL_AUTOIMAGECAL_OFF 0x00 // Default 241 | 242 | #define RF_IMAGECAL_IMAGECAL_MASK 0xBF 243 | #define RF_IMAGECAL_IMAGECAL_START 0x40 244 | 245 | #define RF_IMAGECAL_IMAGECAL_RUNNING 0x20 246 | #define RF_IMAGECAL_IMAGECAL_DONE 0x00 // Default 247 | 248 | 249 | // RADIO STATE 250 | // (initialized by radio_init(), used by radio_rand1()) 251 | static u1_t randbuf[16]; 252 | 253 | 254 | #ifdef CFG_sx1276_radio 255 | #define LNA_RX_GAIN (0x20|0x1) 256 | #elif CFG_sx1272_radio 257 | #define LNA_RX_GAIN (0x20|0x03) 258 | #else 259 | #error Missing CFG_sx1272_radio/CFG_sx1276_radio 260 | #endif 261 | 262 | 263 | static void writeReg (u1_t addr, u1_t data ) { 264 | hal_pin_nss(0); 265 | hal_spi(addr | 0x80); 266 | hal_spi(data); 267 | hal_pin_nss(1); 268 | } 269 | 270 | static u1_t readReg (u1_t addr) { 271 | hal_pin_nss(0); 272 | hal_spi(addr & 0x7F); 273 | u1_t val = hal_spi(0x00); 274 | hal_pin_nss(1); 275 | return val; 276 | } 277 | 278 | static void writeBuf (u1_t addr, xref2u1_t buf, u1_t len) { 279 | hal_pin_nss(0); 280 | hal_spi(addr | 0x80); 281 | for (u1_t i=0; i>16)); 393 | writeReg(RegFrfMid, (u1_t)(frf>> 8)); 394 | writeReg(RegFrfLsb, (u1_t)(frf>> 0)); 395 | } 396 | 397 | 398 | 399 | static void configPower () { 400 | #ifdef CFG_sx1276_radio 401 | // no boost used for now 402 | s1_t pw = (s1_t)LMIC.txpow; 403 | if(pw >= 17) { 404 | pw = 15; 405 | } else if(pw < 2) { 406 | pw = 2; 407 | } 408 | // check board type for BOOST pin 409 | writeReg(RegPaConfig, (u1_t)(0x80|(pw&0xf))); 410 | writeReg(RegPaDac, readReg(RegPaDac)|0x4); 411 | 412 | #elif CFG_sx1272_radio 413 | // set PA config (2-17 dBm using PA_BOOST) 414 | s1_t pw = (s1_t)LMIC.txpow; 415 | if(pw > 17) { 416 | pw = 17; 417 | } else if(pw < 2) { 418 | pw = 2; 419 | } 420 | writeReg(RegPaConfig, (u1_t)(0x80|(pw-2))); 421 | #else 422 | #error Missing CFG_sx1272_radio/CFG_sx1276_radio 423 | #endif /* CFG_sx1272_radio */ 424 | } 425 | 426 | static void txfsk () { 427 | // select FSK modem (from sleep mode) 428 | writeReg(RegOpMode, 0x10); // FSK, BT=0.5 429 | ASSERT(readReg(RegOpMode) == 0x10); 430 | // enter standby mode (required for FIFO loading)) 431 | opmode(OPMODE_STANDBY); 432 | // set bitrate 433 | writeReg(FSKRegBitrateMsb, 0x02); // 50kbps 434 | writeReg(FSKRegBitrateLsb, 0x80); 435 | // set frequency deviation 436 | writeReg(FSKRegFdevMsb, 0x01); // +/- 25kHz 437 | writeReg(FSKRegFdevLsb, 0x99); 438 | // frame and packet handler settings 439 | writeReg(FSKRegPreambleMsb, 0x00); 440 | writeReg(FSKRegPreambleLsb, 0x05); 441 | writeReg(FSKRegSyncConfig, 0x12); 442 | writeReg(FSKRegPacketConfig1, 0xD0); 443 | writeReg(FSKRegPacketConfig2, 0x40); 444 | writeReg(FSKRegSyncValue1, 0xC1); 445 | writeReg(FSKRegSyncValue2, 0x94); 446 | writeReg(FSKRegSyncValue3, 0xC1); 447 | // configure frequency 448 | configChannel(); 449 | // configure output power 450 | configPower(); 451 | 452 | // set the IRQ mapping DIO0=PacketSent DIO1=NOP DIO2=NOP 453 | writeReg(RegDioMapping1, MAP_DIO0_FSK_READY|MAP_DIO1_FSK_NOP|MAP_DIO2_FSK_TXNOP); 454 | 455 | // initialize the payload size and address pointers 456 | writeReg(FSKRegPayloadLength, LMIC.dataLen+1); // (insert length byte into payload)) 457 | 458 | // download length byte and buffer to the radio FIFO 459 | writeReg(RegFifo, LMIC.dataLen); 460 | writeBuf(RegFifo, LMIC.frame, LMIC.dataLen); 461 | 462 | // enable antenna switch for TX 463 | hal_pin_rxtx(1); 464 | 465 | // now we actually start the transmission 466 | opmode(OPMODE_TX); 467 | } 468 | 469 | static void txlora () { 470 | // select LoRa modem (from sleep mode) 471 | //writeReg(RegOpMode, OPMODE_LORA); 472 | opmodeLora(); 473 | ASSERT((readReg(RegOpMode) & OPMODE_LORA) != 0); 474 | 475 | // enter standby mode (required for FIFO loading)) 476 | opmode(OPMODE_STANDBY); 477 | // configure LoRa modem (cfg1, cfg2) 478 | configLoraModem(); 479 | // configure frequency 480 | configChannel(); 481 | // configure output power 482 | writeReg(RegPaRamp, (readReg(RegPaRamp) & 0xF0) | 0x08); // set PA ramp-up time 50 uSec 483 | configPower(); 484 | // set sync word 485 | writeReg(LORARegSyncWord, LORA_MAC_PREAMBLE); 486 | 487 | // set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP 488 | writeReg(RegDioMapping1, MAP_DIO0_LORA_TXDONE|MAP_DIO1_LORA_NOP|MAP_DIO2_LORA_NOP); 489 | // clear all radio IRQ flags 490 | writeReg(LORARegIrqFlags, 0xFF); 491 | // mask all IRQs but TxDone 492 | writeReg(LORARegIrqFlagsMask, ~IRQ_LORA_TXDONE_MASK); 493 | 494 | // initialize the payload size and address pointers 495 | writeReg(LORARegFifoTxBaseAddr, 0x00); 496 | writeReg(LORARegFifoAddrPtr, 0x00); 497 | writeReg(LORARegPayloadLength, LMIC.dataLen); 498 | 499 | // download buffer to the radio FIFO 500 | writeBuf(RegFifo, LMIC.frame, LMIC.dataLen); 501 | 502 | // enable antenna switch for TX 503 | hal_pin_rxtx(1); 504 | 505 | // now we actually start the transmission 506 | opmode(OPMODE_TX); 507 | } 508 | 509 | // start transmitter (buf=LMIC.frame, len=LMIC.dataLen) 510 | static void starttx () { 511 | ASSERT( (readReg(RegOpMode) & OPMODE_MASK) == OPMODE_SLEEP ); 512 | if(getSf(LMIC.rps) == FSK) { // FSK modem 513 | txfsk(); 514 | } else { // LoRa modem 515 | txlora(); 516 | } 517 | // the radio will go back to STANDBY mode as soon as the TX is finished 518 | // the corresponding IRQ will inform us about completion. 519 | } 520 | 521 | enum { RXMODE_SINGLE, RXMODE_SCAN, RXMODE_RSSI }; 522 | 523 | static const u1_t rxlorairqmask[] = { 524 | [RXMODE_SINGLE] = IRQ_LORA_RXDONE_MASK|IRQ_LORA_RXTOUT_MASK, 525 | [RXMODE_SCAN] = IRQ_LORA_RXDONE_MASK, 526 | [RXMODE_RSSI] = 0x00, 527 | }; 528 | 529 | // start LoRa receiver (time=LMIC.rxtime, timeout=LMIC.rxsyms, result=LMIC.frame[LMIC.dataLen]) 530 | static void rxlora (u1_t rxmode) { 531 | // select LoRa modem (from sleep mode) 532 | opmodeLora(); 533 | ASSERT((readReg(RegOpMode) & OPMODE_LORA) != 0); 534 | // enter standby mode (warm up)) 535 | opmode(OPMODE_STANDBY); 536 | // don't use MAC settings at startup 537 | if(rxmode == RXMODE_RSSI) { // use fixed settings for rssi scan 538 | writeReg(LORARegModemConfig1, RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG1); 539 | writeReg(LORARegModemConfig2, RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2); 540 | } else { // single or continuous rx mode 541 | // configure LoRa modem (cfg1, cfg2) 542 | configLoraModem(); 543 | // configure frequency 544 | configChannel(); 545 | } 546 | // set LNA gain 547 | writeReg(RegLna, LNA_RX_GAIN); 548 | // set max payload size 549 | writeReg(LORARegPayloadMaxLength, 64); 550 | // use inverted I/Q signal (prevent mote-to-mote communication) 551 | writeReg(LORARegInvertIQ, readReg(LORARegInvertIQ)|(1<<6)); 552 | // set symbol timeout (for single rx) 553 | writeReg(LORARegSymbTimeoutLsb, LMIC.rxsyms); 554 | // set sync word 555 | writeReg(LORARegSyncWord, LORA_MAC_PREAMBLE); 556 | 557 | // configure DIO mapping DIO0=RxDone DIO1=RxTout DIO2=NOP 558 | writeReg(RegDioMapping1, MAP_DIO0_LORA_RXDONE|MAP_DIO1_LORA_RXTOUT|MAP_DIO2_LORA_NOP); 559 | // clear all radio IRQ flags 560 | writeReg(LORARegIrqFlags, 0xFF); 561 | // enable required radio IRQs 562 | writeReg(LORARegIrqFlagsMask, ~rxlorairqmask[rxmode]); 563 | 564 | // enable antenna switch for RX 565 | hal_pin_rxtx(0); 566 | 567 | // now instruct the radio to receive 568 | if (rxmode == RXMODE_SINGLE) { // single rx 569 | hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time 570 | opmode(OPMODE_RX_SINGLE); 571 | } else { // continous rx (scan or rssi) 572 | opmode(OPMODE_RX); 573 | } 574 | } 575 | 576 | static void rxfsk (u1_t rxmode) { 577 | // only single rx (no continuous scanning, no noise sampling) 578 | ASSERT( rxmode == RXMODE_SINGLE ); 579 | // select FSK modem (from sleep mode) 580 | //writeReg(RegOpMode, 0x00); // (not LoRa) 581 | opmodeFSK(); 582 | ASSERT((readReg(RegOpMode) & OPMODE_LORA) == 0); 583 | // enter standby mode (warm up)) 584 | opmode(OPMODE_STANDBY); 585 | // configure frequency 586 | configChannel(); 587 | // set LNA gain 588 | //writeReg(RegLna, 0x20|0x03); // max gain, boost enable 589 | writeReg(RegLna, LNA_RX_GAIN); 590 | // configure receiver 591 | writeReg(FSKRegRxConfig, 0x1E); // AFC auto, AGC, trigger on preamble?!? 592 | // set receiver bandwidth 593 | writeReg(FSKRegRxBw, 0x0B); // 50kHz SSb 594 | // set AFC bandwidth 595 | writeReg(FSKRegAfcBw, 0x12); // 83.3kHz SSB 596 | // set preamble detection 597 | writeReg(FSKRegPreambleDetect, 0xAA); // enable, 2 bytes, 10 chip errors 598 | // set sync config 599 | writeReg(FSKRegSyncConfig, 0x12); // no auto restart, preamble 0xAA, enable, fill FIFO, 3 bytes sync 600 | // set packet config 601 | writeReg(FSKRegPacketConfig1, 0xD8); // var-length, whitening, crc, no auto-clear, no adr filter 602 | writeReg(FSKRegPacketConfig2, 0x40); // packet mode 603 | // set sync value 604 | writeReg(FSKRegSyncValue1, 0xC1); 605 | writeReg(FSKRegSyncValue2, 0x94); 606 | writeReg(FSKRegSyncValue3, 0xC1); 607 | // set preamble timeout 608 | writeReg(FSKRegRxTimeout2, 0xFF);//(LMIC.rxsyms+1)/2); 609 | // set bitrate 610 | writeReg(FSKRegBitrateMsb, 0x02); // 50kbps 611 | writeReg(FSKRegBitrateLsb, 0x80); 612 | // set frequency deviation 613 | writeReg(FSKRegFdevMsb, 0x01); // +/- 25kHz 614 | writeReg(FSKRegFdevLsb, 0x99); 615 | 616 | // configure DIO mapping DIO0=PayloadReady DIO1=NOP DIO2=TimeOut 617 | writeReg(RegDioMapping1, MAP_DIO0_FSK_READY|MAP_DIO1_FSK_NOP|MAP_DIO2_FSK_TIMEOUT); 618 | 619 | // enable antenna switch for RX 620 | hal_pin_rxtx(0); 621 | 622 | // now instruct the radio to receive 623 | hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time 624 | opmode(OPMODE_RX); // no single rx mode available in FSK 625 | } 626 | 627 | static void startrx (u1_t rxmode) { 628 | ASSERT( (readReg(RegOpMode) & OPMODE_MASK) == OPMODE_SLEEP ); 629 | if(getSf(LMIC.rps) == FSK) { // FSK modem 630 | rxfsk(rxmode); 631 | } else { // LoRa modem 632 | rxlora(rxmode); 633 | } 634 | // the radio will go back to STANDBY mode as soon as the RX is finished 635 | // or timed out, and the corresponding IRQ will inform us about completion. 636 | } 637 | 638 | // get random seed from wideband noise rssi 639 | void radio_init () { 640 | hal_disableIRQs(); 641 | 642 | // manually reset radio 643 | #ifdef CFG_sx1276_radio 644 | hal_pin_rst(0); // drive RST pin low 645 | #else 646 | hal_pin_rst(1); // drive RST pin high 647 | #endif 648 | hal_waitUntil(os_getTime()+ms2osticks(1)); // wait >100us 649 | hal_pin_rst(2); // configure RST pin floating! 650 | hal_waitUntil(os_getTime()+ms2osticks(5)); // wait 5ms 651 | 652 | opmode(OPMODE_SLEEP); 653 | 654 | // some sanity checks, e.g., read version number 655 | u1_t v = readReg(RegVersion); 656 | #ifdef CFG_sx1276_radio 657 | ASSERT(v == 0x12 ); 658 | #elif CFG_sx1272_radio 659 | ASSERT(v == 0x22); 660 | #else 661 | #error Missing CFG_sx1272_radio/CFG_sx1276_radio 662 | #endif 663 | // seed 15-byte randomness via noise rssi 664 | rxlora(RXMODE_RSSI); 665 | while( (readReg(RegOpMode) & OPMODE_MASK) != OPMODE_RX ); // continuous rx 666 | for(int i=1; i<16; i++) { 667 | for(int j=0; j<8; j++) { 668 | u1_t b; // wait for two non-identical subsequent least-significant bits 669 | while( (b = readReg(LORARegRssiWideband) & 0x01) == (readReg(LORARegRssiWideband) & 0x01) ); 670 | randbuf[i] = (randbuf[i] << 1) | b; 671 | } 672 | } 673 | randbuf[0] = 16; // set initial index 674 | 675 | #ifdef CFG_sx1276_radio //CFG_sx1276mb1_board 676 | // chain calibration 677 | writeReg(RegPaConfig, 0); 678 | 679 | // Launch Rx chain calibration for LF band 680 | writeReg(FSKRegImageCal, (readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_MASK)|RF_IMAGECAL_IMAGECAL_START); 681 | while((readReg(FSKRegImageCal)&RF_IMAGECAL_IMAGECAL_RUNNING) == RF_IMAGECAL_IMAGECAL_RUNNING){ ; } 682 | 683 | // Sets a Frequency in HF band 684 | u4_t frf = 868000000; 685 | writeReg(RegFrfMsb, (u1_t)(frf>>16)); 686 | writeReg(RegFrfMid, (u1_t)(frf>> 8)); 687 | writeReg(RegFrfLsb, (u1_t)(frf>> 0)); 688 | 689 | // Launch Rx chain calibration for HF band 690 | writeReg(FSKRegImageCal, (readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_MASK)|RF_IMAGECAL_IMAGECAL_START); 691 | while((readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_RUNNING) == RF_IMAGECAL_IMAGECAL_RUNNING) { ; } 692 | #endif /* CFG_sx1276_radio //CFG_sx1276mb1_board */ 693 | 694 | opmode(OPMODE_SLEEP); 695 | 696 | hal_enableIRQs(); 697 | } 698 | 699 | // return next random byte derived from seed buffer 700 | // (buf[0] holds index of next byte to be returned) 701 | u1_t radio_rand1 () { 702 | u1_t i = randbuf[0]; 703 | ASSERT( i != 0 ); 704 | if( i==16 ) { 705 | os_aes(AES_ENC, randbuf, 16); // encrypt seed with any key 706 | i = 0; 707 | } 708 | u1_t v = randbuf[i++]; 709 | randbuf[0] = i; 710 | return v; 711 | } 712 | 713 | u1_t radio_rssi () { 714 | hal_disableIRQs(); 715 | u1_t r = readReg(LORARegRssiValue); 716 | hal_enableIRQs(); 717 | return r; 718 | } 719 | 720 | static const u2_t LORA_RXDONE_FIXUP[] = { 721 | [FSK] = us2osticks(0), // ( 0 ticks) 722 | [SF7] = us2osticks(0), // ( 0 ticks) 723 | [SF8] = us2osticks(1648), // ( 54 ticks) 724 | [SF9] = us2osticks(3265), // ( 107 ticks) 725 | [SF10] = us2osticks(7049), // ( 231 ticks) 726 | [SF11] = us2osticks(13641), // ( 447 ticks) 727 | [SF12] = us2osticks(31189), // (1022 ticks) 728 | }; 729 | 730 | // called by hal ext IRQ handler 731 | // (radio goes to stanby mode after tx/rx operations) 732 | void radio_irq_handler (u1_t dio) { 733 | ostime_t now = os_getTime(); 734 | if( (readReg(RegOpMode) & OPMODE_LORA) != 0) { // LORA modem 735 | u1_t flags = readReg(LORARegIrqFlags); 736 | if( flags & IRQ_LORA_TXDONE_MASK ) { 737 | // save exact tx time 738 | LMIC.txend = now - us2osticks(43); // TXDONE FIXUP 739 | } else if( flags & IRQ_LORA_RXDONE_MASK ) { 740 | // save exact rx time 741 | if(getBw(LMIC.rps) == BW125) { 742 | now -= LORA_RXDONE_FIXUP[getSf(LMIC.rps)]; 743 | } 744 | LMIC.rxtime = now; 745 | // read the PDU and inform the MAC that we received something 746 | LMIC.dataLen = (readReg(LORARegModemConfig1) & SX1272_MC1_IMPLICIT_HEADER_MODE_ON) ? 747 | readReg(LORARegPayloadLength) : readReg(LORARegRxNbBytes); 748 | // set FIFO read address pointer 749 | writeReg(LORARegFifoAddrPtr, readReg(LORARegFifoRxCurrentAddr)); 750 | // now read the FIFO 751 | readBuf(RegFifo, LMIC.frame, LMIC.dataLen); 752 | // read rx quality parameters 753 | LMIC.snr = readReg(LORARegPktSnrValue); // SNR [dB] * 4 754 | LMIC.rssi = readReg(LORARegPktRssiValue) - 125 + 64; // RSSI [dBm] (-196...+63) 755 | } else if( flags & IRQ_LORA_RXTOUT_MASK ) { 756 | // indicate timeout 757 | LMIC.dataLen = 0; 758 | } 759 | // mask all radio IRQs 760 | writeReg(LORARegIrqFlagsMask, 0xFF); 761 | // clear radio IRQ flags 762 | writeReg(LORARegIrqFlags, 0xFF); 763 | } else { // FSK modem 764 | u1_t flags1 = readReg(FSKRegIrqFlags1); 765 | u1_t flags2 = readReg(FSKRegIrqFlags2); 766 | if( flags2 & IRQ_FSK2_PACKETSENT_MASK ) { 767 | // save exact tx time 768 | LMIC.txend = now; 769 | } else if( flags2 & IRQ_FSK2_PAYLOADREADY_MASK ) { 770 | // save exact rx time 771 | LMIC.rxtime = now; 772 | // read the PDU and inform the MAC that we received something 773 | LMIC.dataLen = readReg(FSKRegPayloadLength); 774 | // now read the FIFO 775 | readBuf(RegFifo, LMIC.frame, LMIC.dataLen); 776 | // read rx quality parameters 777 | LMIC.snr = 0; // determine snr 778 | LMIC.rssi = 0; // determine rssi 779 | } else if( flags1 & IRQ_FSK1_TIMEOUT_MASK ) { 780 | // indicate timeout 781 | LMIC.dataLen = 0; 782 | } else { 783 | while(1); 784 | } 785 | } 786 | // go from stanby to sleep 787 | opmode(OPMODE_SLEEP); 788 | // run os job (use preset func ptr) 789 | os_setCallback(&LMIC.osjob, LMIC.osjob.func); 790 | } 791 | 792 | void os_radio (u1_t mode) { 793 | hal_disableIRQs(); 794 | switch (mode) { 795 | case RADIO_RST: 796 | // put radio to sleep 797 | opmode(OPMODE_SLEEP); 798 | break; 799 | 800 | case RADIO_TX: 801 | // transmit frame now 802 | starttx(); // buf=LMIC.frame, len=LMIC.dataLen 803 | break; 804 | 805 | case RADIO_RX: 806 | // receive frame now (exactly at rxtime) 807 | startrx(RXMODE_SINGLE); // buf=LMIC.frame, time=LMIC.rxtime, timeout=LMIC.rxsyms 808 | break; 809 | 810 | case RADIO_RXON: 811 | // start scanning for beacon now 812 | startrx(RXMODE_SCAN); // buf=LMIC.frame 813 | break; 814 | } 815 | hal_enableIRQs(); 816 | } 817 | --------------------------------------------------------------------------------