├── .gitignore ├── LICENSE ├── README.md ├── extras ├── cad │ ├── README.md │ ├── antenna_base.FCStd │ ├── antenna_base.stl │ ├── antenna_cover_short.FCStd │ ├── antenna_cover_short.stl │ ├── base.FCStd │ ├── base.stl │ ├── battery_lid.FCStd │ ├── battery_lid.stl │ ├── images │ │ └── base.png │ ├── knob.FCStd │ ├── knob.stl │ ├── ptt.FCStd │ ├── ptt.stl │ ├── upper.FCStd │ ├── upper.stl │ ├── upper_no_battery.FCStd │ └── upper_no_battery.stl ├── images │ ├── device.png │ └── peripherals.png └── schematics │ ├── LICENSE │ ├── README.md │ ├── fp-info-cache │ ├── fp-lib-table │ ├── gerber │ ├── lora_tracker-B_Cu.gbl │ ├── lora_tracker-B_Mask.gbs │ ├── lora_tracker-B_Silkscreen.gbo │ ├── lora_tracker-Edge_Cuts.gm1 │ ├── lora_tracker-F_Cu.gtl │ ├── lora_tracker-F_Mask.gts │ ├── lora_tracker-F_Silkscreen.gto │ ├── lora_tracker-NPTH.drl │ └── lora_tracker-PTH.drl │ ├── images │ ├── board.png │ └── board_assembled.png │ ├── lora_tracker-cache.lib │ ├── lora_tracker-rescue.bak │ ├── lora_tracker-rescue.dcm │ ├── lora_tracker-rescue.kicad_sym │ ├── lora_tracker-rescue.lib │ ├── lora_tracker.kicad_pcb │ ├── lora_tracker.kicad_prl │ ├── lora_tracker.kicad_pro │ ├── lora_tracker.kicad_sch │ ├── lora_tracker.kicad_sym │ ├── lora_tracker.lib │ ├── lora_tracker.net │ ├── lora_tracker.pretty │ ├── ATGM336H.kicad_mod │ ├── E22-400M30S.kicad_mod │ ├── MAX98357A.kicad_mod │ ├── SSD1306.kicad_mod │ ├── ec11.kicad_mod │ ├── esp32 devkit.kicad_mod │ ├── esp32-devkit-narrow.kicad_mod │ ├── esp32-devkit-wide.kicad_mod │ ├── esp32-devkit-wide_30pin.kicad_mod │ └── inp441.kicad_mod │ ├── lora_tracker.pro │ ├── lora_tracker.sch │ ├── lora_tracker_narrow.net │ └── sym-lib-table ├── include ├── audio │ ├── audio_codec.h │ ├── audio_codec_codec2.h │ ├── audio_codec_opus.h │ └── audio_task.h ├── hal │ ├── hw_monitor.h │ ├── pm_service.h │ └── radio_task.h ├── service.h ├── settings │ ├── config.h │ ├── default_config.h │ ├── settings_menu.h │ └── settings_menu_item.h ├── utils │ ├── dsp.h │ └── utils.h └── version.h ├── platformio.ini └── src ├── audio ├── audio_codec_codec2.cpp ├── audio_codec_opus.cpp └── audio_task.cpp ├── hal ├── hw_monitor.cpp ├── pm_service.cpp └── radio_task.cpp ├── main.cpp ├── service.cpp ├── settings ├── config.cpp └── settings_menu.cpp └── utils ├── dsp.cpp └── utils.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode 3 | *.FCStd1 4 | gerber.zip 5 | *.bak 6 | *-backups 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP32 Codec2/OPUS DV Handheld Transceiver 2 | 3 | ## Introduction 4 | ⚠ **Please note that this device is experimental and lacks any form of certification. The author holds no responsibility for any fines incurred due to spectrum misuse, legal violations, or damages caused during its use. As with any experimental project, it is essential that you fully understand what you are doing and use it at your own risk.** 5 | 6 | This project is a hobby/amateur/toy/educational radio ESP32 based LoRa/FSK Codec2/OPUS DV 3d printed handheld trasceiver a.k.a. walkie-talkie, which is using 1W/2W `E22-400M30S/E22-400M33S` (SX1268) radio module (UHF, 70cm band) or optionally 100mW `RA-01/RA-02` (SX1278) module. In theory, it could also be used with `E22-868M30S/E22-900M30S` (SX1262) modules (UHF, 868/915 MHz), but not tested. 7 | 8 | It functions like a standard FM walkie-talkie and, for simplicity and traffic optimization, does not utilize any communication protocol. Instead, it transmits audio codec frames (DV) using pre-configured digital radio modulation, such as LoRA or FSK. There are ideas to add voice over AX.25 and perhaps M17 protocol support in the future. 9 | 10 | Overall components cost for this project is about 15-20$. 11 | 12 | Schematics for the new board design, which includes integrated components, can be found in the `extras/schematics` directory. The pinouts remain compatible with the first prototype version. While there is a designated space for a GPS module, it should not be soldered as it is not currently supported; it is included solely for potential future experiments. 13 | 14 | First prototype is based on https://github.com/sh123/esp32_loraprs modem, but uses additional peripherals: 15 | - I2S speaker module MAX98357A + 4-8ohm 3w speaker (40mm diameter) 16 | - I2S microphone INMP441 17 | - PTT button (new board uses right angeled push button) 18 | - Rotary encoder with push button (new board uses EC11 right angeled encoder) 19 | - Small OLED display SSD1306 128x32 20 | - Battery voltage monitoring (just voltage divider fed into ADC pin, see schematics) 21 | - Powered from a single commonly avaialble 18650 cell (for example from old laptop battery) 22 | - Uses combined charge + 5v boost controller based on Hotchip HT4928S (it is usually used in low capacity single cell USB power banks). 23 | 24 | Supports next features: 25 | - Supports LoRa and FSK (no FEC) modulation with configurable modulation parameters from settings 26 | - Supports Codec2 (low bit rate, 700-3200 bps) and OPUS (medium/high bit rate, 2400-512000 bps) audio codecs, codec could be selected from settings 27 | - Goes into ESP32 light sleep when no activity, so all power consumption is around 30-40mA when in sleep RX, wakes up on new data from radio module or when user starts transmitting, consumes about 90-100mA in active receive and about 700-800mA in full power 1W transmit 28 | - Settings menu on long encoder button click, allows to change frequency and other parameters 29 | - Output power tunable from settings from ~1mW (for ISM toy usage) up to 2W (for amateur radio experiments) 30 | - Experimental no warranty privacy option for ISM low power usage (⚠ **check your country regulations if it is allowed by the ISM band plan before experimenting as it might be illegal in some countries**), it is based on [ChaCha20-Poly1305](https://en.wikipedia.org/wiki/ChaCha20-Poly1305) stream cypher provided by [rwheater/Crypto](https://github.com/rweather/arduinolibs) library, it is comparable to AES256, uses 256 bits key, provides message authentication, but should have lower CPU requirements and power usage. 31 | 32 | Planned features/ideas: 33 | - Frequency split repeater mode, where two transceivers will be linked using espnow, so one will receive voice on RX frequency and then send packet using espnow to second transmitter which will receive packet using espnow and re-transmit it on TX frequency, this way receiver and transmitter could be positioned further apart with separate antennas thus eliminating need for duplexer 34 | - Bluetooth headset pairing to use with hands free, so can use headset instead of i2s speaker/mic when needed 35 | - Voice over AX.25, so meta data such as callsign could be included and visible on the other end 36 | - M17 protocol support 37 | 38 | ## Build instructions 39 | - Modify `include/config.h` if needed 40 | - Install platformio 41 | - Build with platformio 42 | - Upload with platformio 43 | 44 | ## BOM 45 | Bill of materials (BOM) for the new board constuction (credits to n0p and his club members for collecting it) 46 | ``` 47 | ESP-WROOM32 30pin - https://es.aliexpress.com/item/1005005953505528.html 48 | Modem LoRa E22-400M30S (SX1268) - https://es.aliexpress.com/item/1005003122961059.html 49 | I2S speaker module MAX98357A - https://es.aliexpress.com/item/1005005383121121.html 50 | 4ohm 3w speaker (40mm diameter) - https://es.aliexpress.com/item/1005006684947554.html 51 | I2S microphone INMP441 - https://es.aliexpress.com/item/1005007889064664.html 52 | Rotary encoder with push button - https://es.aliexpress.com/item/1005008091948369.html 53 | Small OLED display SSD1306 128×32 - https://es.aliexpress.com/item/1005008096924594.html 54 | Uses combined charge + 5v boost controller - https://es.aliexpress.com/item/1005008657948784.html 55 | 56 | 18650 Cell 57 | Botón switch tactile SKHH angled - https://es.aliexpress.com/item/1005005369415986.html 58 | SMA-J-P-X-ST-EM1 Edgemount - https://es.aliexpress.com/item/10000000835065.html 59 | R1 - 100k 0603 - https://es.aliexpress.com/item/1005005677654015.html 60 | R2-R7 - 10k 0603 - https://es.aliexpress.com/item/1005005677654015.html 61 | C1, C3-C8, C10, C11 - 100nF 0603 - https://es.aliexpress.com/item/32371454429.html 62 | C2 - Elec 100uF SMD 3×5,3 - https://es.aliexpress.com/item/1005006724593986.html 63 | C9 - 47uF Radial D4 mm P2 mm - https://es.aliexpress.com/item/1005005022177024.html 64 | 65 | GPS - OPTIONAL - UNSUPPORTED ON WALKIE FW - CONFLICTS WITH ON BOARD SERIAL PORT PROGRAMMER - https://es.aliexpress.com/item/1005008733474270.html 66 | ``` 67 | 68 | ## Pictures 69 | 70 | Two fully 3d printed prototypes were built based on `esp32_loraprs` modem board. 71 | 72 | ![Device](extras/images/device.png) 73 | 74 | List of peripherals used. 75 | 76 | ![Device](extras/images/peripherals.png) 77 | 78 | New board design with all components integrated into the board (except battery and charging circuit). 79 | 80 | ![Device](extras/schematics/images/board.png) 81 | 82 | Case for the new board version with battery compartment. 83 | 84 | ![CAD](extras/cad/images/base.png) 85 | 86 | Assembled board with new design. 87 | 88 | ![Device](extras/schematics/images/board_assembled.png) 89 | -------------------------------------------------------------------------------- /extras/cad/README.md: -------------------------------------------------------------------------------- 1 | # CAD models for the transceiver case 2 | - `antenna_base.*` - antenna foundation, antenna spiral widing is done with 1.3mm copper solid wire on 8mm diameter scaffolding, ~8 turns with 6mm step, with this configuration resonance will be at around 400 MHz, cut with small 2-4mm incriments to move resonance to higher frequency (e.g. to desired 433 or 446 MHz), control resonance after each step with antenna analyzer when antenna cover is attached. 3 | - `antenna_cover_short.*` - antenna cover for 433 MHz (TPU plastic is preferred). 4 | - `base.*` - model for the base part of the case where board is inserted. 5 | - `upper.*` - upper part of the case with 18650 battery compartment and combined charge 5v boost up converter. 6 | - `upper_no_battery.*` - upper part of the case without battery compartment, e.g. when planning to power using ESP32 USB port only. 7 | - `knob.*` - rotary encoder knob (TPU plastic is preferred). 8 | - `ptt.*` - PTT button cover (TPU plastic is preferred). 9 | - `battery_lid.*` - battery compartment lid. 10 | 11 | ![CAD](images/base.png) 12 | 13 | -------------------------------------------------------------------------------- /extras/cad/antenna_base.FCStd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/antenna_base.FCStd -------------------------------------------------------------------------------- /extras/cad/antenna_base.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/antenna_base.stl -------------------------------------------------------------------------------- /extras/cad/antenna_cover_short.FCStd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/antenna_cover_short.FCStd -------------------------------------------------------------------------------- /extras/cad/antenna_cover_short.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/antenna_cover_short.stl -------------------------------------------------------------------------------- /extras/cad/base.FCStd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/base.FCStd -------------------------------------------------------------------------------- /extras/cad/base.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/base.stl -------------------------------------------------------------------------------- /extras/cad/battery_lid.FCStd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/battery_lid.FCStd -------------------------------------------------------------------------------- /extras/cad/battery_lid.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/battery_lid.stl -------------------------------------------------------------------------------- /extras/cad/images/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/images/base.png -------------------------------------------------------------------------------- /extras/cad/knob.FCStd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/knob.FCStd -------------------------------------------------------------------------------- /extras/cad/knob.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/knob.stl -------------------------------------------------------------------------------- /extras/cad/ptt.FCStd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/ptt.FCStd -------------------------------------------------------------------------------- /extras/cad/ptt.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/ptt.stl -------------------------------------------------------------------------------- /extras/cad/upper.FCStd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/upper.FCStd -------------------------------------------------------------------------------- /extras/cad/upper.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/upper.stl -------------------------------------------------------------------------------- /extras/cad/upper_no_battery.FCStd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/upper_no_battery.FCStd -------------------------------------------------------------------------------- /extras/cad/upper_no_battery.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/cad/upper_no_battery.stl -------------------------------------------------------------------------------- /extras/images/device.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/images/device.png -------------------------------------------------------------------------------- /extras/images/peripherals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/images/peripherals.png -------------------------------------------------------------------------------- /extras/schematics/README.md: -------------------------------------------------------------------------------- 1 | # ESP32 DV transceiver board 2 | 3 | This is transceiver board for ESP32 DV handheld transceiver with integrated modules, except battery and charge controller. 4 | 5 | ![Board](images/board.png) 6 | 7 | ![Board](images/board_assembled.png) 8 | -------------------------------------------------------------------------------- /extras/schematics/fp-lib-table: -------------------------------------------------------------------------------- 1 | (fp_lib_table 2 | (lib (name lora_tracker)(type KiCad)(uri ${KIPRJMOD}/lora_tracker.pretty)(options "")(descr "")) 3 | ) 4 | -------------------------------------------------------------------------------- /extras/schematics/gerber/lora_tracker-B_Mask.gbs: -------------------------------------------------------------------------------- 1 | G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,6.0.11+dfsg-1* 2 | G04 #@! TF.CreationDate,2024-12-21T17:09:36+02:00* 3 | G04 #@! TF.ProjectId,lora_tracker,6c6f7261-5f74-4726-9163-6b65722e6b69,rev?* 4 | G04 #@! TF.SameCoordinates,Original* 5 | G04 #@! TF.FileFunction,Soldermask,Bot* 6 | G04 #@! TF.FilePolarity,Negative* 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW 6.0.11+dfsg-1) date 2024-12-21 17:09:36* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | G04 Aperture macros list* 15 | %AMRoundRect* 16 | 0 Rectangle with rounded corners* 17 | 0 $1 Rounding radius* 18 | 0 $2 $3 $4 $5 $6 $7 $8 $9 X,Y pos of 4 corners* 19 | 0 Add a 4 corners polygon primitive as box body* 20 | 4,1,4,$2,$3,$4,$5,$6,$7,$8,$9,$2,$3,0* 21 | 0 Add four circle primitives for the rounded corners* 22 | 1,1,$1+$1,$2,$3* 23 | 1,1,$1+$1,$4,$5* 24 | 1,1,$1+$1,$6,$7* 25 | 1,1,$1+$1,$8,$9* 26 | 0 Add four rect primitives between the rounded corners* 27 | 20,1,$1+$1,$2,$3,$4,$5,0* 28 | 20,1,$1+$1,$4,$5,$6,$7,0* 29 | 20,1,$1+$1,$6,$7,$8,$9,0* 30 | 20,1,$1+$1,$8,$9,$2,$3,0*% 31 | G04 Aperture macros list end* 32 | %ADD10R,1.200000X1.200000*% 33 | %ADD11C,1.200000*% 34 | %ADD12C,2.200000*% 35 | %ADD13C,1.700000*% 36 | %ADD14C,1.524000*% 37 | %ADD15R,2.500000X3.000000*% 38 | %ADD16R,1.700000X1.700000*% 39 | %ADD17O,1.700000X1.700000*% 40 | %ADD18R,1.350000X4.200000*% 41 | %ADD19R,1.500000X1.500000*% 42 | %ADD20RoundRect,0.237500X-0.237500X0.300000X-0.237500X-0.300000X0.237500X-0.300000X0.237500X0.300000X0*% 43 | %ADD21R,2.000000X1.524000*% 44 | %ADD22R,2.000000X1.254000*% 45 | %ADD23RoundRect,0.237500X-0.237500X0.250000X-0.237500X-0.250000X0.237500X-0.250000X0.237500X0.250000X0*% 46 | %ADD24RoundRect,0.237500X-0.250000X-0.237500X0.250000X-0.237500X0.250000X0.237500X-0.250000X0.237500X0*% 47 | %ADD25RoundRect,0.237500X0.300000X0.237500X-0.300000X0.237500X-0.300000X-0.237500X0.300000X-0.237500X0*% 48 | %ADD26R,3.150000X1.000000*% 49 | %ADD27RoundRect,0.237500X0.250000X0.237500X-0.250000X0.237500X-0.250000X-0.237500X0.250000X-0.237500X0*% 50 | G04 APERTURE END LIST* 51 | D10* 52 | X84455000Y-133094604D03* 53 | D11* 54 | X84455000Y-135094604D03* 55 | D12* 56 | X108335000Y-87320000D03* 57 | X108335000Y-80320000D03* 58 | D13* 59 | X110835000Y-81570000D03* 60 | X110835000Y-86070000D03* 61 | D14* 62 | X86360000Y-129627500D03* 63 | X88900000Y-129627500D03* 64 | X91440000Y-129627500D03* 65 | X93980000Y-129627500D03* 66 | X96520000Y-129627500D03* 67 | X99060000Y-129627500D03* 68 | X101600000Y-129627500D03* 69 | X95885000Y-116292500D03* 70 | X92075000Y-116292500D03* 71 | X103417500Y-45077500D03* 72 | X98337500Y-45077500D03* 73 | X100877500Y-45077500D03* 74 | D15* 75 | X94527500Y-46347500D03* 76 | X107227500Y-46347500D03* 77 | D14* 78 | X98337500Y-47617500D03* 79 | X103417500Y-47617500D03* 80 | X81280000Y-93432500D03* 81 | X81280000Y-95972500D03* 82 | X81280000Y-98512500D03* 83 | X81280000Y-101052500D03* 84 | X81280000Y-103592500D03* 85 | X81280000Y-106132500D03* 86 | X81280000Y-108672500D03* 87 | X81280000Y-111212500D03* 88 | X81280000Y-113752500D03* 89 | X81280000Y-116292500D03* 90 | X81280000Y-118832500D03* 91 | X81280000Y-121372500D03* 92 | X81280000Y-123912500D03* 93 | X81280000Y-126452500D03* 94 | X81280000Y-128992500D03* 95 | X106680000Y-128992500D03* 96 | X106680000Y-126452500D03* 97 | X106680000Y-123912500D03* 98 | X106680000Y-121372500D03* 99 | X106680000Y-118832500D03* 100 | X106680000Y-116292500D03* 101 | X106680000Y-113752500D03* 102 | X106680000Y-111212500D03* 103 | X106680000Y-108672500D03* 104 | X106680000Y-106132500D03* 105 | X106680000Y-103592500D03* 106 | X106680000Y-101052500D03* 107 | X106680000Y-98512500D03* 108 | X106680000Y-95972500D03* 109 | X106680000Y-93432500D03* 110 | D16* 111 | X78105000Y-129525000D03* 112 | D17* 113 | X78105000Y-126985000D03* 114 | X78105000Y-124445000D03* 115 | D18* 116 | X85375000Y-45937500D03* 117 | X79725000Y-45937500D03* 118 | D14* 119 | X102870000Y-94615000D03* 120 | X102870000Y-97155000D03* 121 | X102870000Y-99695000D03* 122 | X102870000Y-102235000D03* 123 | X102870000Y-104775000D03* 124 | D19* 125 | X112395000Y-71120000D03* 126 | X74930000Y-55245000D03* 127 | D20* 128 | X96520000Y-132487500D03* 129 | X96520000Y-134212500D03* 130 | D21* 131 | X111125000Y-59142500D03* 132 | D22* 133 | X111125000Y-61682500D03* 134 | D21* 135 | X111125000Y-64222500D03* 136 | X111125000Y-66762500D03* 137 | D23* 138 | X93865000Y-132437500D03* 139 | X93865000Y-134262500D03* 140 | D24* 141 | X102730000Y-87185000D03* 142 | X104555000Y-87185000D03* 143 | D19* 144 | X112395000Y-55245000D03* 145 | D25* 146 | X105637500Y-71260000D03* 147 | X103912500Y-71260000D03* 148 | D14* 149 | X87630000Y-83118423D03* 150 | X87630000Y-85658423D03* 151 | X87630000Y-88198423D03* 152 | X80010000Y-88198423D03* 153 | X80010000Y-85658423D03* 154 | X80010000Y-83118423D03* 155 | D25* 156 | X104411267Y-83820000D03* 157 | X102686267Y-83820000D03* 158 | D26* 159 | X93995000Y-120015000D03* 160 | X99045000Y-120015000D03* 161 | D27* 162 | X101600000Y-51735000D03* 163 | X99775000Y-51735000D03* 164 | D19* 165 | X74930000Y-71120000D03* 166 | D24* 167 | X104497500Y-51625000D03* 168 | X106322500Y-51625000D03* 169 | D23* 170 | X90805000Y-47347500D03* 171 | X90805000Y-49172500D03* 172 | M02* 173 | -------------------------------------------------------------------------------- /extras/schematics/gerber/lora_tracker-B_Silkscreen.gbo: -------------------------------------------------------------------------------- 1 | G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,6.0.11+dfsg-1* 2 | G04 #@! TF.CreationDate,2024-12-21T17:09:36+02:00* 3 | G04 #@! TF.ProjectId,lora_tracker,6c6f7261-5f74-4726-9163-6b65722e6b69,rev?* 4 | G04 #@! TF.SameCoordinates,Original* 5 | G04 #@! TF.FileFunction,Legend,Bot* 6 | G04 #@! TF.FilePolarity,Positive* 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW 6.0.11+dfsg-1) date 2024-12-21 17:09:36* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | %ADD10C,0.150000*% 15 | %ADD11C,0.300000*% 16 | %ADD12C,0.200000*% 17 | %ADD13C,0.120000*% 18 | G04 APERTURE END LIST* 19 | D10* 20 | X105069798Y-116205000D02* 21 | G75* 22 | G03* 23 | X105069798Y-116205000I-11089798J0D01* 24 | G01* 25 | D11* 26 | X99631428Y-122662142D02* 27 | X98488571Y-122662142D01* 28 | X99060000Y-123233571D02* 29 | X99060000Y-122090714D01* 30 | X93916428Y-122662142D02* 31 | X92773571Y-122662142D01* 32 | D12* 33 | X100765714Y-111438571D02* 34 | X100765714Y-112438571D01* 35 | X101122857Y-110867142D02* 36 | X101480000Y-111938571D01* 37 | X100551428Y-111938571D01* 38 | X99980000Y-111867142D02* 39 | X98837142Y-111867142D01* 40 | X97908571Y-111581428D02* 41 | X98051428Y-111510000D01* 42 | X98122857Y-111438571D01* 43 | X98194285Y-111295714D01* 44 | X98194285Y-111224285D01* 45 | X98122857Y-111081428D01* 46 | X98051428Y-111010000D01* 47 | X97908571Y-110938571D01* 48 | X97622857Y-110938571D01* 49 | X97480000Y-111010000D01* 50 | X97408571Y-111081428D01* 51 | X97337142Y-111224285D01* 52 | X97337142Y-111295714D01* 53 | X97408571Y-111438571D01* 54 | X97480000Y-111510000D01* 55 | X97622857Y-111581428D01* 56 | X97908571Y-111581428D01* 57 | X98051428Y-111652857D01* 58 | X98122857Y-111724285D01* 59 | X98194285Y-111867142D01* 60 | X98194285Y-112152857D01* 61 | X98122857Y-112295714D01* 62 | X98051428Y-112367142D01* 63 | X97908571Y-112438571D01* 64 | X97622857Y-112438571D01* 65 | X97480000Y-112367142D01* 66 | X97408571Y-112295714D01* 67 | X97337142Y-112152857D01* 68 | X97337142Y-111867142D01* 69 | X97408571Y-111724285D01* 70 | X97480000Y-111652857D01* 71 | X97622857Y-111581428D01* 72 | X95337142Y-112438571D02* 73 | X95480000Y-112367142D01* 74 | X95551428Y-112295714D01* 75 | X95622857Y-112152857D01* 76 | X95622857Y-111724285D01* 77 | X95551428Y-111581428D01* 78 | X95480000Y-111510000D01* 79 | X95337142Y-111438571D01* 80 | X95122857Y-111438571D01* 81 | X94980000Y-111510000D01* 82 | X94908571Y-111581428D01* 83 | X94837142Y-111724285D01* 84 | X94837142Y-112152857D01* 85 | X94908571Y-112295714D01* 86 | X94980000Y-112367142D01* 87 | X95122857Y-112438571D01* 88 | X95337142Y-112438571D01* 89 | X94194285Y-112438571D02* 90 | X94194285Y-110938571D01* 91 | X93551428Y-112438571D02* 92 | X93551428Y-111652857D01* 93 | X93622857Y-111510000D01* 94 | X93765714Y-111438571D01* 95 | X93980000Y-111438571D01* 96 | X94122857Y-111510000D01* 97 | X94194285Y-111581428D01* 98 | X92837142Y-112438571D02* 99 | X92837142Y-111438571D01* 100 | X92837142Y-111581428D02* 101 | X92765714Y-111510000D01* 102 | X92622857Y-111438571D01* 103 | X92408571Y-111438571D01* 104 | X92265714Y-111510000D01* 105 | X92194285Y-111652857D01* 106 | X92194285Y-112438571D01* 107 | X92194285Y-111652857D02* 108 | X92122857Y-111510000D01* 109 | X91980000Y-111438571D01* 110 | X91765714Y-111438571D01* 111 | X91622857Y-111510000D01* 112 | X91551428Y-111652857D01* 113 | X91551428Y-112438571D01* 114 | X90765714Y-112367142D02* 115 | X90765714Y-112438571D01* 116 | X90837142Y-112581428D01* 117 | X90908571Y-112652857D01* 118 | X89122857Y-110938571D02* 119 | X88194285Y-110938571D01* 120 | X88694285Y-111510000D01* 121 | X88480000Y-111510000D01* 122 | X88337142Y-111581428D01* 123 | X88265714Y-111652857D01* 124 | X88194285Y-111795714D01* 125 | X88194285Y-112152857D01* 126 | X88265714Y-112295714D01* 127 | X88337142Y-112367142D01* 128 | X88480000Y-112438571D01* 129 | X88908571Y-112438571D01* 130 | X89051428Y-112367142D01* 131 | X89122857Y-112295714D01* 132 | X87694285Y-110938571D02* 133 | X87337142Y-112438571D01* 134 | X87051428Y-111367142D01* 135 | X86765714Y-112438571D01* 136 | X86408571Y-110938571D01* 137 | D10* 138 | X112728333Y-73112380D02* 139 | X112728333Y-73826666D01* 140 | X112775952Y-73969523D01* 141 | X112871190Y-74064761D01* 142 | X113014047Y-74112380D01* 143 | X113109285Y-74112380D01* 144 | X112347380Y-73112380D02* 145 | X111680714Y-73112380D01* 146 | X112109285Y-74112380D01* 147 | X75263333Y-53049380D02* 148 | X75263333Y-53763666D01* 149 | X75310952Y-53906523D01* 150 | X75406190Y-54001761D01* 151 | X75549047Y-54049380D01* 152 | X75644285Y-54049380D01* 153 | X74310952Y-53049380D02* 154 | X74787142Y-53049380D01* 155 | X74834761Y-53525571D01* 156 | X74787142Y-53477952D01* 157 | X74691904Y-53430333D01* 158 | X74453809Y-53430333D01* 159 | X74358571Y-53477952D01* 160 | X74310952Y-53525571D01* 161 | X74263333Y-53620809D01* 162 | X74263333Y-53858904D01* 163 | X74310952Y-53954142D01* 164 | X74358571Y-54001761D01* 165 | X74453809Y-54049380D01* 166 | X74691904Y-54049380D01* 167 | X74787142Y-54001761D01* 168 | X74834761Y-53954142D01* 169 | X99417142Y-133329600D02* 170 | X99464761Y-133281981D01* 171 | X99512380Y-133139124D01* 172 | X99512380Y-133043886D01* 173 | X99464761Y-132901028D01* 174 | X99369523Y-132805790D01* 175 | X99274285Y-132758171D01* 176 | X99083809Y-132710552D01* 177 | X98940952Y-132710552D01* 178 | X98750476Y-132758171D01* 179 | X98655238Y-132805790D01* 180 | X98560000Y-132901028D01* 181 | X98512380Y-133043886D01* 182 | X98512380Y-133139124D01* 183 | X98560000Y-133281981D01* 184 | X98607619Y-133329600D01* 185 | X98512380Y-134186743D02* 186 | X98512380Y-133996267D01* 187 | X98560000Y-133901028D01* 188 | X98607619Y-133853409D01* 189 | X98750476Y-133758171D01* 190 | X98940952Y-133710552D01* 191 | X99321904Y-133710552D01* 192 | X99417142Y-133758171D01* 193 | X99464761Y-133805790D01* 194 | X99512380Y-133901028D01* 195 | X99512380Y-134091505D01* 196 | X99464761Y-134186743D01* 197 | X99417142Y-134234362D01* 198 | X99321904Y-134281981D01* 199 | X99083809Y-134281981D01* 200 | X98988571Y-134234362D01* 201 | X98940952Y-134186743D01* 202 | X98893333Y-134091505D01* 203 | X98893333Y-133901028D01* 204 | X98940952Y-133805790D01* 205 | X98988571Y-133758171D01* 206 | X99083809Y-133710552D01* 207 | X94106904Y-53014880D02* 208 | X94106904Y-53824404D01* 209 | X94059285Y-53919642D01* 210 | X94011666Y-53967261D01* 211 | X93916428Y-54014880D01* 212 | X93725952Y-54014880D01* 213 | X93630714Y-53967261D01* 214 | X93583095Y-53919642D01* 215 | X93535476Y-53824404D01* 216 | X93535476Y-53014880D01* 217 | X92630714Y-53014880D02* 218 | X92821190Y-53014880D01* 219 | X92916428Y-53062500D01* 220 | X92964047Y-53110119D01* 221 | X93059285Y-53252976D01* 222 | X93106904Y-53443452D01* 223 | X93106904Y-53824404D01* 224 | X93059285Y-53919642D01* 225 | X93011666Y-53967261D01* 226 | X92916428Y-54014880D01* 227 | X92725952Y-54014880D01* 228 | X92630714Y-53967261D01* 229 | X92583095Y-53919642D01* 230 | X92535476Y-53824404D01* 231 | X92535476Y-53586309D01* 232 | X92583095Y-53491071D01* 233 | X92630714Y-53443452D01* 234 | X92725952Y-53395833D01* 235 | X92916428Y-53395833D01* 236 | X93011666Y-53443452D01* 237 | X93059285Y-53491071D01* 238 | X93106904Y-53586309D01* 239 | X92527380Y-132928609D02* 240 | X92051190Y-132595276D01* 241 | X92527380Y-132357180D02* 242 | X91527380Y-132357180D01* 243 | X91527380Y-132738133D01* 244 | X91575000Y-132833371D01* 245 | X91622619Y-132880990D01* 246 | X91717857Y-132928609D01* 247 | X91860714Y-132928609D01* 248 | X91955952Y-132880990D01* 249 | X92003571Y-132833371D01* 250 | X92051190Y-132738133D01* 251 | X92051190Y-132357180D01* 252 | X92527380Y-133880990D02* 253 | X92527380Y-133309561D01* 254 | X92527380Y-133595276D02* 255 | X91527380Y-133595276D01* 256 | X91670238Y-133500037D01* 257 | X91765476Y-133404799D01* 258 | X91813095Y-133309561D01* 259 | X103809166Y-89067380D02* 260 | X104142500Y-88591190D01* 261 | X104380595Y-89067380D02* 262 | X104380595Y-88067380D01* 263 | X103999642Y-88067380D01* 264 | X103904404Y-88115000D01* 265 | X103856785Y-88162619D01* 266 | X103809166Y-88257857D01* 267 | X103809166Y-88400714D01* 268 | X103856785Y-88495952D01* 269 | X103904404Y-88543571D01* 270 | X103999642Y-88591190D01* 271 | X104380595Y-88591190D01* 272 | X103428214Y-88162619D02* 273 | X103380595Y-88115000D01* 274 | X103285357Y-88067380D01* 275 | X103047261Y-88067380D01* 276 | X102952023Y-88115000D01* 277 | X102904404Y-88162619D01* 278 | X102856785Y-88257857D01* 279 | X102856785Y-88353095D01* 280 | X102904404Y-88495952D01* 281 | X103475833Y-89067380D01* 282 | X102856785Y-89067380D01* 283 | X112728333Y-53049380D02* 284 | X112728333Y-53763666D01* 285 | X112775952Y-53906523D01* 286 | X112871190Y-54001761D01* 287 | X113014047Y-54049380D01* 288 | X113109285Y-54049380D01* 289 | X111823571Y-53049380D02* 290 | X112014047Y-53049380D01* 291 | X112109285Y-53097000D01* 292 | X112156904Y-53144619D01* 293 | X112252142Y-53287476D01* 294 | X112299761Y-53477952D01* 295 | X112299761Y-53858904D01* 296 | X112252142Y-53954142D01* 297 | X112204523Y-54001761D01* 298 | X112109285Y-54049380D01* 299 | X111918809Y-54049380D01* 300 | X111823571Y-54001761D01* 301 | X111775952Y-53954142D01* 302 | X111728333Y-53858904D01* 303 | X111728333Y-53620809D01* 304 | X111775952Y-53525571D01* 305 | X111823571Y-53477952D01* 306 | X111918809Y-53430333D01* 307 | X112109285Y-53430333D01* 308 | X112204523Y-53477952D01* 309 | X112252142Y-53525571D01* 310 | X112299761Y-53620809D01* 311 | X106141666Y-74017142D02* 312 | X106189285Y-74064761D01* 313 | X106332142Y-74112380D01* 314 | X106427380Y-74112380D01* 315 | X106570238Y-74064761D01* 316 | X106665476Y-73969523D01* 317 | X106713095Y-73874285D01* 318 | X106760714Y-73683809D01* 319 | X106760714Y-73540952D01* 320 | X106713095Y-73350476D01* 321 | X106665476Y-73255238D01* 322 | X106570238Y-73160000D01* 323 | X106427380Y-73112380D01* 324 | X106332142Y-73112380D01* 325 | X106189285Y-73160000D01* 326 | X106141666Y-73207619D01* 327 | X105808333Y-73112380D02* 328 | X105141666Y-73112380D01* 329 | X105570238Y-74112380D01* 330 | X85851904Y-76990803D02* 331 | X85851904Y-77800327D01* 332 | X85804285Y-77895565D01* 333 | X85756666Y-77943184D01* 334 | X85661428Y-77990803D01* 335 | X85470952Y-77990803D01* 336 | X85375714Y-77943184D01* 337 | X85328095Y-77895565D01* 338 | X85280476Y-77800327D01* 339 | X85280476Y-76990803D01* 340 | X84375714Y-77324137D02* 341 | X84375714Y-77990803D01* 342 | X84613809Y-76943184D02* 343 | X84851904Y-77657470D01* 344 | X84232857Y-77657470D01* 345 | X103715433Y-82747142D02* 346 | X103763052Y-82794761D01* 347 | X103905909Y-82842380D01* 348 | X104001147Y-82842380D01* 349 | X104144005Y-82794761D01* 350 | X104239243Y-82699523D01* 351 | X104286862Y-82604285D01* 352 | X104334481Y-82413809D01* 353 | X104334481Y-82270952D01* 354 | X104286862Y-82080476D01* 355 | X104239243Y-81985238D01* 356 | X104144005Y-81890000D01* 357 | X104001147Y-81842380D01* 358 | X103905909Y-81842380D01* 359 | X103763052Y-81890000D01* 360 | X103715433Y-81937619D01* 361 | X103144005Y-82270952D02* 362 | X103239243Y-82223333D01* 363 | X103286862Y-82175714D01* 364 | X103334481Y-82080476D01* 365 | X103334481Y-82032857D01* 366 | X103286862Y-81937619D01* 367 | X103239243Y-81890000D01* 368 | X103144005Y-81842380D01* 369 | X102953528Y-81842380D01* 370 | X102858290Y-81890000D01* 371 | X102810671Y-81937619D01* 372 | X102763052Y-82032857D01* 373 | X102763052Y-82080476D01* 374 | X102810671Y-82175714D01* 375 | X102858290Y-82223333D01* 376 | X102953528Y-82270952D01* 377 | X103144005Y-82270952D01* 378 | X103239243Y-82318571D01* 379 | X103286862Y-82366190D01* 380 | X103334481Y-82461428D01* 381 | X103334481Y-82651904D01* 382 | X103286862Y-82747142D01* 383 | X103239243Y-82794761D01* 384 | X103144005Y-82842380D01* 385 | X102953528Y-82842380D01* 386 | X102858290Y-82794761D01* 387 | X102810671Y-82747142D01* 388 | X102763052Y-82651904D01* 389 | X102763052Y-82461428D01* 390 | X102810671Y-82366190D01* 391 | X102858290Y-82318571D01* 392 | X102953528Y-82270952D01* 393 | X96853333Y-121797380D02* 394 | X96853333Y-122511666D01* 395 | X96900952Y-122654523D01* 396 | X96996190Y-122749761D01* 397 | X97139047Y-122797380D01* 398 | X97234285Y-122797380D01* 399 | X96424761Y-121892619D02* 400 | X96377142Y-121845000D01* 401 | X96281904Y-121797380D01* 402 | X96043809Y-121797380D01* 403 | X95948571Y-121845000D01* 404 | X95900952Y-121892619D01* 405 | X95853333Y-121987857D01* 406 | X95853333Y-122083095D01* 407 | X95900952Y-122225952D01* 408 | X96472380Y-122797380D01* 409 | X95853333Y-122797380D01* 410 | X100854166Y-50757380D02* 411 | X101187500Y-50281190D01* 412 | X101425595Y-50757380D02* 413 | X101425595Y-49757380D01* 414 | X101044642Y-49757380D01* 415 | X100949404Y-49805000D01* 416 | X100901785Y-49852619D01* 417 | X100854166Y-49947857D01* 418 | X100854166Y-50090714D01* 419 | X100901785Y-50185952D01* 420 | X100949404Y-50233571D01* 421 | X101044642Y-50281190D01* 422 | X101425595Y-50281190D01* 423 | X99949404Y-49757380D02* 424 | X100425595Y-49757380D01* 425 | X100473214Y-50233571D01* 426 | X100425595Y-50185952D01* 427 | X100330357Y-50138333D01* 428 | X100092261Y-50138333D01* 429 | X99997023Y-50185952D01* 430 | X99949404Y-50233571D01* 431 | X99901785Y-50328809D01* 432 | X99901785Y-50566904D01* 433 | X99949404Y-50662142D01* 434 | X99997023Y-50709761D01* 435 | X100092261Y-50757380D01* 436 | X100330357Y-50757380D01* 437 | X100425595Y-50709761D01* 438 | X100473214Y-50662142D01* 439 | X75263333Y-73112380D02* 440 | X75263333Y-73826666D01* 441 | X75310952Y-73969523D01* 442 | X75406190Y-74064761D01* 443 | X75549047Y-74112380D01* 444 | X75644285Y-74112380D01* 445 | X74882380Y-73112380D02* 446 | X74263333Y-73112380D01* 447 | X74596666Y-73493333D01* 448 | X74453809Y-73493333D01* 449 | X74358571Y-73540952D01* 450 | X74310952Y-73588571D01* 451 | X74263333Y-73683809D01* 452 | X74263333Y-73921904D01* 453 | X74310952Y-74017142D01* 454 | X74358571Y-74064761D01* 455 | X74453809Y-74112380D01* 456 | X74739523Y-74112380D01* 457 | X74834761Y-74064761D01* 458 | X74882380Y-74017142D01* 459 | X105576666Y-53507380D02* 460 | X105910000Y-53031190D01* 461 | X106148095Y-53507380D02* 462 | X106148095Y-52507380D01* 463 | X105767142Y-52507380D01* 464 | X105671904Y-52555000D01* 465 | X105624285Y-52602619D01* 466 | X105576666Y-52697857D01* 467 | X105576666Y-52840714D01* 468 | X105624285Y-52935952D01* 469 | X105671904Y-52983571D01* 470 | X105767142Y-53031190D01* 471 | X106148095Y-53031190D01* 472 | X104719523Y-52840714D02* 473 | X104719523Y-53507380D01* 474 | X104957619Y-52459761D02* 475 | X105195714Y-53174047D01* 476 | X104576666Y-53174047D01* 477 | X89827380Y-48093333D02* 478 | X89351190Y-47760000D01* 479 | X89827380Y-47521904D02* 480 | X88827380Y-47521904D01* 481 | X88827380Y-47902857D01* 482 | X88875000Y-47998095D01* 483 | X88922619Y-48045714D01* 484 | X89017857Y-48093333D01* 485 | X89160714Y-48093333D01* 486 | X89255952Y-48045714D01* 487 | X89303571Y-47998095D01* 488 | X89351190Y-47902857D01* 489 | X89351190Y-47521904D01* 490 | X88827380Y-48426666D02* 491 | X88827380Y-49045714D01* 492 | X89208333Y-48712380D01* 493 | X89208333Y-48855238D01* 494 | X89255952Y-48950476D01* 495 | X89303571Y-48998095D01* 496 | X89398809Y-49045714D01* 497 | X89636904Y-49045714D01* 498 | X89732142Y-48998095D01* 499 | X89779761Y-48950476D01* 500 | X89827380Y-48855238D01* 501 | X89827380Y-48569523D01* 502 | X89779761Y-48474285D01* 503 | X89732142Y-48426666D01* 504 | D13* 505 | X111445000Y-72070000D02* 506 | X113345000Y-72070000D01* 507 | X111445000Y-70170000D02* 508 | X111445000Y-72070000D01* 509 | X113345000Y-70170000D02* 510 | X111445000Y-70170000D01* 511 | X113345000Y-72070000D02* 512 | X113345000Y-70170000D01* 513 | X75880000Y-56195000D02* 514 | X75880000Y-54295000D01* 515 | X75880000Y-54295000D02* 516 | X73980000Y-54295000D01* 517 | X73980000Y-56195000D02* 518 | X75880000Y-56195000D01* 519 | X73980000Y-54295000D02* 520 | X73980000Y-56195000D01* 521 | X96010000Y-133203733D02* 522 | X96010000Y-133496267D01* 523 | X97030000Y-133203733D02* 524 | X97030000Y-133496267D01* 525 | D10* 526 | X112395000Y-56602500D02* 527 | X74295000Y-56602500D01* 528 | X74295000Y-56602500D02* 529 | X74295000Y-69302500D01* 530 | X74295000Y-69302500D02* 531 | X112395000Y-69302500D01* 532 | X112395000Y-69302500D02* 533 | X112395000Y-56602500D01* 534 | D13* 535 | X94387500Y-133095276D02* 536 | X94387500Y-133604724D01* 537 | X93342500Y-133095276D02* 538 | X93342500Y-133604724D01* 539 | X103387776Y-86662500D02* 540 | X103897224Y-86662500D01* 541 | X103387776Y-87707500D02* 542 | X103897224Y-87707500D01* 543 | X113345000Y-56195000D02* 544 | X113345000Y-54295000D01* 545 | X113345000Y-54295000D02* 546 | X111445000Y-54295000D01* 547 | X111445000Y-54295000D02* 548 | X111445000Y-56195000D01* 549 | X111445000Y-56195000D02* 550 | X113345000Y-56195000D01* 551 | X104921267Y-70750000D02* 552 | X104628733Y-70750000D01* 553 | X104921267Y-71770000D02* 554 | X104628733Y-71770000D01* 555 | D10* 556 | X90570000Y-85658423D02* 557 | G75* 558 | G03* 559 | X90570000Y-85658423I-6750000J0D01* 560 | G01* 561 | D13* 562 | X103695034Y-83310000D02* 563 | X103402500Y-83310000D01* 564 | X103695034Y-84330000D02* 565 | X103402500Y-84330000D01* 566 | X93920000Y-119255000D02* 567 | X93920000Y-118685000D01* 568 | X99120000Y-121345000D02* 569 | X99120000Y-120775000D01* 570 | X93920000Y-118685000D02* 571 | X99120000Y-118685000D01* 572 | X93920000Y-121345000D02* 573 | X99120000Y-121345000D01* 574 | X92480000Y-120775000D02* 575 | X93920000Y-120775000D01* 576 | X99120000Y-119255000D02* 577 | X99120000Y-118685000D01* 578 | X93920000Y-121345000D02* 579 | X93920000Y-120775000D01* 580 | X100942224Y-52257500D02* 581 | X100432776Y-52257500D01* 582 | X100942224Y-51212500D02* 583 | X100432776Y-51212500D01* 584 | X75880000Y-70170000D02* 585 | X73980000Y-70170000D01* 586 | X75880000Y-72070000D02* 587 | X75880000Y-70170000D01* 588 | X73980000Y-70170000D02* 589 | X73980000Y-72070000D01* 590 | X73980000Y-72070000D02* 591 | X75880000Y-72070000D01* 592 | X105155276Y-51102500D02* 593 | X105664724Y-51102500D01* 594 | X105155276Y-52147500D02* 595 | X105664724Y-52147500D01* 596 | X90282500Y-48005276D02* 597 | X90282500Y-48514724D01* 598 | X91327500Y-48005276D02* 599 | X91327500Y-48514724D01* 600 | M02* 601 | -------------------------------------------------------------------------------- /extras/schematics/gerber/lora_tracker-Edge_Cuts.gm1: -------------------------------------------------------------------------------- 1 | G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,6.0.11+dfsg-1* 2 | G04 #@! TF.CreationDate,2024-12-21T17:09:37+02:00* 3 | G04 #@! TF.ProjectId,lora_tracker,6c6f7261-5f74-4726-9163-6b65722e6b69,rev?* 4 | G04 #@! TF.SameCoordinates,Original* 5 | G04 #@! TF.FileFunction,Profile,NP* 6 | %FSLAX46Y46*% 7 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 8 | G04 Created by KiCad (PCBNEW 6.0.11+dfsg-1) date 2024-12-21 17:09:37* 9 | %MOMM*% 10 | %LPD*% 11 | G01* 12 | G04 APERTURE LIST* 13 | G04 #@! TA.AperFunction,Profile* 14 | %ADD10C,0.200000*% 15 | G04 #@! TD* 16 | G04 #@! TA.AperFunction,Profile* 17 | %ADD11C,0.150000*% 18 | G04 #@! TD* 19 | G04 APERTURE END LIST* 20 | D10* 21 | X73660000Y-136525000D02* 22 | X73660000Y-45085000D01* 23 | D11* 24 | X73660000Y-136525000D02* 25 | G75* 26 | G03* 27 | X75565000Y-138430000I1905000J0D01* 28 | G01* 29 | D10* 30 | X75565000Y-43180000D02* 31 | X111760000Y-43180000D01* 32 | D11* 33 | X111760000Y-138430000D02* 34 | G75* 35 | G03* 36 | X113665000Y-136525000I0J1905000D01* 37 | G01* 38 | X75565000Y-43180000D02* 39 | G75* 40 | G03* 41 | X73660000Y-45085000I0J-1905000D01* 42 | G01* 43 | X113665000Y-45085000D02* 44 | X113665000Y-136525000D01* 45 | X113665000Y-45085000D02* 46 | G75* 47 | G03* 48 | X111760000Y-43180000I-1905000J0D01* 49 | G01* 50 | X111760000Y-138430000D02* 51 | X75565000Y-138430000D01* 52 | M02* 53 | -------------------------------------------------------------------------------- /extras/schematics/gerber/lora_tracker-F_Mask.gts: -------------------------------------------------------------------------------- 1 | G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,6.0.11+dfsg-1* 2 | G04 #@! TF.CreationDate,2024-12-21T17:09:36+02:00* 3 | G04 #@! TF.ProjectId,lora_tracker,6c6f7261-5f74-4726-9163-6b65722e6b69,rev?* 4 | G04 #@! TF.SameCoordinates,Original* 5 | G04 #@! TF.FileFunction,Soldermask,Top* 6 | G04 #@! TF.FilePolarity,Negative* 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW 6.0.11+dfsg-1) date 2024-12-21 17:09:36* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | G04 Aperture macros list* 15 | %AMRoundRect* 16 | 0 Rectangle with rounded corners* 17 | 0 $1 Rounding radius* 18 | 0 $2 $3 $4 $5 $6 $7 $8 $9 X,Y pos of 4 corners* 19 | 0 Add a 4 corners polygon primitive as box body* 20 | 4,1,4,$2,$3,$4,$5,$6,$7,$8,$9,$2,$3,0* 21 | 0 Add four circle primitives for the rounded corners* 22 | 1,1,$1+$1,$2,$3* 23 | 1,1,$1+$1,$4,$5* 24 | 1,1,$1+$1,$6,$7* 25 | 1,1,$1+$1,$8,$9* 26 | 0 Add four rect primitives between the rounded corners* 27 | 20,1,$1+$1,$2,$3,$4,$5,0* 28 | 20,1,$1+$1,$4,$5,$6,$7,0* 29 | 20,1,$1+$1,$6,$7,$8,$9,0* 30 | 20,1,$1+$1,$8,$9,$2,$3,0*% 31 | G04 Aperture macros list end* 32 | %ADD10R,1.600000X2.200000*% 33 | %ADD11RoundRect,0.237500X-0.237500X0.300000X-0.237500X-0.300000X0.237500X-0.300000X0.237500X0.300000X0*% 34 | %ADD12R,2.000000X1.500000*% 35 | %ADD13RoundRect,0.237500X0.237500X-0.300000X0.237500X0.300000X-0.237500X0.300000X-0.237500X-0.300000X0*% 36 | %ADD14RoundRect,0.101600X0.850000X1.250000X-0.850000X1.250000X-0.850000X-1.250000X0.850000X-1.250000X0*% 37 | %ADD15R,1.200000X1.200000*% 38 | %ADD16C,1.200000*% 39 | %ADD17C,2.200000*% 40 | %ADD18C,1.700000*% 41 | %ADD19C,1.524000*% 42 | %ADD20R,2.500000X3.000000*% 43 | %ADD21RoundRect,0.237500X0.237500X-0.250000X0.237500X0.250000X-0.237500X0.250000X-0.237500X-0.250000X0*% 44 | %ADD22R,1.700000X1.700000*% 45 | %ADD23O,1.700000X1.700000*% 46 | %ADD24R,1.270000X3.600000*% 47 | %ADD25R,1.350000X4.200000*% 48 | %ADD26RoundRect,0.237500X0.300000X0.237500X-0.300000X0.237500X-0.300000X-0.237500X0.300000X-0.237500X0*% 49 | %ADD27R,2.000000X1.524000*% 50 | %ADD28R,2.000000X1.254000*% 51 | G04 APERTURE END LIST* 52 | D10* 53 | X99060000Y-82955000D03* 54 | X99060000Y-85955000D03* 55 | D11* 56 | X103545000Y-82157500D03* 57 | X103545000Y-83882500D03* 58 | D12* 59 | X82424000Y-58405000D03* 60 | X82424000Y-60405000D03* 61 | X82424000Y-62405000D03* 62 | X82424000Y-64405000D03* 63 | X82424000Y-66405000D03* 64 | X82424000Y-68405000D03* 65 | X82424000Y-70405000D03* 66 | X82424000Y-72405000D03* 67 | X98424000Y-72405000D03* 68 | X98424000Y-70405000D03* 69 | X98424000Y-68405000D03* 70 | X98424000Y-66405000D03* 71 | X98424000Y-64405000D03* 72 | X98424000Y-62405000D03* 73 | X98424000Y-60405000D03* 74 | X98424000Y-58405000D03* 75 | D13* 76 | X78740000Y-62230000D03* 77 | X78740000Y-60505000D03* 78 | D14* 79 | X79868501Y-76770000D03* 80 | X82408501Y-76770000D03* 81 | X84948501Y-76770000D03* 82 | X92548501Y-76770000D03* 83 | X95088501Y-76770000D03* 84 | X97628501Y-76770000D03* 85 | X100168501Y-76770000D03* 86 | X102708501Y-76770000D03* 87 | X105248501Y-76770000D03* 88 | X107788501Y-76770000D03* 89 | X110328501Y-76770000D03* 90 | X110328501Y-52770000D03* 91 | X107788501Y-52770000D03* 92 | X105248501Y-52770000D03* 93 | X102708501Y-52770000D03* 94 | X100168501Y-52770000D03* 95 | X97628501Y-52770000D03* 96 | X95088501Y-52770000D03* 97 | X92548501Y-52770000D03* 98 | X84948501Y-52770000D03* 99 | X82408501Y-52770000D03* 100 | X79868501Y-52770000D03* 101 | D15* 102 | X84455000Y-133094604D03* 103 | D16* 104 | X84455000Y-135094604D03* 105 | D17* 106 | X108335000Y-87320000D03* 107 | X108335000Y-80320000D03* 108 | D18* 109 | X110835000Y-81570000D03* 110 | X110835000Y-86070000D03* 111 | D19* 112 | X86360000Y-129627500D03* 113 | X88900000Y-129627500D03* 114 | X91440000Y-129627500D03* 115 | X93980000Y-129627500D03* 116 | X96520000Y-129627500D03* 117 | X99060000Y-129627500D03* 118 | X101600000Y-129627500D03* 119 | X95885000Y-116292500D03* 120 | X92075000Y-116292500D03* 121 | D13* 122 | X90805000Y-49122500D03* 123 | X90805000Y-47397500D03* 124 | D19* 125 | X103417500Y-45077500D03* 126 | X98337500Y-45077500D03* 127 | X100877500Y-45077500D03* 128 | D20* 129 | X94527500Y-46347500D03* 130 | X107227500Y-46347500D03* 131 | D19* 132 | X98337500Y-47617500D03* 133 | X103417500Y-47617500D03* 134 | D13* 135 | X78105000Y-85317500D03* 136 | X78105000Y-83592500D03* 137 | X84855000Y-96685000D03* 138 | X84855000Y-94960000D03* 139 | D21* 140 | X78740000Y-120292500D03* 141 | X78740000Y-118467500D03* 142 | D19* 143 | X81280000Y-93432500D03* 144 | X81280000Y-95972500D03* 145 | X81280000Y-98512500D03* 146 | X81280000Y-101052500D03* 147 | X81280000Y-103592500D03* 148 | X81280000Y-106132500D03* 149 | X81280000Y-108672500D03* 150 | X81280000Y-111212500D03* 151 | X81280000Y-113752500D03* 152 | X81280000Y-116292500D03* 153 | X81280000Y-118832500D03* 154 | X81280000Y-121372500D03* 155 | X81280000Y-123912500D03* 156 | X81280000Y-126452500D03* 157 | X81280000Y-128992500D03* 158 | X106680000Y-128992500D03* 159 | X106680000Y-126452500D03* 160 | X106680000Y-123912500D03* 161 | X106680000Y-121372500D03* 162 | X106680000Y-118832500D03* 163 | X106680000Y-116292500D03* 164 | X106680000Y-113752500D03* 165 | X106680000Y-111212500D03* 166 | X106680000Y-108672500D03* 167 | X106680000Y-106132500D03* 168 | X106680000Y-103592500D03* 169 | X106680000Y-101052500D03* 170 | X106680000Y-98512500D03* 171 | X106680000Y-95972500D03* 172 | X106680000Y-93432500D03* 173 | D22* 174 | X78105000Y-129525000D03* 175 | D23* 176 | X78105000Y-126985000D03* 177 | X78105000Y-124445000D03* 178 | D21* 179 | X78740000Y-116482500D03* 180 | X78740000Y-114657500D03* 181 | D24* 182 | X82550000Y-45737500D03* 183 | D25* 184 | X85375000Y-45937500D03* 185 | X79725000Y-45937500D03* 186 | D26* 187 | X99922500Y-99695000D03* 188 | X98197500Y-99695000D03* 189 | D19* 190 | X102870000Y-94615000D03* 191 | X102870000Y-97155000D03* 192 | X102870000Y-99695000D03* 193 | X102870000Y-102235000D03* 194 | X102870000Y-104775000D03* 195 | D27* 196 | X111125000Y-59142500D03* 197 | D28* 198 | X111125000Y-61682500D03* 199 | D27* 200 | X111125000Y-64222500D03* 201 | X111125000Y-66762500D03* 202 | D19* 203 | X87630000Y-83118423D03* 204 | X87630000Y-85658423D03* 205 | X87630000Y-88198423D03* 206 | X80010000Y-88198423D03* 207 | X80010000Y-85658423D03* 208 | X80010000Y-83118423D03* 209 | M02* 210 | -------------------------------------------------------------------------------- /extras/schematics/gerber/lora_tracker-NPTH.drl: -------------------------------------------------------------------------------- 1 | M48 2 | INCH,TZ 3 | % 4 | G90 5 | G05 6 | T0 7 | M30 8 | -------------------------------------------------------------------------------- /extras/schematics/gerber/lora_tracker-PTH.drl: -------------------------------------------------------------------------------- 1 | M48 2 | INCH,TZ 3 | T1C0.0157 4 | T2C0.0236 5 | T3C0.0300 6 | T4C0.0354 7 | T5C0.0394 8 | T6C0.0512 9 | T7C0.0787 10 | T8C0.1063 11 | % 12 | G90 13 | G05 14 | T1 15 | X29500Y-19500 16 | X29500Y-21000 17 | X29500Y-22500 18 | X29500Y-24000 19 | X29500Y-25600 20 | X29500Y-27200 21 | X29500Y-29250 22 | X29500Y-31200 23 | X29500Y-32800 24 | X29500Y-34400 25 | X29500Y-36000 26 | X29500Y-37600 27 | X29500Y-39200 28 | X29500Y-40800 29 | X29500Y-42400 30 | X29500Y-44000 31 | X29500Y-45600 32 | X29500Y-47250 33 | X30500Y-23000 34 | X31250Y-40250 35 | X31250Y-42250 36 | X31250Y-44250 37 | X31250Y-52000 38 | X31500Y-23750 39 | X31500Y-25750 40 | X31500Y-27250 41 | X31500Y-29000 42 | X31750Y-19500 43 | X31750Y-22000 44 | X31750Y-36000 45 | X32000Y-52000 46 | X32000Y-52750 47 | X32500Y-31500 48 | X32750Y-37000 49 | X32750Y-43250 50 | X32750Y-49250 51 | X33000Y-33250 52 | X33000Y-34750 53 | X33000Y-39500 54 | X33000Y-41000 55 | X33000Y-48000 56 | X33250Y-19500 57 | X33250Y-22000 58 | X33250Y-25250 59 | X33250Y-27250 60 | X33500Y-28500 61 | X33500Y-36000 62 | X33500Y-43000 63 | X33750Y-26250 64 | X33750Y-47250 65 | X34000Y-42500 66 | X34198Y-27750 67 | X34250Y-19500 68 | X34250Y-21000 69 | X34500Y-29500 70 | X34500Y-31250 71 | X34500Y-35500 72 | X34500Y-36500 73 | X34500Y-42000 74 | X34500Y-51750 75 | X34600Y-17500 76 | X34600Y-18400 77 | X34750Y-25000 78 | X34750Y-26500 79 | X34800Y-54000 80 | X34860Y-41500 81 | X35000Y-47000 82 | X35000Y-47750 83 | X35000Y-48750 84 | X35000Y-53000 85 | X35250Y-19000 86 | X35250Y-46000 87 | X35500Y-21500 88 | X35500Y-45000 89 | X35500Y-51750 90 | X35600Y-23400 91 | X35750Y-17500 92 | X35785Y-39250 93 | X36000Y-22500 94 | X36000Y-25000 95 | X36000Y-39750 96 | X36400Y-54000 97 | X36500Y-22000 98 | X36500Y-28500 99 | X36500Y-32000 100 | X36750Y-24000 101 | X36750Y-41250 102 | X36750Y-42250 103 | X36750Y-44500 104 | X36750Y-48750 105 | X37000Y-20000 106 | X37000Y-23000 107 | X37000Y-27000 108 | X37000Y-28000 109 | X37000Y-31250 110 | X37000Y-50000 111 | X37250Y-24750 112 | X37250Y-45000 113 | X37500Y-22000 114 | X37500Y-24000 115 | X37500Y-28750 116 | X37500Y-33500 117 | X37500Y-34000 118 | X37500Y-36000 119 | X37500Y-36500 120 | X37750Y-26750 121 | X37750Y-27750 122 | X37750Y-48750 123 | X38000Y-23000 124 | X38000Y-24750 125 | X38000Y-34500 126 | X38000Y-37250 127 | X38000Y-38500 128 | X38000Y-49500 129 | X38000Y-54000 130 | X38250Y-22000 131 | X38500Y-42750 132 | X38500Y-48250 133 | X39000Y-35500 134 | X39000Y-37250 135 | X39000Y-38500 136 | X39000Y-50000 137 | X39500Y-43750 138 | X39500Y-53000 139 | X39600Y-54000 140 | X39750Y-25500 141 | X39750Y-26500 142 | X39750Y-34500 143 | X40000Y-32500 144 | X40000Y-49250 145 | X40250Y-23000 146 | X40250Y-29000 147 | X40400Y-21750 148 | X40500Y-25500 149 | X40500Y-44750 150 | X40750Y-19750 151 | X41000Y-29000 152 | X41000Y-35500 153 | X41000Y-48500 154 | X41000Y-50000 155 | X41000Y-51500 156 | X41000Y-52750 157 | X41200Y-54000 158 | X41250Y-24250 159 | X41250Y-25000 160 | X41500Y-21750 161 | X41500Y-35000 162 | X41750Y-29000 163 | X41750Y-31500 164 | X41750Y-32250 165 | X42000Y-27000 166 | X42000Y-28064 167 | X42250Y-32750 168 | X42500Y-21750 169 | X42750Y-22750 170 | X42750Y-37250 171 | X42750Y-40250 172 | X42750Y-43250 173 | X42750Y-46250 174 | X42750Y-48250 175 | X42750Y-50000 176 | X42750Y-52000 177 | X43250Y-28000 178 | X43250Y-29250 179 | X43250Y-35250 180 | X43500Y-33000 181 | X43500Y-51500 182 | X44250Y-19500 183 | X44250Y-20750 184 | X44250Y-22500 185 | X44250Y-29250 186 | X44250Y-30500 187 | X44250Y-35250 188 | X44250Y-36800 189 | X44250Y-38400 190 | X44250Y-40000 191 | X44250Y-41600 192 | X44250Y-43200 193 | X44250Y-44800 194 | X44250Y-46400 195 | X44250Y-48000 196 | X44250Y-49600 197 | X44250Y-51200 198 | T2 199 | X33250Y-52399 200 | X33250Y-53187 201 | T3 202 | X40500Y-37250 203 | X40500Y-38250 204 | X40500Y-39250 205 | X40500Y-40250 206 | X40500Y-41250 207 | T4 208 | X31500Y-32724 209 | X31500Y-33724 210 | X31500Y-34724 211 | X32000Y-36784 212 | X32000Y-37784 213 | X32000Y-38784 214 | X32000Y-39784 215 | X32000Y-40784 216 | X32000Y-41784 217 | X32000Y-42784 218 | X32000Y-43784 219 | X32000Y-44784 220 | X32000Y-45784 221 | X32000Y-46784 222 | X32000Y-47784 223 | X32000Y-48784 224 | X32000Y-49784 225 | X32000Y-50784 226 | X34000Y-51034 227 | X34500Y-32724 228 | X34500Y-33724 229 | X34500Y-34724 230 | X35000Y-51034 231 | X36000Y-51034 232 | X36250Y-45784 233 | X37000Y-51034 234 | X37750Y-45784 235 | X38000Y-51034 236 | X38716Y-17747 237 | X38716Y-18747 238 | X39000Y-51034 239 | X39716Y-17747 240 | X40000Y-51034 241 | X40716Y-17747 242 | X40716Y-18747 243 | X42000Y-36784 244 | X42000Y-37784 245 | X42000Y-38784 246 | X42000Y-39784 247 | X42000Y-40784 248 | X42000Y-41784 249 | X42000Y-42784 250 | X42000Y-43784 251 | X42000Y-44784 252 | X42000Y-45784 253 | X42000Y-46784 254 | X42000Y-47784 255 | X42000Y-48784 256 | X42000Y-49784 257 | X42000Y-50784 258 | X43750Y-23284 259 | X43750Y-24284 260 | X43750Y-25284 261 | X43750Y-26284 262 | T5 263 | X30750Y-48994 264 | X30750Y-49994 265 | X30750Y-50994 266 | X43636Y-32114 267 | X43636Y-33886 268 | T6 269 | X42652Y-31622 270 | X42652Y-34378 271 | T7 272 | X37216Y-18247 273 | X42216Y-18247 274 | T8 275 | X30000Y-18000 276 | X30000Y-53500 277 | X43750Y-18000 278 | X43750Y-53500 279 | T0 280 | M30 281 | -------------------------------------------------------------------------------- /extras/schematics/images/board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/schematics/images/board.png -------------------------------------------------------------------------------- /extras/schematics/images/board_assembled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh123/esp32_loradv/4a2354acb180de79bf1678bfeb24efb5b974c48b/extras/schematics/images/board_assembled.png -------------------------------------------------------------------------------- /extras/schematics/lora_tracker-cache.lib: -------------------------------------------------------------------------------- 1 | EESchema-LIBRARY Version 2.4 2 | #encoding utf-8 3 | # 4 | # Connector_Conn_01x03_Female 5 | # 6 | DEF Connector_Conn_01x03_Female J 0 40 Y N 1 F N 7 | F0 "J" 0 200 50 H V C CNN 8 | F1 "Connector_Conn_01x03_Female" 0 -200 50 H V C CNN 9 | F2 "" 0 0 50 H I C CNN 10 | F3 "" 0 0 50 H I C CNN 11 | $FPLIST 12 | Connector*:*_1x??_* 13 | $ENDFPLIST 14 | DRAW 15 | A 0 -100 20 901 -901 1 1 6 N 0 -80 0 -120 16 | A 0 0 20 901 -901 1 1 6 N 0 20 0 -20 17 | A 0 100 20 901 -901 1 1 6 N 0 120 0 80 18 | P 2 1 1 6 -50 -100 -20 -100 N 19 | P 2 1 1 6 -50 0 -20 0 N 20 | P 2 1 1 6 -50 100 -20 100 N 21 | X Pin_1 1 -200 100 150 R 50 50 1 1 P 22 | X Pin_2 2 -200 0 150 R 50 50 1 1 P 23 | X Pin_3 3 -200 -100 150 R 50 50 1 1 P 24 | ENDDRAW 25 | ENDDEF 26 | # 27 | # Connector_Conn_01x10_Female 28 | # 29 | DEF Connector_Conn_01x10_Female J 0 40 Y N 1 F N 30 | F0 "J" 0 500 50 H V C CNN 31 | F1 "Connector_Conn_01x10_Female" 0 -600 50 H V C CNN 32 | F2 "" 0 0 50 H I C CNN 33 | F3 "" 0 0 50 H I C CNN 34 | $FPLIST 35 | Connector*:*_1x??_* 36 | $ENDFPLIST 37 | DRAW 38 | A 0 -500 20 901 -901 1 1 6 N 0 -480 0 -520 39 | A 0 -400 20 901 -901 1 1 6 N 0 -380 0 -420 40 | A 0 -300 20 901 -901 1 1 6 N 0 -280 0 -320 41 | A 0 -200 20 901 -901 1 1 6 N 0 -180 0 -220 42 | A 0 -100 20 901 -901 1 1 6 N 0 -80 0 -120 43 | A 0 0 20 901 -901 1 1 6 N 0 20 0 -20 44 | A 0 100 20 901 -901 1 1 6 N 0 120 0 80 45 | A 0 200 20 901 -901 1 1 6 N 0 220 0 180 46 | A 0 300 20 901 -901 1 1 6 N 0 320 0 280 47 | A 0 400 20 901 -901 1 1 6 N 0 420 0 380 48 | P 2 1 1 6 -50 -500 -20 -500 N 49 | P 2 1 1 6 -50 -400 -20 -400 N 50 | P 2 1 1 6 -50 -300 -20 -300 N 51 | P 2 1 1 6 -50 -200 -20 -200 N 52 | P 2 1 1 6 -50 -100 -20 -100 N 53 | P 2 1 1 6 -50 0 -20 0 N 54 | P 2 1 1 6 -50 100 -20 100 N 55 | P 2 1 1 6 -50 200 -20 200 N 56 | P 2 1 1 6 -50 300 -20 300 N 57 | P 2 1 1 6 -50 400 -20 400 N 58 | X Pin_1 1 -200 400 150 R 50 50 1 1 P 59 | X Pin_10 10 -200 -500 150 R 50 50 1 1 P 60 | X Pin_2 2 -200 300 150 R 50 50 1 1 P 61 | X Pin_3 3 -200 200 150 R 50 50 1 1 P 62 | X Pin_4 4 -200 100 150 R 50 50 1 1 P 63 | X Pin_5 5 -200 0 150 R 50 50 1 1 P 64 | X Pin_6 6 -200 -100 150 R 50 50 1 1 P 65 | X Pin_7 7 -200 -200 150 R 50 50 1 1 P 66 | X Pin_8 8 -200 -300 150 R 50 50 1 1 P 67 | X Pin_9 9 -200 -400 150 R 50 50 1 1 P 68 | ENDDRAW 69 | ENDDEF 70 | # 71 | # Connector_Conn_01x12_Female 72 | # 73 | DEF Connector_Conn_01x12_Female J 0 40 Y N 1 F N 74 | F0 "J" 0 600 50 H V C CNN 75 | F1 "Connector_Conn_01x12_Female" 0 -700 50 H V C CNN 76 | F2 "" 0 0 50 H I C CNN 77 | F3 "" 0 0 50 H I C CNN 78 | $FPLIST 79 | Connector*:*_1x??_* 80 | $ENDFPLIST 81 | DRAW 82 | A 0 -600 20 901 -901 1 1 6 N 0 -580 0 -620 83 | A 0 -500 20 901 -901 1 1 6 N 0 -480 0 -520 84 | A 0 -400 20 901 -901 1 1 6 N 0 -380 0 -420 85 | A 0 -300 20 901 -901 1 1 6 N 0 -280 0 -320 86 | A 0 -200 20 901 -901 1 1 6 N 0 -180 0 -220 87 | A 0 -100 20 901 -901 1 1 6 N 0 -80 0 -120 88 | A 0 0 20 901 -901 1 1 6 N 0 20 0 -20 89 | A 0 100 20 901 -901 1 1 6 N 0 120 0 80 90 | A 0 200 20 901 -901 1 1 6 N 0 220 0 180 91 | A 0 300 20 901 -901 1 1 6 N 0 320 0 280 92 | A 0 400 20 901 -901 1 1 6 N 0 420 0 380 93 | A 0 500 20 901 -901 1 1 6 N 0 520 0 480 94 | P 2 1 1 6 -50 -600 -20 -600 N 95 | P 2 1 1 6 -50 -500 -20 -500 N 96 | P 2 1 1 6 -50 -400 -20 -400 N 97 | P 2 1 1 6 -50 -300 -20 -300 N 98 | P 2 1 1 6 -50 -200 -20 -200 N 99 | P 2 1 1 6 -50 -100 -20 -100 N 100 | P 2 1 1 6 -50 0 -20 0 N 101 | P 2 1 1 6 -50 100 -20 100 N 102 | P 2 1 1 6 -50 200 -20 200 N 103 | P 2 1 1 6 -50 300 -20 300 N 104 | P 2 1 1 6 -50 400 -20 400 N 105 | P 2 1 1 6 -50 500 -20 500 N 106 | X Pin_1 1 -200 500 150 R 50 50 1 1 P 107 | X Pin_10 10 -200 -400 150 R 50 50 1 1 P 108 | X Pin_11 11 -200 -500 150 R 50 50 1 1 P 109 | X Pin_12 12 -200 -600 150 R 50 50 1 1 P 110 | X Pin_2 2 -200 400 150 R 50 50 1 1 P 111 | X Pin_3 3 -200 300 150 R 50 50 1 1 P 112 | X Pin_4 4 -200 200 150 R 50 50 1 1 P 113 | X Pin_5 5 -200 100 150 R 50 50 1 1 P 114 | X Pin_6 6 -200 0 150 R 50 50 1 1 P 115 | X Pin_7 7 -200 -100 150 R 50 50 1 1 P 116 | X Pin_8 8 -200 -200 150 R 50 50 1 1 P 117 | X Pin_9 9 -200 -300 150 R 50 50 1 1 P 118 | ENDDRAW 119 | ENDDEF 120 | # 121 | # Connector_Conn_Coaxial 122 | # 123 | DEF Connector_Conn_Coaxial J 0 40 Y N 1 F N 124 | F0 "J" 10 120 50 H V C CNN 125 | F1 "Connector_Conn_Coaxial" 115 0 50 V V C CNN 126 | F2 "" 0 0 50 H I C CNN 127 | F3 "" 0 0 50 H I C CNN 128 | $FPLIST 129 | *BNC* 130 | *SMA* 131 | *SMB* 132 | *SMC* 133 | *Cinch* 134 | $ENDFPLIST 135 | DRAW 136 | A -2 0 71 1636 0 0 1 10 N -70 20 70 0 137 | A -1 0 71 0 -1638 0 1 10 N 70 0 -70 -20 138 | C 0 0 20 0 1 8 N 139 | P 2 0 1 0 -100 0 -20 0 N 140 | P 2 0 1 0 0 -100 0 -70 N 141 | X In 1 -200 0 100 R 50 50 1 1 P 142 | X Ext 2 0 -200 100 U 50 50 1 1 P 143 | ENDDRAW 144 | ENDDEF 145 | # 146 | # Device_C 147 | # 148 | DEF Device_C C 0 10 N Y 1 F N 149 | F0 "C" 25 100 50 H V L CNN 150 | F1 "Device_C" 25 -100 50 H V L CNN 151 | F2 "" 38 -150 50 H I C CNN 152 | F3 "" 0 0 50 H I C CNN 153 | $FPLIST 154 | C_* 155 | $ENDFPLIST 156 | DRAW 157 | P 2 0 1 20 -80 -30 80 -30 N 158 | P 2 0 1 20 -80 30 80 30 N 159 | X ~ 1 0 150 110 D 50 50 1 1 P 160 | X ~ 2 0 -150 110 U 50 50 1 1 P 161 | ENDDRAW 162 | ENDDEF 163 | # 164 | # Device_CP1 165 | # 166 | DEF Device_CP1 C 0 10 N N 1 F N 167 | F0 "C" 25 100 50 H V L CNN 168 | F1 "Device_CP1" 25 -100 50 H V L CNN 169 | F2 "" 0 0 50 H I C CNN 170 | F3 "" 0 0 50 H I C CNN 171 | $FPLIST 172 | CP_* 173 | $ENDFPLIST 174 | DRAW 175 | A 0 -150 128 1287 513 0 1 20 N -80 -50 80 -50 176 | P 2 0 1 20 -80 30 80 30 N 177 | P 2 0 1 0 -70 90 -30 90 N 178 | P 2 0 1 0 -50 70 -50 110 N 179 | X ~ 1 0 150 110 D 50 50 1 1 P 180 | X ~ 2 0 -150 130 U 50 50 1 1 P 181 | ENDDRAW 182 | ENDDEF 183 | # 184 | # Jumper_SolderJumper_2_Open 185 | # 186 | DEF Jumper_SolderJumper_2_Open JP 0 0 Y N 1 F N 187 | F0 "JP" 0 80 50 H V C CNN 188 | F1 "Jumper_SolderJumper_2_Open" 0 -100 50 H V C CNN 189 | F2 "" 0 0 50 H I C CNN 190 | F3 "" 0 0 50 H I C CNN 191 | $FPLIST 192 | SolderJumper*Open* 193 | $ENDFPLIST 194 | DRAW 195 | A -10 0 40 901 -901 0 1 0 N -10 40 -10 -40 196 | A -10 0 40 901 -901 0 1 0 F -10 40 -10 -40 197 | A 10 0 40 -899 899 0 1 0 N 10 -40 10 40 198 | A 10 0 40 -899 899 0 1 0 F 10 -40 10 40 199 | P 2 0 1 0 -10 40 -10 -40 N 200 | P 2 0 1 0 10 40 10 -40 N 201 | X A 1 -150 0 100 R 50 50 1 1 P 202 | X B 2 150 0 100 L 50 50 1 1 P 203 | ENDDRAW 204 | ENDDEF 205 | # 206 | # Jumper_SolderJumper_3_Open 207 | # 208 | DEF Jumper_SolderJumper_3_Open JP 0 0 Y N 1 F N 209 | F0 "JP" -100 -100 50 H V C CNN 210 | F1 "Jumper_SolderJumper_3_Open" 0 110 50 H V C CNN 211 | F2 "" 0 0 50 H I C CNN 212 | F3 "" 0 0 50 H I C CNN 213 | $FPLIST 214 | SolderJumper*Open* 215 | $ENDFPLIST 216 | DRAW 217 | A -40 0 40 901 -901 0 1 0 N -40 40 -40 -40 218 | A -40 0 40 901 -901 0 1 0 F -40 40 -40 -40 219 | A 40 0 40 -899 899 0 1 0 N 40 -40 40 40 220 | A 40 0 40 -899 899 0 1 0 F 40 -40 40 40 221 | S -20 40 20 -40 0 1 0 F 222 | P 2 0 1 0 -100 0 -80 0 N 223 | P 2 0 1 0 -40 40 -40 -40 N 224 | P 2 0 1 0 0 -50 0 -40 N 225 | P 2 0 1 0 40 40 40 -40 N 226 | P 2 0 1 0 100 0 80 0 N 227 | X A 1 -200 0 100 R 50 50 1 1 P 228 | X C 2 0 -150 100 U 50 50 1 1 I 229 | X B 3 200 0 100 L 50 50 1 1 P 230 | ENDDRAW 231 | ENDDEF 232 | # 233 | # RF_Module_Ai-Thinker-Ra-01 234 | # 235 | DEF RF_Module_Ai-Thinker-Ra-01 U 0 40 Y Y 1 F N 236 | F0 "U" 100 700 50 H V C CNN 237 | F1 "RF_Module_Ai-Thinker-Ra-01" 400 -550 50 H V C CNN 238 | F2 "RF_Module:Ai-Thinker-Ra-01-LoRa" 1000 -400 50 H I C CNN 239 | F3 "" 100 700 50 H I C CNN 240 | $FPLIST 241 | Ai?Thinker?Ra?01* 242 | $ENDFPLIST 243 | DRAW 244 | S -300 600 300 -500 0 1 10 f 245 | X Ant 1 -500 500 200 R 50 50 1 1 I 246 | X DIO4 10 500 0 200 L 50 50 1 1 B 247 | X DIO5 11 500 -100 200 L 50 50 1 1 B 248 | X SCK 12 -500 0 200 R 50 50 1 1 B 249 | X MISO 13 -500 -100 200 R 50 50 1 1 O 250 | X MOSI 14 -500 -200 200 R 50 50 1 1 I 251 | X ~SS 15 -500 100 200 R 50 50 1 1 I 252 | X Gnd 16 0 -700 200 U 50 50 1 1 P N 253 | X Gnd 2 0 -700 200 U 50 50 1 1 W 254 | X 3v3 3 0 800 200 D 50 50 1 1 W 255 | X ~Reset 4 -500 300 200 R 50 50 1 1 I 256 | X DIO0 5 500 400 200 L 50 50 1 1 B 257 | X DIO1 6 500 300 200 L 50 50 1 1 B 258 | X DIO2 7 500 200 200 L 50 50 1 1 B 259 | X DIO3 8 500 100 200 L 50 50 1 1 B 260 | X Gnd 9 0 -700 200 U 50 50 1 1 P N 261 | ENDDRAW 262 | ENDDEF 263 | # 264 | # lora_tracker_E22-400M30S 265 | # 266 | DEF lora_tracker_E22-400M30S U 0 40 Y Y 1 L N 267 | F0 "U" -800 1300 85 H V L BNN 268 | F1 "lora_tracker_E22-400M30S" 0 0 50 H I C CNN 269 | F2 "" 0 0 50 H I C CNN 270 | F3 "" 0 0 50 H I C CNN 271 | DRAW 272 | T 0 0 500 85 0 1 0 E22-400M30S Normal 0 C C 273 | P 2 1 0 0 -800 -1200 800 -1200 N 274 | P 2 1 0 0 -800 1200 -800 -1200 N 275 | P 2 1 0 0 800 -1200 800 1200 N 276 | P 2 1 0 0 800 1200 -800 1200 N 277 | X GND@1 1 -1000 1100 200 R 0 50 1 0 B 278 | X VCC@2 10 -1000 -900 200 R 0 50 1 0 B 279 | X GND@6 11 -1000 -1100 200 R 0 50 1 0 B 280 | X GND@7 12 1000 -1100 200 L 0 50 1 0 B 281 | X DIO1 13 1000 -900 200 L 0 50 1 0 B 282 | X BUSY 14 1000 -700 200 L 0 50 1 0 B 283 | X NRST 15 1000 -500 200 L 0 50 1 0 B 284 | X MISO 16 1000 -300 200 L 0 50 1 0 B 285 | X MOSI 17 1000 -100 200 L 0 50 1 0 B 286 | X SCK 18 1000 100 200 L 0 50 1 0 B 287 | X NSS 19 1000 300 200 L 0 50 1 0 B 288 | X GND@2 2 -1000 900 200 R 0 50 1 0 B 289 | X GND@8 20 1000 700 200 L 0 50 1 0 B 290 | X ANT 21 1000 900 200 L 0 50 1 0 B 291 | X GND@9 22 1000 1100 200 L 0 50 1 0 B 292 | X GND@3 3 -1000 700 200 R 0 50 1 0 B 293 | X GND@4 4 -1000 300 200 R 0 50 1 0 B 294 | X GND@5 5 -1000 100 200 R 0 50 1 0 B 295 | X RXEN 6 -1000 -100 200 R 0 50 1 0 B 296 | X TXEN 7 -1000 -300 200 R 0 50 1 0 B 297 | X DIO2 8 -1000 -500 200 R 0 50 1 0 B 298 | X VCC@1 9 -1000 -700 200 R 0 50 1 0 B 299 | ENDDRAW 300 | ENDDEF 301 | # 302 | # lora_tracker_ESP32 303 | # 304 | DEF lora_tracker_ESP32 U 0 40 Y Y 1 F N 305 | F0 "U" 50 150 50 H V C CNN 306 | F1 "lora_tracker_ESP32" 50 50 50 H V C CNN 307 | F2 "" 50 150 50 H I C CNN 308 | F3 "" 50 150 50 H I C CNN 309 | DRAW 310 | S -300 0 450 -2000 0 1 0 N 311 | X +3V3 1 -400 -100 100 R 50 50 1 1 I 312 | X GPIO26 10 -400 -1000 100 R 50 50 1 1 I 313 | X GPIO27 11 -400 -1100 100 R 50 50 1 1 I 314 | X GPIO14 12 -400 -1200 100 R 50 50 1 1 I 315 | X GPIO12 13 -400 -1300 100 R 50 50 1 1 I 316 | X GND 14 -400 -1400 100 R 50 50 1 1 I 317 | X GPIO13 15 -400 -1500 100 R 50 50 1 1 I 318 | X GPIO9 16 -400 -1600 100 R 50 50 1 1 I 319 | X GPIO10 17 -400 -1700 100 R 50 50 1 1 I 320 | X GPIO11 18 -400 -1800 100 R 50 50 1 1 I 321 | X VIN 19 -400 -1900 100 R 50 50 1 1 I 322 | X EN 2 -400 -200 100 R 50 50 1 1 I 323 | X GPIO6 20 550 -1900 100 L 50 50 1 1 I 324 | X GPIO7 21 550 -1800 100 L 50 50 1 1 I 325 | X GPIO8 22 550 -1700 100 L 50 50 1 1 I 326 | X GPIO15 23 550 -1600 100 L 50 50 1 1 I 327 | X GPIO2 24 550 -1500 100 L 50 50 1 1 I 328 | X GPIO0 25 550 -1400 100 L 50 50 1 1 I 329 | X GPIO4 26 550 -1300 100 L 50 50 1 1 I 330 | X GPIO16 27 550 -1200 100 L 50 50 1 1 I 331 | X GPIO17 28 550 -1100 100 L 50 50 1 1 I 332 | X GPIO5 29 550 -1000 100 L 50 50 1 1 I 333 | X GPIO36 3 -400 -300 100 R 50 50 1 1 I 334 | X GPIO18 30 550 -900 100 L 50 50 1 1 I 335 | X GPIO19 31 550 -800 100 L 50 50 1 1 I 336 | X GND 32 550 -700 100 L 50 50 1 1 I 337 | X GPIO21 33 550 -600 100 L 50 50 1 1 I 338 | X GPIO3 34 550 -500 100 L 50 50 1 1 I 339 | X GPIO1 35 550 -400 100 L 50 50 1 1 I 340 | X GPIO22 36 550 -300 100 L 50 50 1 1 I 341 | X GPIO23 37 550 -200 100 L 50 50 1 1 I 342 | X GND 38 550 -100 100 L 50 50 1 1 I 343 | X GPIO39 4 -400 -400 100 R 50 50 1 1 I 344 | X GPIO34 5 -400 -500 100 R 50 50 1 1 I 345 | X GPIO35 6 -400 -600 100 R 50 50 1 1 I 346 | X GPIO32 7 -400 -700 100 R 50 50 1 1 I 347 | X GPIO33 8 -400 -800 100 R 50 50 1 1 I 348 | X GPIO25 9 -400 -900 100 R 50 50 1 1 I 349 | ENDDRAW 350 | ENDDEF 351 | # 352 | #End Library 353 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker-rescue.bak: -------------------------------------------------------------------------------- 1 | (kicad_symbol_lib (version 20211014) (generator kicad_symbol_editor) 2 | (symbol "Ai-Thinker-Ra-01-RF_Module" (pin_names (offset 1.016)) (in_bom yes) (on_board yes) 3 | (property "Reference" "U" (id 0) (at 2.54 17.78 0) 4 | (effects (font (size 1.27 1.27))) 5 | ) 6 | (property "Value" "Ai-Thinker-Ra-01-RF_Module" (id 1) (at 10.16 -13.97 0) 7 | (effects (font (size 1.27 1.27))) 8 | ) 9 | (property "Footprint" "RF_Module:Ai-Thinker-Ra-01-LoRa" (id 2) (at 25.4 -10.16 0) 10 | (effects (font (size 1.27 1.27)) hide) 11 | ) 12 | (property "Datasheet" "" (id 3) (at 2.54 17.78 0) 13 | (effects (font (size 1.27 1.27)) hide) 14 | ) 15 | (property "ki_fp_filters" "Ai?Thinker?Ra?01*" (id 4) (at 0 0 0) 16 | (effects (font (size 1.27 1.27)) hide) 17 | ) 18 | (symbol "Ai-Thinker-Ra-01-RF_Module_0_1" 19 | (rectangle (start -7.62 15.24) (end 7.62 -12.7) 20 | (stroke (width 0.254) (type default) (color 0 0 0 0)) 21 | (fill (type background)) 22 | ) 23 | ) 24 | (symbol "Ai-Thinker-Ra-01-RF_Module_1_1" 25 | (pin input line (at -12.7 12.7 0) (length 5.08) 26 | (name "Ant" (effects (font (size 1.27 1.27)))) 27 | (number "1" (effects (font (size 1.27 1.27)))) 28 | ) 29 | (pin bidirectional line (at 12.7 0 180) (length 5.08) 30 | (name "DIO4" (effects (font (size 1.27 1.27)))) 31 | (number "10" (effects (font (size 1.27 1.27)))) 32 | ) 33 | (pin bidirectional line (at 12.7 -2.54 180) (length 5.08) 34 | (name "DIO5" (effects (font (size 1.27 1.27)))) 35 | (number "11" (effects (font (size 1.27 1.27)))) 36 | ) 37 | (pin bidirectional line (at -12.7 0 0) (length 5.08) 38 | (name "SCK" (effects (font (size 1.27 1.27)))) 39 | (number "12" (effects (font (size 1.27 1.27)))) 40 | ) 41 | (pin output line (at -12.7 -2.54 0) (length 5.08) 42 | (name "MISO" (effects (font (size 1.27 1.27)))) 43 | (number "13" (effects (font (size 1.27 1.27)))) 44 | ) 45 | (pin input line (at -12.7 -5.08 0) (length 5.08) 46 | (name "MOSI" (effects (font (size 1.27 1.27)))) 47 | (number "14" (effects (font (size 1.27 1.27)))) 48 | ) 49 | (pin input line (at -12.7 2.54 0) (length 5.08) 50 | (name "~{SS}" (effects (font (size 1.27 1.27)))) 51 | (number "15" (effects (font (size 1.27 1.27)))) 52 | ) 53 | (pin passive line (at 0 -17.78 90) (length 5.08) hide 54 | (name "Gnd" (effects (font (size 1.27 1.27)))) 55 | (number "16" (effects (font (size 1.27 1.27)))) 56 | ) 57 | (pin power_in line (at 0 -17.78 90) (length 5.08) 58 | (name "Gnd" (effects (font (size 1.27 1.27)))) 59 | (number "2" (effects (font (size 1.27 1.27)))) 60 | ) 61 | (pin power_in line (at 0 20.32 270) (length 5.08) 62 | (name "3v3" (effects (font (size 1.27 1.27)))) 63 | (number "3" (effects (font (size 1.27 1.27)))) 64 | ) 65 | (pin input line (at -12.7 7.62 0) (length 5.08) 66 | (name "~{Reset}" (effects (font (size 1.27 1.27)))) 67 | (number "4" (effects (font (size 1.27 1.27)))) 68 | ) 69 | (pin bidirectional line (at 12.7 10.16 180) (length 5.08) 70 | (name "DIO0" (effects (font (size 1.27 1.27)))) 71 | (number "5" (effects (font (size 1.27 1.27)))) 72 | ) 73 | (pin bidirectional line (at 12.7 7.62 180) (length 5.08) 74 | (name "DIO1" (effects (font (size 1.27 1.27)))) 75 | (number "6" (effects (font (size 1.27 1.27)))) 76 | ) 77 | (pin bidirectional line (at 12.7 5.08 180) (length 5.08) 78 | (name "DIO2" (effects (font (size 1.27 1.27)))) 79 | (number "7" (effects (font (size 1.27 1.27)))) 80 | ) 81 | (pin bidirectional line (at 12.7 2.54 180) (length 5.08) 82 | (name "DIO3" (effects (font (size 1.27 1.27)))) 83 | (number "8" (effects (font (size 1.27 1.27)))) 84 | ) 85 | (pin passive line (at 0 -17.78 90) (length 5.08) hide 86 | (name "Gnd" (effects (font (size 1.27 1.27)))) 87 | (number "9" (effects (font (size 1.27 1.27)))) 88 | ) 89 | ) 90 | ) 91 | (symbol "CP1-Device" (pin_numbers hide) (pin_names (offset 0.254) hide) (in_bom yes) (on_board yes) 92 | (property "Reference" "C" (id 0) (at 0.635 2.54 0) 93 | (effects (font (size 1.27 1.27)) (justify left)) 94 | ) 95 | (property "Value" "CP1-Device" (id 1) (at 0.635 -2.54 0) 96 | (effects (font (size 1.27 1.27)) (justify left)) 97 | ) 98 | (property "Footprint" "" (id 2) (at 0 0 0) 99 | (effects (font (size 1.27 1.27)) hide) 100 | ) 101 | (property "Datasheet" "" (id 3) (at 0 0 0) 102 | (effects (font (size 1.27 1.27)) hide) 103 | ) 104 | (property "ki_fp_filters" "CP_*" (id 4) (at 0 0 0) 105 | (effects (font (size 1.27 1.27)) hide) 106 | ) 107 | (symbol "CP1-Device_0_1" 108 | (polyline 109 | (pts 110 | (xy -2.032 0.762) 111 | (xy 2.032 0.762) 112 | ) 113 | (stroke (width 0.508) (type default) (color 0 0 0 0)) 114 | (fill (type none)) 115 | ) 116 | (polyline 117 | (pts 118 | (xy -1.778 2.286) 119 | (xy -0.762 2.286) 120 | ) 121 | (stroke (width 0) (type default) (color 0 0 0 0)) 122 | (fill (type none)) 123 | ) 124 | (polyline 125 | (pts 126 | (xy -1.27 1.778) 127 | (xy -1.27 2.794) 128 | ) 129 | (stroke (width 0) (type default) (color 0 0 0 0)) 130 | (fill (type none)) 131 | ) 132 | (arc (start 2.032 -1.27) (mid 0 -0.5572) (end -2.032 -1.27) 133 | (stroke (width 0.508) (type default) (color 0 0 0 0)) 134 | (fill (type none)) 135 | ) 136 | ) 137 | (symbol "CP1-Device_1_1" 138 | (pin passive line (at 0 3.81 270) (length 2.794) 139 | (name "~" (effects (font (size 1.27 1.27)))) 140 | (number "1" (effects (font (size 1.27 1.27)))) 141 | ) 142 | (pin passive line (at 0 -3.81 90) (length 3.302) 143 | (name "~" (effects (font (size 1.27 1.27)))) 144 | (number "2" (effects (font (size 1.27 1.27)))) 145 | ) 146 | ) 147 | ) 148 | (symbol "SolderJumper_3_Open-Jumper" (pin_names (offset 0) hide) (in_bom yes) (on_board yes) 149 | (property "Reference" "JP" (id 0) (at -2.54 -2.54 0) 150 | (effects (font (size 1.27 1.27))) 151 | ) 152 | (property "Value" "SolderJumper_3_Open-Jumper" (id 1) (at 0 2.794 0) 153 | (effects (font (size 1.27 1.27))) 154 | ) 155 | (property "Footprint" "" (id 2) (at 0 0 0) 156 | (effects (font (size 1.27 1.27)) hide) 157 | ) 158 | (property "Datasheet" "" (id 3) (at 0 0 0) 159 | (effects (font (size 1.27 1.27)) hide) 160 | ) 161 | (property "ki_fp_filters" "SolderJumper*Open*" (id 4) (at 0 0 0) 162 | (effects (font (size 1.27 1.27)) hide) 163 | ) 164 | (symbol "SolderJumper_3_Open-Jumper_0_1" 165 | (arc (start -1.016 1.016) (mid -2.032 0) (end -1.016 -1.016) 166 | (stroke (width 0) (type default) (color 0 0 0 0)) 167 | (fill (type none)) 168 | ) 169 | (arc (start -1.016 1.016) (mid -2.032 0) (end -1.016 -1.016) 170 | (stroke (width 0) (type default) (color 0 0 0 0)) 171 | (fill (type outline)) 172 | ) 173 | (rectangle (start -0.508 1.016) (end 0.508 -1.016) 174 | (stroke (width 0) (type default) (color 0 0 0 0)) 175 | (fill (type outline)) 176 | ) 177 | (polyline 178 | (pts 179 | (xy -2.54 0) 180 | (xy -2.032 0) 181 | ) 182 | (stroke (width 0) (type default) (color 0 0 0 0)) 183 | (fill (type none)) 184 | ) 185 | (polyline 186 | (pts 187 | (xy -1.016 1.016) 188 | (xy -1.016 -1.016) 189 | ) 190 | (stroke (width 0) (type default) (color 0 0 0 0)) 191 | (fill (type none)) 192 | ) 193 | (polyline 194 | (pts 195 | (xy 0 -1.27) 196 | (xy 0 -1.016) 197 | ) 198 | (stroke (width 0) (type default) (color 0 0 0 0)) 199 | (fill (type none)) 200 | ) 201 | (polyline 202 | (pts 203 | (xy 1.016 1.016) 204 | (xy 1.016 -1.016) 205 | ) 206 | (stroke (width 0) (type default) (color 0 0 0 0)) 207 | (fill (type none)) 208 | ) 209 | (polyline 210 | (pts 211 | (xy 2.54 0) 212 | (xy 2.032 0) 213 | ) 214 | (stroke (width 0) (type default) (color 0 0 0 0)) 215 | (fill (type none)) 216 | ) 217 | (arc (start 1.016 -1.016) (mid 2.032 0) (end 1.016 1.016) 218 | (stroke (width 0) (type default) (color 0 0 0 0)) 219 | (fill (type none)) 220 | ) 221 | (arc (start 1.016 -1.016) (mid 2.032 0) (end 1.016 1.016) 222 | (stroke (width 0) (type default) (color 0 0 0 0)) 223 | (fill (type outline)) 224 | ) 225 | ) 226 | (symbol "SolderJumper_3_Open-Jumper_1_1" 227 | (pin passive line (at -5.08 0 0) (length 2.54) 228 | (name "A" (effects (font (size 1.27 1.27)))) 229 | (number "1" (effects (font (size 1.27 1.27)))) 230 | ) 231 | (pin input line (at 0 -3.81 90) (length 2.54) 232 | (name "C" (effects (font (size 1.27 1.27)))) 233 | (number "2" (effects (font (size 1.27 1.27)))) 234 | ) 235 | (pin passive line (at 5.08 0 180) (length 2.54) 236 | (name "B" (effects (font (size 1.27 1.27)))) 237 | (number "3" (effects (font (size 1.27 1.27)))) 238 | ) 239 | ) 240 | ) 241 | ) 242 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker-rescue.dcm: -------------------------------------------------------------------------------- 1 | EESchema-DOCLIB Version 2.0 2 | # 3 | #End Doc Library 4 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker-rescue.kicad_sym: -------------------------------------------------------------------------------- 1 | (kicad_symbol_lib (version 20211014) (generator kicad_symbol_editor) 2 | (symbol "Ai-Thinker-Ra-01-RF_Module" (pin_names (offset 1.016)) (in_bom yes) (on_board yes) 3 | (property "Reference" "U" (id 0) (at 2.54 17.78 0) 4 | (effects (font (size 1.27 1.27))) 5 | ) 6 | (property "Value" "Ai-Thinker-Ra-01-RF_Module" (id 1) (at 10.16 -13.97 0) 7 | (effects (font (size 1.27 1.27))) 8 | ) 9 | (property "Footprint" "RF_Module:Ai-Thinker-Ra-01-LoRa" (id 2) (at 25.4 -10.16 0) 10 | (effects (font (size 1.27 1.27)) hide) 11 | ) 12 | (property "Datasheet" "" (id 3) (at 2.54 17.78 0) 13 | (effects (font (size 1.27 1.27)) hide) 14 | ) 15 | (property "ki_fp_filters" "Ai?Thinker?Ra?01*" (id 4) (at 0 0 0) 16 | (effects (font (size 1.27 1.27)) hide) 17 | ) 18 | (symbol "Ai-Thinker-Ra-01-RF_Module_0_1" 19 | (rectangle (start -7.62 15.24) (end 7.62 -12.7) 20 | (stroke (width 0.254) (type default) (color 0 0 0 0)) 21 | (fill (type background)) 22 | ) 23 | ) 24 | (symbol "Ai-Thinker-Ra-01-RF_Module_1_1" 25 | (pin input line (at -12.7 12.7 0) (length 5.08) 26 | (name "Ant" (effects (font (size 1.27 1.27)))) 27 | (number "1" (effects (font (size 1.27 1.27)))) 28 | ) 29 | (pin bidirectional line (at 12.7 0 180) (length 5.08) 30 | (name "DIO4" (effects (font (size 1.27 1.27)))) 31 | (number "10" (effects (font (size 1.27 1.27)))) 32 | ) 33 | (pin bidirectional line (at 12.7 -2.54 180) (length 5.08) 34 | (name "DIO5" (effects (font (size 1.27 1.27)))) 35 | (number "11" (effects (font (size 1.27 1.27)))) 36 | ) 37 | (pin bidirectional line (at -12.7 0 0) (length 5.08) 38 | (name "SCK" (effects (font (size 1.27 1.27)))) 39 | (number "12" (effects (font (size 1.27 1.27)))) 40 | ) 41 | (pin output line (at -12.7 -2.54 0) (length 5.08) 42 | (name "MISO" (effects (font (size 1.27 1.27)))) 43 | (number "13" (effects (font (size 1.27 1.27)))) 44 | ) 45 | (pin input line (at -12.7 -5.08 0) (length 5.08) 46 | (name "MOSI" (effects (font (size 1.27 1.27)))) 47 | (number "14" (effects (font (size 1.27 1.27)))) 48 | ) 49 | (pin input line (at -12.7 2.54 0) (length 5.08) 50 | (name "~{SS}" (effects (font (size 1.27 1.27)))) 51 | (number "15" (effects (font (size 1.27 1.27)))) 52 | ) 53 | (pin passive line (at 0 -17.78 90) (length 5.08) hide 54 | (name "Gnd" (effects (font (size 1.27 1.27)))) 55 | (number "16" (effects (font (size 1.27 1.27)))) 56 | ) 57 | (pin power_in line (at 0 -17.78 90) (length 5.08) 58 | (name "Gnd" (effects (font (size 1.27 1.27)))) 59 | (number "2" (effects (font (size 1.27 1.27)))) 60 | ) 61 | (pin power_in line (at 0 20.32 270) (length 5.08) 62 | (name "3v3" (effects (font (size 1.27 1.27)))) 63 | (number "3" (effects (font (size 1.27 1.27)))) 64 | ) 65 | (pin input line (at -12.7 7.62 0) (length 5.08) 66 | (name "~{Reset}" (effects (font (size 1.27 1.27)))) 67 | (number "4" (effects (font (size 1.27 1.27)))) 68 | ) 69 | (pin bidirectional line (at 12.7 10.16 180) (length 5.08) 70 | (name "DIO0" (effects (font (size 1.27 1.27)))) 71 | (number "5" (effects (font (size 1.27 1.27)))) 72 | ) 73 | (pin bidirectional line (at 12.7 7.62 180) (length 5.08) 74 | (name "DIO1" (effects (font (size 1.27 1.27)))) 75 | (number "6" (effects (font (size 1.27 1.27)))) 76 | ) 77 | (pin bidirectional line (at 12.7 5.08 180) (length 5.08) 78 | (name "DIO2" (effects (font (size 1.27 1.27)))) 79 | (number "7" (effects (font (size 1.27 1.27)))) 80 | ) 81 | (pin bidirectional line (at 12.7 2.54 180) (length 5.08) 82 | (name "DIO3" (effects (font (size 1.27 1.27)))) 83 | (number "8" (effects (font (size 1.27 1.27)))) 84 | ) 85 | (pin passive line (at 0 -17.78 90) (length 5.08) hide 86 | (name "Gnd" (effects (font (size 1.27 1.27)))) 87 | (number "9" (effects (font (size 1.27 1.27)))) 88 | ) 89 | ) 90 | ) 91 | (symbol "CP1-Device" (pin_numbers hide) (pin_names (offset 0.254) hide) (in_bom yes) (on_board yes) 92 | (property "Reference" "C" (id 0) (at 0.635 2.54 0) 93 | (effects (font (size 1.27 1.27)) (justify left)) 94 | ) 95 | (property "Value" "CP1-Device" (id 1) (at 0.635 -2.54 0) 96 | (effects (font (size 1.27 1.27)) (justify left)) 97 | ) 98 | (property "Footprint" "" (id 2) (at 0 0 0) 99 | (effects (font (size 1.27 1.27)) hide) 100 | ) 101 | (property "Datasheet" "" (id 3) (at 0 0 0) 102 | (effects (font (size 1.27 1.27)) hide) 103 | ) 104 | (property "ki_fp_filters" "CP_*" (id 4) (at 0 0 0) 105 | (effects (font (size 1.27 1.27)) hide) 106 | ) 107 | (symbol "CP1-Device_0_1" 108 | (polyline 109 | (pts 110 | (xy -2.032 0.762) 111 | (xy 2.032 0.762) 112 | ) 113 | (stroke (width 0.508) (type default) (color 0 0 0 0)) 114 | (fill (type none)) 115 | ) 116 | (polyline 117 | (pts 118 | (xy -1.778 2.286) 119 | (xy -0.762 2.286) 120 | ) 121 | (stroke (width 0) (type default) (color 0 0 0 0)) 122 | (fill (type none)) 123 | ) 124 | (polyline 125 | (pts 126 | (xy -1.27 1.778) 127 | (xy -1.27 2.794) 128 | ) 129 | (stroke (width 0) (type default) (color 0 0 0 0)) 130 | (fill (type none)) 131 | ) 132 | (arc (start 2.032 -1.27) (mid 0 -0.5572) (end -2.032 -1.27) 133 | (stroke (width 0.508) (type default) (color 0 0 0 0)) 134 | (fill (type none)) 135 | ) 136 | ) 137 | (symbol "CP1-Device_1_1" 138 | (pin passive line (at 0 3.81 270) (length 2.794) 139 | (name "~" (effects (font (size 1.27 1.27)))) 140 | (number "1" (effects (font (size 1.27 1.27)))) 141 | ) 142 | (pin passive line (at 0 -3.81 90) (length 3.302) 143 | (name "~" (effects (font (size 1.27 1.27)))) 144 | (number "2" (effects (font (size 1.27 1.27)))) 145 | ) 146 | ) 147 | ) 148 | (symbol "SolderJumper_3_Open-Jumper" (pin_names (offset 0) hide) (in_bom yes) (on_board yes) 149 | (property "Reference" "JP" (id 0) (at -2.54 -2.54 0) 150 | (effects (font (size 1.27 1.27))) 151 | ) 152 | (property "Value" "SolderJumper_3_Open-Jumper" (id 1) (at 0 2.794 0) 153 | (effects (font (size 1.27 1.27))) 154 | ) 155 | (property "Footprint" "" (id 2) (at 0 0 0) 156 | (effects (font (size 1.27 1.27)) hide) 157 | ) 158 | (property "Datasheet" "" (id 3) (at 0 0 0) 159 | (effects (font (size 1.27 1.27)) hide) 160 | ) 161 | (property "ki_fp_filters" "SolderJumper*Open*" (id 4) (at 0 0 0) 162 | (effects (font (size 1.27 1.27)) hide) 163 | ) 164 | (symbol "SolderJumper_3_Open-Jumper_0_1" 165 | (arc (start -1.016 1.016) (mid -2.032 0) (end -1.016 -1.016) 166 | (stroke (width 0) (type default) (color 0 0 0 0)) 167 | (fill (type none)) 168 | ) 169 | (arc (start -1.016 1.016) (mid -2.032 0) (end -1.016 -1.016) 170 | (stroke (width 0) (type default) (color 0 0 0 0)) 171 | (fill (type outline)) 172 | ) 173 | (rectangle (start -0.508 1.016) (end 0.508 -1.016) 174 | (stroke (width 0) (type default) (color 0 0 0 0)) 175 | (fill (type outline)) 176 | ) 177 | (polyline 178 | (pts 179 | (xy -2.54 0) 180 | (xy -2.032 0) 181 | ) 182 | (stroke (width 0) (type default) (color 0 0 0 0)) 183 | (fill (type none)) 184 | ) 185 | (polyline 186 | (pts 187 | (xy -1.016 1.016) 188 | (xy -1.016 -1.016) 189 | ) 190 | (stroke (width 0) (type default) (color 0 0 0 0)) 191 | (fill (type none)) 192 | ) 193 | (polyline 194 | (pts 195 | (xy 0 -1.27) 196 | (xy 0 -1.016) 197 | ) 198 | (stroke (width 0) (type default) (color 0 0 0 0)) 199 | (fill (type none)) 200 | ) 201 | (polyline 202 | (pts 203 | (xy 1.016 1.016) 204 | (xy 1.016 -1.016) 205 | ) 206 | (stroke (width 0) (type default) (color 0 0 0 0)) 207 | (fill (type none)) 208 | ) 209 | (polyline 210 | (pts 211 | (xy 2.54 0) 212 | (xy 2.032 0) 213 | ) 214 | (stroke (width 0) (type default) (color 0 0 0 0)) 215 | (fill (type none)) 216 | ) 217 | (arc (start 1.016 -1.016) (mid 2.032 0) (end 1.016 1.016) 218 | (stroke (width 0) (type default) (color 0 0 0 0)) 219 | (fill (type none)) 220 | ) 221 | (arc (start 1.016 -1.016) (mid 2.032 0) (end 1.016 1.016) 222 | (stroke (width 0) (type default) (color 0 0 0 0)) 223 | (fill (type outline)) 224 | ) 225 | ) 226 | (symbol "SolderJumper_3_Open-Jumper_1_1" 227 | (pin passive line (at -5.08 0 0) (length 2.54) 228 | (name "A" (effects (font (size 1.27 1.27)))) 229 | (number "1" (effects (font (size 1.27 1.27)))) 230 | ) 231 | (pin input line (at 0 -3.81 90) (length 2.54) 232 | (name "C" (effects (font (size 1.27 1.27)))) 233 | (number "2" (effects (font (size 1.27 1.27)))) 234 | ) 235 | (pin passive line (at 5.08 0 180) (length 2.54) 236 | (name "B" (effects (font (size 1.27 1.27)))) 237 | (number "3" (effects (font (size 1.27 1.27)))) 238 | ) 239 | ) 240 | ) 241 | ) 242 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker-rescue.lib: -------------------------------------------------------------------------------- 1 | EESchema-LIBRARY Version 2.4 2 | #encoding utf-8 3 | # 4 | # Ai-Thinker-Ra-01-RF_Module 5 | # 6 | DEF Ai-Thinker-Ra-01-RF_Module U 0 40 Y Y 1 F N 7 | F0 "U" 100 700 50 H V C CNN 8 | F1 "Ai-Thinker-Ra-01-RF_Module" 400 -550 50 H V C CNN 9 | F2 "RF_Module:Ai-Thinker-Ra-01-LoRa" 1000 -400 50 H I C CNN 10 | F3 "" 100 700 50 H I C CNN 11 | $FPLIST 12 | Ai?Thinker?Ra?01* 13 | $ENDFPLIST 14 | DRAW 15 | S -300 600 300 -500 0 1 10 f 16 | X Ant 1 -500 500 200 R 50 50 1 1 I 17 | X DIO4 10 500 0 200 L 50 50 1 1 B 18 | X DIO5 11 500 -100 200 L 50 50 1 1 B 19 | X SCK 12 -500 0 200 R 50 50 1 1 B 20 | X MISO 13 -500 -100 200 R 50 50 1 1 O 21 | X MOSI 14 -500 -200 200 R 50 50 1 1 I 22 | X ~{SS} 15 -500 100 200 R 50 50 1 1 I 23 | X Gnd 16 0 -700 200 U 50 50 1 1 P N 24 | X Gnd 2 0 -700 200 U 50 50 1 1 W 25 | X 3v3 3 0 800 200 D 50 50 1 1 W 26 | X ~{Reset} 4 -500 300 200 R 50 50 1 1 I 27 | X DIO0 5 500 400 200 L 50 50 1 1 B 28 | X DIO1 6 500 300 200 L 50 50 1 1 B 29 | X DIO2 7 500 200 200 L 50 50 1 1 B 30 | X DIO3 8 500 100 200 L 50 50 1 1 B 31 | X Gnd 9 0 -700 200 U 50 50 1 1 P N 32 | ENDDRAW 33 | ENDDEF 34 | # 35 | # CP1-Device 36 | # 37 | DEF CP1-Device C 0 10 N N 1 F N 38 | F0 "C" 25 100 50 H V L CNN 39 | F1 "CP1-Device" 25 -100 50 H V L CNN 40 | F2 "" 0 0 50 H I C CNN 41 | F3 "" 0 0 50 H I C CNN 42 | $FPLIST 43 | CP_* 44 | $ENDFPLIST 45 | DRAW 46 | P 2 0 1 20 -80 30 80 30 N 47 | P 2 0 1 0 -70 90 -30 90 N 48 | P 2 0 1 0 -50 70 -50 110 N 49 | A 0 -150 128 513 1287 0 1 20 N 80 -50 -80 -50 50 | X ~ 1 0 150 110 D 50 50 1 1 P 51 | X ~ 2 0 -150 130 U 50 50 1 1 P 52 | ENDDRAW 53 | ENDDEF 54 | # 55 | # SolderJumper_3_Open-Jumper 56 | # 57 | DEF SolderJumper_3_Open-Jumper JP 0 0 Y N 1 F N 58 | F0 "JP" -100 -100 50 H V C CNN 59 | F1 "SolderJumper_3_Open-Jumper" 0 110 50 H V C CNN 60 | F2 "" 0 0 50 H I C CNN 61 | F3 "" 0 0 50 H I C CNN 62 | $FPLIST 63 | SolderJumper*Open* 64 | $ENDFPLIST 65 | DRAW 66 | A -40 0 40 901 -901 0 1 0 N -40 40 -40 -40 67 | A -40 0 40 901 -901 0 1 0 F -40 40 -40 -40 68 | S -20 40 20 -40 0 1 0 F 69 | P 2 0 1 0 -100 0 -80 0 N 70 | P 2 0 1 0 -40 40 -40 -40 N 71 | P 2 0 1 0 0 -50 0 -40 N 72 | P 2 0 1 0 40 40 40 -40 N 73 | P 2 0 1 0 100 0 80 0 N 74 | A 40 0 40 -899 899 0 1 0 N 40 -40 40 40 75 | A 40 0 40 -899 899 0 1 0 F 40 -40 40 40 76 | X A 1 -200 0 100 R 50 50 1 1 P 77 | X C 2 0 -150 100 U 50 50 1 1 I 78 | X B 3 200 0 100 L 50 50 1 1 P 79 | ENDDRAW 80 | ENDDEF 81 | # 82 | #End Library 83 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker.kicad_prl: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "active_layer": 0, 4 | "active_layer_preset": "All Layers", 5 | "auto_track_width": true, 6 | "hidden_nets": [], 7 | "high_contrast_mode": 0, 8 | "net_color_mode": 1, 9 | "opacity": { 10 | "pads": 1.0, 11 | "tracks": 1.0, 12 | "vias": 1.0, 13 | "zones": 0.6 14 | }, 15 | "ratsnest_display_mode": 0, 16 | "selection_filter": { 17 | "dimensions": true, 18 | "footprints": true, 19 | "graphics": true, 20 | "keepouts": true, 21 | "lockedItems": true, 22 | "otherItems": true, 23 | "pads": true, 24 | "text": true, 25 | "tracks": true, 26 | "vias": true, 27 | "zones": true 28 | }, 29 | "visible_items": [ 30 | 0, 31 | 1, 32 | 2, 33 | 3, 34 | 4, 35 | 5, 36 | 8, 37 | 9, 38 | 10, 39 | 11, 40 | 12, 41 | 13, 42 | 14, 43 | 15, 44 | 16, 45 | 17, 46 | 18, 47 | 19, 48 | 20, 49 | 21, 50 | 22, 51 | 23, 52 | 24, 53 | 25, 54 | 26, 55 | 27, 56 | 28, 57 | 29, 58 | 30, 59 | 32, 60 | 33, 61 | 34, 62 | 35, 63 | 36 64 | ], 65 | "visible_layers": "fffffff_ffffffff", 66 | "zone_display_mode": 0 67 | }, 68 | "meta": { 69 | "filename": "lora_tracker.kicad_prl", 70 | "version": 3 71 | }, 72 | "project": { 73 | "files": [] 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker.kicad_pro: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "design_settings": { 4 | "defaults": { 5 | "board_outline_line_width": 0.15, 6 | "copper_line_width": 0.19999999999999998, 7 | "copper_text_italic": false, 8 | "copper_text_size_h": 1.5, 9 | "copper_text_size_v": 1.5, 10 | "copper_text_thickness": 0.3, 11 | "copper_text_upright": false, 12 | "courtyard_line_width": 0.049999999999999996, 13 | "dimension_precision": 4, 14 | "dimension_units": 3, 15 | "dimensions": { 16 | "arrow_length": 1270000, 17 | "extension_offset": 500000, 18 | "keep_text_aligned": true, 19 | "suppress_zeroes": false, 20 | "text_position": 0, 21 | "units_format": 1 22 | }, 23 | "fab_line_width": 0.09999999999999999, 24 | "fab_text_italic": false, 25 | "fab_text_size_h": 1.0, 26 | "fab_text_size_v": 1.0, 27 | "fab_text_thickness": 0.15, 28 | "fab_text_upright": false, 29 | "other_line_width": 0.09999999999999999, 30 | "other_text_italic": false, 31 | "other_text_size_h": 1.0, 32 | "other_text_size_v": 1.0, 33 | "other_text_thickness": 0.15, 34 | "other_text_upright": false, 35 | "pads": { 36 | "drill": 1.3, 37 | "height": 2.2, 38 | "width": 2.2 39 | }, 40 | "silk_line_width": 0.15, 41 | "silk_text_italic": false, 42 | "silk_text_size_h": 1.0, 43 | "silk_text_size_v": 1.0, 44 | "silk_text_thickness": 0.15, 45 | "silk_text_upright": false, 46 | "zones": { 47 | "45_degree_only": false, 48 | "min_clearance": 0.508 49 | } 50 | }, 51 | "diff_pair_dimensions": [ 52 | { 53 | "gap": 0.0, 54 | "via_gap": 0.0, 55 | "width": 0.0 56 | } 57 | ], 58 | "drc_exclusions": [], 59 | "meta": { 60 | "filename": "board_design_settings.json", 61 | "version": 2 62 | }, 63 | "rule_severities": { 64 | "annular_width": "error", 65 | "clearance": "error", 66 | "copper_edge_clearance": "error", 67 | "courtyards_overlap": "error", 68 | "diff_pair_gap_out_of_range": "error", 69 | "diff_pair_uncoupled_length_too_long": "error", 70 | "drill_out_of_range": "error", 71 | "duplicate_footprints": "warning", 72 | "extra_footprint": "warning", 73 | "footprint_type_mismatch": "error", 74 | "hole_clearance": "error", 75 | "hole_near_hole": "error", 76 | "invalid_outline": "error", 77 | "item_on_disabled_layer": "error", 78 | "items_not_allowed": "error", 79 | "length_out_of_range": "error", 80 | "malformed_courtyard": "error", 81 | "microvia_drill_out_of_range": "error", 82 | "missing_courtyard": "ignore", 83 | "missing_footprint": "warning", 84 | "net_conflict": "warning", 85 | "npth_inside_courtyard": "ignore", 86 | "padstack": "error", 87 | "pth_inside_courtyard": "ignore", 88 | "shorting_items": "error", 89 | "silk_over_copper": "warning", 90 | "silk_overlap": "warning", 91 | "skew_out_of_range": "error", 92 | "through_hole_pad_without_hole": "error", 93 | "too_many_vias": "error", 94 | "track_dangling": "warning", 95 | "track_width": "error", 96 | "tracks_crossing": "error", 97 | "unconnected_items": "error", 98 | "unresolved_variable": "error", 99 | "via_dangling": "warning", 100 | "zone_has_empty_net": "error", 101 | "zones_intersect": "error" 102 | }, 103 | "rules": { 104 | "allow_blind_buried_vias": false, 105 | "allow_microvias": false, 106 | "max_error": 0.005, 107 | "min_clearance": 0.0, 108 | "min_copper_edge_clearance": 0.09999999999999999, 109 | "min_hole_clearance": 0.25, 110 | "min_hole_to_hole": 0.25, 111 | "min_microvia_diameter": 0.19999999999999998, 112 | "min_microvia_drill": 0.09999999999999999, 113 | "min_silk_clearance": 0.0, 114 | "min_through_hole_diameter": 0.3, 115 | "min_track_width": 0.19999999999999998, 116 | "min_via_annular_width": 0.049999999999999996, 117 | "min_via_diameter": 0.39999999999999997, 118 | "use_height_for_length_calcs": true 119 | }, 120 | "track_widths": [ 121 | 0.0 122 | ], 123 | "via_dimensions": [ 124 | { 125 | "diameter": 0.0, 126 | "drill": 0.0 127 | } 128 | ], 129 | "zones_allow_external_fillets": false, 130 | "zones_use_no_outline": true 131 | }, 132 | "layer_presets": [] 133 | }, 134 | "boards": [], 135 | "cvpcb": { 136 | "equivalence_files": [] 137 | }, 138 | "erc": { 139 | "erc_exclusions": [], 140 | "meta": { 141 | "version": 0 142 | }, 143 | "pin_map": [ 144 | [ 145 | 0, 146 | 0, 147 | 0, 148 | 0, 149 | 0, 150 | 0, 151 | 1, 152 | 0, 153 | 0, 154 | 0, 155 | 0, 156 | 2 157 | ], 158 | [ 159 | 0, 160 | 2, 161 | 0, 162 | 1, 163 | 0, 164 | 0, 165 | 1, 166 | 0, 167 | 2, 168 | 2, 169 | 2, 170 | 2 171 | ], 172 | [ 173 | 0, 174 | 0, 175 | 0, 176 | 0, 177 | 0, 178 | 0, 179 | 1, 180 | 0, 181 | 1, 182 | 0, 183 | 1, 184 | 2 185 | ], 186 | [ 187 | 0, 188 | 1, 189 | 0, 190 | 0, 191 | 0, 192 | 0, 193 | 1, 194 | 1, 195 | 2, 196 | 1, 197 | 1, 198 | 2 199 | ], 200 | [ 201 | 0, 202 | 0, 203 | 0, 204 | 0, 205 | 0, 206 | 0, 207 | 1, 208 | 0, 209 | 0, 210 | 0, 211 | 0, 212 | 2 213 | ], 214 | [ 215 | 0, 216 | 0, 217 | 0, 218 | 0, 219 | 0, 220 | 0, 221 | 0, 222 | 0, 223 | 0, 224 | 0, 225 | 0, 226 | 2 227 | ], 228 | [ 229 | 1, 230 | 1, 231 | 1, 232 | 1, 233 | 1, 234 | 0, 235 | 1, 236 | 1, 237 | 1, 238 | 1, 239 | 1, 240 | 2 241 | ], 242 | [ 243 | 0, 244 | 0, 245 | 0, 246 | 1, 247 | 0, 248 | 0, 249 | 1, 250 | 0, 251 | 0, 252 | 0, 253 | 0, 254 | 2 255 | ], 256 | [ 257 | 0, 258 | 2, 259 | 1, 260 | 2, 261 | 0, 262 | 0, 263 | 1, 264 | 0, 265 | 2, 266 | 2, 267 | 2, 268 | 2 269 | ], 270 | [ 271 | 0, 272 | 2, 273 | 0, 274 | 1, 275 | 0, 276 | 0, 277 | 1, 278 | 0, 279 | 2, 280 | 0, 281 | 0, 282 | 2 283 | ], 284 | [ 285 | 0, 286 | 2, 287 | 1, 288 | 1, 289 | 0, 290 | 0, 291 | 1, 292 | 0, 293 | 2, 294 | 0, 295 | 0, 296 | 2 297 | ], 298 | [ 299 | 2, 300 | 2, 301 | 2, 302 | 2, 303 | 2, 304 | 2, 305 | 2, 306 | 2, 307 | 2, 308 | 2, 309 | 2, 310 | 2 311 | ] 312 | ], 313 | "rule_severities": { 314 | "bus_definition_conflict": "error", 315 | "bus_entry_needed": "error", 316 | "bus_label_syntax": "error", 317 | "bus_to_bus_conflict": "error", 318 | "bus_to_net_conflict": "error", 319 | "different_unit_footprint": "error", 320 | "different_unit_net": "error", 321 | "duplicate_reference": "error", 322 | "duplicate_sheet_names": "error", 323 | "extra_units": "error", 324 | "global_label_dangling": "warning", 325 | "hier_label_mismatch": "error", 326 | "label_dangling": "error", 327 | "lib_symbol_issues": "warning", 328 | "multiple_net_names": "warning", 329 | "net_not_bus_member": "warning", 330 | "no_connect_connected": "warning", 331 | "no_connect_dangling": "warning", 332 | "pin_not_connected": "error", 333 | "pin_not_driven": "error", 334 | "pin_to_pin": "warning", 335 | "power_pin_not_driven": "error", 336 | "similar_labels": "warning", 337 | "unannotated": "error", 338 | "unit_value_mismatch": "error", 339 | "unresolved_variable": "error", 340 | "wire_dangling": "error" 341 | } 342 | }, 343 | "libraries": { 344 | "pinned_footprint_libs": [], 345 | "pinned_symbol_libs": [] 346 | }, 347 | "meta": { 348 | "filename": "lora_tracker.kicad_pro", 349 | "version": 1 350 | }, 351 | "net_settings": { 352 | "classes": [ 353 | { 354 | "bus_width": 12.0, 355 | "clearance": 0.2, 356 | "diff_pair_gap": 0.25, 357 | "diff_pair_via_gap": 0.25, 358 | "diff_pair_width": 0.2, 359 | "line_style": 0, 360 | "microvia_diameter": 0.3, 361 | "microvia_drill": 0.1, 362 | "name": "Default", 363 | "pcb_color": "rgba(0, 0, 0, 0.000)", 364 | "schematic_color": "rgba(0, 0, 0, 0.000)", 365 | "track_width": 0.25, 366 | "via_diameter": 0.8, 367 | "via_drill": 0.4, 368 | "wire_width": 6.0 369 | } 370 | ], 371 | "meta": { 372 | "version": 2 373 | }, 374 | "net_colors": null 375 | }, 376 | "pcbnew": { 377 | "last_paths": { 378 | "gencad": "", 379 | "idf": "", 380 | "netlist": "", 381 | "specctra_dsn": "", 382 | "step": "", 383 | "vrml": "" 384 | }, 385 | "page_layout_descr_file": "" 386 | }, 387 | "schematic": { 388 | "annotate_start_num": 0, 389 | "drawing": { 390 | "default_line_thickness": 6.0, 391 | "default_text_size": 50.0, 392 | "field_names": [], 393 | "intersheets_ref_own_page": false, 394 | "intersheets_ref_prefix": "", 395 | "intersheets_ref_short": false, 396 | "intersheets_ref_show": false, 397 | "intersheets_ref_suffix": "", 398 | "junction_size_choice": 3, 399 | "label_size_ratio": 0.25, 400 | "pin_symbol_size": 0.0, 401 | "text_offset_ratio": 0.08 402 | }, 403 | "legacy_lib_dir": "", 404 | "legacy_lib_list": [], 405 | "meta": { 406 | "version": 1 407 | }, 408 | "net_format_name": "Pcbnew", 409 | "ngspice": { 410 | "fix_include_paths": true, 411 | "fix_passive_vals": false, 412 | "meta": { 413 | "version": 0 414 | }, 415 | "model_mode": 0, 416 | "workbook_filename": "" 417 | }, 418 | "page_layout_descr_file": "", 419 | "plot_directory": "", 420 | "spice_adjust_passive_values": false, 421 | "spice_external_command": "spice \"%I\"", 422 | "subpart_first_id": 65, 423 | "subpart_id_separator": 0 424 | }, 425 | "sheets": [ 426 | [ 427 | "30151d3f-0370-46fd-a14d-d9f6ef15ba3b", 428 | "" 429 | ] 430 | ], 431 | "text_variables": {} 432 | } 433 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker.pretty/ATGM336H.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "ATGM336H" (version 20211014) (generator pcbnew) 2 | (layer "F.Cu") 3 | (tedit 0) 4 | (attr through_hole) 5 | (fp_text reference "REF**" (at -1.27 -0.23 unlocked) (layer "F.SilkS") 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | (tstamp 1f6477fb-45d3-4ecf-b791-e9339072e6ea) 8 | ) 9 | (fp_text value "ATGM336H" (at -1.27 1.27 unlocked) (layer "F.Fab") 10 | (effects (font (size 1 1) (thickness 0.15))) 11 | (tstamp 1bd47e4a-5b19-4051-81ae-385ca2770522) 12 | ) 13 | (fp_rect (start -10.16 3.81) (end 6.35 16.51) (layer "F.SilkS") (width 0.15) (fill none) (tstamp 5422b73a-e488-4813-9bf8-3779235a35ee)) 14 | (pad "1" thru_hole circle (at 5.08 5.08) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 8231c3d3-5689-446b-8d6c-332cb66ef452)) 15 | (pad "2" thru_hole circle (at 5.08 7.62) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 1c9a2115-e244-40e7-a4a7-ec8534b24156)) 16 | (pad "3" thru_hole circle (at 5.08 10.16) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 565ef2eb-6b08-468c-bd3c-dd5bd9e1ffa3)) 17 | (pad "4" thru_hole circle (at 5.08 12.7) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 0a48bd86-d80a-4bf4-80fa-bbb135224abb)) 18 | (pad "5" thru_hole circle (at 5.08 15.24) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp e6030516-192d-4d86-b20e-7557ebee07f7)) 19 | ) 20 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker.pretty/E22-400M30S.kicad_mod: -------------------------------------------------------------------------------- 1 | (module E22-400M30S (layer F.Cu) (tedit 0) 2 | (fp_text reference U4 (at 12.266 19.62 -270) (layer F.Fab) 3 | (effects (font (size 0.77216 0.77216) (thickness 0.061772)) (justify left bottom)) 4 | ) 5 | (fp_text value E22-400M30S (at 0 0) (layer F.SilkS) hide 6 | (effects (font (size 1.27 1.27) (thickness 0.15)) (justify right top)) 7 | ) 8 | (fp_line (start -12 -19.25) (end 12 -19.25) (layer F.Fab) (width 0.127)) 9 | (fp_line (start 12 -19.25) (end 12 19.25) (layer F.Fab) (width 0.127)) 10 | (fp_line (start -12 -19.25) (end -12 19.25) (layer F.Fab) (width 0.127)) 11 | (fp_line (start -12 19.25) (end 12 19.25) (layer F.Fab) (width 0.127)) 12 | (fp_line (start -12 -15.1) (end -12 -19.3) (layer F.SilkS) (width 0.127)) 13 | (fp_line (start -12 -19.3) (end 12 -19.3) (layer F.SilkS) (width 0.127)) 14 | (fp_line (start 12 -19.3) (end 12 -15.1) (layer F.SilkS) (width 0.127)) 15 | (fp_line (start 12 -12.7) (end 12 -12.3) (layer F.SilkS) (width 0.127)) 16 | (fp_line (start 12 -10.2) (end 12 -9.8) (layer F.SilkS) (width 0.127)) 17 | (fp_line (start 12 -0.1) (end 12 0.3) (layer F.SilkS) (width 0.127)) 18 | (fp_line (start 12 2.5) (end 12 2.9) (layer F.SilkS) (width 0.127)) 19 | (fp_line (start 12 5) (end 12 5.4) (layer F.SilkS) (width 0.127)) 20 | (fp_line (start 12 7.6) (end 12 8) (layer F.SilkS) (width 0.127)) 21 | (fp_line (start 12 10.1) (end 12 10.5) (layer F.SilkS) (width 0.127)) 22 | (fp_line (start 12 12.7) (end 12 13.1) (layer F.SilkS) (width 0.127)) 23 | (fp_line (start 12 15.2) (end 12 15.6) (layer F.SilkS) (width 0.127)) 24 | (fp_line (start -12 15.2) (end -12 15.6) (layer F.SilkS) (width 0.127)) 25 | (fp_line (start -12 12.6) (end -12 13) (layer F.SilkS) (width 0.127)) 26 | (fp_line (start -12 10.1) (end -12 10.5) (layer F.SilkS) (width 0.127)) 27 | (fp_line (start -12 7.6) (end -12 8) (layer F.SilkS) (width 0.127)) 28 | (fp_line (start -12 5) (end -12 5.4) (layer F.SilkS) (width 0.127)) 29 | (fp_line (start -12 2.5) (end -12 2.9) (layer F.SilkS) (width 0.127)) 30 | (fp_line (start -12 -0.1) (end -12 0.3) (layer F.SilkS) (width 0.127)) 31 | (fp_line (start -12 -10.2) (end -12 -9.8) (layer F.SilkS) (width 0.127)) 32 | (fp_line (start -12 -12.7) (end -12 -12.3) (layer F.SilkS) (width 0.127)) 33 | (fp_line (start -12 -7.4) (end -12 -2.4) (layer F.SilkS) (width 0.127)) 34 | (fp_line (start 12 -7.4) (end 12 -2.4) (layer F.SilkS) (width 0.127)) 35 | (fp_line (start -12 18) (end -12 19.3) (layer F.SilkS) (width 0.127)) 36 | (fp_line (start -12 19.3) (end 12 19.3) (layer F.SilkS) (width 0.127)) 37 | (fp_line (start 12 19.3) (end 12 18) (layer F.SilkS) (width 0.127)) 38 | (pad 1 smd rect (at -12 -13.79 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 39 | (solder_mask_margin 0.1016)) 40 | (pad 2 smd rect (at -12 -11.25 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 41 | (solder_mask_margin 0.1016)) 42 | (pad 3 smd rect (at -12 -8.71 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 43 | (solder_mask_margin 0.1016)) 44 | (pad 4 smd rect (at -12 -1.11 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 45 | (solder_mask_margin 0.1016)) 46 | (pad 5 smd rect (at -12 1.43 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 47 | (solder_mask_margin 0.1016)) 48 | (pad 6 smd rect (at -12 3.97 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 49 | (solder_mask_margin 0.1016)) 50 | (pad 7 smd rect (at -12 6.51 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 51 | (solder_mask_margin 0.1016)) 52 | (pad 8 smd rect (at -12 9.05 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 53 | (solder_mask_margin 0.1016)) 54 | (pad 9 smd rect (at -12 11.59 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 55 | (solder_mask_margin 0.1016)) 56 | (pad 10 smd rect (at -12 14.13 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 57 | (solder_mask_margin 0.1016)) 58 | (pad 11 smd rect (at -12 16.67 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 59 | (solder_mask_margin 0.1016)) 60 | (pad 12 smd rect (at 12 16.67 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 61 | (solder_mask_margin 0.1016)) 62 | (pad 13 smd rect (at 12 14.13 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 63 | (solder_mask_margin 0.1016)) 64 | (pad 14 smd rect (at 12 11.59 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 65 | (solder_mask_margin 0.1016)) 66 | (pad 15 smd rect (at 12 9.05 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 67 | (solder_mask_margin 0.1016)) 68 | (pad 16 smd rect (at 12 6.51 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 69 | (solder_mask_margin 0.1016)) 70 | (pad 17 smd rect (at 12 3.97 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 71 | (solder_mask_margin 0.1016)) 72 | (pad 18 smd rect (at 12 1.43 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 73 | (solder_mask_margin 0.1016)) 74 | (pad 19 smd rect (at 12 -1.11 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 75 | (solder_mask_margin 0.1016)) 76 | (pad 20 smd rect (at 12 -8.71 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 77 | (solder_mask_margin 0.1016)) 78 | (pad 21 smd rect (at 12 -11.25 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 79 | (solder_mask_margin 0.1016)) 80 | (pad 22 smd rect (at 12 -13.79 90) (size 1.7 2.5) (layers F.Cu F.Paste F.Mask) 81 | (solder_mask_margin 0.1016)) 82 | ) 83 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker.pretty/MAX98357A.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "MAX98357A" (version 20211014) (generator pcbnew) 2 | (layer "F.Cu") 3 | (tedit 0) 4 | (attr through_hole) 5 | (fp_text reference "REF**" (at 0 -0.5 unlocked) (layer "F.SilkS") 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | (tstamp 8cb2ee70-4cbd-4f16-9ed1-3cc54deed5a0) 8 | ) 9 | (fp_text value "MAX98357A" (at 0 1 unlocked) (layer "F.Fab") 10 | (effects (font (size 1 1) (thickness 0.15))) 11 | (tstamp 4d8c3b6c-191b-462f-8b85-2b45335a7417) 12 | ) 13 | (fp_rect (start -8.89 21.59) (end 8.89 2.54) (layer "F.SilkS") (width 0.15) (fill none) (tstamp 66ff1785-5858-49c4-b6f3-652b5fe69e2e)) 14 | (pad "1" thru_hole circle (at -7.62 20.32) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 96b8a264-a9bc-4929-8dac-555652bd349e)) 15 | (pad "2" thru_hole circle (at -5.08 20.32) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp e0c47485-9e16-41ff-bb0a-09b5fb513432)) 16 | (pad "3" thru_hole circle (at -2.54 20.32) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp cae80281-31a4-4b5c-8110-1adedb946e4c)) 17 | (pad "4" thru_hole circle (at 0 20.32) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp faf047c4-9af7-4138-9428-9a7a63c7170a)) 18 | (pad "5" thru_hole circle (at 2.54 20.32) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 2fb66bf1-d553-4fec-8e35-a777b80e77e5)) 19 | (pad "6" thru_hole circle (at 5.08 20.32) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 1963db50-b134-4766-8b46-0c755cdd141d)) 20 | (pad "7" thru_hole circle (at 7.62 20.32) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 9afb7f0c-8e76-4da4-90dd-1114af707f3e)) 21 | (pad "8" thru_hole circle (at 1.905 6.985) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 51e0bd84-8c6a-4cb3-a19a-37032ee61bb3)) 22 | (pad "9" thru_hole circle (at -1.905 6.985) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 478fe9ee-6395-4fb0-93ee-a334a408bb4d)) 23 | ) 24 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker.pretty/SSD1306.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "SSD1306" (version 20211014) (generator pcbnew) 2 | (layer "F.Cu") 3 | (tedit 0) 4 | (attr smd) 5 | (fp_text reference "REF**" (at 0 -0.5 unlocked) (layer "F.SilkS") 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | (tstamp 0bbf0f24-ec11-461a-a751-23ef55b06de8) 8 | ) 9 | (fp_text value "SSD1306" (at 0 1 unlocked) (layer "F.Fab") 10 | (effects (font (size 1 1) (thickness 0.15))) 11 | (tstamp 55bacfeb-9de3-4552-a8cb-8ee56f081eec) 12 | ) 13 | (fp_rect (start -19.05 2.54) (end 19.05 15.24) (layer "F.SilkS") (width 0.15) (fill none) (tstamp 153f6f58-73f4-4cd8-bde0-844682dffdb4)) 14 | (pad "1" thru_hole rect (at -17.78 5.08) (size 2 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 95cc060f-e7fa-4471-9c5d-315a06a70451)) 15 | (pad "2" thru_hole rect (at -17.78 7.62) (size 2 1.254) (drill 0.9) (layers *.Cu *.Mask) (tstamp ddba0ff2-7851-40b6-b76e-b2126ad9c2f4)) 16 | (pad "3" thru_hole rect (at -17.78 10.16) (size 2 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 7b15ff0e-bd9a-4956-af11-9a45a57a75f0)) 17 | (pad "4" thru_hole rect (at -17.78 12.7) (size 2 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 8a57a4da-cf8c-4fe4-8d92-f1e6e8c9da2a)) 18 | ) 19 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker.pretty/ec11.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "ec11" (version 20211014) (generator pcbnew) 2 | (layer "F.Cu") 3 | (tedit 0) 4 | (attr through_hole) 5 | (fp_text reference "REF**" (at 0 -2.54 unlocked) (layer "F.SilkS") 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | (tstamp 39182712-afc3-479e-ad3e-dcc6226a381c) 8 | ) 9 | (fp_text value "ec11" (at 0 -1.27 unlocked) (layer "F.Fab") 10 | (effects (font (size 1 1) (thickness 0.15))) 11 | (tstamp 82b5a08f-e543-4dde-a8dd-3aaeeeefccc6) 12 | ) 13 | (fp_rect (start 2.54 0) (end -3.81 17.78) (layer "Dwgs.User") (width 0.12) (fill none) (tstamp 2d484def-8a6d-438b-8a70-cc5d28ad0f12)) 14 | (fp_rect (start -3.81 5.08) (end -19.05 12.7) (layer "Dwgs.User") (width 0.12) (fill none) (tstamp dd5d939f-879c-4123-9aa8-16cfb9d41426)) 15 | (pad "A" thru_hole circle (at -1.27 6.35) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 2b4240f6-a171-4bbe-bf3a-af5ec9767791)) 16 | (pad "B" thru_hole circle (at -1.27 11.43) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 08afac6a-f449-463b-a7c8-8ab3b4f71e95)) 17 | (pad "C" thru_hole circle (at -1.27 8.89) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 309fe8ba-7a81-44c7-ac6f-e02491348527)) 18 | (pad "MP" thru_hole rect (at 0 15.24) (size 3 2.5) (drill 2) (layers *.Cu *.Mask) (tstamp 52962ee2-6646-446f-8362-631916119a2c)) 19 | (pad "MP" thru_hole rect (at 0 2.54) (size 3 2.5) (drill 2) (layers *.Cu *.Mask) (tstamp e7c5ea19-d487-4ef6-be0d-19759a442b8c)) 20 | (pad "S1" thru_hole circle (at 1.27 11.43) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 80db1b5b-24ca-4d61-a847-0cefd9c54897)) 21 | (pad "S2" thru_hole circle (at 1.27 6.35) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 88ef2a3b-4c8a-4874-86a6-a6b364f08794)) 22 | ) 23 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker.pretty/esp32 devkit.kicad_mod: -------------------------------------------------------------------------------- 1 | (module "esp32 devkit" (layer F.Cu) (tedit 61967ABE) 2 | (fp_text reference REF** (at -11.43 -1.27) (layer F.SilkS) 3 | (effects (font (size 1 1) (thickness 0.15))) 4 | ) 5 | (fp_text value "esp32 devkit" (at -3.81 -3.04) (layer F.Fab) 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | ) 8 | (fp_line (start -13.97 50.8) (end -13.97 0) (layer F.SilkS) (width 0.15)) 9 | (fp_line (start 6.35 0) (end 6.35 50.8) (layer F.SilkS) (width 0.15)) 10 | (fp_line (start 6.35 0) (end -13.97 0) (layer F.SilkS) (width 0.15)) 11 | (fp_line (start 6.35 50.8) (end -13.97 50.8) (layer F.SilkS) (width 0.15)) 12 | (pad 1 thru_hole circle (at -15.24 2.54) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 13 | (pad 2 thru_hole circle (at -15.24 5.08) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 14 | (pad 3 thru_hole circle (at -15.24 7.62) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 15 | (pad 4 thru_hole circle (at -15.24 10.16) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 16 | (pad 5 thru_hole circle (at -15.24 12.7) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 17 | (pad 6 thru_hole circle (at -15.24 15.24) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 18 | (pad 7 thru_hole circle (at -15.24 17.78) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 19 | (pad 8 thru_hole circle (at -15.24 20.32) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 20 | (pad 9 thru_hole circle (at -15.24 22.86) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 21 | (pad 10 thru_hole circle (at -15.24 25.4) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 22 | (pad 11 thru_hole circle (at -15.24 27.94) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 23 | (pad 12 thru_hole circle (at -15.24 30.48) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 24 | (pad 13 thru_hole circle (at -15.24 33.02) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 25 | (pad 14 thru_hole circle (at -15.24 35.56) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 26 | (pad 15 thru_hole circle (at -15.24 38.1) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 27 | (pad 16 thru_hole circle (at -15.24 40.64) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 28 | (pad 17 thru_hole circle (at -15.24 43.18) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 29 | (pad 18 thru_hole circle (at -15.24 45.72) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 30 | (pad 19 thru_hole circle (at -15.24 48.26) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 31 | (pad 20 thru_hole circle (at 7.62 48.26) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 32 | (pad 21 thru_hole circle (at 7.62 45.72) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 33 | (pad 22 thru_hole circle (at 7.62 43.18) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 34 | (pad 23 thru_hole circle (at 7.62 40.64) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 35 | (pad 24 thru_hole circle (at 7.62 38.1) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 36 | (pad 25 thru_hole circle (at 7.62 35.56) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 37 | (pad 26 thru_hole circle (at 7.62 33.02) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 38 | (pad 27 thru_hole circle (at 7.62 30.48) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 39 | (pad 28 thru_hole circle (at 7.62 27.94) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 40 | (pad 29 thru_hole circle (at 7.62 25.4) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 41 | (pad 30 thru_hole circle (at 7.62 22.86) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 42 | (pad 31 thru_hole circle (at 7.62 20.32) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 43 | (pad 32 thru_hole circle (at 7.62 17.78) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 44 | (pad 33 thru_hole circle (at 7.62 15.24) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 45 | (pad 34 thru_hole circle (at 7.62 12.7) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 46 | (pad 35 thru_hole circle (at 7.62 10.16) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 47 | (pad 36 thru_hole circle (at 7.62 7.62) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 48 | (pad 37 thru_hole circle (at 7.62 5.08) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 49 | (pad 38 thru_hole circle (at 7.62 2.54) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 50 | ) 51 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker.pretty/esp32-devkit-narrow.kicad_mod: -------------------------------------------------------------------------------- 1 | (module esp32-devkit-narrow (layer F.Cu) (tedit 64160EBC) 2 | (fp_text reference REF** (at -11.43 -1.27) (layer F.SilkS) 3 | (effects (font (size 1 1) (thickness 0.15))) 4 | ) 5 | (fp_text value "esp32 devkit narrow" (at -3.81 -3.04) (layer F.Fab) 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | ) 8 | (fp_line (start -13.97 50.8) (end -13.97 0) (layer F.SilkS) (width 0.15)) 9 | (fp_line (start 6.35 0) (end 6.35 50.8) (layer F.SilkS) (width 0.15)) 10 | (fp_line (start 6.35 0) (end -13.97 0) (layer F.SilkS) (width 0.15)) 11 | (fp_line (start 6.35 50.8) (end -13.97 50.8) (layer F.SilkS) (width 0.15)) 12 | (pad 1 thru_hole circle (at -15.24 2.54) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 13 | (pad 2 thru_hole circle (at -15.24 5.08) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 14 | (pad 3 thru_hole circle (at -15.24 7.62) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 15 | (pad 4 thru_hole circle (at -15.24 10.16) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 16 | (pad 5 thru_hole circle (at -15.24 12.7) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 17 | (pad 6 thru_hole circle (at -15.24 15.24) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 18 | (pad 7 thru_hole circle (at -15.24 17.78) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 19 | (pad 8 thru_hole circle (at -15.24 20.32) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 20 | (pad 9 thru_hole circle (at -15.24 22.86) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 21 | (pad 10 thru_hole circle (at -15.24 25.4) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 22 | (pad 11 thru_hole circle (at -15.24 27.94) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 23 | (pad 12 thru_hole circle (at -15.24 30.48) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 24 | (pad 13 thru_hole circle (at -15.24 33.02) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 25 | (pad 14 thru_hole circle (at -15.24 35.56) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 26 | (pad 15 thru_hole circle (at -15.24 38.1) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 27 | (pad 16 thru_hole circle (at -15.24 40.64) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 28 | (pad 17 thru_hole circle (at -15.24 43.18) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 29 | (pad 18 thru_hole circle (at -15.24 45.72) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 30 | (pad 19 thru_hole circle (at -15.24 48.26) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 31 | (pad 20 thru_hole circle (at 7.62 48.26) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 32 | (pad 21 thru_hole circle (at 7.62 45.72) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 33 | (pad 22 thru_hole circle (at 7.62 43.18) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 34 | (pad 23 thru_hole circle (at 7.62 40.64) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 35 | (pad 24 thru_hole circle (at 7.62 38.1) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 36 | (pad 25 thru_hole circle (at 7.62 35.56) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 37 | (pad 26 thru_hole circle (at 7.62 33.02) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 38 | (pad 27 thru_hole circle (at 7.62 30.48) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 39 | (pad 28 thru_hole circle (at 7.62 27.94) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 40 | (pad 29 thru_hole circle (at 7.62 25.4) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 41 | (pad 30 thru_hole circle (at 7.62 22.86) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 42 | (pad 31 thru_hole circle (at 7.62 20.32) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 43 | (pad 32 thru_hole circle (at 7.62 17.78) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 44 | (pad 33 thru_hole circle (at 7.62 15.24) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 45 | (pad 34 thru_hole circle (at 7.62 12.7) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 46 | (pad 35 thru_hole circle (at 7.62 10.16) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 47 | (pad 36 thru_hole circle (at 7.62 7.62) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 48 | (pad 37 thru_hole circle (at 7.62 5.08) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 49 | (pad 38 thru_hole circle (at 7.62 2.54) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 50 | ) 51 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker.pretty/esp32-devkit-wide.kicad_mod: -------------------------------------------------------------------------------- 1 | (module esp32-devkit-wide (layer F.Cu) (tedit 64161444) 2 | (fp_text reference REF** (at -11.43 -1.27) (layer F.SilkS) 3 | (effects (font (size 1 1) (thickness 0.15))) 4 | ) 5 | (fp_text value "esp32 devkit wide" (at -1.27 -3.04) (layer F.Fab) 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | ) 8 | (fp_line (start -13.97 49.53) (end 6.35 49.53) (layer F.SilkS) (width 0.15)) 9 | (fp_line (start -13.97 46.99) (end -13.97 49.53) (layer F.SilkS) (width 0.15)) 10 | (fp_line (start 6.35 0) (end -13.97 0) (layer F.SilkS) (width 0.15)) 11 | (fp_line (start -13.97 0) (end -13.97 46.99) (layer F.SilkS) (width 0.15)) 12 | (fp_line (start 6.35 0) (end 8.89 0) (layer F.SilkS) (width 0.15)) 13 | (fp_line (start 8.89 0) (end 8.89 49.53) (layer F.SilkS) (width 0.15)) 14 | (fp_line (start 6.35 49.53) (end 8.89 49.53) (layer F.SilkS) (width 0.15)) 15 | (pad 1 thru_hole circle (at -15.24 2.54) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 16 | (pad 2 thru_hole circle (at -15.24 5.08) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 17 | (pad 3 thru_hole circle (at -15.24 7.62) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 18 | (pad 4 thru_hole circle (at -15.24 10.16) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 19 | (pad 5 thru_hole circle (at -15.24 12.7) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 20 | (pad 6 thru_hole circle (at -15.24 15.24) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 21 | (pad 7 thru_hole circle (at -15.24 17.78) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 22 | (pad 8 thru_hole circle (at -15.24 20.32) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 23 | (pad 9 thru_hole circle (at -15.24 22.86) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 24 | (pad 10 thru_hole circle (at -15.24 25.4) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 25 | (pad 11 thru_hole circle (at -15.24 27.94) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 26 | (pad 12 thru_hole circle (at -15.24 30.48) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 27 | (pad 13 thru_hole circle (at -15.24 33.02) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 28 | (pad 14 thru_hole circle (at -15.24 35.56) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 29 | (pad 15 thru_hole circle (at -15.24 38.1) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 30 | (pad 16 thru_hole circle (at -15.24 40.64) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 31 | (pad 17 thru_hole circle (at -15.24 43.18) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 32 | (pad 18 thru_hole circle (at -15.24 45.72) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 33 | (pad 20 thru_hole circle (at 10.16 48.26) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 34 | (pad 21 thru_hole circle (at 10.16 45.72) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 35 | (pad 22 thru_hole circle (at 10.16 43.18) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 36 | (pad 23 thru_hole circle (at 10.16 40.64) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 37 | (pad 24 thru_hole circle (at 10.16 38.1) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 38 | (pad 25 thru_hole circle (at 10.16 35.56) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 39 | (pad 26 thru_hole circle (at 10.16 33.02) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 40 | (pad 27 thru_hole circle (at 10.16 30.48) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 41 | (pad 28 thru_hole circle (at 10.16 27.94) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 42 | (pad 29 thru_hole circle (at 10.16 25.4) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 43 | (pad 30 thru_hole circle (at 10.16 22.86) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 44 | (pad 31 thru_hole circle (at 10.16 20.32) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 45 | (pad 32 thru_hole circle (at 10.16 17.78) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 46 | (pad 33 thru_hole circle (at 10.16 15.24) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 47 | (pad 34 thru_hole circle (at 10.16 12.7) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 48 | (pad 35 thru_hole circle (at 10.16 10.16) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 49 | (pad 36 thru_hole circle (at 10.16 7.62) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 50 | (pad 37 thru_hole circle (at 10.16 5.08) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 51 | (pad 19 thru_hole circle (at -15.24 48.26) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 52 | (pad 38 thru_hole circle (at 10.16 2.54) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 53 | ) 54 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker.pretty/esp32-devkit-wide_30pin.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "esp32-devkit-wide_30pin" (version 20211014) (generator pcbnew) 2 | (layer "F.Cu") 3 | (tedit 64161444) 4 | (attr through_hole) 5 | (fp_text reference "REF**" (at -11.43 -1.27) (layer "F.SilkS") 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | (tstamp f1cc7c04-5ff0-4ffd-a051-66b6c8e7309d) 8 | ) 9 | (fp_text value "esp32 devkit wide 30pin" (at -1.27 -3.04) (layer "F.Fab") 10 | (effects (font (size 1 1) (thickness 0.15))) 11 | (tstamp 3ef736f0-a3a5-4a8f-bd5d-99c69a1781f3) 12 | ) 13 | (fp_line (start 8.89 0) (end 8.89 40.64) (layer "F.SilkS") (width 0.15) (tstamp 049bee37-4604-46ef-9c41-c78646c9aa79)) 14 | (fp_line (start -13.97 0) (end -13.97 40.64) (layer "F.SilkS") (width 0.15) (tstamp 08a2874b-fcb1-42b2-9925-14672e12525b)) 15 | (fp_line (start 6.35 0) (end 8.89 0) (layer "F.SilkS") (width 0.15) (tstamp a3e0f25b-0a62-4052-9d99-936aa6887d7c)) 16 | (fp_line (start -13.97 40.64) (end 8.89 40.64) (layer "F.SilkS") (width 0.15) (tstamp c2974ede-db68-40e9-83bb-e46096ad6dbc)) 17 | (fp_line (start 6.35 0) (end -13.97 0) (layer "F.SilkS") (width 0.15) (tstamp ec9c3605-11d5-4f94-a3e9-cb4536d95a0e)) 18 | (pad "1" thru_hole circle (at -15.24 2.54) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp cc9e6d1a-dc04-44f8-a08c-4e97619cabf8)) 19 | (pad "2" thru_hole circle (at -15.24 5.08) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp f6c99f73-3c90-40ed-93a0-583455b20c18)) 20 | (pad "3" thru_hole circle (at -15.24 7.62) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp f7a0a19e-201b-4577-97f7-839966059c7c)) 21 | (pad "4" thru_hole circle (at -15.24 10.16) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp b64397cc-7542-4ff9-a3ed-cd8596a5045a)) 22 | (pad "5" thru_hole circle (at -15.24 12.7) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 9b544e94-c01c-4327-8db7-34e4723ca554)) 23 | (pad "6" thru_hole circle (at -15.24 15.24) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 951f6b27-ba6c-43de-90e4-c307cf698196)) 24 | (pad "7" thru_hole circle (at -15.24 17.78) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 92e9f2db-d586-4bb0-9d8a-3ed9e701d68c)) 25 | (pad "8" thru_hole circle (at -15.24 20.32) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 072f46c7-718b-4104-bf3b-7d3491ad4ff4)) 26 | (pad "9" thru_hole circle (at -15.24 22.86) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp abfba11f-4ecb-43e6-a743-e6c830b63136)) 27 | (pad "10" thru_hole circle (at -15.24 25.4) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp ad2e7043-1786-41c1-a608-bc83bc6009b0)) 28 | (pad "11" thru_hole circle (at -15.24 27.94) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 665abf37-d215-42a2-bf63-0a356240eed4)) 29 | (pad "12" thru_hole circle (at -15.24 30.48) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp d025a462-e603-468f-ace3-246c0d0a39c7)) 30 | (pad "13" thru_hole circle (at -15.24 33.02) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 445e0dc9-0568-481a-af70-f9cd09356dff)) 31 | (pad "14" thru_hole circle (at -15.24 35.56) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 903f3900-cb86-4888-a871-7e9e6ae3cb4d)) 32 | (pad "15" thru_hole circle (at -15.24 38.1) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 1150c6f3-042e-4e5b-9945-f99122e844b9)) 33 | (pad "16" thru_hole circle (at 10.16 38.1) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp bf5f9dc9-21ce-4156-bd43-45955076a3d3)) 34 | (pad "17" thru_hole circle (at 10.16 35.56) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp da626b06-c533-4409-a5a4-c5d32b04355b)) 35 | (pad "18" thru_hole circle (at 10.16 33.02) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 09f1d8d1-5d26-47aa-bd4f-54f6e661f7b6)) 36 | (pad "19" thru_hole circle (at 10.16 30.48) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 66265d48-7efc-41ff-a36e-326d30e1aa0e)) 37 | (pad "20" thru_hole circle (at 10.16 27.94) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 83925b03-4aca-4df1-8454-548b820c0029)) 38 | (pad "21" thru_hole circle (at 10.16 25.4) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 49101ae2-dbcc-4d39-91da-13cbd5e8b327)) 39 | (pad "22" thru_hole circle (at 10.16 22.86) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp c73098d5-8e8f-4adf-bcb2-87e6359bac2b)) 40 | (pad "23" thru_hole circle (at 10.16 20.32) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 3e4c4523-bc89-4fc7-8b31-06d56562c464)) 41 | (pad "24" thru_hole circle (at 10.16 17.78) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp a6ac8ce3-0e02-40c3-bde3-3516bc3fb3aa)) 42 | (pad "25" thru_hole circle (at 10.16 15.24) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 262f6140-4b40-4998-a371-b2cc54a4d993)) 43 | (pad "26" thru_hole circle (at 10.16 12.7) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 59b81a06-7886-441b-aea5-706b5f816e7a)) 44 | (pad "27" thru_hole circle (at 10.16 10.16) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp ebc68fc0-3e9b-42b5-9d1b-15ca635ee864)) 45 | (pad "28" thru_hole circle (at 10.16 7.62) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp c2728234-4c22-44af-9673-785b8a5b877b)) 46 | (pad "29" thru_hole circle (at 10.16 5.08) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp ded032ec-746d-421d-b9aa-bdf38a1139c6)) 47 | (pad "30" thru_hole circle (at 10.16 2.54) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp adfd84ea-8cf2-4efb-84fc-7005d5b8546c)) 48 | ) 49 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker.pretty/inp441.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "inp441" (version 20211014) (generator pcbnew) 2 | (layer "F.Cu") 3 | (tedit 0) 4 | (attr smd) 5 | (fp_text reference "REF**" (at 1.27 -1.27 unlocked) (layer "F.SilkS") 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | (tstamp 9e7f9d68-c727-4b9e-a2a7-2efd70632de6) 8 | ) 9 | (fp_text value "inp441" (at 1.27 0 unlocked) (layer "F.Fab") 10 | (effects (font (size 1 1) (thickness 0.15))) 11 | (tstamp 0ab3971c-3753-4011-aac7-0cfe964be156) 12 | ) 13 | (fp_circle (center 1.27 7.62) (end 8.02 7.62) (layer "F.SilkS") (width 0.15) (fill none) (tstamp 4c904dde-5f65-4608-95d1-207c7e0564ca)) 14 | (pad "1" thru_hole circle (at -2.54 5.08) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp a8ebf39e-fd3b-4904-9ed0-2e7ce5bf2a95)) 15 | (pad "2" thru_hole circle (at -2.54 7.62) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 178bc297-f598-46fd-af3c-aae9904df6d5)) 16 | (pad "3" thru_hole circle (at -2.54 10.16) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp ef21f679-2e49-4ce6-9c28-bf31abea9d5d)) 17 | (pad "4" thru_hole circle (at 5.08 10.16) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 6df23fcd-1ece-4e66-83b3-b1d877b528b3)) 18 | (pad "5" thru_hole circle (at 5.08 7.62) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 1d73ca4a-ac2d-4a9d-a48d-4eacf83e98bb)) 19 | (pad "6" thru_hole circle (at 5.08 5.08) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp ca8b09a1-1363-4dc7-960d-7b9e2c543c3c)) 20 | ) 21 | -------------------------------------------------------------------------------- /extras/schematics/lora_tracker.pro: -------------------------------------------------------------------------------- 1 | update=Sat 18 Mar 2023 09:44:06 PM EET 2 | version=1 3 | last_client=kicad 4 | [general] 5 | version=1 6 | RootSch= 7 | BoardNm= 8 | [pcbnew] 9 | version=1 10 | LastNetListRead= 11 | UseCmpFile=1 12 | PadDrill=0.600000000000 13 | PadDrillOvalY=0.600000000000 14 | PadSizeH=1.500000000000 15 | PadSizeV=1.500000000000 16 | PcbTextSizeV=1.500000000000 17 | PcbTextSizeH=1.500000000000 18 | PcbTextThickness=0.300000000000 19 | ModuleTextSizeV=1.000000000000 20 | ModuleTextSizeH=1.000000000000 21 | ModuleTextSizeThickness=0.150000000000 22 | SolderMaskClearance=0.000000000000 23 | SolderMaskMinWidth=0.000000000000 24 | DrawSegmentWidth=0.200000000000 25 | BoardOutlineThickness=0.100000000000 26 | ModuleOutlineThickness=0.150000000000 27 | [cvpcb] 28 | version=1 29 | NetIExt=net 30 | [eeschema] 31 | version=1 32 | LibDir= 33 | [eeschema/libraries] 34 | [schematic_editor] 35 | version=1 36 | PageLayoutDescrFile= 37 | PlotDirectoryName= 38 | SubpartIdSeparator=0 39 | SubpartFirstId=65 40 | NetFmtName=Pcbnew 41 | SpiceAjustPassiveValues=0 42 | LabSize=50 43 | ERC_TestSimilarLabels=1 44 | -------------------------------------------------------------------------------- /extras/schematics/sym-lib-table: -------------------------------------------------------------------------------- 1 | (sym_lib_table 2 | (lib (name "lora_tracker")(type "KiCad")(uri "${KIPRJMOD}/lora_tracker.kicad_sym")(options "")(descr "")) 3 | (lib (name "lora_tracker-rescue")(type "KiCad")(uri "${KIPRJMOD}/lora_tracker-rescue.kicad_sym")(options "")(descr "")) 4 | ) 5 | -------------------------------------------------------------------------------- /include/audio/audio_codec.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIO_CODEC_H 2 | #define AUDIO_CODEC_H 3 | 4 | #include 5 | #include "settings/config.h" 6 | 7 | namespace LoraDv { 8 | 9 | class AudioCodec { 10 | 11 | public: 12 | virtual ~AudioCodec() = default; 13 | 14 | virtual bool start(std::shared_ptr config) = 0; 15 | virtual void stop() = 0; 16 | 17 | virtual int encode(uint8_t *encodedOut, int16_t *pcmIn) = 0; 18 | virtual int decode(int16_t *pcmOut, uint8_t *encodedIn, uint16_t encodedSize) = 0; 19 | 20 | virtual bool isFixedFrameSize() const = 0; 21 | 22 | virtual int getFrameSize() const = 0; 23 | virtual int getPcmFrameSize() const = 0; 24 | virtual int getPcmFrameBufferSize() const = 0; 25 | }; 26 | 27 | } // namespace LoraDv 28 | 29 | #endif // AUDIO_CODEC_H -------------------------------------------------------------------------------- /include/audio/audio_codec_codec2.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIO_CODEC2_H 2 | #define AUDIO_CODEC2_H 3 | 4 | #include "audio/audio_codec.h" 5 | 6 | namespace LoraDv { 7 | 8 | class AudioCodecCodec2 : public AudioCodec { 9 | 10 | public: 11 | AudioCodecCodec2(); 12 | 13 | virtual bool start(std::shared_ptr config) override; 14 | virtual void stop() override; 15 | 16 | virtual int encode(uint8_t *encodedOut, int16_t *pcmIn) override; 17 | virtual int decode(int16_t *pcmOut, uint8_t *encodedIn, uint16_t encodedSize) override; 18 | 19 | virtual bool isFixedFrameSize() const override { return true; } 20 | 21 | virtual int getFrameSize() const override; 22 | virtual int getPcmFrameSize() const override; 23 | virtual int getPcmFrameBufferSize() const override; 24 | 25 | private: 26 | struct CODEC2 *codec_; 27 | 28 | int codecSamplesPerFrame_; 29 | int codecBytesPerFrame_; 30 | }; 31 | 32 | } // namespace LoraDv 33 | 34 | #endif // AUDIO_CODEC2_H 35 | -------------------------------------------------------------------------------- /include/audio/audio_codec_opus.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIO_CODEC_OPUS_H 2 | #define AUDIO_CODEC_OPUS_H 3 | 4 | #include 5 | #include "audio/audio_codec.h" 6 | 7 | namespace LoraDv { 8 | 9 | class AudioCodecOpus : public AudioCodec { 10 | 11 | public: 12 | AudioCodecOpus(); 13 | 14 | virtual bool start(std::shared_ptr config) override; 15 | virtual void stop() override; 16 | 17 | virtual int encode(uint8_t *encodedOut, int16_t *pcmIn) override; 18 | virtual int decode(int16_t *pcmOut, uint8_t *encodedIn, uint16_t encodedSize) override; 19 | 20 | virtual bool isFixedFrameSize() const override { return false; } 21 | 22 | virtual int getFrameSize() const override { return encodedFrameBufferSize_; } 23 | virtual int getPcmFrameSize() const override { return pcmFrameSize_; }; 24 | virtual int getPcmFrameBufferSize() const override { return pcmFrameBufferSize_; }; 25 | 26 | private: 27 | const int CfgComplexity = 0; 28 | const int CfgEncodedFrameBufferSize = 1024; 29 | 30 | OpusEncoder *opusEncoder_; 31 | OpusDecoder *opusDecoder_; 32 | 33 | int pcmFrameSize_; 34 | int pcmFrameBufferSize_; 35 | int encodedFrameBufferSize_; 36 | }; 37 | 38 | } 39 | 40 | #endif // AUDIO_CODEC_OPUS_H -------------------------------------------------------------------------------- /include/audio/audio_task.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIO_TASK_H 2 | #define AUDIO_TASK_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "hal/radio_task.h" 9 | #include "settings/config.h" 10 | #include "hal/pm_service.h" 11 | #include "audio/audio_codec.h" 12 | #include "utils/dsp.h" 13 | 14 | namespace LoraDv { 15 | 16 | class RadioTask; 17 | 18 | class AudioTask { 19 | 20 | public: 21 | explicit AudioTask(std::shared_ptr config, std::shared_ptr pmService); 22 | 23 | void start(std::shared_ptr radioTask); 24 | inline void stop() { isRunning_ = false; } 25 | bool loop(); 26 | 27 | void play() const; 28 | bool isPlaying() const { return isPlaying_; } 29 | void record() const; 30 | 31 | void setPtt(bool isPttOn); 32 | 33 | inline void setVolume(int volume) { 34 | if (volume >= 0 && volume <= maxVolume_) { 35 | volume_ = volume; 36 | } 37 | } 38 | void changeVolume(int deltaVolume); 39 | inline int getVolume() const { return volume_; } 40 | 41 | private: 42 | static constexpr int CfgCoreId = 0; // core id where task will run 43 | static constexpr int CfgTaskPriority = 2; // task priority 44 | 45 | static constexpr i2s_port_t CfgAudioI2sSpkId = I2S_NUM_0; // audio i2s speaker number 46 | static constexpr i2s_port_t CfgAudioI2sMicId = I2S_NUM_1; // audio i2s mic number 47 | 48 | static constexpr uint32_t CfgAudioPlayBit = 0x01; // task bit for playback 49 | static constexpr uint32_t CfgAudioRecBit = 0x02; // task bit for recording 50 | 51 | static constexpr int CfgStartupDelayMs = 3000; // startup delay 52 | static constexpr int CfgAudioTaskStack = 32768; // audio stack size 53 | static constexpr int CfgPlayCompletedDelayMs = 500; // playback stopped status after ms 54 | static constexpr int CfgAudioMaxVolumePcmMultiplier = 10; // multipier to get max pcm volume from max control volume 55 | 56 | private: 57 | void installAudio(int bytesPerSample) const; 58 | void uninstallAudio() const; 59 | 60 | static void task(void *param); 61 | 62 | void audioTask(); 63 | void audioTaskPlay(); 64 | void audioTaskRecord(); 65 | 66 | void decodeAndPlay(int frameSize, int16_t targetLevel); 67 | int encodeAndQueue(int pcmFrameSize); 68 | 69 | void playTimerReset(); 70 | static bool playTimerEnter(void *param); 71 | void playTimer(); 72 | 73 | private: 74 | std::shared_ptr config_; 75 | TaskHandle_t audioTaskHandle_; 76 | 77 | std::shared_ptr radioTask_; 78 | std::shared_ptr pmService_; 79 | 80 | Timer<1> playTimer_; 81 | Timer<1>::Task playTimerTask_; 82 | 83 | std::shared_ptr dsp_; 84 | std::shared_ptr audioCodec_; 85 | 86 | int16_t *pcmFrameBuffer_; 87 | int16_t *pcmResampleBuffer_; 88 | uint8_t *encodedFrameBuffer_; 89 | 90 | int codecSamplesPerFrame_; 91 | int codecBytesPerFrame_; 92 | 93 | long volume_; 94 | long maxVolume_; 95 | 96 | volatile bool isPttOn_; 97 | volatile bool isRunning_; 98 | volatile bool shouldUpdateScreen_; 99 | volatile bool isPlaying_; 100 | }; 101 | 102 | } 103 | 104 | #endif // RADIO_TASK_H -------------------------------------------------------------------------------- /include/hal/hw_monitor.h: -------------------------------------------------------------------------------- 1 | #ifndef HW_MONITOR_H 2 | #define HW_MONITOR_H 3 | 4 | #include 5 | #include 6 | #include "settings/config.h" 7 | 8 | namespace LoraDv { 9 | 10 | class HwMonitor { 11 | 12 | public: 13 | HwMonitor(std::shared_ptr config); 14 | 15 | float getBatteryVoltage() const; 16 | 17 | private: 18 | std::shared_ptr config_; 19 | 20 | }; 21 | 22 | } // LoraDv 23 | 24 | #endif // HW_MONITOR_H -------------------------------------------------------------------------------- /include/hal/pm_service.h: -------------------------------------------------------------------------------- 1 | #ifndef PM_SERVICE_H 2 | #define PM_SERVICE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "settings/config.h" 10 | 11 | namespace LoraDv { 12 | 13 | class PmService { 14 | 15 | public: 16 | PmService(std::shared_ptr config, std::shared_ptr display); 17 | 18 | void setup(); 19 | bool loop(); 20 | 21 | void lightSleepReset(); 22 | 23 | private: 24 | static bool lightSleepEnterTimer(void *param); 25 | void lightSleepEnter(); 26 | esp_sleep_wakeup_cause_t lightSleepWait(uint64_t sleepTimeUs) const; 27 | 28 | private: 29 | std::shared_ptr config_; 30 | std::shared_ptr display_; 31 | 32 | Timer<1> lightSleepTimer_; 33 | Timer<1>::Task lightSleepTimerTask_; 34 | 35 | bool isExitFromSleep_; 36 | }; 37 | 38 | } // LoraDv 39 | 40 | #endif // PM_SERVICE_H -------------------------------------------------------------------------------- /include/hal/radio_task.h: -------------------------------------------------------------------------------- 1 | #ifndef RADIO_TASK_H 2 | #define RADIO_TASK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include "settings/config.h" 14 | #include "audio/audio_task.h" 15 | #include "utils/utils.h" 16 | #include "settings/settings_menu.h" 17 | 18 | namespace LoraDv { 19 | 20 | class AudioTask; 21 | 22 | class RadioTask { 23 | 24 | public: 25 | explicit RadioTask(std::shared_ptr config); 26 | 27 | void start(std::shared_ptr audioTask); 28 | inline void stop() { isRunning_ = false; } 29 | bool loop(); 30 | 31 | void setFreq(long freq) const; 32 | inline bool isHalfDuplex() const { return config_->LoraFreqTx != config_->LoraFreqRx; } 33 | inline float getRssi() const { return lastRssi_; } 34 | 35 | bool hasData() const; 36 | bool readPacketSize(byte &packetSize); 37 | bool readNextByte(byte &b); 38 | 39 | void transmit() const; 40 | void startTransmit() const; 41 | void startReceive() const; 42 | 43 | bool writePacketSize(byte packetSize); 44 | bool writeNextByte(byte b); 45 | 46 | private: 47 | static constexpr int CfgCoreId = 1; // core id where task will run 48 | static constexpr int CfgTaskPriority = 2; // task priority 49 | 50 | static constexpr int CfgRadioQueueLen = 512; // circular buffer length 51 | static constexpr int CfgRadioPacketBufLen = 256; // packet buffer length 52 | 53 | static constexpr uint32_t CfgRadioRxBit = 0x01; // task bit for rx 54 | static constexpr uint32_t CfgRadioTxBit = 0x02; // task bit for tx 55 | static constexpr uint32_t CfgRadioRxStartBit = 0x04; // task bit for start rx 56 | static constexpr uint32_t CfgRadioTxStartBit = 0x10; // task bit for start tx 57 | 58 | static constexpr int CfgRadioTaskStack = 4096; // task stack size 59 | static constexpr size_t CfgIvSize = 12; // IV/nonce, initialization vector size 60 | static constexpr size_t CfgAuthTagSize = 16; // auth tag size 61 | 62 | private: 63 | void setupRig(long freq, long bw, int sf, int cr, int pwr, int sync, int crcBytes); 64 | void setupRigFsk(long freq, float bitRate, float freqDev, float rxBw, int pwr, byte shaping); 65 | 66 | static IRAM_ATTR void onRigIsrRxPacket(); 67 | 68 | static void task(void *param); 69 | 70 | void rigTask(); 71 | void rigTaskReceive(byte *packetBuf, byte *tmpBuf); 72 | void rigTaskTransmit(byte *packetBuf, byte *tmpBuf); 73 | void rigTaskStartReceive(); 74 | void rigTaskStartTransmit(); 75 | 76 | void encryptPacket(byte *inBuf, byte *outBuf, int inBufSize, int& outBufSize); 77 | bool decryptPacket(byte *inBuf, byte *outBuf, int inBufSize, int& outBufSize); 78 | private: 79 | std::shared_ptr config_; 80 | 81 | std::shared_ptr radioModule_; 82 | std::shared_ptr audioTask_; 83 | 84 | std::shared_ptr cipher_; 85 | 86 | static TaskHandle_t loraTaskHandle_; 87 | 88 | struct RadioQueue { 89 | CircularBuffer data; 90 | CircularBuffer index; 91 | }; 92 | 93 | RadioQueue radioRxQueue_; 94 | RadioQueue radioTxQueue_; 95 | 96 | bool isImplicitMode_; 97 | bool isIsrInstalled_; 98 | static volatile bool isIsrEnabled_; 99 | volatile bool isRunning_; 100 | volatile bool shouldUpdateScreen_; 101 | float lastRssi_; 102 | }; 103 | 104 | } 105 | 106 | #endif // RADIO_TASK_H -------------------------------------------------------------------------------- /include/service.h: -------------------------------------------------------------------------------- 1 | #ifndef LORADV_SERVICE_H 2 | #define LORADV_SERVICE_H 3 | 4 | #include 5 | #include 6 | #define DEBUGLOG_DEFAULT_LOG_LEVEL_INFO 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "settings/config.h" 20 | #include "hal/radio_task.h" 21 | #include "audio/audio_task.h" 22 | #include "hal/pm_service.h" 23 | #include "hal/hw_monitor.h" 24 | #include "settings/settings_menu.h" 25 | 26 | namespace LoraDv { 27 | 28 | class Service { 29 | 30 | public: 31 | Service(std::shared_ptr conf); 32 | 33 | void setup(); 34 | void loop(); 35 | 36 | private: 37 | static constexpr int CfgDisplayWidth = 128; // display width 38 | static constexpr int CfgDisplayHeight = 32; // display height 39 | 40 | static constexpr int CfgEncoderBtnLongMs = 2000; // encoder long button press 41 | 42 | private: 43 | void setupEncoder(); 44 | void setupScreen(); 45 | void setupPttButton(); 46 | 47 | static IRAM_ATTR void isrReadEncoder(); 48 | 49 | void updateScreen() const; 50 | 51 | bool processPttButton(); 52 | bool processRotaryEncoder(); 53 | 54 | private: 55 | std::shared_ptr config_; 56 | 57 | std::shared_ptr display_; 58 | static std::shared_ptr rotaryEncoder_; 59 | 60 | std::shared_ptr pmService_; 61 | std::shared_ptr hwMonitor_; 62 | 63 | std::shared_ptr radioTask_; 64 | std::shared_ptr audioTask_; 65 | 66 | std::shared_ptr settingsMenu_; 67 | 68 | // other 69 | volatile bool btnPressed_; 70 | 71 | }; // Service 72 | 73 | } // LoraDv 74 | 75 | #endif // LORADV_SERVICE_H -------------------------------------------------------------------------------- /include/settings/config.h: -------------------------------------------------------------------------------- 1 | #ifndef LORADV_CONFIG_H 2 | #define LORADV_CONFIG_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "version.h" 9 | 10 | #if __has_include("/tmp/esp32_loradv_default_config.h") 11 | #pragma message("Using external config") 12 | #include "/tmp/esp32_loradv_default_config.h" 13 | #else 14 | #pragma message("Using default built-in config") 15 | #include "settings/default_config.h" 16 | #endif 17 | 18 | namespace LoraDv { 19 | 20 | class Config { 21 | public: 22 | int Version; // config version 23 | 24 | DebugLogLevel LogLevel; // log level 25 | 26 | // modulation type 27 | int ModType; // 0 - lora, 1 - fsk 28 | 29 | // lora modulation parameters 30 | long LoraFreqRx; // lora RX frequency, e.g. 433.775e6 31 | long LoraFreqTx; // lora TX frequency, e.g. 433.775e6 32 | long LoraFreqStep; // lora frequency step 33 | long LoraBw; // lora bandwidth, e.g. 125e3 34 | int LoraSf; // lora spreading factor, e.g. 12 35 | int LoraCodingRate; // lora coding rate, e.g. 7 36 | int LoraPower; // lora power level in dbm, 20 37 | int LoraSync_; // lora sync word/packet id, 0x34 38 | int LoraCrc_; // lora crc mode, 0 - disabled, 1 - 1 byte, 2 - 2 bytes 39 | int LoraPreambleLen_; // lora preamble length from 6 to 65535 40 | 41 | // fsk modulation parameters 42 | float FskBitRate; // fsk bit rate, 0.6 - 300.0 Kbps 43 | float FskFreqDev; // fsk frequency deviation 0.6 - 200 kHz 44 | float FskRxBw; // fsk rx bandwidth, discrete from 4.8 to 467 kHz 45 | byte FskShaping; // fsk gaussian shaping 46 | 47 | // lora hardware pinouts and isr 48 | byte LoraPinSs_; // lora ss pin 49 | byte LoraPinRst_; // lora rst pin 50 | byte LoraPinA_; // (sx127x - dio0, sx126x/sx128x - dio1) 51 | byte LoraPinB_; // (sx127x - dio1, sx126x/sx128x - busy) 52 | byte LoraPinSwitchRx_; // (sx127x - unused, sx126x - RXEN pin number) 53 | byte LoraPinSwitchTx_; // (sx127x - unused, sx126x - TXEN pin number) 54 | 55 | // rotary encoder 56 | byte EncoderPinA_; // Encoder A pin number 57 | byte EncoderPinB_; // Encoder B pin number 58 | byte EncoderPinBtn_; // Encoder button pin number 59 | byte EncoderPinVcc_; // Encoder VCC pin (or -1 if not connected) 60 | byte EncoderSteps_; // Encoder number of steps 61 | 62 | // audio params 63 | int AudioCodec; // type of audio codec, 0 - Codec2, 1 - OPUS 64 | int AudioResampleCoeff_; // resample coefficient when audio rate is not equal code rate 65 | uint32_t AudioSampleRate_; // sample rate for mic and speaker 66 | uint32_t AudioCodecSampleRate_; // sammple rate for codec 67 | int AudioHpfCutoffHz_; // high pass fitler cutoff frequency 68 | 69 | // codec2 70 | int AudioCodec2Mode; // Audio Codec2 mode 71 | int AudioMaxPktSize; // Aggregated packet maximum size 72 | 73 | // audio opus 74 | int AudioOpusRate; // opus bit rate 2.4 - 512 kbps 75 | float AudioOpusPcmLen; // opus pcm frame length, 2.5, 5, 10, 20, 40, 60, 80, 100, 120 ms 76 | 77 | // i2s speaker 78 | byte AudioSpkPinBclk_; // Speaker i2s clk pin 79 | byte AudioSpkPinLrc_; // Speaker i2s lrc pin 80 | byte AudioSpkPinDin_; // Speaker i2s din pin 81 | 82 | // i2s mic 83 | byte AudioMicPinSd_; // Mic i2s sd pin 84 | byte AudioMicPinWs_; // Mic i2s ws pin 85 | byte AudioMicPinSck_; // Mic i2s sck pin 86 | 87 | // audio state 88 | int AudioMaxVol_; // maximum volume 89 | int AudioVol; // current volume 90 | 91 | // privacy 92 | bool AudioEnPriv; // enable/disable privacy 93 | byte AudioPrivacyKey_[32]; // privacy key 94 | 95 | // battery monitor 96 | byte BatteryMonPin_; // Battery monitor adc pin 97 | float BatteryMonCal; // Battery monitor calibrarion value 98 | 99 | // power management 100 | int PmSleepAfterMs; // Light sleep activation after given ms 101 | int PmLightSleepDurationMs_; // How long to sleep 102 | int PmLightSleepAwakeMs_; // How long to be active 103 | 104 | // ptt button 105 | int PttBtnPin_; // ptt pin 106 | 107 | public: 108 | Config(); 109 | void Load(); 110 | void Save(); 111 | void Reset(); 112 | 113 | private: 114 | void InitializeDefault(); 115 | 116 | Preferences prefs_; 117 | 118 | }; // Config 119 | 120 | } // LoraDv 121 | 122 | #endif // LORADV_CONFIG_H -------------------------------------------------------------------------------- /include/settings/default_config.h: -------------------------------------------------------------------------------- 1 | #ifndef DEFAULT_CONFIG_H 2 | #define DEFAULT_CONFIG_H 3 | 4 | #include 5 | #include 6 | 7 | // saved settings version, increment to load new settings 8 | #define CFG_VERSION 10 9 | 10 | // Comment out for SX127X module usage, passed from platform.io 11 | //#define USE_SX126X 12 | 13 | // Check your module name at https://github.com/jgromes/RadioLib/wiki/Modules 14 | #ifdef USE_SX126X 15 | #define MODULE_NAME SX1268 16 | #else 17 | #define MODULE_NAME SX1278 18 | #endif 19 | 20 | #define SERIAL_BAUD_RATE 115200 // USB serial baud rate 21 | 22 | // USB serial logging 23 | // set to DebugLogLevel::LVL_TRACE for packet logging 24 | // set to DebugLogLevel::LVL_NONE to disable logging 25 | #define CFG_LOG_LEVEL DebugLogLevel::LVL_INFO 26 | 27 | // change pinouts if not defined through native board LORA_* definitions 28 | #ifndef LORA_RST 29 | #pragma message("LoRa pin definitions are not found, redefining...") 30 | #define LORA_RST 26 31 | #define LORA_IRQ 12 32 | #endif 33 | 34 | // modulation 35 | #define CFG_MOD_TYPE_LORA 0 36 | #define CFG_MOD_TYPE_FSK 1 37 | #define CFG_MOD_TYPE CFG_MOD_TYPE_LORA 38 | 39 | // LoRa pinouts 40 | #define CFG_LORA_PIN_SS SS 41 | #define CFG_LORA_PIN_RST LORA_RST 42 | #define CFG_LORA_PIN_A LORA_IRQ // (sx127x - dio0, sx126x/sx128x - dio1) 43 | #ifdef USE_SX126X 44 | #define CFG_LORA_PIN_B 14 // (sx127x - dio1, sx126x/sx128x - busy) 45 | #define CFG_LORA_PIN_RXEN 32 // (sx127x - unused, sx126x - RXEN pin number) 46 | #define CFG_LORA_PIN_TXEN 33 // (sx127x - unused, sx126x - TXEN pin number) 47 | #else 48 | #define CFG_LORA_PIN_B RADIOLIB_NC // (sx127x - dio1, sx126x/sx128x - busy) 49 | #define CFG_LORA_PIN_RXEN RADIOLIB_NC // (sx127x - unused, sx126x - RXEN pin number) 50 | #define CFG_LORA_PIN_TXEN RADIOLIB_NC // (sx127x - unused, sx126x - TXEN pin number) 51 | #endif 52 | 53 | // generic - frequencies, tune step, power 54 | #define CFG_LORA_FREQ_RX 433.775e6 // RX frequency in MHz 55 | #define CFG_LORA_FREQ_TX 433.775e6 // TX frequency in MHz 56 | #define CFG_LORA_FREQ_STEP 25e3 // frquency step 57 | #define CFG_LORA_PWR 2 // output power in dBm (sx1268 with amplifier + 12 dbm) 58 | 59 | // LoRa protocol default parameters (they need to match between devices!!!) 60 | #define CFG_LORA_BW 31.25e3 // discreate bandwidth (from 7.8 kHz up to 500 kHz) 61 | #define CFG_LORA_SF 7 // spreading factor (6 - 12), 6 requires implicit header mode 62 | #define CFG_LORA_CR 5 // coding rate (5 - 8) 63 | #define CFG_LORA_CRC 1 // 0 - disabled, 1 - 1 byte, 2 - 2 bytes 64 | #define CFG_LORA_SYNC 0x12 // sync word (0x12 - private used by other trackers, 0x34 - public used by LoRaWAN) 65 | #define CFG_LORA_PREAMBLE_LEN 8 // preamble length from 6 to 65535 66 | 67 | // fsk modem default parameters (they need to match between devices!!!) 68 | #define CFG_FSK_BIT_RATE 4.8 // bit rate in Kbps from 0.6 to 300.0 69 | #define CFG_FSK_FREQ_DEV 1.2 // frequency deviation in kHz from 0.6 to 200.0 70 | #define CFG_FSK_RX_BW 9.7 // rx bandwidth in kHz discrete from 4.8 to 467.0 71 | #define CFG_FSK_SHAPING RADIOLIB_SHAPING_NONE 72 | 73 | // ptt button 74 | #define CFG_PTT_BTN_PIN 39 // pin for ptt button 75 | 76 | // rotary encoder 77 | #define CFG_ENCODER_PIN_A 17 78 | #define CFG_ENCODER_PIN_B 16 79 | #define CFG_ENCODER_PIN_BTN 34 80 | #define CFG_ENCODER_PIN_VCC -1 81 | #define CFG_ENCODER_STEPS 4 82 | 83 | // i2s speaker 84 | #define CFG_AUDIO_SPK_PIN_BCLK 26 85 | #define CFG_AUDIO_SPK_PIN_LRC 13 86 | #define CFG_AUDIO_SPK_PIN_DIN 25 87 | 88 | // i2s mic 89 | #define CFG_AUDIO_MIC_PIN_SD 2 90 | #define CFG_AUDIO_MIC_PIN_WS 15 91 | #define CFG_AUDIO_MIC_PIN_SCK 4 92 | 93 | // battery monitor 94 | #define CFG_AUDIO_BATTERY_MON_PIN 36 95 | #define CFG_AUDIO_BATTERY_MON_CAL 0.25f 96 | 97 | // power management 98 | #define CFG_PM_LSLEEP_AFTER_MS 60000 // how long to wait before going to sleep 99 | #define CFG_PM_LSLEEP_DURATION_MS 3000 // light sleep duration for polling 100 | #define CFG_PM_LSLEEP_AWAKE_MS 100 // how long to be awake in light sleep polling 101 | 102 | // audio 103 | #define CFG_AUDIO_CODEC_CODEC2 0 104 | #define CFG_AUDIO_CODEC_OPUS 1 105 | #define CFG_AUDIO_CODEC CFG_AUDIO_CODEC_CODEC2 106 | #define CFG_AUDIO_SAMPLE_RATE 16000 // 8000 or 16000, i2s mic/spk have poor quality at 8000 107 | #define CFG_AUDIO_CODEC_SAMPLE_RATE 8000 // 8000 108 | #define CFG_AUDIO_RESAMPLE_COEFF 2 // 1 or 2 only 109 | #define CFG_AUDIO_HPF_CUTOFF_HZ 30 // high pass filter cutoff frequency 110 | #define CFG_AUDIO_CODEC2_MODE CODEC2_MODE_1600 111 | #define CFG_AUDIO_MAX_PKT_SIZE 48 // maximum super frame size 112 | #define CFG_AUDIO_MAX_VOL 30 // maximum volume 113 | #define CFG_AUDIO_VOL 10 // default volume 114 | 115 | // audio, opus 116 | #define CFG_AUDIO_OPUS_BITRATE 3200 117 | #define CFG_AUDIO_OPUS_PCMLEN 120 118 | 119 | // audio, experimental 120 | #define CFG_AUDIO_ENABLE_PRIVACY false 121 | 122 | // keys must be randomly generated using true random generator and re-generated as often as possible 123 | #define CFG_AUDIO_PRIVACY_KEY \ 124 | byte AudioPrivacyKey[32] = {0xe7,0x5c,0xf0,0x43,0x80,0xec,0x45,0x93,0xe8,0x3b,0xfb,0x72,0x22,0x40,0x19,0x57,\ 125 | 0x6c,0xde,0x05,0x00,0xff,0x88,0x12,0x42,0x20,0xf2,0x89,0x9d,0x7f,0x57,0xee,0xd6} 126 | #endif // DEFAULT_CONFIG_H -------------------------------------------------------------------------------- /include/settings/settings_menu.h: -------------------------------------------------------------------------------- 1 | #ifndef SETTINGS_MENU_H 2 | #define SETTINGS_MENU_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "settings/config.h" 13 | #include "settings/settings_menu_item.h" 14 | #include "hal/radio_task.h" 15 | #include "utils/utils.h" 16 | 17 | using namespace std; 18 | 19 | namespace LoraDv { 20 | 21 | class SettingsMenu { 22 | public: 23 | SettingsMenu(std::shared_ptr config); 24 | 25 | void draw(std::shared_ptr display); 26 | 27 | void onEncoderPositionChanged(int delta); 28 | void onEncoderButtonClicked(); 29 | 30 | private: 31 | bool isValueSelected_; 32 | int selectedMenuItemIndex_; 33 | std::shared_ptr config_; 34 | std::vector> items_; // Updated type 35 | }; 36 | 37 | } // LoraDv 38 | 39 | #endif // SETTINGS_MENU_H -------------------------------------------------------------------------------- /include/utils/dsp.h: -------------------------------------------------------------------------------- 1 | #ifndef DSP_H 2 | #define DSP_H 3 | 4 | #include 5 | 6 | namespace LoraDv { 7 | 8 | class Dsp { 9 | 10 | public: 11 | explicit Dsp(int hpfCutoffFreqHz, int hpfSampleRate); 12 | 13 | int audioDownsample2x(int16_t *pcmInput, int16_t *pcmOutput, int pcmInputSize); 14 | int audioUpsample2x(int16_t *pcmInput, int16_t *pcmOutput, int pcmInputSize); 15 | 16 | void audioAdjustGain(int16_t *pcmBuffer, int inputSize, float gain); 17 | void audioAdjustGainAgc(int16_t *pcmBuffer, int inputSize, int16_t targetLevel); 18 | 19 | void audioFilterHpf(int16_t *pcmBuffer, int pcmBufferSize); 20 | 21 | int16_t audioVolumeToLogPcm(int volume, int maxVolume, int maxPcmValue); 22 | 23 | private: 24 | // AGC configuration 25 | static constexpr float CfgAgcMaxGain = 20.0; 26 | static constexpr float CfgAgcMinGain = 0.1; 27 | static constexpr float CfgAgcStep = 0.1; 28 | 29 | // agc 30 | float currentAgcGain_; 31 | 32 | // high pass filter 33 | float hpfX1_, hpfX2_, hpfY1_, hpfY2_; 34 | float hpfA0_, hpfA1_, hpfA2_, hpfB1_, hpfB2_; 35 | }; 36 | 37 | } // namespace LoraDv 38 | 39 | #endif // DSP_H 40 | -------------------------------------------------------------------------------- /include/utils/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #include 5 | 6 | namespace LoraDv { 7 | 8 | class Utils { 9 | 10 | public: 11 | static float loraGetSnrLimit(int sf, long bw); 12 | static int loraGetSpeed(int sf, int cr, long bw) { return (int)(sf * (4.0 / cr) / (pow(2.0, sf) / bw)); } 13 | }; 14 | 15 | } // LoraDv 16 | 17 | #endif // UTILS_H -------------------------------------------------------------------------------- /include/version.h: -------------------------------------------------------------------------------- 1 | #ifndef VERSION_H 2 | #define VERSION_H 3 | 4 | #define LORADV_VERSION "1.0.29" 5 | 6 | #endif // VERSION_H 7 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | description = ESP32 LoRA/FSK DV Codec2/OPUS handheld transceiver 3 | default_envs = esp32dev_sx126x 4 | 5 | [env] 6 | platform = espressif32 @ 6.10.0 7 | framework = arduino 8 | monitor_speed = 115200 9 | board_build.partitions = min_spiffs.csv 10 | board_build.f_cpu = 240000000L 11 | upload_protocol = esptool 12 | lib_deps = 13 | hideakitai/DebugLog @ 0.6.6 14 | contrem/arduino-timer @ 3.0.1 15 | jgromes/RadioLib @ 6.6.0 16 | rlogiacco/CircularBuffer @ 1.4.0 17 | sh123/esp32_codec2 @ 1.0.5 18 | sh123/esp32_opus @ 1.0.1 19 | adafruit/Adafruit SSD1306 @ 2.5.12 20 | igorantolic/Ai Esp32 Rotary Encoder @ 1.7 21 | rweather/Crypto @ 0.4.0 22 | check_tool = cppcheck 23 | check_flags = 24 | cppcheck: --suppress=*:*.pio\* --inline-suppr -DCPPCHECK 25 | check_skip_packages = yes 26 | 27 | [env:esp32dev_sx126x] 28 | board = esp32dev 29 | build_flags = 30 | -D USE_SX126X 31 | 32 | [env:esp32dev_sx127x] 33 | board = esp32dev 34 | -------------------------------------------------------------------------------- /src/audio/audio_codec_codec2.cpp: -------------------------------------------------------------------------------- 1 | #include "audio/audio_codec_codec2.h" 2 | 3 | namespace LoraDv { 4 | 5 | AudioCodecCodec2::AudioCodecCodec2() 6 | : codec_(0) 7 | , codecSamplesPerFrame_(0) 8 | , codecBytesPerFrame_(0) 9 | { 10 | } 11 | 12 | bool AudioCodecCodec2::start(std::shared_ptr config) 13 | { 14 | codec_ = codec2_create(config->AudioCodec2Mode); 15 | if (codec_ == NULL) { 16 | LOG_ERROR("Failed to create Codec2"); 17 | return false; 18 | } 19 | codecSamplesPerFrame_ = codec2_samples_per_frame(codec_); 20 | codecBytesPerFrame_ = codec2_bytes_per_frame(codec_); 21 | LOG_INFO("Codec2 started", config->AudioCodec2Mode, codecSamplesPerFrame_, codecBytesPerFrame_); 22 | return true; 23 | } 24 | 25 | void AudioCodecCodec2::stop() 26 | { 27 | codec2_destroy(codec_); 28 | } 29 | 30 | int AudioCodecCodec2::encode(uint8_t *encodedOut, int16_t *pcmIn) 31 | { 32 | codec2_encode(codec_, encodedOut, pcmIn); 33 | return codecBytesPerFrame_; 34 | } 35 | 36 | int AudioCodecCodec2::decode(int16_t *pcmOut, uint8_t *encodedIn, uint16_t encodedSize) 37 | { 38 | codec2_decode(codec_, pcmOut, encodedIn); 39 | return codecSamplesPerFrame_; 40 | } 41 | 42 | int AudioCodecCodec2::getFrameSize() const 43 | { 44 | return codec2_bytes_per_frame(codec_); 45 | } 46 | 47 | int AudioCodecCodec2::getPcmFrameSize() const 48 | { 49 | return codec2_samples_per_frame(codec_); 50 | } 51 | 52 | int AudioCodecCodec2::getPcmFrameBufferSize() const 53 | { 54 | return codec2_samples_per_frame(codec_); 55 | } 56 | 57 | } // namespace LoraDv -------------------------------------------------------------------------------- /src/audio/audio_codec_opus.cpp: -------------------------------------------------------------------------------- 1 | #include "audio/audio_codec_opus.h" 2 | 3 | namespace LoraDv { 4 | 5 | AudioCodecOpus::AudioCodecOpus() 6 | : opusEncoder_(0) 7 | , opusDecoder_(0) 8 | , pcmFrameSize_(0) 9 | , pcmFrameBufferSize_(0) 10 | , encodedFrameBufferSize_(0) 11 | { 12 | } 13 | 14 | bool AudioCodecOpus::start(std::shared_ptr config) 15 | { 16 | int encoderError; 17 | opusEncoder_ = opus_encoder_create(config->AudioCodecSampleRate_, 1, OPUS_APPLICATION_VOIP, &encoderError); 18 | if (encoderError != OPUS_OK) { 19 | LOG_ERROR("Failed to create OPUS encoder, error", encoderError); 20 | return false; 21 | } 22 | encoderError = opus_encoder_init(opusEncoder_, config->AudioCodecSampleRate_, 1, OPUS_APPLICATION_VOIP); 23 | if (encoderError != OPUS_OK) { 24 | LOG_ERROR("Failed to initialize OPUS encoder, error", encoderError); 25 | return false; 26 | } 27 | opus_encoder_ctl(opusEncoder_, OPUS_SET_BITRATE(config->AudioOpusRate)); 28 | opus_encoder_ctl(opusEncoder_, OPUS_SET_COMPLEXITY(CfgComplexity)); 29 | opus_encoder_ctl(opusEncoder_, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); 30 | 31 | // configure decoder 32 | int decoderError; 33 | opusDecoder_ = opus_decoder_create(config->AudioCodecSampleRate_, 1, &decoderError); 34 | if (decoderError != OPUS_OK) { 35 | LOG_ERROR("Failed to create OPUS decoder, error", decoderError); 36 | return false; 37 | } 38 | 39 | pcmFrameSize_ = (int)(config->AudioCodecSampleRate_ / 1000 * config->AudioOpusPcmLen); 40 | pcmFrameBufferSize_ = 10 * pcmFrameSize_; 41 | encodedFrameBufferSize_ = CfgEncodedFrameBufferSize; 42 | return true; 43 | } 44 | 45 | void AudioCodecOpus::stop() 46 | { 47 | opus_encoder_destroy(opusEncoder_); 48 | opus_decoder_destroy(opusDecoder_); 49 | } 50 | 51 | int AudioCodecOpus::encode(uint8_t *encodedOut, int16_t *pcmIn) 52 | { 53 | return opus_encode(opusEncoder_, pcmIn, pcmFrameSize_, encodedOut, encodedFrameBufferSize_); 54 | } 55 | 56 | int AudioCodecOpus::decode(int16_t *pcmOut, uint8_t *encodedIn, uint16_t encodedSize) 57 | { 58 | return opus_decode(opusDecoder_, encodedIn, encodedSize, pcmOut, pcmFrameBufferSize_, 0); 59 | } 60 | 61 | } // namespace LoraDv -------------------------------------------------------------------------------- /src/audio/audio_task.cpp: -------------------------------------------------------------------------------- 1 | #include "audio/audio_task.h" 2 | 3 | #include "audio/audio_codec_codec2.h" 4 | #include "audio/audio_codec_opus.h" 5 | 6 | namespace LoraDv { 7 | 8 | AudioTask::AudioTask(std::shared_ptr config, std::shared_ptr pmService) 9 | : config_(config) 10 | , audioTaskHandle_(0) 11 | , radioTask_(nullptr) 12 | , pmService_(pmService) 13 | , dsp_(make_shared(config->AudioHpfCutoffHz_, config->AudioSampleRate_)) 14 | , audioCodec_(nullptr) 15 | , pcmResampleBuffer_(0) 16 | , pcmFrameBuffer_(0) 17 | , encodedFrameBuffer_(0) 18 | , codecSamplesPerFrame_(0) 19 | , codecBytesPerFrame_(0) 20 | , volume_(config->AudioVol) 21 | , maxVolume_(config->AudioMaxVol_) 22 | , isPttOn_(false) 23 | , isRunning_(false) 24 | , shouldUpdateScreen_(false) 25 | , isPlaying_(false) 26 | , playTimerTask_(0) 27 | { 28 | } 29 | 30 | void AudioTask::start(std::shared_ptr radioTask) 31 | { 32 | radioTask_ = radioTask; 33 | xTaskCreatePinnedToCore(&task, "AudioTask", CfgAudioTaskStack, this, CfgTaskPriority, &audioTaskHandle_, CfgCoreId); 34 | } 35 | 36 | void AudioTask::changeVolume(int deltaVolume) 37 | { 38 | int newVolume = volume_ + deltaVolume; 39 | if (newVolume >= 0 && newVolume <= maxVolume_) 40 | setVolume(newVolume); 41 | } 42 | 43 | void AudioTask::installAudio(int bytesPerSample) const 44 | { 45 | // speaker 46 | i2s_config_t i2sSpeakerConfig = { 47 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), 48 | .sample_rate = config_->AudioSampleRate_, 49 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 50 | .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, 51 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S), 52 | .intr_alloc_flags = 0, 53 | .dma_buf_count = 8, 54 | .dma_buf_len = bytesPerSample, 55 | .use_apll = false, 56 | .tx_desc_auto_clear = true, 57 | .fixed_mclk = -1 58 | }; 59 | i2s_pin_config_t i2sSpeakerPinConfig = { 60 | .bck_io_num = config_->AudioSpkPinBclk_, 61 | .ws_io_num = config_->AudioSpkPinLrc_, 62 | .data_out_num = config_->AudioSpkPinDin_, 63 | .data_in_num = I2S_PIN_NO_CHANGE 64 | }; 65 | if (i2s_driver_install(CfgAudioI2sSpkId, &i2sSpeakerConfig, 0, NULL) != ESP_OK) { 66 | LOG_ERROR("Failed to install i2s speaker driver"); 67 | } 68 | if (i2s_set_pin(CfgAudioI2sSpkId, &i2sSpeakerPinConfig) != ESP_OK) { 69 | LOG_ERROR("Failed to set i2s speaker pins"); 70 | } 71 | // mic 72 | i2s_config_t i2sMicConfig = { 73 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX), 74 | .sample_rate = config_->AudioSampleRate_, 75 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 76 | .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, 77 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S), 78 | .intr_alloc_flags = 0, 79 | .dma_buf_count = 8, 80 | .dma_buf_len = bytesPerSample, 81 | .use_apll = false, 82 | .tx_desc_auto_clear = true, 83 | .fixed_mclk = -1 84 | }; 85 | i2s_pin_config_t i2sMicPinConfig = { 86 | .bck_io_num = config_->AudioMicPinSck_, 87 | .ws_io_num = config_->AudioMicPinWs_, 88 | .data_out_num = I2S_PIN_NO_CHANGE, 89 | .data_in_num = config_->AudioMicPinSd_ 90 | }; 91 | if (i2s_driver_install(CfgAudioI2sMicId, &i2sMicConfig, 0, NULL) != ESP_OK) { 92 | LOG_ERROR("Failed to install i2s mic driver"); 93 | } 94 | if (i2s_set_pin(CfgAudioI2sMicId, &i2sMicPinConfig) != ESP_OK) { 95 | LOG_ERROR("Failed to set i2s mic pins"); 96 | } 97 | } 98 | 99 | void AudioTask::uninstallAudio() const 100 | { 101 | i2s_stop(CfgAudioI2sSpkId); 102 | i2s_stop(CfgAudioI2sMicId); 103 | i2s_driver_uninstall(CfgAudioI2sSpkId); 104 | i2s_driver_uninstall(CfgAudioI2sMicId); 105 | } 106 | 107 | void AudioTask::playTimerReset() 108 | { 109 | isPlaying_ = true; 110 | shouldUpdateScreen_ = true; 111 | if (playTimerTask_ != 0) { 112 | playTimer_.cancel(playTimerTask_); 113 | } 114 | playTimerTask_ = playTimer_.in(CfgPlayCompletedDelayMs, playTimerEnter, this); 115 | } 116 | 117 | bool AudioTask::playTimerEnter(void *param) 118 | { 119 | static_cast(param)->playTimer(); 120 | return false; 121 | } 122 | 123 | void AudioTask::playTimer() 124 | { 125 | isPlaying_ = false; 126 | shouldUpdateScreen_ = true; 127 | } 128 | 129 | bool AudioTask::loop() 130 | { 131 | playTimer_.tick(); 132 | bool shouldUpdateScreen = shouldUpdateScreen_; 133 | shouldUpdateScreen_ = false; 134 | return shouldUpdateScreen; 135 | } 136 | 137 | void AudioTask::setPtt(bool isPttOn) 138 | { 139 | isPttOn_ = isPttOn; 140 | } 141 | 142 | void AudioTask::play() const 143 | { 144 | xTaskNotify(audioTaskHandle_, CfgAudioPlayBit, eSetBits); 145 | } 146 | 147 | void AudioTask::record() const 148 | { 149 | radioTask_->startTransmit(); 150 | xTaskNotify(audioTaskHandle_, CfgAudioRecBit, eSetBits); 151 | } 152 | 153 | void AudioTask::task(void *param) { 154 | static_cast(param)->audioTask(); 155 | } 156 | 157 | void AudioTask::audioTask() 158 | { 159 | LOG_INFO("Audio task started"); 160 | isRunning_ = true; 161 | 162 | // select and codec 163 | if (config_->AudioCodec == CFG_AUDIO_CODEC_CODEC2) 164 | audioCodec_.reset(new AudioCodecCodec2()); 165 | else if (config_->AudioCodec == CFG_AUDIO_CODEC_OPUS) 166 | audioCodec_.reset(new AudioCodecOpus()); 167 | else { 168 | LOG_ERROR("Unknown codec", config_->AudioCodec); 169 | return; 170 | } 171 | 172 | audioCodec_->start(config_); 173 | 174 | // construct buffers 175 | codecSamplesPerFrame_ = audioCodec_->getPcmFrameSize(); 176 | codecBytesPerFrame_ = audioCodec_->getFrameSize(); 177 | pcmFrameBuffer_ = new int16_t[audioCodec_->getPcmFrameBufferSize()]; 178 | pcmResampleBuffer_ = new int16_t[audioCodec_->getPcmFrameBufferSize() * config_->AudioResampleCoeff_]; 179 | encodedFrameBuffer_ = new uint8_t[codecBytesPerFrame_]; 180 | 181 | delay(CfgStartupDelayMs); 182 | installAudio(codecSamplesPerFrame_); 183 | 184 | while(isRunning_) { 185 | uint32_t audioBits = 0; 186 | xTaskNotifyWaitIndexed(0, 0x00, ULONG_MAX, &audioBits, portMAX_DELAY); 187 | 188 | LOG_DEBUG("Audio task command bits", audioBits); 189 | if (audioBits & CfgAudioPlayBit) { 190 | audioTaskPlay(); 191 | } else if (audioBits & CfgAudioRecBit) { 192 | audioTaskRecord(); 193 | } 194 | } 195 | 196 | delete encodedFrameBuffer_; 197 | delete pcmResampleBuffer_; 198 | delete pcmFrameBuffer_; 199 | audioCodec_->stop(); 200 | 201 | uninstallAudio(); 202 | 203 | LOG_INFO("Audio task stopped"); 204 | vTaskDelete(NULL); 205 | } 206 | 207 | void AudioTask::audioTaskPlay() 208 | { 209 | LOG_DEBUG("Playing audio"); 210 | playTimerReset(); 211 | 212 | int16_t targetLevel = dsp_->audioVolumeToLogPcm(volume_, maxVolume_, maxVolume_ * CfgAudioMaxVolumePcmMultiplier); 213 | LOG_DEBUG("Target level is", targetLevel); 214 | 215 | // run till ptt is not pressed and radio has data 216 | while (!isPttOn_ && radioTask_->hasData()) { 217 | byte packetSize; 218 | if (!radioTask_->readPacketSize(packetSize)) { 219 | LOG_ERROR("Failed to read packet size"); 220 | vTaskDelay(1); 221 | continue; 222 | } 223 | pmService_->lightSleepReset(); 224 | LOG_DEBUG("Playing packet", packetSize); 225 | 226 | // split by frame, decode and play 227 | for (int i = 0; i < packetSize; i++) { 228 | 229 | // read byte by byte from radio task 230 | byte b; 231 | if (!radioTask_->readNextByte(b)) { 232 | LOG_ERROR("Failed to read next byte"); 233 | vTaskDelay(1); 234 | continue; 235 | } 236 | 237 | // split only if codec has fixed frame size, otherwise just process complete packet 238 | int subFrameSize = audioCodec_->isFixedFrameSize() ? codecBytesPerFrame_ : packetSize; 239 | encodedFrameBuffer_[i % subFrameSize] = b; 240 | 241 | // one encoded audio frame is read, decode and process 242 | if (i % subFrameSize == subFrameSize - 1) { 243 | 244 | // decode to pcm, adjust agc, upsample, and send for playback 245 | decodeAndPlay(subFrameSize, targetLevel); 246 | vTaskDelay(1); 247 | } 248 | } 249 | } // while rx data available 250 | } 251 | 252 | void AudioTask::decodeAndPlay(int frameSize, int16_t targetLevel) 253 | { 254 | // decode in current codec 255 | int pcmFrameSize = audioCodec_->decode(pcmFrameBuffer_, encodedFrameBuffer_, frameSize); 256 | 257 | // adjust volume 258 | dsp_->audioAdjustGainAgc(pcmFrameBuffer_, pcmFrameSize, targetLevel); 259 | 260 | // upsample if codec rate is lower than speaker rate 261 | int writeDataSize = pcmFrameSize; 262 | int16_t* pcmBuffer = pcmFrameBuffer_; 263 | if (config_->AudioResampleCoeff_ == 2) { 264 | writeDataSize = dsp_->audioUpsample2x(pcmFrameBuffer_, pcmResampleBuffer_, pcmFrameSize); 265 | pcmBuffer = pcmResampleBuffer_; 266 | } 267 | 268 | // write to i2s speaker 269 | size_t bytesWritten; 270 | if (i2s_write(CfgAudioI2sSpkId, pcmBuffer, sizeof(int16_t) * writeDataSize, &bytesWritten, portMAX_DELAY) != ESP_OK) { 271 | LOG_ERROR("Failed to write to I2S speaker"); 272 | } 273 | } 274 | 275 | void AudioTask::audioTaskRecord() 276 | { 277 | LOG_DEBUG("Recording audio"); 278 | 279 | size_t bytesRead; 280 | int packetSize = 0; 281 | i2s_start(CfgAudioI2sMicId); 282 | 283 | // record while ptt button is pressed 284 | while (isPttOn_) { 285 | 286 | // transmit if enough audio frames aggregated for fixed frame codec (e.g. codec2) 287 | // or transmit immediately if variable size frame is read (e.g. OPUS) 288 | bool shouldTransmit = 289 | (audioCodec_->isFixedFrameSize() && packetSize + codecBytesPerFrame_ > config_->AudioMaxPktSize) || 290 | (!audioCodec_->isFixedFrameSize() && packetSize > 0); 291 | 292 | // perform packet transmission to radio 293 | if (shouldTransmit) { 294 | LOG_DEBUG("Recorded packet", packetSize); 295 | if (!radioTask_->writePacketSize(packetSize)) { 296 | LOG_ERROR("Failed to write packet size"); 297 | vTaskDelay(1); 298 | continue; 299 | } 300 | radioTask_->transmit(); 301 | pmService_->lightSleepReset(); 302 | packetSize = 0; 303 | } 304 | 305 | // read one pcm sample from i2s microphone 306 | int readDataSize = codecSamplesPerFrame_ * config_->AudioResampleCoeff_; 307 | if (i2s_read(CfgAudioI2sMicId, pcmResampleBuffer_, sizeof(uint16_t) * readDataSize, &bytesRead, portMAX_DELAY) != ESP_OK) { 308 | LOG_ERROR("Failed to read from I2S microphone"); 309 | continue; 310 | } 311 | 312 | // process pcm frame, apply filter, downsample and encode in selected codec, queue for transmission 313 | int encodedFrameSize = encodeAndQueue(readDataSize); 314 | packetSize += encodedFrameSize; 315 | 316 | vTaskDelay(1); 317 | } // while ptt pressed 318 | 319 | // send remaining tail audio encoded samples if any 320 | if (packetSize > 0) { 321 | LOG_DEBUG("Recorded packet tail", packetSize); 322 | if (radioTask_->writePacketSize(packetSize)) { 323 | radioTask_->transmit(); 324 | pmService_->lightSleepReset(); 325 | } else { 326 | LOG_ERROR("Failed to write byte"); 327 | } 328 | packetSize = 0; 329 | } 330 | 331 | // stop mic and tell radio to start transmission 332 | vTaskDelay(1); 333 | i2s_stop(CfgAudioI2sMicId); 334 | radioTask_->startReceive(); 335 | } 336 | 337 | int AudioTask::encodeAndQueue(int pcmFrameSize) 338 | { 339 | int16_t *pcmReadBuffer = pcmResampleBuffer_; 340 | 341 | // apply high pass filter 342 | dsp_->audioFilterHpf(pcmReadBuffer, pcmFrameSize); 343 | 344 | // downsample if mic sample rate is higher than codec rate 345 | if (config_->AudioResampleCoeff_ == 2) { 346 | dsp_->audioDownsample2x(pcmReadBuffer, pcmFrameBuffer_, pcmFrameSize); 347 | pcmReadBuffer = pcmFrameBuffer_; 348 | } 349 | 350 | // encode in selected codec 351 | int encodedFrameSize = audioCodec_->encode(encodedFrameBuffer_, pcmReadBuffer); 352 | 353 | // transfer data to the radio packet queue without actual transmission 354 | for (int i = 0; i < encodedFrameSize; i++) { 355 | radioTask_->writeNextByte(encodedFrameBuffer_[i]); 356 | } 357 | return encodedFrameSize; 358 | } 359 | 360 | } // LoraDv -------------------------------------------------------------------------------- /src/hal/hw_monitor.cpp: -------------------------------------------------------------------------------- 1 | #include "hal/hw_monitor.h" 2 | 3 | namespace LoraDv { 4 | 5 | HwMonitor::HwMonitor(std::shared_ptr config) 6 | : config_(config) 7 | { 8 | } 9 | 10 | float HwMonitor::getBatteryVoltage() const 11 | { 12 | int bat_value = analogRead(config_->BatteryMonPin_); 13 | return 2 * bat_value * (3.3 / 4096.0) + config_->BatteryMonCal; 14 | } 15 | 16 | } // LoraDv -------------------------------------------------------------------------------- /src/hal/pm_service.cpp: -------------------------------------------------------------------------------- 1 | #include "hal/pm_service.h" 2 | 3 | namespace LoraDv { 4 | 5 | PmService::PmService(std::shared_ptr config, std::shared_ptr display) 6 | : config_(config) 7 | , display_(display) 8 | , lightSleepTimerTask_(0) 9 | , isExitFromSleep_(false) 10 | { 11 | lightSleepReset(); 12 | } 13 | 14 | void PmService::lightSleepReset() 15 | { 16 | LOG_DEBUG("Reset light sleep"); 17 | if (lightSleepTimerTask_ != 0) { 18 | lightSleepTimer_.cancel(lightSleepTimerTask_); 19 | } 20 | lightSleepTimerTask_ = lightSleepTimer_.in(config_->PmSleepAfterMs, lightSleepEnterTimer, this); 21 | } 22 | 23 | bool PmService::lightSleepEnterTimer(void *param) 24 | { 25 | static_cast(param)->lightSleepEnter(); 26 | return false; 27 | } 28 | 29 | void PmService::lightSleepEnter(void) 30 | { 31 | LOG_INFO("Entering light sleep"); 32 | display_->clearDisplay(); 33 | display_->display(); 34 | 35 | esp_sleep_wakeup_cause_t wakeupCause = ESP_SLEEP_WAKEUP_UNDEFINED; 36 | while (true) { 37 | wakeupCause = lightSleepWait(config_->PmLightSleepDurationMs_ * 1000UL); 38 | if (wakeupCause != ESP_SLEEP_WAKEUP_TIMER) break; 39 | delay(config_->PmLightSleepAwakeMs_); 40 | } 41 | 42 | LOG_INFO("Exiting light sleep"); 43 | isExitFromSleep_ = true; 44 | } 45 | 46 | esp_sleep_wakeup_cause_t PmService::lightSleepWait(uint64_t sleepTimeUs) const 47 | { 48 | esp_sleep_enable_ext0_wakeup((gpio_num_t)config_->PttBtnPin_, LOW); 49 | #ifdef USE_SX126X 50 | uint64_t bitMask = (uint64_t)(1 << config_->LoraPinA_) | (uint64_t)(1 << config_->LoraPinB_); 51 | #else 52 | uint64_t bitMask = (uint64_t)(1 << config_->LoraPinA_); 53 | #endif 54 | esp_sleep_enable_ext1_wakeup(bitMask, ESP_EXT1_WAKEUP_ANY_HIGH); 55 | esp_sleep_enable_timer_wakeup(sleepTimeUs); 56 | esp_light_sleep_start(); 57 | return esp_sleep_get_wakeup_cause(); 58 | } 59 | 60 | bool PmService::loop() 61 | { 62 | lightSleepTimer_.tick(); 63 | bool isExitFromSleep = isExitFromSleep_; 64 | isExitFromSleep_ = false; 65 | if (isExitFromSleep) 66 | lightSleepReset(); 67 | return isExitFromSleep; 68 | } 69 | 70 | } // LoraDv -------------------------------------------------------------------------------- /src/hal/radio_task.cpp: -------------------------------------------------------------------------------- 1 | #include "hal/radio_task.h" 2 | 3 | namespace LoraDv { 4 | 5 | volatile bool RadioTask::isIsrEnabled_ = true; 6 | TaskHandle_t RadioTask::loraTaskHandle_; 7 | 8 | RadioTask::RadioTask(std::shared_ptr config) 9 | : config_(config) 10 | , radioModule_(nullptr) 11 | , audioTask_(nullptr) 12 | , cipher_(new ChaChaPoly()) 13 | , isImplicitMode_(false) 14 | , isIsrInstalled_(false) 15 | , isRunning_(false) 16 | , shouldUpdateScreen_(false) 17 | , lastRssi_(0) 18 | { 19 | } 20 | 21 | void RadioTask::start(std::shared_ptr audioTask) 22 | { 23 | audioTask_ = audioTask; 24 | cipher_->setKey(config_->AudioPrivacyKey_, sizeof(config_->AudioPrivacyKey_)); 25 | xTaskCreatePinnedToCore(&task, "RadioTask", CfgRadioTaskStack, this, CfgTaskPriority, &loraTaskHandle_, CfgCoreId); 26 | } 27 | 28 | void RadioTask::setupRig(long loraFreq, long bw, int sf, int cr, int pwr, int sync, int crcBytes) 29 | { 30 | LOG_INFO("Initializing LoRa"); 31 | LOG_INFO("Frequency:", loraFreq, "Hz"); 32 | LOG_INFO("Bandwidth:", bw, "Hz"); 33 | LOG_INFO("Spreading:", sf); 34 | LOG_INFO("Coding rate:", cr); 35 | LOG_INFO("Power:", pwr, "dBm"); 36 | LOG_INFO("Sync:", "0x" + String(sync, HEX)); 37 | LOG_INFO("CRC:", crcBytes); 38 | LOG_INFO("Speed:", Utils::loraGetSpeed(sf, cr, bw), "bps"); 39 | LOG_INFO("Min level:", Utils::loraGetSnrLimit(sf, bw)); 40 | radioModule_ = std::make_shared(new Module(config_->LoraPinSs_, config_->LoraPinA_, config_->LoraPinRst_, config_->LoraPinB_)); 41 | int state = radioModule_->begin((float)loraFreq / 1e6, (float)bw / 1e3, sf, cr, sync, pwr); 42 | if (state != RADIOLIB_ERR_NONE) { 43 | LOG_ERROR("Radio start error:", state); 44 | } 45 | radioModule_->setCRC(crcBytes); 46 | radioModule_->setPreambleLength(config_->LoraPreambleLen_); 47 | #ifdef USE_SX126X 48 | #pragma message("Using SX126X") 49 | LOG_INFO("Using SX126X module"); 50 | radioModule_->setRfSwitchPins(config_->LoraPinSwitchRx_, config_->LoraPinSwitchTx_); 51 | if (isIsrInstalled_) radioModule_->clearDio1Action(); 52 | radioModule_->setDio1Action(onRigIsrRxPacket); 53 | isIsrInstalled_ = true; 54 | #else 55 | #pragma message("Using SX127X") 56 | LOG_INFO("Using SX127X module"); 57 | if (isIsrInstalled_) radioModule_->clearDio0Action(); 58 | radioModule_->setDio0Action(onRigIsrRxPacket, RISING); 59 | isIsrInstalled_ = true; 60 | #endif 61 | radioModule_->explicitHeader(); 62 | LOG_INFO("LoRa initialized"); 63 | } 64 | 65 | void RadioTask::setupRigFsk(long freq, float bitRate, float freqDev, float rxBw, int pwr, byte shaping) 66 | { 67 | LOG_INFO("Initializing FSK"); 68 | LOG_INFO("Frequency:", freq, "Hz"); 69 | LOG_INFO("Bit rate:", bitRate, "kbps"); 70 | LOG_INFO("Deviation:", freqDev, "kHz"); 71 | LOG_INFO("Bandwidth:", rxBw, "kHz"); 72 | LOG_INFO("Power:", pwr, "dBm"); 73 | LOG_INFO("Shaping:", shaping); 74 | radioModule_ = make_shared(new Module(config_->LoraPinSs_, config_->LoraPinA_, config_->LoraPinRst_, config_->LoraPinB_)); 75 | int state = radioModule_->beginFSK((float)freq / 1e6, bitRate, freqDev, rxBw, pwr); 76 | if (state != RADIOLIB_ERR_NONE) { 77 | LOG_ERROR("Radio start error:", state); 78 | } 79 | radioModule_->disableAddressFiltering(); 80 | radioModule_->setDataShaping(shaping); 81 | #ifdef USE_SX126X 82 | #pragma message("Using SX126X") 83 | LOG_INFO("Using SX126X module"); 84 | radioModule_->setRfSwitchPins(config_->LoraPinSwitchRx_, config_->LoraPinSwitchTx_); 85 | if (isIsrInstalled_) radioModule_->clearDio1Action(); 86 | radioModule_->setDio1Action(onRigIsrRxPacket); 87 | isIsrInstalled_ = true; 88 | #else 89 | #pragma message("Using SX127X") 90 | LOG_INFO("Using SX127X module"); 91 | if (isIsrInstalled_) radioModule_->clearDio0Action(); 92 | radioModule_->setDio0Action(onRigIsrRxPacket, RISING); 93 | isIsrInstalled_ = true; 94 | #endif 95 | LOG_INFO("FSK initialized"); 96 | } 97 | 98 | void RadioTask::setFreq(long loraFreq) const 99 | { 100 | radioModule_->setFrequency((float)loraFreq / (float)1e6); 101 | } 102 | 103 | bool RadioTask::hasData() const 104 | { 105 | return radioRxQueue_.index.size() > 0; 106 | } 107 | 108 | bool RadioTask::readPacketSize(byte &packetSize) 109 | { 110 | if (!hasData()) return false; 111 | packetSize = radioRxQueue_.index.shift(); 112 | return true; 113 | } 114 | 115 | bool RadioTask::readNextByte(byte &b) 116 | { 117 | if (radioRxQueue_.data.size() == 0) return false; 118 | b = radioRxQueue_.data.shift(); 119 | return true; 120 | } 121 | 122 | bool RadioTask::writePacketSize(byte packetSize) 123 | { 124 | return radioTxQueue_.index.push(packetSize); 125 | } 126 | 127 | bool RadioTask::writeNextByte(byte b) 128 | { 129 | return radioTxQueue_.data.push(b); 130 | } 131 | 132 | IRAM_ATTR void RadioTask::onRigIsrRxPacket() 133 | { 134 | if (!isIsrEnabled_) return; 135 | BaseType_t xHigherPriorityTaskWoken; 136 | xTaskNotifyFromISR(loraTaskHandle_, CfgRadioRxBit, eSetBits, &xHigherPriorityTaskWoken); 137 | } 138 | 139 | void RadioTask::task(void *param) 140 | { 141 | reinterpret_cast(param)->rigTask(); 142 | } 143 | 144 | void RadioTask::startTransmit() const 145 | { 146 | xTaskNotify(loraTaskHandle_, CfgRadioTxStartBit, eSetBits); 147 | } 148 | 149 | void RadioTask::startReceive() const 150 | { 151 | xTaskNotify(loraTaskHandle_, CfgRadioRxStartBit, eSetBits); 152 | } 153 | 154 | void RadioTask::transmit() const 155 | { 156 | xTaskNotify(loraTaskHandle_, CfgRadioTxBit, eSetBits); 157 | } 158 | 159 | void RadioTask::rigTask() 160 | { 161 | LOG_INFO("Radio task started"); 162 | isRunning_ = true; 163 | 164 | if (config_->ModType == CFG_MOD_TYPE_LORA) { 165 | setupRig(config_->LoraFreqRx, config_->LoraBw, config_->LoraSf, 166 | config_->LoraCodingRate, config_->LoraPower, config_->LoraSync_, config_->LoraCrc_); 167 | } else { 168 | setupRigFsk(config_->LoraFreqRx, config_->FskBitRate, config_->FskFreqDev, 169 | config_->FskRxBw, config_->LoraPower, config_->FskShaping); 170 | } 171 | 172 | int32_t seed = radioModule_->random(0x7FFFFFFF); 173 | LOG_INFO("Random seed:", String(seed, HEX)); 174 | randomSeed(seed); 175 | 176 | rigTaskStartReceive(); 177 | 178 | byte *packetBuf = new byte[CfgRadioPacketBufLen]; 179 | byte *tmpBuf = new byte[CfgRadioPacketBufLen + CfgIvSize + CfgAuthTagSize]; 180 | 181 | while (isRunning_) { 182 | uint32_t cmdBits = 0; 183 | xTaskNotifyWaitIndexed(0, 0x00, ULONG_MAX, &cmdBits, portMAX_DELAY); 184 | 185 | LOG_DEBUG("Radio task bits", cmdBits); 186 | if (cmdBits & CfgRadioRxBit) { 187 | rigTaskReceive(packetBuf, tmpBuf); 188 | } 189 | else if (cmdBits & CfgRadioTxBit) { 190 | rigTaskTransmit(packetBuf, tmpBuf); 191 | } 192 | if (cmdBits & CfgRadioRxStartBit) { 193 | rigTaskStartReceive(); 194 | } 195 | else if (cmdBits & CfgRadioTxStartBit) { 196 | rigTaskStartTransmit(); 197 | } 198 | } 199 | 200 | delete tmpBuf; 201 | delete packetBuf; 202 | LOG_INFO("Radio task stopped"); 203 | vTaskDelete(NULL); 204 | } 205 | 206 | bool RadioTask::loop() 207 | { 208 | bool shouldUpdateScreen = shouldUpdateScreen_; 209 | shouldUpdateScreen_ = false; 210 | return shouldUpdateScreen; 211 | } 212 | 213 | void RadioTask::rigTaskStartReceive() 214 | { 215 | LOG_INFO("Start receive"); 216 | if (isHalfDuplex()) setFreq(config_->LoraFreqRx); 217 | int loraRadioState = radioModule_->startReceive(); 218 | if (loraRadioState != RADIOLIB_ERR_NONE) { 219 | LOG_ERROR("Start receive error: ", loraRadioState); 220 | } 221 | vTaskDelay(1); 222 | isIsrEnabled_ = true; 223 | } 224 | 225 | void RadioTask::rigTaskStartTransmit() 226 | { 227 | LOG_INFO("Start transmit"); 228 | isIsrEnabled_ = false; 229 | if (isHalfDuplex()) setFreq(config_->LoraFreqTx); 230 | } 231 | 232 | void RadioTask::rigTaskReceive(byte *packetBuf, byte *tmpBuf) 233 | { 234 | int packetSize = radioModule_->getPacketLength(); 235 | if (packetSize > CfgIvSize + CfgAuthTagSize && packetSize <= CfgRadioPacketBufLen) { 236 | // receive packet 237 | int state = radioModule_->readData(packetBuf, packetSize); 238 | bool isValidPacket = true; 239 | if (state == RADIOLIB_ERR_NONE) { 240 | byte *receiveBuf = packetBuf; 241 | // if privacy enabled 242 | if (config_->AudioEnPriv) { 243 | isValidPacket = decryptPacket(packetBuf, tmpBuf, packetSize, packetSize); 244 | receiveBuf = tmpBuf; 245 | } 246 | // send packet to the RX queue 247 | if (isValidPacket) { 248 | LOG_DEBUG("Received packet, size", packetSize); 249 | for (int i = 0; i < packetSize; i++) { 250 | radioRxQueue_.data.push(receiveBuf[i]); 251 | } 252 | radioRxQueue_.index.push(packetSize); 253 | audioTask_->play(); 254 | } else { 255 | LOG_ERROR("Invalid packet was received"); 256 | } 257 | } else { 258 | LOG_ERROR("Read data error: ", state); 259 | } 260 | lastRssi_ = radioModule_->getRSSI(); 261 | // probably not needed, still in receive 262 | state = radioModule_->startReceive(); 263 | if (state != RADIOLIB_ERR_NONE) { 264 | LOG_ERROR("Start receive error: ", state); 265 | } 266 | } else { 267 | LOG_ERROR("Wrong incoming packet size: ", packetSize); 268 | } 269 | } 270 | 271 | void RadioTask::rigTaskTransmit(byte *packetBuf, byte *tmpBuf) 272 | { 273 | // while there are no more packets 274 | while (radioTxQueue_.index.size() > 0) { 275 | // fetch packet size 276 | int txBytesCnt = radioTxQueue_.index.shift(); 277 | // ignore wrong too large packets 278 | if (txBytesCnt > CfgRadioPacketBufLen) { 279 | LOG_ERROR("Packet size is too large, not transmitting"); 280 | for (int i = 0; i < txBytesCnt; i++) { 281 | radioTxQueue_.data.shift(); 282 | } 283 | vTaskDelay(1); 284 | continue; 285 | } 286 | // read packet from the queue 287 | for (int i = 0; i < txBytesCnt; i++) { 288 | packetBuf[i] = radioTxQueue_.data.shift(); 289 | } 290 | byte *sendBuf = packetBuf; 291 | // if privacy enabled 292 | if (config_->AudioEnPriv) { 293 | encryptPacket(packetBuf, tmpBuf, txBytesCnt, txBytesCnt); 294 | sendBuf = tmpBuf; 295 | } 296 | // transmit 297 | int loraRadioState = radioModule_->transmit(sendBuf, txBytesCnt); 298 | if (loraRadioState != RADIOLIB_ERR_NONE) { 299 | LOG_ERROR("Radio transmit failed:", loraRadioState, txBytesCnt); 300 | } else { 301 | LOG_DEBUG("Transmitted packet", txBytesCnt); 302 | } 303 | vTaskDelay(1); 304 | } 305 | } 306 | 307 | void RadioTask::encryptPacket(byte *inBuf, byte *outBuf, int inBufSize, int& outBufSize) 308 | { 309 | int curOutBufSize = inBufSize; 310 | // generate iv and include it into payload head 311 | esp_fill_random(outBuf, CfgIvSize); 312 | cipher_->setIV(outBuf, CfgIvSize); 313 | // encrypt 314 | cipher_->encrypt(outBuf + CfgIvSize, inBuf, inBufSize); 315 | curOutBufSize += CfgIvSize; 316 | // generate auth tag and include it into payload tail 317 | cipher_->computeTag(outBuf + curOutBufSize, CfgAuthTagSize); 318 | curOutBufSize += CfgAuthTagSize; 319 | outBufSize = curOutBufSize; 320 | } 321 | 322 | bool RadioTask::decryptPacket(byte *inBuf, byte *outBuf, int inBufSize, int& outBufSize) 323 | { 324 | int curOutBufSize = inBufSize - (CfgIvSize + CfgAuthTagSize); 325 | // set iv from the packet and decrypt 326 | cipher_->setIV(inBuf, CfgIvSize); 327 | cipher_->decrypt(outBuf, inBuf + CfgIvSize, curOutBufSize); 328 | outBufSize = curOutBufSize; 329 | // check tag validity from the received packet 330 | return cipher_->checkTag(inBuf + CfgIvSize + curOutBufSize, CfgAuthTagSize); 331 | } 332 | 333 | } // LoraDv -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "service.h" 5 | 6 | using namespace LoraDv; 7 | 8 | static constexpr int LoopDelayMs = 10; 9 | 10 | std::shared_ptr config_; 11 | std::shared_ptr service_; 12 | 13 | void setup() { 14 | Serial.begin(SERIAL_BAUD_RATE); 15 | while (!Serial); 16 | 17 | config_ = std::make_shared(); 18 | config_->Load(); 19 | 20 | service_ = std::make_shared(config_); 21 | service_->setup(); 22 | } 23 | 24 | void loop() { 25 | service_->loop(); 26 | delay(LoopDelayMs); 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/service.cpp: -------------------------------------------------------------------------------- 1 | #include "service.h" 2 | 3 | namespace LoraDv { 4 | 5 | std::shared_ptr Service::rotaryEncoder_; 6 | 7 | Service::Service(std::shared_ptr config) 8 | : config_(config) 9 | , display_(std::make_shared(CfgDisplayWidth, CfgDisplayHeight, &Wire, -1)) 10 | , pmService_(std::make_shared(config, display_)) 11 | , hwMonitor_(std::make_shared(config)) 12 | , radioTask_(std::make_shared(config)) 13 | , audioTask_(std::make_shared(config, pmService_)) 14 | , settingsMenu_(nullptr) 15 | , btnPressed_(false) 16 | { 17 | rotaryEncoder_ = std::make_shared(config->EncoderPinA_, config->EncoderPinB_, 18 | config->EncoderPinBtn_, config->EncoderPinVcc_, config->EncoderSteps_); 19 | } 20 | 21 | void Service::setup() 22 | { 23 | LOG_SET_LEVEL(config_->LogLevel); 24 | LOG_SET_OPTION(false, false, true); // disable file, line, enable func 25 | 26 | LOG_INFO("Board setup started"); 27 | 28 | // setup bootloader random source as WiFi and BT are not used 29 | bootloader_random_enable(); 30 | 31 | setupEncoder(); 32 | setupScreen(); 33 | setupPttButton(); 34 | 35 | audioTask_->start(radioTask_); 36 | radioTask_->start(audioTask_); 37 | 38 | updateScreen(); 39 | 40 | LOG_INFO("Board setup completed"); 41 | } 42 | 43 | void Service::setupEncoder() 44 | { 45 | LOG_INFO("Encoder setup started"); 46 | rotaryEncoder_->begin(); 47 | rotaryEncoder_->setup(isrReadEncoder); 48 | LOG_INFO("Encoder setup completed"); 49 | } 50 | 51 | void Service::setupScreen() 52 | { 53 | if(display_->begin(SSD1306_SWITCHCAPVCC, 0x3C)) { 54 | LOG_INFO("Display setup completed"); 55 | } else { 56 | LOG_ERROR("Display init failed"); 57 | } 58 | } 59 | 60 | void Service::setupPttButton() 61 | { 62 | LOG_INFO("PTT setup started"); 63 | pinMode(config_->PttBtnPin_, INPUT); 64 | LOG_INFO("PTT setup completed"); 65 | } 66 | 67 | IRAM_ATTR void Service::isrReadEncoder() 68 | { 69 | rotaryEncoder_->readEncoder_ISR(); 70 | } 71 | 72 | void Service::updateScreen() const 73 | { 74 | bool isPlaying = audioTask_->isPlaying(); 75 | display_->clearDisplay(); 76 | display_->setTextColor(WHITE); 77 | display_->setCursor(0, 0); 78 | 79 | display_->setTextSize(1); 80 | display_->print("["); display_->print(audioTask_->getVolume()); display_->print("] "); 81 | display_->print(hwMonitor_->getBatteryVoltage()); display_->print("V "); 82 | if (isPlaying) 83 | display_->print(radioTask_->getRssi()); 84 | display_->println(); 85 | 86 | display_->setCursor(0, CfgDisplayHeight/2 + 2); 87 | display_->setTextSize(2); 88 | if (btnPressed_) 89 | display_->print((float)config_->LoraFreqTx / 1e6, 3); 90 | else 91 | display_->print((float)config_->LoraFreqRx / 1e6, 3); 92 | display_->print(" "); 93 | display_->print(btnPressed_ ? "TX" : isPlaying ? "RX" : "--"); 94 | display_->println(); 95 | 96 | display_->display(); 97 | } 98 | 99 | bool Service::processPttButton() 100 | { 101 | if (digitalRead(config_->PttBtnPin_) == LOW && !btnPressed_) { 102 | btnPressed_ = true; 103 | LOG_INFO("PTT pushed, start TX"); 104 | audioTask_->setPtt(true); 105 | audioTask_->record(); 106 | return true; 107 | } else if (digitalRead(config_->PttBtnPin_) == HIGH && btnPressed_) { 108 | btnPressed_ = false; 109 | LOG_INFO("PTT released"); 110 | audioTask_->setPtt(false); 111 | return true; 112 | } 113 | return false; 114 | } 115 | 116 | bool Service::processRotaryEncoder() 117 | { 118 | bool shouldUpdateScreen = false; 119 | long encoderDelta = rotaryEncoder_->encoderChanged(); 120 | 121 | if (encoderDelta != 0) { 122 | LOG_INFO("Encoder changed:", rotaryEncoder_->readEncoder(), encoderDelta); 123 | if (settingsMenu_) { 124 | settingsMenu_->onEncoderPositionChanged(encoderDelta); 125 | settingsMenu_->draw(display_); 126 | } else { 127 | audioTask_->changeVolume(encoderDelta); 128 | shouldUpdateScreen = true; 129 | } 130 | pmService_->lightSleepReset(); 131 | } 132 | 133 | if (rotaryEncoder_->isEncoderButtonClicked()) { 134 | LOG_INFO("Encoder button clicked", esp_get_free_heap_size()); 135 | if (settingsMenu_) { 136 | settingsMenu_->onEncoderButtonClicked(); 137 | settingsMenu_->draw(display_); 138 | } else { 139 | shouldUpdateScreen = true; 140 | } 141 | pmService_->lightSleepReset(); 142 | } 143 | 144 | if (rotaryEncoder_->isEncoderButtonClicked(CfgEncoderBtnLongMs)) { 145 | LOG_INFO("Encoder button long clicked"); 146 | if (settingsMenu_) { 147 | settingsMenu_.reset(); 148 | shouldUpdateScreen = true; 149 | } else { 150 | settingsMenu_ = std::make_shared(config_); 151 | settingsMenu_->draw(display_); 152 | } 153 | pmService_->lightSleepReset(); 154 | } 155 | 156 | return shouldUpdateScreen; 157 | } 158 | 159 | void Service::loop() 160 | { 161 | bool screenNeedsUpdate = false; 162 | 163 | screenNeedsUpdate |= audioTask_->loop(); 164 | screenNeedsUpdate |= radioTask_->loop(); 165 | screenNeedsUpdate |= pmService_->loop(); 166 | screenNeedsUpdate |= processPttButton(); 167 | screenNeedsUpdate |= processRotaryEncoder(); 168 | 169 | if (screenNeedsUpdate) { 170 | updateScreen(); 171 | } 172 | } 173 | 174 | } // LoraDv -------------------------------------------------------------------------------- /src/settings/config.cpp: -------------------------------------------------------------------------------- 1 | #include "settings/config.h" 2 | 3 | namespace LoraDv { 4 | 5 | #define N(v) #v 6 | 7 | CFG_AUDIO_PRIVACY_KEY; 8 | 9 | Config::Config() 10 | { 11 | InitializeDefault(); 12 | } 13 | 14 | void Config::InitializeDefault() 15 | { 16 | // default version 17 | Version = CFG_VERSION; 18 | 19 | // log level 20 | LogLevel = CFG_LOG_LEVEL; 21 | 22 | // modulation type 23 | ModType = CFG_MOD_TYPE; 24 | 25 | // generic parameters 26 | LoraFreqRx = CFG_LORA_FREQ_RX; 27 | LoraFreqTx = CFG_LORA_FREQ_TX; 28 | LoraFreqStep = CFG_LORA_FREQ_STEP; 29 | LoraPower = CFG_LORA_PWR; 30 | 31 | // lora parameters, must match on devices 32 | LoraBw = CFG_LORA_BW; 33 | LoraSf = CFG_LORA_SF; 34 | LoraCodingRate = CFG_LORA_CR; 35 | LoraSync_ = CFG_LORA_SYNC; 36 | LoraCrc_ = CFG_LORA_CRC; // set to 0 to disable 37 | LoraPreambleLen_ = CFG_LORA_PREAMBLE_LEN; 38 | 39 | // fsk parameters 40 | FskBitRate = CFG_FSK_BIT_RATE; 41 | FskFreqDev = CFG_FSK_FREQ_DEV; 42 | FskRxBw = CFG_FSK_RX_BW; 43 | FskShaping = CFG_FSK_SHAPING; 44 | 45 | // lora pinouts 46 | LoraPinSs_ = CFG_LORA_PIN_SS; 47 | LoraPinRst_ = CFG_LORA_PIN_RST; 48 | LoraPinA_ = CFG_LORA_PIN_A; // (sx127x - dio0, sx126x/sx128x - dio1) 49 | LoraPinB_ = CFG_LORA_PIN_B; // (sx127x - dio1, sx126x/sx128x - busy) 50 | LoraPinSwitchRx_ = CFG_LORA_PIN_RXEN; // (sx127x - unused, sx126x - RXEN pin number) 51 | LoraPinSwitchTx_ = CFG_LORA_PIN_TXEN; // (sx127x - unused, sx126x - TXEN pin number) 52 | 53 | // ptt button 54 | PttBtnPin_ = CFG_PTT_BTN_PIN; 55 | 56 | // encoder 57 | EncoderPinA_ = CFG_ENCODER_PIN_A; 58 | EncoderPinB_ = CFG_ENCODER_PIN_B; 59 | EncoderPinBtn_ = CFG_ENCODER_PIN_BTN; 60 | EncoderPinVcc_ = CFG_ENCODER_PIN_VCC; 61 | EncoderSteps_ = CFG_ENCODER_STEPS; 62 | 63 | // audio parameters 64 | AudioCodec = CFG_AUDIO_CODEC_CODEC2; 65 | AudioResampleCoeff_ = CFG_AUDIO_RESAMPLE_COEFF; 66 | AudioSampleRate_ = CFG_AUDIO_SAMPLE_RATE; 67 | AudioCodecSampleRate_ = CFG_AUDIO_CODEC_SAMPLE_RATE; 68 | AudioHpfCutoffHz_ = CFG_AUDIO_HPF_CUTOFF_HZ; 69 | AudioCodec2Mode = CFG_AUDIO_CODEC2_MODE; 70 | AudioMaxPktSize = CFG_AUDIO_MAX_PKT_SIZE; 71 | AudioMaxVol_ = CFG_AUDIO_MAX_VOL; 72 | AudioVol = CFG_AUDIO_VOL; 73 | AudioEnPriv = CFG_AUDIO_ENABLE_PRIVACY; 74 | 75 | // audio, opus 76 | AudioOpusRate = CFG_AUDIO_OPUS_BITRATE; 77 | AudioOpusPcmLen = CFG_AUDIO_OPUS_PCMLEN; 78 | 79 | // i2s speaker 80 | AudioSpkPinBclk_ = CFG_AUDIO_SPK_PIN_BCLK; 81 | AudioSpkPinLrc_ = CFG_AUDIO_SPK_PIN_LRC; 82 | AudioSpkPinDin_ = CFG_AUDIO_SPK_PIN_DIN; 83 | 84 | // i2s mic 85 | AudioMicPinSd_ = CFG_AUDIO_MIC_PIN_SD; 86 | AudioMicPinWs_ = CFG_AUDIO_MIC_PIN_WS; 87 | AudioMicPinSck_ = CFG_AUDIO_MIC_PIN_SCK; 88 | 89 | // battery monitor 90 | BatteryMonPin_ = CFG_AUDIO_BATTERY_MON_PIN; 91 | BatteryMonCal = CFG_AUDIO_BATTERY_MON_CAL; 92 | 93 | // power management 94 | PmSleepAfterMs = CFG_PM_LSLEEP_AFTER_MS; 95 | PmLightSleepDurationMs_ = CFG_PM_LSLEEP_DURATION_MS; 96 | PmLightSleepAwakeMs_ = CFG_PM_LSLEEP_AWAKE_MS; 97 | 98 | // encryption key 99 | memcpy(AudioPrivacyKey_, AudioPrivacyKey, sizeof(AudioPrivacyKey)); 100 | } 101 | 102 | void Config::Reset() 103 | { 104 | InitializeDefault(); 105 | Save(); 106 | } 107 | 108 | void Config::Load() 109 | { 110 | LOG_INFO("Loading settings"); 111 | prefs_.begin("LoraDv"); 112 | 113 | // uninitialized, save 114 | if (!prefs_.isKey(N(Version))) { 115 | LOG_INFO("Not loaded, first time settings"); 116 | prefs_.end(); 117 | Save(); 118 | return; 119 | } 120 | // new default version is higher, save and use default settings 121 | int version = prefs_.getInt(N(Version)); 122 | LOG_INFO("Current prefs version", version); 123 | LOG_INFO("New prefs version", Version); 124 | if (Version > version) { 125 | LOG_INFO("Not loaded, new default settings version requested"); 126 | prefs_.end(); 127 | Save(); 128 | return; 129 | } 130 | if (prefs_.isKey(N(LoraFreqRx))) { 131 | LoraFreqRx = prefs_.getLong(N(LoraFreqRx)); 132 | } else { 133 | prefs_.putLong(N(LoraFreqRx), LoraFreqRx); 134 | } 135 | if (prefs_.isKey(N(LoraFreqTx))) { 136 | LoraFreqTx = prefs_.getLong(N(LoraFreqTx)); 137 | } else { 138 | prefs_.putLong(N(LoraFreqTx), LoraFreqTx); 139 | } 140 | if (prefs_.isKey(N(LoraFreqStep))) { 141 | LoraFreqStep = prefs_.getLong(N(LoraFreqStep)); 142 | } else { 143 | prefs_.putLong(N(LoraFreqStep), LoraFreqStep); 144 | } 145 | if (prefs_.isKey(N(LoraBw))) { 146 | LoraBw = prefs_.getLong(N(LoraBw)); 147 | } else { 148 | prefs_.putLong(N(LoraBw), LoraBw); 149 | } 150 | if (prefs_.isKey(N(LoraSf))) { 151 | LoraSf = prefs_.getInt(N(LoraSf)); 152 | } else { 153 | prefs_.putInt(N(LoraSf), LoraSf); 154 | } 155 | if (prefs_.isKey(N(LoraCodingRate))) { 156 | LoraCodingRate = prefs_.getInt(N(LoraCodingRate)); 157 | } else { 158 | prefs_.putInt(N(LoraCodingRate), LoraCodingRate); 159 | } 160 | if (prefs_.isKey(N(LoraPower))) { 161 | LoraPower = prefs_.getInt(N(LoraPower)); 162 | } else { 163 | prefs_.putInt(N(LoraPower), LoraPower); 164 | } 165 | if (prefs_.isKey(N(AudioCodec2Mode))) { 166 | AudioCodec2Mode = prefs_.getInt(N(AudioCodec2Mode)); 167 | } else { 168 | prefs_.putInt(N(AudioCodec2Mode), AudioCodec2Mode); 169 | } 170 | if (prefs_.isKey(N(AudioVol))) { 171 | AudioVol = prefs_.getInt(N(AudioVol)); 172 | if (AudioVol > CFG_AUDIO_MAX_VOL) { 173 | AudioVol = CFG_AUDIO_VOL; 174 | prefs_.putInt(N(AudioVol), AudioVol); 175 | } 176 | } else { 177 | prefs_.putInt(N(AudioVol), AudioVol); 178 | } 179 | if (prefs_.isKey(N(AudioMaxPktSize))) { 180 | AudioMaxPktSize = prefs_.getInt(N(AudioMaxPktSize)); 181 | } else { 182 | prefs_.putInt(N(AudioMaxPktSize), AudioMaxPktSize); 183 | } 184 | if (prefs_.isKey(N(AudioEnPriv))) { 185 | AudioEnPriv = prefs_.getBool(N(AudioEnPriv)); 186 | } else { 187 | prefs_.putBool(N(AudioEnPriv), AudioEnPriv); 188 | } 189 | if (prefs_.isKey(N(BatteryMonCal))) { 190 | BatteryMonCal = prefs_.getFloat(N(BatteryMonCal)); 191 | } else { 192 | prefs_.putFloat(N(BatteryMonCal), BatteryMonCal); 193 | } 194 | if (prefs_.isKey(N(PmSleepAfterMs))) { 195 | PmSleepAfterMs = prefs_.getInt(N(PmSleepAfterMs)); 196 | } else { 197 | prefs_.putInt(N(PmSleepAfterMs), PmSleepAfterMs); 198 | } 199 | if (prefs_.isKey(N(FskBitRate))) { 200 | FskBitRate = prefs_.getFloat(N(FskBitRate)); 201 | } else { 202 | prefs_.putFloat(N(FskBitRate), FskBitRate); 203 | } 204 | if (prefs_.isKey(N(FskFreqDev))) { 205 | FskFreqDev = prefs_.getFloat(N(FskFreqDev)); 206 | } else { 207 | prefs_.putFloat(N(FskFreqDev), FskFreqDev); 208 | } 209 | if (prefs_.isKey(N(FskRxBw))) { 210 | FskRxBw = prefs_.getFloat(N(FskRxBw)); 211 | } else { 212 | prefs_.putFloat(N(FskRxBw), FskRxBw); 213 | } 214 | if (prefs_.isKey(N(FskShaping))) { 215 | FskShaping = prefs_.getInt(N(FskShaping)); 216 | } else { 217 | prefs_.putInt(N(FskShaping), FskShaping); 218 | } 219 | if (prefs_.isKey(N(ModType))) { 220 | ModType = prefs_.getInt(N(ModType)); 221 | } else { 222 | prefs_.putInt(N(ModType), ModType); 223 | } 224 | if (prefs_.isKey(N(AudioOpusRate))) { 225 | AudioOpusRate = prefs_.getInt(N(AudioOpusRate)); 226 | } else { 227 | prefs_.putInt(N(AudioOpusRate), AudioOpusRate); 228 | } 229 | if (prefs_.isKey(N(AudioOpusPcmLen))) { 230 | AudioOpusPcmLen = prefs_.getInt(N(AudioOpusPcmLen)); 231 | } else { 232 | prefs_.putInt(N(AudioOpusPcmLen), AudioOpusPcmLen); 233 | } 234 | if (prefs_.isKey(N(AudioCodec))) { 235 | AudioCodec = prefs_.getInt(N(AudioCodec)); 236 | } else { 237 | prefs_.putInt(N(AudioCodec), AudioCodec); 238 | } 239 | 240 | prefs_.end(); 241 | LOG_INFO("Settings are loaded"); 242 | } 243 | 244 | void Config::Save() 245 | { 246 | LOG_INFO("Saving settings"); 247 | prefs_.begin("LoraDv"); 248 | prefs_.putInt(N(Version), Version); 249 | prefs_.putLong(N(LoraFreqRx), LoraFreqRx); 250 | prefs_.putLong(N(LoraFreqTx), LoraFreqTx); 251 | prefs_.putLong(N(LoraFreqStep), LoraFreqStep); 252 | prefs_.putLong(N(LoraBw), LoraBw); 253 | prefs_.putInt(N(LoraSf), LoraSf); 254 | prefs_.putInt(N(LoraCodingRate), LoraCodingRate); 255 | prefs_.putInt(N(LoraPower), LoraPower); 256 | prefs_.putInt(N(AudioCodec2Mode), AudioCodec2Mode); 257 | prefs_.putInt(N(AudioVol), AudioVol); 258 | prefs_.putInt(N(AudioMaxPktSize), AudioMaxPktSize); 259 | prefs_.putBool(N(AudioEnPriv), AudioEnPriv); 260 | prefs_.putFloat(N(BatteryMonCal), BatteryMonCal); 261 | prefs_.putInt(N(PmSleepAfterMs), PmSleepAfterMs); 262 | prefs_.putFloat(N(FskBitRate), FskBitRate); 263 | prefs_.putFloat(N(FskFreqDev), FskFreqDev); 264 | prefs_.putFloat(N(FskRxBw), FskRxBw); 265 | prefs_.putInt(N(FskShaping), FskShaping); 266 | prefs_.putInt(N(ModType), ModType); 267 | prefs_.putInt(N(AudioOpusRate), AudioOpusRate); 268 | prefs_.putInt(N(AudioOpusPcmLen), AudioOpusPcmLen); 269 | prefs_.putInt(N(AudioCodec), AudioCodec); 270 | prefs_.end(); 271 | LOG_INFO("Saved settings"); 272 | } 273 | 274 | } // LoraDv -------------------------------------------------------------------------------- /src/settings/settings_menu.cpp: -------------------------------------------------------------------------------- 1 | #include "settings/settings_menu.h" 2 | 3 | namespace LoraDv { 4 | 5 | SettingsMenu::SettingsMenu(std::shared_ptr config) 6 | : config_(config) 7 | , selectedMenuItemIndex_(0) 8 | , isValueSelected_(false) 9 | { 10 | int i = 0; 11 | // frequency 12 | items_.push_back(std::make_shared(config, ++i)); 13 | items_.push_back(std::make_shared(config, ++i)); 14 | items_.push_back(std::make_shared(config, ++i)); 15 | items_.push_back(std::make_shared(config, ++i)); 16 | // modulation, codec 17 | items_.push_back(std::make_shared(config, ++i)); 18 | items_.push_back(std::make_shared(config, ++i)); 19 | // codec2 20 | items_.push_back(std::make_shared(config, ++i)); 21 | items_.push_back(std::make_shared(config, ++i)); 22 | // opus 23 | items_.push_back(std::make_shared(config, ++i)); 24 | items_.push_back(std::make_shared(config, ++i)); 25 | // audio 26 | items_.push_back(std::make_shared(config, ++i)); 27 | items_.push_back(std::make_shared(config, ++i)); 28 | // lora 29 | items_.push_back(std::make_shared(config, ++i)); 30 | items_.push_back(std::make_shared(config, ++i)); 31 | items_.push_back(std::make_shared(config, ++i)); 32 | // fsk 33 | items_.push_back(std::make_shared(config, ++i)); 34 | items_.push_back(std::make_shared(config, ++i)); 35 | items_.push_back(std::make_shared(config, ++i)); 36 | items_.push_back(std::make_shared(config, ++i)); 37 | // other 38 | items_.push_back(std::make_shared(config, ++i)); 39 | items_.push_back(std::make_shared(config, ++i)); 40 | items_.push_back(std::make_shared(config, ++i)); 41 | items_.push_back(std::make_shared(config, ++i)); 42 | items_.push_back(std::make_shared(config, ++i)); 43 | items_.push_back(std::make_shared(config, ++i)); 44 | } 45 | 46 | void SettingsMenu::draw(std::shared_ptr display) 47 | { 48 | stringstream s; 49 | items_[selectedMenuItemIndex_]->getName(s); 50 | s << endl; 51 | if (isValueSelected_) s << ">"; 52 | items_[selectedMenuItemIndex_]->getValue(s); 53 | 54 | display->clearDisplay(); 55 | display->setTextSize(1); 56 | display->setTextColor(WHITE); 57 | display->setCursor(0, 0); 58 | display->print(s.str().c_str()); 59 | display->display(); 60 | } 61 | 62 | void SettingsMenu::onEncoderPositionChanged(int delta) 63 | { 64 | if (isValueSelected_) { 65 | items_[selectedMenuItemIndex_]->changeValue(delta); 66 | } else { 67 | int newIndex = selectedMenuItemIndex_ + delta; 68 | if (newIndex >= 0 && newIndex < items_.size()) selectedMenuItemIndex_ = newIndex; 69 | } 70 | } 71 | 72 | void SettingsMenu::onEncoderButtonClicked() 73 | { 74 | isValueSelected_ = !isValueSelected_; 75 | if (isValueSelected_) { 76 | items_[selectedMenuItemIndex_]->select(); 77 | } 78 | } 79 | 80 | } // LoraDv -------------------------------------------------------------------------------- /src/utils/dsp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "utils/dsp.h" 3 | 4 | namespace LoraDv { 5 | 6 | Dsp::Dsp(int hpfCutoffFreqHz, int hpfSampleRate) 7 | : currentAgcGain_(1.0) 8 | , hpfX1_(0.0f) 9 | , hpfX2_(0.0f) 10 | , hpfY1_(0.0f) 11 | , hpfY2_(0.0f) 12 | { 13 | // initialize hpf coefficients 14 | float omega = 2.0f * M_PI * hpfCutoffFreqHz / hpfSampleRate; 15 | float alpha = sinf(omega) / (1.0f + cosf(omega)); 16 | 17 | hpfA0_ = (1.0f + cosf(omega)) / 2.0f; 18 | hpfA1_ = -(1.0f + cosf(omega)); 19 | hpfA2_ = (1.0f + cosf(omega)) / 2.0f; 20 | hpfB1_ = -cosf(omega); 21 | hpfB2_ = alpha; 22 | } 23 | 24 | int Dsp::audioDownsample2x(int16_t *pcmInput, int16_t *pcmOutput, int pcmInputSize) 25 | { 26 | for (int i = 0; i < pcmInputSize / 2; i++) 27 | { 28 | pcmOutput[i] = pcmInput[i * 2] / 2 + pcmInput[(i * 2) + 1] / 2; 29 | } 30 | return pcmInputSize / 2; 31 | } 32 | 33 | int Dsp::audioUpsample2x(int16_t* pcmInput, int16_t* pcmOutput, int pcmInputSize) 34 | { 35 | for (int i = 0; i < pcmInputSize; i++) 36 | { 37 | pcmOutput[2 * i] = pcmInput[i]; 38 | } 39 | for (int i = 0; i < pcmInputSize - 1; i++) 40 | { 41 | pcmOutput[2 * i + 1] = pcmOutput[2 * i] + (pcmOutput[2 * i + 2] - pcmOutput[2 * i]) / 2; 42 | } 43 | pcmOutput[2 * pcmInputSize - 1] = pcmInput[pcmInputSize - 1]; 44 | return pcmInputSize * 2; 45 | } 46 | 47 | void Dsp::audioAdjustGain(int16_t* pcmBuffer, int pcmBufferSize, float gain) 48 | { 49 | for (int i = 0; i < pcmBufferSize; i++) 50 | { 51 | pcmBuffer[i] *= gain; 52 | } 53 | } 54 | 55 | void Dsp::audioAdjustGainAgc(int16_t* pcmBuffer, int pcmBufferSize, int16_t targetLevel) 56 | { 57 | for (int i = 0; i < pcmBufferSize; i++) 58 | { 59 | int16_t sample = pcmBuffer[i]; 60 | int16_t newSample = sample * currentAgcGain_; 61 | 62 | if (abs(newSample) > targetLevel) currentAgcGain_ -= CfgAgcStep; 63 | else currentAgcGain_ += CfgAgcStep; 64 | 65 | if (currentAgcGain_ < CfgAgcMinGain) currentAgcGain_ = CfgAgcMinGain; 66 | if (currentAgcGain_ > CfgAgcMaxGain) currentAgcGain_ = CfgAgcMaxGain; 67 | 68 | pcmBuffer[i] = newSample; 69 | } 70 | } 71 | 72 | void Dsp::audioFilterHpf(int16_t *pcmBuffer, int pcmBufferSize) 73 | { 74 | for (int i = 0; i < pcmBufferSize; i++) 75 | { 76 | float x0 = (float)pcmBuffer[i]; 77 | float y0 = hpfA0_ * x0 + hpfA1_ * hpfX1_ + hpfA2_ * hpfX2_ - hpfB1_ * hpfY1_ - hpfB2_ * hpfY2_; 78 | 79 | pcmBuffer[i] = (int16_t)y0; 80 | 81 | hpfX2_ = hpfX1_; hpfX1_ = x0; hpfY2_ = hpfY1_; hpfY1_ = y0; 82 | } 83 | } 84 | 85 | int16_t Dsp::audioVolumeToLogPcm(int volume, int maxVolume, int maxPcmValue) 86 | { 87 | if (volume <= 0) return 0; 88 | if (volume > maxVolume) volume = maxVolume; 89 | 90 | float normalizedVolume = static_cast(volume) / maxVolume; 91 | float logScaled = std::log10(1 + 9 * normalizedVolume); 92 | 93 | return static_cast(logScaled * maxPcmValue); 94 | } 95 | 96 | } // namespace LoraDv -------------------------------------------------------------------------------- /src/utils/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils/utils.h" 2 | 3 | namespace LoraDv { 4 | 5 | float Utils::loraGetSnrLimit(int sf, long bw) 6 | { 7 | float snrLimit = -7; 8 | switch (sf) { 9 | case 7: 10 | snrLimit = -7.5; 11 | break; 12 | case 8: 13 | snrLimit = -10.0; 14 | break; 15 | case 9: 16 | snrLimit = -12.6; 17 | break; 18 | case 10: 19 | snrLimit = -15.0; 20 | break; 21 | case 11: 22 | snrLimit = -17.5; 23 | break; 24 | case 12: 25 | snrLimit = -20.0; 26 | break; 27 | } 28 | return -174 + 10 * log10(bw) + 6 + snrLimit; 29 | } 30 | 31 | } // LoraDv --------------------------------------------------------------------------------