├── .gitignore ├── LICENSE ├── README.md ├── examples ├── basic │ ├── GetRSSI │ │ └── GetRSSI.ino │ ├── GetTime │ │ └── GetTime.ino │ ├── LedSetRGB │ │ └── LedSetRGB.ino │ └── SDReadWrite │ │ └── SDReadWrite.ino ├── gnss │ └── GetGNSSLocation │ │ └── GetGNSSLocation.ino ├── grove │ ├── grove-accelerometer │ │ └── grove-accelerometer.ino │ ├── grove-button-using-int │ │ └── grove-button-using-int.ino │ ├── grove-button │ │ └── grove-button.ino │ ├── grove-buzzer │ │ └── grove-buzzer.ino │ ├── grove-gps │ │ └── grove-gps.ino │ ├── grove-magnetic-switch │ │ └── grove-magnetic-switch.ino │ ├── grove-rotary-angle-sensor │ │ └── grove-rotary-angle-sensor.ino │ ├── grove-temperature-and-humidity-sensor │ │ └── grove-temperature-and-humidity-sensor.ino │ └── grove-ultrasonic-ranger │ │ └── grove-ultrasonic-ranger.ino ├── http │ └── ifttt-webhook │ │ └── ifttt-webhook.ino ├── mqtt │ └── mqtt-client │ │ └── mqtt-client.ino ├── sms │ ├── ReceiveSMS │ │ └── ReceiveSMS.ino │ └── SendSMS │ │ └── SendSMS.ino └── soracom │ ├── soracom-funnel │ └── soracom-funnel.ino │ ├── soracom-harvest │ └── soracom-harvest.ino │ └── soracom-unified │ └── soracom-unified.ino ├── keywords.txt ├── library.properties └── src ├── Internal ├── ArgumentParser.cpp ├── ArgumentParser.h ├── AtSerial.cpp ├── AtSerial.h ├── CMSIS │ ├── cmsis_gcc.h │ └── core_cm4.h ├── Debug.cpp ├── Debug.h ├── SerialAPI.h ├── Stopwatch.h ├── StringBuilder.cpp ├── StringBuilder.h ├── WioSK6812.cpp ├── WioSK6812.h └── slre.901d42c │ ├── LICENSE │ ├── README.md │ ├── slre.c │ └── slre.h ├── WioLTE.cpp ├── WioLTE.h ├── WioLTEClient.cpp ├── WioLTEClient.h ├── WioLTEConfig.h ├── WioLTEHardware.cpp ├── WioLTEHardware.h ├── WioLTEHardwarePin.h ├── WioLTEHttpHeader.h └── WioLTEforArduino.h /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # この .gitignore ファイルは Microsoft(R) Visual Studio によって自動的に作成されました。 3 | ################################################################################ 4 | 5 | /.vs 6 | -------------------------------------------------------------------------------- /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 | # Wio LTE for Arduino 2 | 3 | Wio LTEのArduino IDE用ライブラリです。 4 | 5 | A cellular module library for Wio LTE, for Japan market. We developed and maintaining this repository by historical reason. Since GSM is not available in Japan, there are some non implemented functions. 6 | 7 | **This library is for SeeedJP STM32 Boards.** 8 | Please add `http://www.seeed.co.jp/package_SeeedJP_index.json` to additional board manager URL of Arduino IDE, and install `SeeedJP STM32 Boards`. 9 | 10 | ## Wio LTE 11 | 12 | ![1](https://raw.githubusercontent.com/wiki/SeeedJP/WioLTEforArduino/img/1.png) 13 | 14 | Wio LTEは、Seeedが開発しているマイコンモジュールです。 Wio LTE is MCU module provided by Seeed. 15 | 16 | GroveコネクターとSTM32F4マイコン、LTEモジュールが載っており、Arduino IDEで素早くプロトタイピングすることができます。 17 | Wio LTE has Grove connector, STM32F4 and LTE Cat.1 module. You can quickly prototype cellular IoT by using Arduino IDE. 18 | 19 | ## Document 20 | 21 | [wikiページ](https://seeedjp.github.io/Wiki/Wio_LTE_for_Arduino/Home-ja.html)をご参照ください。 22 | 23 | Since this library is provided for Japan market, we only have documents in Japanese. 24 | 25 | [^1]: application/x-www-form-urlencoded 26 | -------------------------------------------------------------------------------- /examples/basic/GetRSSI/GetRSSI.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define INTERVAL (5000) 5 | 6 | WioCellular Wio; 7 | 8 | void setup() { 9 | delay(200); 10 | 11 | SerialUSB.begin(115200); 12 | SerialUSB.println(""); 13 | SerialUSB.println("--- START ---------------------------------------------------"); 14 | 15 | SerialUSB.println("### I/O Initialize."); 16 | Wio.Init(); 17 | 18 | SerialUSB.println("### Power supply ON."); 19 | Wio.PowerSupplyCellular(true); 20 | delay(500); 21 | 22 | SerialUSB.println("### Turn on or reset."); 23 | if (!Wio.TurnOnOrReset()) { 24 | SerialUSB.println("### ERROR! ###"); 25 | return; 26 | } 27 | delay(3000); 28 | 29 | SerialUSB.println("### Setup completed."); 30 | } 31 | 32 | void loop() { 33 | SerialUSB.println("### Get RSSI."); 34 | int rssi = Wio.GetReceivedSignalStrength(); 35 | if (rssi == INT_MIN) { 36 | SerialUSB.println("### ERROR! ###"); 37 | goto err; 38 | } 39 | SerialUSB.print("RSSI:"); 40 | SerialUSB.print(rssi); 41 | SerialUSB.println(""); 42 | 43 | err: 44 | delay(INTERVAL); 45 | } 46 | -------------------------------------------------------------------------------- /examples/basic/GetTime/GetTime.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define INTERVAL (5000) 4 | 5 | WioCellular Wio; 6 | 7 | void setup() { 8 | delay(200); 9 | 10 | SerialUSB.begin(115200); 11 | SerialUSB.println(""); 12 | SerialUSB.println("--- START ---------------------------------------------------"); 13 | 14 | SerialUSB.println("### I/O Initialize."); 15 | Wio.Init(); 16 | 17 | SerialUSB.println("### Power supply ON."); 18 | Wio.PowerSupplyCellular(true); 19 | delay(500); 20 | 21 | SerialUSB.println("### Turn on or reset."); 22 | if (!Wio.TurnOnOrReset()) { 23 | SerialUSB.println("### ERROR! ###"); 24 | return; 25 | } 26 | delay(3000); 27 | 28 | SerialUSB.println("### Sync time."); 29 | if (!Wio.SyncTime("ntp.nict.jp")) { 30 | SerialUSB.println("### ERROR! ###"); 31 | return; 32 | } 33 | 34 | SerialUSB.println("### Setup completed."); 35 | } 36 | 37 | void loop() { 38 | SerialUSB.println("### Get time."); 39 | struct tm now; 40 | if (!Wio.GetTime(&now)) { 41 | SerialUSB.println("### ERROR! ###"); 42 | goto err; 43 | } 44 | SerialUSB.print("UTC:"); 45 | char str[100]; 46 | sprintf(str, "%04d/%02d/%02d %02d:%02d:%02d", now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec); 47 | SerialUSB.println(str); 48 | 49 | err: 50 | delay(INTERVAL); 51 | } 52 | -------------------------------------------------------------------------------- /examples/basic/LedSetRGB/LedSetRGB.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define LED_VALUE (10) 4 | #define INTERVAL (50) 5 | 6 | WioCellular Wio; 7 | int Hue = 0; 8 | 9 | void setup() { 10 | delay(200); 11 | 12 | SerialUSB.begin(115200); 13 | SerialUSB.println(""); 14 | SerialUSB.println("--- START ---------------------------------------------------"); 15 | 16 | SerialUSB.println("### I/O Initialize."); 17 | Wio.Init(); 18 | 19 | SerialUSB.println("### Setup completed."); 20 | } 21 | 22 | void loop() { 23 | int r; 24 | int g; 25 | int b; 26 | 27 | if (Hue < 60) { 28 | r = LED_VALUE; 29 | g = Hue * LED_VALUE / 60; 30 | b = 0; 31 | } 32 | else if (Hue < 120) { 33 | r = (120 - Hue) * LED_VALUE / 60; 34 | g = LED_VALUE; 35 | b = 0; 36 | } 37 | else if (Hue < 180) { 38 | r = 0; 39 | g = LED_VALUE; 40 | b = (Hue - 120) * LED_VALUE / 60; 41 | } 42 | else if (Hue < 240) { 43 | r = 0; 44 | g = (240 - Hue) * LED_VALUE / 60; 45 | b = LED_VALUE; 46 | } 47 | else if (Hue < 300) { 48 | r = (Hue - 240) * LED_VALUE / 60; 49 | g = 0; 50 | b = LED_VALUE; 51 | } 52 | else { 53 | r = LED_VALUE; 54 | g = 0; 55 | b = (360 - Hue) * LED_VALUE / 60; 56 | } 57 | 58 | Wio.LedSetRGB(r, g, b); 59 | 60 | Hue += 10; 61 | if (Hue >= 360) Hue = 0; 62 | 63 | delay(INTERVAL); 64 | } 65 | -------------------------------------------------------------------------------- /examples/basic/SDReadWrite/SDReadWrite.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #if defined ARDUINO_ARCH_STM32F4 3 | #include // https://github.com/Seeed-Studio/SD 4 | #elif defined ARDUINO_ARCH_STM32 5 | #include // https://github.com/SeeedJP/SDforWioLTE 6 | #endif 7 | 8 | #define FILE_NAME "test.txt" 9 | 10 | WioCellular Wio; 11 | 12 | void setup() { 13 | delay(200); 14 | 15 | SerialUSB.begin(115200); 16 | SerialUSB.println(""); 17 | SerialUSB.println("--- START ---------------------------------------------------"); 18 | 19 | SerialUSB.println("### I/O Initialize."); 20 | Wio.Init(); 21 | 22 | SerialUSB.println("### Power supply ON."); 23 | Wio.PowerSupplySD(true); 24 | delay(500); 25 | 26 | SerialUSB.println("### Initialize SD card."); 27 | if (!SD.begin()) { 28 | SerialUSB.println("### ERROR! ###"); 29 | return; 30 | } 31 | 32 | File myFile; 33 | 34 | SerialUSB.println("### Writing to "FILE_NAME"."); 35 | myFile = SD.open(FILE_NAME, FILE_WRITE); 36 | if (!myFile) { 37 | SerialUSB.println("### ERROR! ###"); 38 | return; 39 | } 40 | myFile.println("testing 1, 2, 3."); 41 | myFile.close(); 42 | 43 | SerialUSB.println("### Reading from "FILE_NAME"."); 44 | myFile = SD.open(FILE_NAME); 45 | if (!myFile) { 46 | SerialUSB.println("### ERROR! ###"); 47 | return; 48 | } 49 | SerialUSB.println(FILE_NAME":"); 50 | while (myFile.available()) { 51 | SerialUSB.write(myFile.read()); 52 | } 53 | myFile.close(); 54 | 55 | SerialUSB.println("### Setup completed."); 56 | } 57 | 58 | void loop() { 59 | } 60 | -------------------------------------------------------------------------------- /examples/gnss/GetGNSSLocation/GetGNSSLocation.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define INTERVAL (5000) 4 | 5 | WioCellular Wio; 6 | 7 | void setup() { 8 | delay(200); 9 | 10 | SerialUSB.begin(115200); 11 | SerialUSB.println(""); 12 | SerialUSB.println("--- START ---------------------------------------------------"); 13 | 14 | SerialUSB.println("### I/O Initialize."); 15 | Wio.Init(); 16 | 17 | SerialUSB.println("### Power supply ON."); 18 | Wio.PowerSupplyCellular(true); 19 | SerialUSB.println("### Power supply GNSS."); 20 | Wio.PowerSupplyGNSS(true); 21 | delay(500); 22 | 23 | SerialUSB.println("### Turn on or reset."); 24 | if (!Wio.TurnOnOrReset()) { 25 | SerialUSB.println("### ERROR! ###"); 26 | return; 27 | } 28 | 29 | SerialUSB.println("### Enable GNSS."); 30 | if (!Wio.EnableGNSS()) { 31 | SerialUSB.println("### ERROR! ###"); 32 | return; 33 | } 34 | 35 | SerialUSB.println("### Setup completed."); 36 | } 37 | 38 | void loop() { 39 | double longitude; 40 | double latitude; 41 | double altitude; 42 | struct tm utc; 43 | 44 | SerialUSB.println("### Get GNSS location."); 45 | bool getLocation = Wio.GetGNSSLocation(&longitude, &latitude, &altitude, &utc); 46 | 47 | if (getLocation) { 48 | SerialUSB.print(" long: "); 49 | SerialUSB.println(longitude, 6); 50 | SerialUSB.print(" lat: "); 51 | SerialUSB.println(latitude, 6); 52 | SerialUSB.print(" altitude: "); 53 | SerialUSB.println(altitude, 6); 54 | SerialUSB.print(" utc: "); 55 | SerialUSB.println(asctime(&utc)); 56 | } 57 | else if (Wio.GetLastError() == WioLTE::E_GNSS_NOT_FIXED) { 58 | SerialUSB.println("### NOT FIXED. ###"); 59 | } 60 | else { 61 | SerialUSB.println("### ERROR! ###"); 62 | } 63 | 64 | delay(INTERVAL); 65 | } 66 | -------------------------------------------------------------------------------- /examples/grove/grove-accelerometer/grove-accelerometer.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define INTERVAL (100) 4 | 5 | #define I2C_ADDRESS (0x53) 6 | #define REG_POWER_CTL (0x2d) 7 | #define REG_DATAX0 (0x32) 8 | 9 | WioCellular Wio; 10 | 11 | void setup() { 12 | delay(200); 13 | 14 | SerialUSB.begin(115200); 15 | SerialUSB.println(""); 16 | SerialUSB.println("--- START ---------------------------------------------------"); 17 | 18 | SerialUSB.println("### I/O Initialize."); 19 | Wio.Init(); 20 | 21 | SerialUSB.println("### Power supply ON."); 22 | Wio.PowerSupplyGrove(true); 23 | delay(500); 24 | 25 | SerialUSB.println("### Sensor Initialize."); 26 | AccelInitialize(); 27 | 28 | SerialUSB.println("### Setup completed."); 29 | } 30 | 31 | void loop() { 32 | float x; 33 | float y; 34 | float z; 35 | AccelReadXYZ(&x, &y, &z); 36 | SerialUSB.print(x); 37 | SerialUSB.print(' '); 38 | SerialUSB.print(y); 39 | SerialUSB.print(' '); 40 | SerialUSB.println(z); 41 | 42 | delay(INTERVAL); 43 | } 44 | 45 | //////////////////////////////////////////////////////////////////////////////////////// 46 | // 47 | 48 | void AccelInitialize() { 49 | Wire.begin(); 50 | Wire.beginTransmission(I2C_ADDRESS); 51 | Wire.write(REG_POWER_CTL); 52 | Wire.write(0x08); 53 | Wire.endTransmission(); 54 | } 55 | 56 | void AccelReadXYZ(float* x, float* y, float* z) { 57 | Wire.beginTransmission(I2C_ADDRESS); 58 | Wire.write(REG_DATAX0); 59 | Wire.endTransmission(); 60 | 61 | if (Wire.requestFrom(I2C_ADDRESS, 6) != 6) { 62 | *x = 0; 63 | *y = 0; 64 | *z = 0; 65 | return; 66 | } 67 | 68 | int16_t val; 69 | ((uint8_t*)&val)[0] = Wire.read(); 70 | ((uint8_t*)&val)[1] = Wire.read(); 71 | *x = val * 2.0 / 512; 72 | ((uint8_t*)&val)[0] = Wire.read(); 73 | ((uint8_t*)&val)[1] = Wire.read(); 74 | *y = val * 2.0 / 512; 75 | ((uint8_t*)&val)[0] = Wire.read(); 76 | ((uint8_t*)&val)[1] = Wire.read(); 77 | *z = val * 2.0 / 512; 78 | } 79 | 80 | //////////////////////////////////////////////////////////////////////////////////////// 81 | -------------------------------------------------------------------------------- /examples/grove/grove-button-using-int/grove-button-using-int.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // You can use WIOLTE_(D20|A4|A6) with `Wio.PowerSupplyGrove(true);` 4 | #define BUTTON_PIN (WIOLTE_D38) 5 | 6 | #define COLOR_ON 127, 127, 127 7 | #define COLOR_OFF 0, 0, 0 8 | 9 | WioCellular Wio; 10 | 11 | volatile bool StateChanged = false; 12 | volatile bool State = false; 13 | 14 | void change_state() { 15 | State = !State; 16 | StateChanged = true; 17 | } 18 | 19 | void setup() { 20 | SerialUSB.begin(115200); 21 | Wio.Init(); 22 | 23 | pinMode(BUTTON_PIN, INPUT); 24 | attachInterrupt(BUTTON_PIN, change_state, RISING); 25 | } 26 | 27 | void loop() { 28 | if (StateChanged) { 29 | SerialUSB.print(State ? '*' : '.'); 30 | 31 | if (State) { 32 | Wio.LedSetRGB(COLOR_ON); 33 | } 34 | else { 35 | Wio.LedSetRGB(COLOR_OFF); 36 | } 37 | 38 | StateChanged = false; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/grove/grove-button/grove-button.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define BUTTON_PIN (WIOLTE_D38) 4 | #define INTERVAL (100) 5 | 6 | void setup() { 7 | SerialUSB.begin(115200); 8 | pinMode(BUTTON_PIN, INPUT); 9 | } 10 | 11 | void loop() { 12 | int buttonState = digitalRead(BUTTON_PIN); 13 | SerialUSB.print(buttonState ? '*' : '.'); 14 | 15 | delay(INTERVAL); 16 | } 17 | -------------------------------------------------------------------------------- /examples/grove/grove-buzzer/grove-buzzer.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define BUZZER_PIN (WIOLTE_D38) 4 | #define BUZZER_ON_TIME (100) 5 | #define BUZZER_OFF_TIME (3000) 6 | 7 | void setup() { 8 | pinMode(BUZZER_PIN, OUTPUT); 9 | delay(500); 10 | } 11 | 12 | void loop() { 13 | digitalWrite(BUZZER_PIN, HIGH); 14 | delay(BUZZER_ON_TIME); 15 | 16 | digitalWrite(BUZZER_PIN, LOW); 17 | delay(BUZZER_OFF_TIME); 18 | } 19 | -------------------------------------------------------------------------------- /examples/grove/grove-gps/grove-gps.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | WioCellular Wio; 4 | 5 | void setup() { 6 | delay(200); 7 | 8 | SerialUSB.begin(115200); 9 | SerialUSB.println(""); 10 | SerialUSB.println("--- START ---------------------------------------------------"); 11 | 12 | SerialUSB.println("### I/O Initialize."); 13 | GpsBegin(&Serial); 14 | Wio.Init(); 15 | 16 | SerialUSB.println("### Power supply ON."); 17 | Wio.PowerSupplyGrove(true); 18 | delay(500); 19 | 20 | SerialUSB.println("### Setup completed."); 21 | } 22 | 23 | void loop() { 24 | const char* data = GpsRead(); 25 | if (data != NULL && strncmp(data, "$GPGGA,", 7) == 0) { 26 | SerialUSB.println(data); 27 | } 28 | } 29 | 30 | //////////////////////////////////////////////////////////////////////////////////////// 31 | // 32 | 33 | #define GPS_OVERFLOW_STRING "OVERFLOW" 34 | 35 | HardwareSerial* GpsSerial; 36 | char GpsData[100]; 37 | char GpsDataLength; 38 | 39 | void GpsBegin(HardwareSerial* serial) { 40 | GpsSerial = serial; 41 | GpsSerial->begin(9600); 42 | GpsDataLength = 0; 43 | } 44 | 45 | const char* GpsRead() { 46 | while (GpsSerial->available()) { 47 | char data = GpsSerial->read(); 48 | if (data == '\r') continue; 49 | if (data == '\n') { 50 | GpsData[GpsDataLength] = '\0'; 51 | GpsDataLength = 0; 52 | return GpsData; 53 | } 54 | 55 | if (GpsDataLength > sizeof (GpsData) - 1) { // Overflow 56 | GpsDataLength = 0; 57 | return GPS_OVERFLOW_STRING; 58 | } 59 | GpsData[GpsDataLength++] = data; 60 | } 61 | 62 | return NULL; 63 | } 64 | 65 | //////////////////////////////////////////////////////////////////////////////////////// 66 | -------------------------------------------------------------------------------- /examples/grove/grove-magnetic-switch/grove-magnetic-switch.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define MAGNETIC_SWITCH_PIN (WIOLTE_D38) 4 | #define INTERVAL (100) 5 | 6 | void setup() { 7 | SerialUSB.begin(115200); 8 | pinMode(MAGNETIC_SWITCH_PIN, INPUT); 9 | } 10 | 11 | void loop() { 12 | int switchState = digitalRead(MAGNETIC_SWITCH_PIN); 13 | SerialUSB.print(switchState ? '*' : '.'); 14 | 15 | delay(INTERVAL); 16 | } 17 | -------------------------------------------------------------------------------- /examples/grove/grove-rotary-angle-sensor/grove-rotary-angle-sensor.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define ROTARY_ANGLE_PIN (WIOLTE_A4) 4 | #define INTERVAL (500) 5 | #define BAR_LENGTH (40) 6 | 7 | WioCellular Wio; 8 | 9 | void setup() { 10 | delay(200); 11 | 12 | SerialUSB.begin(115200); 13 | SerialUSB.println(""); 14 | SerialUSB.println("--- START ---------------------------------------------------"); 15 | 16 | SerialUSB.println("### I/O Initialize."); 17 | Wio.Init(); 18 | 19 | SerialUSB.println("### Power supply ON."); 20 | Wio.PowerSupplyGrove(true); 21 | delay(500); 22 | 23 | SerialUSB.println("### Setup pin mode."); 24 | pinMode(ROTARY_ANGLE_PIN, INPUT_ANALOG); 25 | 26 | #ifdef ARDUINO_ARCH_STM32 27 | analogReadResolution(12); 28 | #endif // ARDUINO_ARCH_STM32 29 | } 30 | 31 | void loop() { 32 | int rotaryAngle = analogRead(ROTARY_ANGLE_PIN); 33 | 34 | int i; 35 | for (i = 0; i < BAR_LENGTH * rotaryAngle / 4095; i++) SerialUSB.print("*"); 36 | for (; i < BAR_LENGTH; i++) SerialUSB.print("."); 37 | SerialUSB.print(" "); 38 | SerialUSB.println(rotaryAngle); 39 | 40 | delay(INTERVAL); 41 | } 42 | -------------------------------------------------------------------------------- /examples/grove/grove-temperature-and-humidity-sensor/grove-temperature-and-humidity-sensor.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define SENSOR_PIN (WIOLTE_D38) 4 | 5 | void setup() { 6 | SerialUSB.begin(115200); 7 | TemperatureAndHumidityBegin(SENSOR_PIN); 8 | } 9 | 10 | void loop() { 11 | float temp; 12 | float humi; 13 | 14 | if (!TemperatureAndHumidityRead(&temp, &humi)) { 15 | SerialUSB.println("ERROR!"); 16 | goto err; 17 | } 18 | 19 | SerialUSB.print("Current humidity = "); 20 | SerialUSB.print(humi); 21 | SerialUSB.print("% "); 22 | SerialUSB.print("temperature = "); 23 | SerialUSB.print(temp); 24 | SerialUSB.println("C"); 25 | 26 | err: 27 | delay(2000); 28 | } 29 | 30 | //////////////////////////////////////////////////////////////////////////////////////// 31 | // 32 | 33 | int TemperatureAndHumidityPin; 34 | 35 | void TemperatureAndHumidityBegin(int pin) { 36 | TemperatureAndHumidityPin = pin; 37 | DHT11Init(TemperatureAndHumidityPin); 38 | } 39 | 40 | bool TemperatureAndHumidityRead(float* temperature, float* humidity) { 41 | byte data[5]; 42 | 43 | DHT11Start(TemperatureAndHumidityPin); 44 | for (int i = 0; i < 5; i++) data[i] = DHT11ReadByte(TemperatureAndHumidityPin); 45 | DHT11Finish(TemperatureAndHumidityPin); 46 | 47 | if(!DHT11Check(data, sizeof (data))) return false; 48 | if (data[1] >= 10) return false; 49 | if (data[3] >= 10) return false; 50 | 51 | *humidity = (float)data[0] + (float)data[1] / 10.0f; 52 | *temperature = (float)data[2] + (float)data[3] / 10.0f; 53 | 54 | return true; 55 | } 56 | 57 | //////////////////////////////////////////////////////////////////////////////////////// 58 | // 59 | 60 | void DHT11Init(int pin) { 61 | digitalWrite(pin, HIGH); 62 | pinMode(pin, OUTPUT); 63 | } 64 | 65 | void DHT11Start(int pin) { 66 | // Host the start of signal 67 | digitalWrite(pin, LOW); 68 | delay(18); 69 | 70 | // Pulled up to wait for 71 | pinMode(pin, INPUT); 72 | while (!digitalRead(pin)) ; 73 | 74 | // Response signal 75 | while (digitalRead(pin)) ; 76 | 77 | // Pulled ready to output 78 | while (!digitalRead(pin)) ; 79 | } 80 | 81 | byte DHT11ReadByte(int pin) { 82 | byte data = 0; 83 | 84 | for (int i = 0; i < 8; i++) { 85 | while (digitalRead(pin)) ; 86 | 87 | while (!digitalRead(pin)) ; 88 | unsigned long start = micros(); 89 | 90 | while (digitalRead(pin)) ; 91 | unsigned long finish = micros(); 92 | 93 | if ((unsigned long)(finish - start) > 50) data |= 1 << (7 - i); 94 | } 95 | 96 | return data; 97 | } 98 | 99 | void DHT11Finish(int pin) { 100 | // Releases the bus 101 | while (!digitalRead(pin)) ; 102 | digitalWrite(pin, HIGH); 103 | pinMode(pin, OUTPUT); 104 | } 105 | 106 | bool DHT11Check(const byte* data, int dataSize) { 107 | if (dataSize != 5) return false; 108 | 109 | byte sum = 0; 110 | for (int i = 0; i < dataSize - 1; i++) { 111 | sum += data[i]; 112 | } 113 | 114 | return data[dataSize - 1] == sum; 115 | } 116 | 117 | //////////////////////////////////////////////////////////////////////////////////////// 118 | -------------------------------------------------------------------------------- /examples/grove/grove-ultrasonic-ranger/grove-ultrasonic-ranger.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include // https://github.com/Seeed-Studio/Grove_Ultrasonic_Ranger 3 | 4 | #define ULTRASONIC_PIN (WIOLTE_D38) 5 | #define INTERVAL (100) 6 | 7 | Ultrasonic UltrasonicRanger(ULTRASONIC_PIN); 8 | 9 | void setup() { 10 | SerialUSB.begin(115200); 11 | } 12 | 13 | void loop() { 14 | long distance; 15 | distance = UltrasonicRanger.MeasureInCentimeters(); 16 | SerialUSB.print(distance); 17 | SerialUSB.println("[cm]"); 18 | 19 | delay(INTERVAL); 20 | } 21 | -------------------------------------------------------------------------------- /examples/http/ifttt-webhook/ifttt-webhook.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define APN "soracom.io" 5 | #define USERNAME "sora" 6 | #define PASSWORD "sora" 7 | 8 | #define WEBHOOK_EVENTNAME "wiolte_uptime" 9 | #define WEBHOOK_KEY "" 10 | #define WEBHOOK_URL "https://maker.ifttt.com/trigger/"WEBHOOK_EVENTNAME"/with/key/"WEBHOOK_KEY 11 | 12 | #define INTERVAL (60000) 13 | 14 | WioCellular Wio; 15 | 16 | void setup() { 17 | delay(200); 18 | 19 | SerialUSB.begin(115200); 20 | SerialUSB.println(""); 21 | SerialUSB.println("--- START ---------------------------------------------------"); 22 | 23 | SerialUSB.println("### I/O Initialize."); 24 | Wio.Init(); 25 | 26 | SerialUSB.println("### Power supply ON."); 27 | Wio.PowerSupplyCellular(true); 28 | delay(500); 29 | 30 | SerialUSB.println("### Turn on or reset."); 31 | if (!Wio.TurnOnOrReset()) { 32 | SerialUSB.println("### ERROR! ###"); 33 | return; 34 | } 35 | 36 | SerialUSB.println("### Connecting to \""APN"\"."); 37 | if (!Wio.Activate(APN, USERNAME, PASSWORD)) { 38 | SerialUSB.println("### ERROR! ###"); 39 | return; 40 | } 41 | 42 | SerialUSB.println("### Setup completed."); 43 | } 44 | 45 | void loop() { 46 | char data[100]; 47 | int status; 48 | 49 | SerialUSB.println("### Post."); 50 | sprintf(data, "{\"value1\":\"uptime %lu\"}", millis() / 1000); 51 | SerialUSB.print("Post:"); 52 | SerialUSB.print(data); 53 | SerialUSB.println(""); 54 | if (!Wio.HttpPost(WEBHOOK_URL, data, &status)) { 55 | SerialUSB.println("### ERROR! ###"); 56 | goto err; 57 | } 58 | SerialUSB.print("Status:"); 59 | SerialUSB.println(status); 60 | 61 | err: 62 | SerialUSB.println("### Wait."); 63 | delay(INTERVAL); 64 | } 65 | -------------------------------------------------------------------------------- /examples/mqtt/mqtt-client/mqtt-client.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // https://github.com/knolleary/PubSubClient 4 | #include 5 | 6 | #define APN "soracom.io" 7 | #define USERNAME "sora" 8 | #define PASSWORD "sora" 9 | 10 | #define MQTT_SERVER_HOST "hostname" 11 | #define MQTT_SERVER_PORT (1883) 12 | 13 | #define ID "WioLTE" 14 | #define OUT_TOPIC "outTopic" 15 | #define IN_TOPIC "inTopic" 16 | 17 | #define INTERVAL (60000) 18 | 19 | #define MQTT_PACKET_SIZE (512) 20 | 21 | WioCellular Wio; 22 | WioCellularClient WioClient(&Wio); 23 | PubSubClient MqttClient; 24 | 25 | void callback(char* topic, byte* payload, unsigned int length) { 26 | SerialUSB.print("Subscribe:"); 27 | for (int i = 0; i < length; i++) SerialUSB.print((char)payload[i]); 28 | SerialUSB.println(""); 29 | } 30 | 31 | void setup() { 32 | delay(200); 33 | 34 | SerialUSB.begin(115200); 35 | SerialUSB.println(""); 36 | SerialUSB.println("--- START ---------------------------------------------------"); 37 | 38 | SerialUSB.println("### I/O Initialize."); 39 | Wio.Init(); 40 | 41 | SerialUSB.println("### Power supply ON."); 42 | Wio.PowerSupplyCellular(true); 43 | delay(500); 44 | 45 | SerialUSB.println("### Turn on or reset."); 46 | if (!Wio.TurnOnOrReset()) { 47 | SerialUSB.println("### ERROR! ###"); 48 | return; 49 | } 50 | 51 | SerialUSB.println("### Connecting to \""APN"\"."); 52 | if (!Wio.Activate(APN, USERNAME, PASSWORD)) { 53 | SerialUSB.println("### ERROR! ###"); 54 | return; 55 | } 56 | 57 | SerialUSB.println("### Connecting to MQTT server \""MQTT_SERVER_HOST"\""); 58 | MqttClient.setBufferSize(MQTT_PACKET_SIZE); 59 | MqttClient.setServer(MQTT_SERVER_HOST, MQTT_SERVER_PORT); 60 | MqttClient.setCallback(callback); 61 | MqttClient.setClient(WioClient); 62 | if (!MqttClient.connect(ID)) { 63 | SerialUSB.println("### ERROR! ###"); 64 | return; 65 | } 66 | MqttClient.subscribe(IN_TOPIC); 67 | 68 | SerialUSB.println("### Setup completed."); 69 | } 70 | 71 | void loop() { 72 | char data[100]; 73 | sprintf(data, "{\"uptime\":%lu}", millis() / 1000); 74 | SerialUSB.print("Publish:"); 75 | SerialUSB.print(data); 76 | SerialUSB.println(""); 77 | MqttClient.publish(OUT_TOPIC, data); 78 | 79 | err: 80 | unsigned long next = millis(); 81 | while (millis() < next + INTERVAL) 82 | { 83 | MqttClient.loop(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /examples/sms/ReceiveSMS/ReceiveSMS.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define INTERVAL (1000) 4 | 5 | WioCellular Wio; 6 | 7 | void setup() { 8 | delay(200); 9 | 10 | SerialUSB.begin(115200); 11 | SerialUSB.println(""); 12 | SerialUSB.println("--- START ---------------------------------------------------"); 13 | 14 | SerialUSB.println("### I/O Initialize."); 15 | Wio.Init(); 16 | 17 | SerialUSB.println("### Power supply ON."); 18 | Wio.PowerSupplyCellular(true); 19 | delay(500); 20 | 21 | SerialUSB.println("### Turn on or reset."); 22 | if (!Wio.TurnOnOrReset()) { 23 | SerialUSB.println("### ERROR! ###"); 24 | return; 25 | } 26 | delay(3000); 27 | 28 | SerialUSB.println("### Get phone number."); 29 | char str[100]; 30 | if (Wio.GetPhoneNumber(str, sizeof (str)) <= 0) { 31 | SerialUSB.println("### ERROR! ###"); 32 | return; 33 | } 34 | SerialUSB.println(str); 35 | 36 | SerialUSB.println("### Setup completed."); 37 | } 38 | 39 | void loop() { 40 | SerialUSB.print("."); 41 | while (true) { 42 | char str[200]; 43 | int strLen = Wio.ReceiveSMS(str, sizeof (str)); 44 | if (strLen < 0) { 45 | SerialUSB.println("### ERROR! ###"); 46 | goto err; 47 | } 48 | if (strLen == 0) break; 49 | 50 | SerialUSB.println(""); 51 | SerialUSB.println(str); 52 | 53 | if (!Wio.DeleteReceivedSMS()) { 54 | SerialUSB.println("### ERROR! ###"); 55 | goto err; 56 | } 57 | } 58 | 59 | err: 60 | delay(INTERVAL); 61 | } 62 | -------------------------------------------------------------------------------- /examples/sms/SendSMS/SendSMS.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define PHONE_NUMBER "01234567890" 4 | 5 | WioCellular Wio; 6 | 7 | void setup() { 8 | delay(200); 9 | 10 | SerialUSB.begin(115200); 11 | SerialUSB.println(""); 12 | SerialUSB.println("--- START ---------------------------------------------------"); 13 | 14 | SerialUSB.println("### I/O Initialize."); 15 | Wio.Init(); 16 | 17 | SerialUSB.println("### Power supply ON."); 18 | Wio.PowerSupplyCellular(true); 19 | delay(500); 20 | 21 | SerialUSB.println("### Turn on or reset."); 22 | if (!Wio.TurnOnOrReset()) { 23 | SerialUSB.println("### ERROR! ###"); 24 | return; 25 | } 26 | delay(3000); 27 | 28 | SerialUSB.println("### Send SMS."); 29 | if (!Wio.SendSMS(PHONE_NUMBER, "Hello world!")) { 30 | SerialUSB.println("### ERROR! ###"); 31 | return; 32 | } 33 | 34 | SerialUSB.println("### Setup completed."); 35 | } 36 | 37 | void loop() { 38 | } 39 | -------------------------------------------------------------------------------- /examples/soracom/soracom-funnel/soracom-funnel.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define INTERVAL (60000) 5 | #define RECEIVE_TIMEOUT (10000) 6 | 7 | WioCellular Wio; 8 | 9 | void setup() { 10 | delay(200); 11 | 12 | SerialUSB.begin(115200); 13 | SerialUSB.println(""); 14 | SerialUSB.println("--- START ---------------------------------------------------"); 15 | 16 | SerialUSB.println("### I/O Initialize."); 17 | Wio.Init(); 18 | 19 | SerialUSB.println("### Power supply ON."); 20 | Wio.PowerSupplyCellular(true); 21 | delay(500); 22 | 23 | SerialUSB.println("### Turn on or reset."); 24 | if (!Wio.TurnOnOrReset()) { 25 | SerialUSB.println("### ERROR! ###"); 26 | return; 27 | } 28 | 29 | SerialUSB.println("### Connecting to \"soracom.io\"."); 30 | if (!Wio.Activate("soracom.io", "sora", "sora")) { 31 | SerialUSB.println("### ERROR! ###"); 32 | return; 33 | } 34 | 35 | SerialUSB.println("### Setup completed."); 36 | } 37 | 38 | void loop() { 39 | char data[100]; 40 | 41 | SerialUSB.println("### Open."); 42 | int connectId; 43 | connectId = Wio.SocketOpen("funnel.soracom.io", 23080, WIOLTE_UDP); 44 | if (connectId < 0) { 45 | SerialUSB.println("### ERROR! ###"); 46 | goto err; 47 | } 48 | 49 | SerialUSB.println("### Send."); 50 | sprintf(data, "{\"uptime\":%lu}", millis() / 1000); 51 | SerialUSB.print("Send:"); 52 | SerialUSB.print(data); 53 | SerialUSB.println(""); 54 | if (!Wio.SocketSend(connectId, data)) { 55 | SerialUSB.println("### ERROR! ###"); 56 | goto err_close; 57 | } 58 | 59 | SerialUSB.println("### Receive."); 60 | int length; 61 | length = Wio.SocketReceive(connectId, data, sizeof (data), RECEIVE_TIMEOUT); 62 | if (length < 0) { 63 | SerialUSB.println("### ERROR! ###"); 64 | goto err_close; 65 | } 66 | if (length == 0) { 67 | SerialUSB.println("### RECEIVE TIMEOUT! ###"); 68 | goto err_close; 69 | } 70 | SerialUSB.print("Receive:"); 71 | SerialUSB.print(data); 72 | SerialUSB.println(""); 73 | 74 | err_close: 75 | SerialUSB.println("### Close."); 76 | if (!Wio.SocketClose(connectId)) { 77 | SerialUSB.println("### ERROR! ###"); 78 | goto err; 79 | } 80 | 81 | err: 82 | delay(INTERVAL); 83 | } 84 | -------------------------------------------------------------------------------- /examples/soracom/soracom-harvest/soracom-harvest.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define INTERVAL (60000) 5 | #define RECEIVE_TIMEOUT (10000) 6 | 7 | // uncomment following line to use Temperature & Humidity sensor 8 | // #define SENSOR_PIN (WIOLTE_D38) 9 | 10 | WioCellular Wio; 11 | 12 | void setup() { 13 | delay(200); 14 | 15 | SerialUSB.begin(115200); 16 | SerialUSB.println(""); 17 | SerialUSB.println("--- START ---------------------------------------------------"); 18 | 19 | SerialUSB.println("### I/O Initialize."); 20 | Wio.Init(); 21 | 22 | SerialUSB.println("### Power supply ON."); 23 | Wio.PowerSupplyCellular(true); 24 | delay(500); 25 | 26 | SerialUSB.println("### Turn on or reset."); 27 | if (!Wio.TurnOnOrReset()) { 28 | SerialUSB.println("### ERROR! ###"); 29 | return; 30 | } 31 | 32 | SerialUSB.println("### Connecting to \"soracom.io\"."); 33 | if (!Wio.Activate("soracom.io", "sora", "sora")) { 34 | SerialUSB.println("### ERROR! ###"); 35 | return; 36 | } 37 | 38 | #ifdef SENSOR_PIN 39 | TemperatureAndHumidityBegin(SENSOR_PIN); 40 | #endif // SENSOR_PIN 41 | 42 | SerialUSB.println("### Setup completed."); 43 | } 44 | 45 | void loop() { 46 | char data[100]; 47 | 48 | #ifdef SENSOR_PIN 49 | float temp; 50 | float humi; 51 | 52 | if (!TemperatureAndHumidityRead(&temp, &humi)) { 53 | SerialUSB.println("ERROR!"); 54 | goto err; 55 | } 56 | 57 | SerialUSB.print("Current humidity = "); 58 | SerialUSB.print(humi); 59 | SerialUSB.print("% "); 60 | SerialUSB.print("temperature = "); 61 | SerialUSB.print(temp); 62 | SerialUSB.println("C"); 63 | 64 | sprintf(data,"{\"temp\":%.1f,\"humi\":%.1f}", temp, humi); 65 | #else 66 | sprintf(data, "{\"uptime\":%lu}", millis() / 1000); 67 | #endif // SENSOR_PIN 68 | 69 | SerialUSB.println("### Open."); 70 | int connectId; 71 | connectId = Wio.SocketOpen("harvest.soracom.io", 8514, WIOLTE_UDP); 72 | if (connectId < 0) { 73 | SerialUSB.println("### ERROR! ###"); 74 | goto err; 75 | } 76 | 77 | SerialUSB.println("### Send."); 78 | SerialUSB.print("Send:"); 79 | SerialUSB.print(data); 80 | SerialUSB.println(""); 81 | if (!Wio.SocketSend(connectId, data)) { 82 | SerialUSB.println("### ERROR! ###"); 83 | goto err_close; 84 | } 85 | 86 | SerialUSB.println("### Receive."); 87 | int length; 88 | length = Wio.SocketReceive(connectId, data, sizeof (data), RECEIVE_TIMEOUT); 89 | if (length < 0) { 90 | SerialUSB.println("### ERROR! ###"); 91 | goto err_close; 92 | } 93 | if (length == 0) { 94 | SerialUSB.println("### RECEIVE TIMEOUT! ###"); 95 | goto err_close; 96 | } 97 | SerialUSB.print("Receive:"); 98 | SerialUSB.print(data); 99 | SerialUSB.println(""); 100 | 101 | err_close: 102 | SerialUSB.println("### Close."); 103 | if (!Wio.SocketClose(connectId)) { 104 | SerialUSB.println("### ERROR! ###"); 105 | goto err; 106 | } 107 | 108 | err: 109 | delay(INTERVAL); 110 | } 111 | 112 | //////////////////////////////////////////////////////////////////////////////////////// 113 | // 114 | 115 | #ifdef SENSOR_PIN 116 | 117 | int TemperatureAndHumidityPin; 118 | 119 | void TemperatureAndHumidityBegin(int pin) { 120 | TemperatureAndHumidityPin = pin; 121 | DHT11Init(TemperatureAndHumidityPin); 122 | } 123 | 124 | bool TemperatureAndHumidityRead(float* temperature, float* humidity) { 125 | byte data[5]; 126 | 127 | DHT11Start(TemperatureAndHumidityPin); 128 | for (int i = 0; i < 5; i++) data[i] = DHT11ReadByte(TemperatureAndHumidityPin); 129 | DHT11Finish(TemperatureAndHumidityPin); 130 | 131 | if(!DHT11Check(data, sizeof (data))) return false; 132 | if (data[1] >= 10) return false; 133 | if (data[3] >= 10) return false; 134 | 135 | *humidity = (float)data[0] + (float)data[1] / 10.0f; 136 | *temperature = (float)data[2] + (float)data[3] / 10.0f; 137 | 138 | return true; 139 | } 140 | 141 | #endif // SENSOR_PIN 142 | 143 | //////////////////////////////////////////////////////////////////////////////////////// 144 | // 145 | 146 | #ifdef SENSOR_PIN 147 | 148 | void DHT11Init(int pin) { 149 | digitalWrite(pin, HIGH); 150 | pinMode(pin, OUTPUT); 151 | } 152 | 153 | void DHT11Start(int pin) { 154 | // Host the start of signal 155 | digitalWrite(pin, LOW); 156 | delay(18); 157 | 158 | // Pulled up to wait for 159 | pinMode(pin, INPUT); 160 | while (!digitalRead(pin)) ; 161 | 162 | // Response signal 163 | while (digitalRead(pin)) ; 164 | 165 | // Pulled ready to output 166 | while (!digitalRead(pin)) ; 167 | } 168 | 169 | byte DHT11ReadByte(int pin) { 170 | byte data = 0; 171 | 172 | for (int i = 0; i < 8; i++) { 173 | while (digitalRead(pin)) ; 174 | 175 | while (!digitalRead(pin)) ; 176 | unsigned long start = micros(); 177 | 178 | while (digitalRead(pin)) ; 179 | unsigned long finish = micros(); 180 | 181 | if ((unsigned long)(finish - start) > 50) data |= 1 << (7 - i); 182 | } 183 | 184 | return data; 185 | } 186 | 187 | void DHT11Finish(int pin) { 188 | // Releases the bus 189 | while (!digitalRead(pin)) ; 190 | digitalWrite(pin, HIGH); 191 | pinMode(pin, OUTPUT); 192 | } 193 | 194 | bool DHT11Check(const byte* data, int dataSize) { 195 | if (dataSize != 5) return false; 196 | 197 | byte sum = 0; 198 | for (int i = 0; i < dataSize - 1; i++) { 199 | sum += data[i]; 200 | } 201 | 202 | return data[dataSize - 1] == sum; 203 | } 204 | 205 | #endif // SENSOR_PIN 206 | 207 | //////////////////////////////////////////////////////////////////////////////////////// 208 | -------------------------------------------------------------------------------- /examples/soracom/soracom-unified/soracom-unified.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define INTERVAL (60000) 5 | #define RECEIVE_TIMEOUT (10000) 6 | 7 | // uncomment following line to use Temperature & Humidity sensor 8 | // #define SENSOR_PIN (WIOLTE_D38) 9 | 10 | WioCellular Wio; 11 | 12 | void setup() { 13 | delay(200); 14 | 15 | SerialUSB.begin(115200); 16 | SerialUSB.println(""); 17 | SerialUSB.println("--- START ---------------------------------------------------"); 18 | 19 | SerialUSB.println("### I/O Initialize."); 20 | Wio.Init(); 21 | 22 | SerialUSB.println("### Power supply ON."); 23 | Wio.PowerSupplyCellular(true); 24 | delay(500); 25 | 26 | SerialUSB.println("### Turn on or reset."); 27 | if (!Wio.TurnOnOrReset()) { 28 | SerialUSB.println("### ERROR! ###"); 29 | return; 30 | } 31 | 32 | SerialUSB.println("### Connecting to \"soracom.io\"."); 33 | if (!Wio.Activate("soracom.io", "sora", "sora")) { 34 | SerialUSB.println("### ERROR! ###"); 35 | return; 36 | } 37 | 38 | #ifdef SENSOR_PIN 39 | TemperatureAndHumidityBegin(SENSOR_PIN); 40 | #endif // SENSOR_PIN 41 | 42 | SerialUSB.println("### Setup completed."); 43 | } 44 | 45 | void loop() { 46 | char data[1024]; 47 | 48 | #ifdef SENSOR_PIN 49 | float temp; 50 | float humi; 51 | 52 | if (!TemperatureAndHumidityRead(&temp, &humi)) { 53 | SerialUSB.println("ERROR!"); 54 | goto err; 55 | } 56 | 57 | SerialUSB.print("Current humidity = "); 58 | SerialUSB.print(humi); 59 | SerialUSB.print("% "); 60 | SerialUSB.print("temperature = "); 61 | SerialUSB.print(temp); 62 | SerialUSB.println("C"); 63 | 64 | sprintf(data,"{\"temp\":%.1f,\"humi\":%.1f}", temp, humi); 65 | #else 66 | sprintf(data, "{\"uptime\":%lu}", millis() / 1000); 67 | #endif // SENSOR_PIN 68 | 69 | SerialUSB.println("### Open."); 70 | int connectId; 71 | connectId = Wio.SocketOpen("uni.soracom.io", 23080, WIOLTE_UDP); 72 | if (connectId < 0) { 73 | SerialUSB.println("### ERROR! ###"); 74 | goto err; 75 | } 76 | 77 | SerialUSB.println("### Send."); 78 | SerialUSB.print("Send:"); 79 | SerialUSB.print(data); 80 | SerialUSB.println(""); 81 | if (!Wio.SocketSend(connectId, data)) { 82 | SerialUSB.println("### ERROR! ###"); 83 | goto err_close; 84 | } 85 | 86 | SerialUSB.println("### Receive."); 87 | int length; 88 | length = Wio.SocketReceive(connectId, data, sizeof (data), RECEIVE_TIMEOUT); 89 | if (length < 0) { 90 | SerialUSB.println("### ERROR! ###"); 91 | goto err_close; 92 | } 93 | if (length == 0) { 94 | SerialUSB.println("### RECEIVE TIMEOUT! ###"); 95 | goto err_close; 96 | } 97 | SerialUSB.print("Receive:"); 98 | SerialUSB.print(data); 99 | SerialUSB.println(""); 100 | 101 | err_close: 102 | SerialUSB.println("### Close."); 103 | if (!Wio.SocketClose(connectId)) { 104 | SerialUSB.println("### ERROR! ###"); 105 | goto err; 106 | } 107 | 108 | err: 109 | delay(INTERVAL); 110 | } 111 | 112 | //////////////////////////////////////////////////////////////////////////////////////// 113 | // 114 | 115 | #ifdef SENSOR_PIN 116 | 117 | int TemperatureAndHumidityPin; 118 | 119 | void TemperatureAndHumidityBegin(int pin) { 120 | TemperatureAndHumidityPin = pin; 121 | DHT11Init(TemperatureAndHumidityPin); 122 | } 123 | 124 | bool TemperatureAndHumidityRead(float* temperature, float* humidity) { 125 | byte data[5]; 126 | 127 | DHT11Start(TemperatureAndHumidityPin); 128 | for (int i = 0; i < 5; i++) data[i] = DHT11ReadByte(TemperatureAndHumidityPin); 129 | DHT11Finish(TemperatureAndHumidityPin); 130 | 131 | if(!DHT11Check(data, sizeof (data))) return false; 132 | if (data[1] >= 10) return false; 133 | if (data[3] >= 10) return false; 134 | 135 | *humidity = (float)data[0] + (float)data[1] / 10.0f; 136 | *temperature = (float)data[2] + (float)data[3] / 10.0f; 137 | 138 | return true; 139 | } 140 | 141 | #endif // SENSOR_PIN 142 | 143 | //////////////////////////////////////////////////////////////////////////////////////// 144 | // 145 | 146 | #ifdef SENSOR_PIN 147 | 148 | void DHT11Init(int pin) { 149 | digitalWrite(pin, HIGH); 150 | pinMode(pin, OUTPUT); 151 | } 152 | 153 | void DHT11Start(int pin) { 154 | // Host the start of signal 155 | digitalWrite(pin, LOW); 156 | delay(18); 157 | 158 | // Pulled up to wait for 159 | pinMode(pin, INPUT); 160 | while (!digitalRead(pin)) ; 161 | 162 | // Response signal 163 | while (digitalRead(pin)) ; 164 | 165 | // Pulled ready to output 166 | while (!digitalRead(pin)) ; 167 | } 168 | 169 | byte DHT11ReadByte(int pin) { 170 | byte data = 0; 171 | 172 | for (int i = 0; i < 8; i++) { 173 | while (digitalRead(pin)) ; 174 | 175 | while (!digitalRead(pin)) ; 176 | unsigned long start = micros(); 177 | 178 | while (digitalRead(pin)) ; 179 | unsigned long finish = micros(); 180 | 181 | if ((unsigned long)(finish - start) > 50) data |= 1 << (7 - i); 182 | } 183 | 184 | return data; 185 | } 186 | 187 | void DHT11Finish(int pin) { 188 | // Releases the bus 189 | while (!digitalRead(pin)) ; 190 | digitalWrite(pin, HIGH); 191 | pinMode(pin, OUTPUT); 192 | } 193 | 194 | bool DHT11Check(const byte* data, int dataSize) { 195 | if (dataSize != 5) return false; 196 | 197 | byte sum = 0; 198 | for (int i = 0; i < dataSize - 1; i++) { 199 | sum += data[i]; 200 | } 201 | 202 | return data[dataSize - 1] == sum; 203 | } 204 | 205 | #endif // SENSOR_PIN 206 | 207 | //////////////////////////////////////////////////////////////////////////////////////// 208 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | WioLTE KEYWORD1 2 | 3 | GetLastError KEYWORD2 4 | Init KEYWORD2 5 | PowerSupplyCellular KEYWORD2 6 | PowerSupplyGNSS KEYWORD2 7 | PowerSupplyLed KEYWORD2 8 | PowerSupplyGrove KEYWORD2 9 | PowerSupplySD KEYWORD2 10 | LedSetRGB KEYWORD2 11 | TurnOnOrReset KEYWORD2 12 | TurnOff KEYWORD2 13 | Sleep KEYWORD2 14 | Wakeup KEYWORD2 15 | 16 | GetIMEI KEYWORD2 17 | GetIMSI KEYWORD2 18 | GetPhoneNumber KEYWORD2 19 | GetReceivedSignalStrength KEYWORD2 20 | GetTime KEYWORD2 21 | 22 | SendSMS KEYWORD2 23 | ReceiveSMS KEYWORD2 24 | DeleteReceivedSMS KEYWORD2 25 | 26 | WaitForCSRegistration KEYWORD2 27 | WaitForPSRegistration KEYWORD2 28 | Activate KEYWORD2 29 | Deactivate KEYWORD2 30 | 31 | SyncTime KEYWORD2 32 | GetLocation KEYWORD2 33 | 34 | SocketOpen KEYWORD2 35 | SocketSend KEYWORD2 36 | SocketReceive KEYWORD2 37 | SocketClose KEYWORD2 38 | 39 | HttpGet KEYWORD2 40 | HttpPost KEYWORD2 41 | 42 | SystemReset KEYWORD2 43 | 44 | WIO_TCP LITERAL1 45 | WIO_UDP LITERAL1 46 | WIO_D38 LITERAL1 47 | WIO_D39 LITERAL1 48 | WIO_D20 LITERAL1 49 | WIO_D19 LITERAL1 50 | WIO_A6 LITERAL1 51 | WIO_A7 LITERAL1 52 | WIO_A4 LITERAL1 53 | WIO_A5 LITERAL1 54 | 55 | E_OK LITERAL1 56 | E_UNKNOWN LITERAL1 57 | 58 | SOCKET_TCP LITERAL1 59 | SOCKET_UDP LITERAL1 60 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Wio LTE for Arduino 2 | version=2.13.0 3 | author=Seeed K.K. 4 | maintainer=matsujirushi 5 | sentence=The LTE module driver for Wio LTE. 6 | paragraph= 7 | category=Communication 8 | url=https://seeedjp.github.io/Wiki/Wio_LTE_for_Arduino/Home.html 9 | architectures=Seeed_STM32F4,stm32 10 | includes=WioLTEforArduino.h 11 | -------------------------------------------------------------------------------- /src/Internal/ArgumentParser.cpp: -------------------------------------------------------------------------------- 1 | #include "../WioLTEConfig.h" 2 | #include "ArgumentParser.h" 3 | #include 4 | 5 | ArgumentParser::ArgumentParser() 6 | { 7 | } 8 | 9 | void ArgumentParser::Parse(const char* str) 10 | { 11 | _Arguments.clear(); 12 | 13 | // Search comma position. 14 | std::vector commaList; 15 | bool inString = false; 16 | for (const char* ptr = str; *ptr != '\0'; ptr++) { 17 | if (!inString) { 18 | switch (*ptr) { 19 | case ',': 20 | commaList.push_back(ptr); 21 | break; 22 | case '"': 23 | inString = true; 24 | break; 25 | } 26 | } 27 | else { 28 | switch (*ptr) { 29 | case '"': 30 | inString = false; 31 | break; 32 | } 33 | } 34 | } 35 | 36 | // Build arguments. 37 | _Arguments.resize(commaList.size() + 1); 38 | for (int i = 0; i < (int)_Arguments.size(); i++) { 39 | const char* begin = i == 0 ? str : commaList[i - 1] + 1; 40 | const char* end = i < (int)commaList.size() ? commaList[i] : str + strlen(str); 41 | 42 | if (end - begin >= 2 && *begin == '"' && *(end - 1) == '"') { 43 | begin++; 44 | end--; 45 | } 46 | 47 | _Arguments[i].resize(end - begin + 1); 48 | memcpy(&_Arguments[i][0], begin, end - begin); 49 | _Arguments[i][end - begin] = '\0'; 50 | } 51 | } 52 | 53 | int ArgumentParser::Size() const 54 | { 55 | return _Arguments.size(); 56 | } 57 | 58 | const char* ArgumentParser::operator[](int index) const 59 | { 60 | return &_Arguments[index][0]; 61 | } 62 | -------------------------------------------------------------------------------- /src/Internal/ArgumentParser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class ArgumentParser 6 | { 7 | private: 8 | std::vector< std::vector > _Arguments; 9 | 10 | public: 11 | ArgumentParser(); 12 | void Parse(const char* str); 13 | int Size() const; 14 | const char* operator[](int index) const; 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /src/Internal/AtSerial.cpp: -------------------------------------------------------------------------------- 1 | #include "../WioLTEConfig.h" 2 | #include "AtSerial.h" 3 | 4 | #include "Debug.h" 5 | #include "slre.901d42c/slre.h" 6 | #include "../WioLTE.h" 7 | #include 8 | 9 | #define READ_BYTE_TIMEOUT (10) 10 | #define RESPONSE_MAX_LENGTH (1024) 11 | 12 | #define WRITE_BINARY_WAIT_SIZE (80) 13 | 14 | #define CHAR_CR (0x0d) 15 | #define CHAR_LF (0x0a) 16 | 17 | AtSerial::AtSerial(SerialAPI* serial, WioLTE* wioLTE) : 18 | _Serial(serial), 19 | _WioLTE(wioLTE), 20 | _DoWorkInWaitForAvailable{ nullptr } 21 | { 22 | } 23 | 24 | void AtSerial::SetDoWorkInWaitForAvailableFunction(std::function func) 25 | { 26 | _DoWorkInWaitForAvailable = func; 27 | } 28 | 29 | bool AtSerial::WaitForAvailable(Stopwatch* sw, unsigned long timeout) const 30 | { 31 | while (!_Serial->Available()) { 32 | if (sw != NULL && sw->ElapsedMilliseconds() >= timeout) { 33 | DEBUG_PRINTLN("### TIMEOUT ###"); 34 | return false; 35 | } 36 | if (_DoWorkInWaitForAvailable) _DoWorkInWaitForAvailable(); 37 | } 38 | 39 | return true; 40 | } 41 | 42 | void AtSerial::WriteBinary(const byte* data, int dataSize) 43 | { 44 | DEBUG_PRINTLN("<- (binary)"); 45 | 46 | for (int i = 0; i < dataSize; i++) { 47 | _Serial->Write(data[i]); 48 | 49 | if (i % WRITE_BINARY_WAIT_SIZE == WRITE_BINARY_WAIT_SIZE - 1) 50 | { 51 | _Serial->Flush(); 52 | delay(1); 53 | } 54 | } 55 | } 56 | 57 | bool AtSerial::ReadBinary(byte* data, int dataSize, unsigned long timeout) 58 | { 59 | Stopwatch sw; 60 | for (int i = 0; i < dataSize; i++) { 61 | sw.Restart(); 62 | if (!WaitForAvailable(&sw, timeout)) return false; 63 | 64 | data[i] = _Serial->Read(); 65 | } 66 | 67 | DEBUG_PRINTLN("-> (binary)"); 68 | 69 | return true; 70 | } 71 | 72 | void AtSerial::WriteCommand(const char* command) 73 | { 74 | DEBUG_PRINT("<- "); 75 | DEBUG_PRINTLN(command); 76 | 77 | while (*command != '\0') { 78 | _Serial->Write((byte)*command); 79 | command++; 80 | } 81 | _Serial->Write((byte)CHAR_CR); 82 | } 83 | 84 | bool AtSerial::ReadResponseInternal(const char* pattern, unsigned long timeout, std::string* response, int responseMaxLength) 85 | { 86 | DEBUG_PRINT("-> "); 87 | 88 | response->clear(); 89 | 90 | Stopwatch sw; 91 | while (true) { 92 | if (response->size() >= (size_t)(responseMaxLength + 2)) { 93 | DEBUG_PRINTLN("### OVERFLOW ###"); 94 | return false; 95 | } 96 | 97 | sw.Restart(); 98 | if (!WaitForAvailable(&sw, timeout)) { 99 | DEBUG_PRINTLN("### TIMEOUT ###"); 100 | return false; 101 | } 102 | 103 | response->push_back(_Serial->Read()); 104 | 105 | if (response->size() >= 2 && response->at(response->size() - 2) == CHAR_CR && response->at(response->size() - 1) == CHAR_LF) { 106 | response->resize(response->size() - 2); 107 | DEBUG_PRINTLN(response->c_str()); 108 | return true; 109 | } 110 | 111 | if (pattern != NULL) { 112 | if (slre_match(pattern, response->c_str(), response->size(), NULL, 0, 0) >= 1) { 113 | DEBUG_PRINTLN(response->c_str()); 114 | return true; 115 | } 116 | } 117 | } 118 | } 119 | 120 | bool AtSerial::ReadResponse(const char* pattern, unsigned long timeout, std::string* capture) 121 | { 122 | const char* internalPattern = NULL; 123 | if (pattern[strlen(pattern) - 1] != '$') { 124 | internalPattern = pattern; 125 | } 126 | 127 | Stopwatch sw; 128 | sw.Restart(); 129 | while (true) { 130 | if (!WaitForAvailable(&sw, timeout)) return false; 131 | 132 | std::string response; 133 | if (!ReadResponseInternal(internalPattern, READ_BYTE_TIMEOUT, &response, RESPONSE_MAX_LENGTH)) return false; 134 | 135 | if (_WioLTE->ReadResponseCallback(response.c_str())) { 136 | continue; 137 | } 138 | 139 | slre_cap cap; 140 | cap.len = 0; 141 | if (slre_match(pattern, response.c_str(), response.size(), &cap, 1, 0) >= 1) { 142 | if (capture != NULL) { 143 | capture->resize(cap.len); 144 | memcpy(&(*capture)[0], cap.ptr, cap.len); 145 | } 146 | return true; 147 | } 148 | } 149 | } 150 | 151 | bool AtSerial::WriteCommandAndReadResponse(const char* command, const char* pattern, unsigned long timeout, std::string* capture) 152 | { 153 | WriteCommand(command); 154 | return ReadResponse(pattern, timeout, capture); 155 | } 156 | 157 | bool AtSerial::ReadResponseQHTTPREAD(char* data, int dataSize, unsigned long timeout) 158 | { 159 | int contentLength = 0; 160 | 161 | Stopwatch sw; 162 | sw.Restart(); 163 | while (true) { 164 | if (!WaitForAvailable(&sw, timeout)) return false; 165 | 166 | std::string response; 167 | if (!ReadResponseInternal(NULL, 1000, &response, dataSize - 2 - 1)) return false; 168 | if (response == "OK") break; 169 | 170 | if (contentLength + response.size() + 2 + 1 > (size_t)dataSize) return false; 171 | memcpy(&data[contentLength], response.c_str(), response.size()); 172 | strcpy(&data[contentLength + response.size()], "\r\n"); 173 | contentLength += response.size() + 2; 174 | } 175 | if (contentLength >= 2 && strcmp(&data[contentLength - 2], "\r\n") == 0) contentLength -= 2; 176 | data[contentLength] = '\0'; 177 | 178 | return true; 179 | } 180 | -------------------------------------------------------------------------------- /src/Internal/AtSerial.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "SerialAPI.h" 4 | #include "Stopwatch.h" 5 | #include 6 | #include 7 | 8 | class WioLTE; 9 | 10 | class AtSerial 11 | { 12 | private: 13 | SerialAPI* _Serial; 14 | WioLTE* _WioLTE; 15 | std::function _DoWorkInWaitForAvailable; 16 | 17 | bool ReadResponseInternal(const char* pattern, unsigned long timeout, std::string* response, int responseMaxLength); 18 | 19 | public: 20 | AtSerial(SerialAPI* serial, WioLTE* wioLTE); 21 | 22 | void SetDoWorkInWaitForAvailableFunction(std::function func); 23 | 24 | bool WaitForAvailable(Stopwatch* sw, unsigned long timeout) const; 25 | 26 | void WriteBinary(const byte* data, int dataSize); 27 | bool ReadBinary(byte* data, int dataSize, unsigned long timeout); 28 | 29 | void WriteCommand(const char* command); 30 | bool ReadResponse(const char* pattern, unsigned long timeout, std::string* capture); 31 | bool WriteCommandAndReadResponse(const char* command, const char* pattern, unsigned long timeout, std::string* capture); 32 | 33 | bool ReadResponseQHTTPREAD(char* data, int dataSize, unsigned long timeout); 34 | 35 | }; 36 | -------------------------------------------------------------------------------- /src/Internal/CMSIS/cmsis_gcc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //////////////////////////////////////////////////////////////////////////////// 4 | // Copy from CMSIS in STM32Cube_FW_F4_V1.19.0 5 | 6 | #define __ASM __asm /*!< asm keyword for GNU Compiler */ 7 | #define __INLINE inline /*!< inline keyword for GNU Compiler */ 8 | #define __STATIC_INLINE static inline 9 | 10 | //////////////////////////////////////////////////////////////////////////////// 11 | // Copy from CMSIS in STM32Cube_FW_F4_V1.19.0 12 | 13 | /** 14 | \brief No Operation 15 | \details No Operation does nothing. This instruction can be used for code alignment purposes. 16 | */ 17 | __attribute__((always_inline)) __STATIC_INLINE void __NOP(void) 18 | { 19 | __ASM volatile ("nop"); 20 | } 21 | 22 | /** 23 | \brief Data Synchronization Barrier 24 | \details Acts as a special kind of Data Memory Barrier. 25 | It completes when all explicit memory accesses before this instruction complete. 26 | */ 27 | __attribute__((always_inline)) __STATIC_INLINE void __DSB(void) 28 | { 29 | __ASM volatile ("dsb 0xF":::"memory"); 30 | } 31 | -------------------------------------------------------------------------------- /src/Internal/CMSIS/core_cm4.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //////////////////////////////////////////////////////////////////////////////// 4 | // Copy from CMSIS in STM32Cube_FW_F4_V1.19.0 5 | 6 | #define __ASM __asm /*!< asm keyword for GNU Compiler */ 7 | #define __INLINE inline /*!< inline keyword for GNU Compiler */ 8 | #define __STATIC_INLINE static inline 9 | 10 | #define __IM volatile const /*! Defines 'read only' structure member permissions */ 11 | #define __OM volatile /*! Defines 'write only' structure member permissions */ 12 | #define __IOM volatile /*! Defines 'read / write' structure member permissions */ 13 | 14 | typedef struct 15 | { 16 | __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ 17 | __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ 18 | __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ 19 | __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ 20 | __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ 21 | __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ 22 | __IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ 23 | __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ 24 | __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ 25 | __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ 26 | __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ 27 | __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ 28 | __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ 29 | __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ 30 | __IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ 31 | __IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ 32 | __IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ 33 | __IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ 34 | __IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ 35 | uint32_t RESERVED0[5U]; 36 | __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ 37 | } SCB_Type; 38 | 39 | #define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ 40 | #define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ 41 | 42 | #define SCB_AIRCR_PRIGROUP_Pos 8U /*!< SCB AIRCR: PRIGROUP Position */ 43 | #define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ 44 | 45 | #define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ 46 | #define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ 47 | 48 | #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ 49 | #define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ 50 | #define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ 51 | 52 | /** 53 | \brief System Reset 54 | \details Initiates a system reset request to reset the MCU. 55 | */ 56 | __STATIC_INLINE void NVIC_SystemReset(void) 57 | { 58 | __DSB(); /* Ensure all outstanding memory accesses included 59 | buffered write are completed before reset */ 60 | SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | 61 | (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | 62 | SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ 63 | __DSB(); /* Ensure completion of memory access */ 64 | 65 | for(;;) /* wait until reset */ 66 | { 67 | __NOP(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Internal/Debug.cpp: -------------------------------------------------------------------------------- 1 | #include "../WioLTEConfig.h" 2 | #include "Debug.h" 3 | 4 | #ifdef WIO_DEBUG 5 | 6 | void Debug::Print(const char* str) 7 | { 8 | for (int i = 0; (unsigned)i < strlen(str); i++) SerialUSB.print(str[i]); 9 | } 10 | 11 | void Debug::Println (const char* str) 12 | { 13 | Print(str); 14 | Print("\r\n"); 15 | } 16 | 17 | #endif // WIO_DEBUG 18 | -------------------------------------------------------------------------------- /src/Internal/Debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef WIO_DEBUG 4 | 5 | #define DEBUG_PRINT(str) Debug::Print(str) 6 | #define DEBUG_PRINTLN(str) Debug::Println(str) 7 | 8 | class Debug 9 | { 10 | public: 11 | static void Print(const char* str); 12 | static void Println(const char* str); 13 | 14 | }; 15 | 16 | #else 17 | 18 | #define DEBUG_PRINT(str) 19 | #define DEBUG_PRINTLN(str) 20 | 21 | #endif // WIO_DEBUG 22 | -------------------------------------------------------------------------------- /src/Internal/SerialAPI.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class SerialAPI 4 | { 5 | private: 6 | HardwareSerial* _Serial; 7 | 8 | public: 9 | SerialAPI(HardwareSerial* serial) : _Serial(serial) {} 10 | void Begin(int baud) { _Serial->begin(baud); } 11 | void Write(byte data) { _Serial->write(data); } 12 | bool Available() const { return _Serial->available() >= 1 ? true : false; } 13 | byte Read() { return _Serial->read(); } 14 | void Flush() { _Serial->flush(); } 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /src/Internal/Stopwatch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Stopwatch 4 | { 5 | private: 6 | unsigned long _BeginTime; 7 | unsigned long _EndTime; 8 | 9 | public: 10 | Stopwatch() : _BeginTime(0), _EndTime(0) 11 | { 12 | } 13 | 14 | void Restart() 15 | { 16 | _BeginTime = millis(); 17 | _EndTime = 0; 18 | } 19 | 20 | void Stop() 21 | { 22 | _EndTime = millis(); 23 | } 24 | 25 | unsigned long ElapsedMilliseconds() const 26 | { 27 | if (_EndTime == 0) { 28 | return millis() - _BeginTime; 29 | } 30 | else { 31 | return _EndTime - _BeginTime; 32 | } 33 | } 34 | 35 | }; 36 | -------------------------------------------------------------------------------- /src/Internal/StringBuilder.cpp: -------------------------------------------------------------------------------- 1 | #include "../WioLTEConfig.h" 2 | #include "StringBuilder.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define STRING_MAX_SIZE (200) 9 | 10 | StringBuilder::StringBuilder() 11 | { 12 | _Buffer.push_back('\0'); 13 | } 14 | 15 | void StringBuilder::Clear() 16 | { 17 | _Buffer.clear(); 18 | _Buffer.push_back('\0'); 19 | } 20 | 21 | int StringBuilder::Length() const 22 | { 23 | return _Buffer.size() - 1; 24 | } 25 | 26 | const char* StringBuilder::GetString() const 27 | { 28 | return &_Buffer[0]; 29 | } 30 | 31 | void StringBuilder::Write(const char* str) 32 | { 33 | int i = Length(); 34 | _Buffer.resize(_Buffer.size() + strlen(str)); 35 | strcpy(&_Buffer[i], str); 36 | } 37 | 38 | void StringBuilder::Write(const char* str, int length) 39 | { 40 | int i = Length(); 41 | _Buffer.resize(_Buffer.size() + length); 42 | memcpy(&_Buffer[i], str, length); 43 | _Buffer[i + length] = '\0'; 44 | } 45 | 46 | bool StringBuilder::WriteFormat(const char* format, ...) 47 | { 48 | va_list arglist; 49 | va_start(arglist, format); 50 | char str[STRING_MAX_SIZE]; 51 | int length = vsnprintf(str, sizeof (str), format, arglist); 52 | va_end(arglist); 53 | 54 | if (length < 0 || (int)(sizeof (str) - 1) <= length) return false; 55 | 56 | Write(str); 57 | 58 | return true; 59 | } 60 | -------------------------------------------------------------------------------- /src/Internal/StringBuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class StringBuilder 6 | { 7 | private: 8 | std::vector _Buffer; 9 | 10 | public: 11 | StringBuilder(); 12 | void Clear(); 13 | int Length() const; 14 | const char* GetString() const; 15 | void Write(const char* str); 16 | void Write(const char* str, int length); 17 | bool WriteFormat(const char* format, ...); 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /src/Internal/WioSK6812.cpp: -------------------------------------------------------------------------------- 1 | #if defined ARDUINO_ARCH_STM32 2 | 3 | #include "WioSK6812.h" 4 | 5 | #include 6 | 7 | #define LED_GPIO_PORT (GPIOB) 8 | #define LED_GPIO_PIN (GPIO_PIN_1) 9 | 10 | #define LED_GPIO_HIGH() (LED_GPIO_PORT->BSRR = LED_GPIO_PIN) 11 | #define LED_GPIO_LOW() (LED_GPIO_PORT->BSRR = (uint32_t)LED_GPIO_PIN << 16U) 12 | 13 | extern "C" void DelayLoop(int32_t iterations); 14 | 15 | asm volatile ( 16 | ".syntax unified\n\t" 17 | ".arch armv7-m\n\t" 18 | ".thumb\n\t" 19 | ".global DelayLoop\n\t" 20 | "@AREA ||i.DelayLoop||, CODE, READONLY @ void DelayLoop(UINT32 count)\n\t" 21 | ".section SectionForCodeDelayLoop, \"ax\", %progbits\n\t" 22 | ".thumb_func\n\t" 23 | "DelayLoop:\n\t" 24 | "subs r0, r0, #3 @@ 1 cycle\n\t" 25 | "bgt DelayLoop @@ 3 cycles taken, 1 cycle not taken.\n\t" 26 | "bx lr @@ 3 cycles\n\t" 27 | ); 28 | 29 | void WioSK6812::SetBit(bool on) 30 | { 31 | if (!on) { 32 | LED_GPIO_HIGH(); 33 | DelayLoop(50); 34 | LED_GPIO_LOW(); 35 | DelayLoop(150); 36 | } 37 | else { 38 | LED_GPIO_HIGH(); 39 | DelayLoop(100); 40 | LED_GPIO_LOW(); 41 | DelayLoop(100); 42 | } 43 | } 44 | 45 | void WioSK6812::SetByte(uint8_t val) 46 | { 47 | for (int i = 0; i < 8; i++) { 48 | SetBit(val & (1 << (7 - i))); 49 | } 50 | } 51 | 52 | void WioSK6812::Reset() 53 | { 54 | LED_GPIO_LOW(); 55 | DelayLoop(13333); 56 | } 57 | 58 | void WioSK6812::SetSingleLED(uint8_t r, uint8_t g, uint8_t b) 59 | { 60 | SetByte(g); 61 | SetByte(r); 62 | SetByte(b); 63 | } 64 | 65 | #endif // ARDUINO_ARCH_STM32 66 | -------------------------------------------------------------------------------- /src/Internal/WioSK6812.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined ARDUINO_ARCH_STM32 4 | 5 | #include 6 | 7 | class WioSK6812 8 | { 9 | private: 10 | void SetBit(bool on); 11 | void SetByte(uint8_t val); 12 | 13 | public: 14 | void Reset(); 15 | void SetSingleLED(uint8_t r, uint8_t g, uint8_t b); 16 | 17 | }; 18 | 19 | #endif // ARDUINO_ARCH_STM32 20 | -------------------------------------------------------------------------------- /src/Internal/slre.901d42c/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2004-2013 Sergey Lyubka 2 | Copyright (c) 2013 Cesanta Software Limited 3 | All rights reserved 4 | 5 | This code is dual-licensed: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. For the terms of this 8 | license, see . 9 | 10 | You are free to use this code under the terms of the GNU General 11 | Public License, but WITHOUT ANY WARRANTY; without even the implied 12 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | See the GNU General Public License for more details. 14 | 15 | Alternatively, you can license this code under a commercial 16 | license, as set out in . 17 | -------------------------------------------------------------------------------- /src/Internal/slre.901d42c/README.md: -------------------------------------------------------------------------------- 1 | SLRE: Super Light Regular Expression library 2 | ============================================ 3 | 4 | Documentation and API reference are at 5 | [docs.cesanta.com/slre](https://docs.cesanta.com/slre) 6 | 7 | # Contributions 8 | 9 | To submit contributions, sign 10 | [Cesanta CLA](https://docs.cesanta.com/contributors_la.shtml) 11 | and send GitHub pull request. You retain the copyright on your contributions. 12 | 13 | # Licensing 14 | 15 | SLRE is released under commercial and 16 | [GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) 17 | open source licenses. 18 | 19 | Commercial Projects: 20 | Once your project becomes commercialised GPLv2 licensing dictates that you need to either open your source fully or purchase a commercial license. Cesanta offer full, royalty-free commercial licenses without any GPL restrictions. If your needs require a custom license, we’d be happy to work on a solution with you. [Contact us for pricing.] (https://www.cesanta.com/contact) 21 | -------------------------------------------------------------------------------- /src/Internal/slre.901d42c/slre.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2013 Sergey Lyubka 3 | * Copyright (c) 2013 Cesanta Software Limited 4 | * All rights reserved 5 | * 6 | * This library is dual-licensed: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 as 8 | * published by the Free Software Foundation. For the terms of this 9 | * license, see . 10 | * 11 | * You are free to use this library under the terms of the GNU General 12 | * Public License, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the GNU General Public License for more details. 15 | * 16 | * Alternatively, you can license this library under a commercial 17 | * license, as set out in . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "slre.h" 25 | 26 | #define MAX_BRANCHES 100 27 | #define MAX_BRACKETS 100 28 | #define FAIL_IF(condition, error_code) if (condition) return (error_code) 29 | 30 | #ifndef ARRAY_SIZE 31 | #define ARRAY_SIZE(ar) (sizeof(ar) / sizeof((ar)[0])) 32 | #endif 33 | 34 | #ifdef SLRE_DEBUG 35 | #define DBG(x) printf x 36 | #else 37 | #define DBG(x) 38 | #endif 39 | 40 | struct bracket_pair { 41 | const char *ptr; /* Points to the first char after '(' in regex */ 42 | int len; /* Length of the text between '(' and ')' */ 43 | int branches; /* Index in the branches array for this pair */ 44 | int num_branches; /* Number of '|' in this bracket pair */ 45 | }; 46 | 47 | struct branch { 48 | int bracket_index; /* index for 'struct bracket_pair brackets' */ 49 | /* array defined below */ 50 | const char *schlong; /* points to the '|' character in the regex */ 51 | }; 52 | 53 | struct regex_info { 54 | /* 55 | * Describes all bracket pairs in the regular expression. 56 | * First entry is always present, and grabs the whole regex. 57 | */ 58 | struct bracket_pair brackets[MAX_BRACKETS]; 59 | int num_brackets; 60 | 61 | /* 62 | * Describes alternations ('|' operators) in the regular expression. 63 | * Each branch falls into a specific branch pair. 64 | */ 65 | struct branch branches[MAX_BRANCHES]; 66 | int num_branches; 67 | 68 | /* Array of captures provided by the user */ 69 | struct slre_cap *caps; 70 | int num_caps; 71 | 72 | /* E.g. SLRE_IGNORE_CASE. See enum below */ 73 | int flags; 74 | }; 75 | 76 | static int is_metacharacter(const unsigned char *s) { 77 | static const char *metacharacters = "^$().[]*+?|\\Ssdbfnrtv"; 78 | return strchr(metacharacters, *s) != NULL; 79 | } 80 | 81 | static int op_len(const char *re) { 82 | return re[0] == '\\' && re[1] == 'x' ? 4 : re[0] == '\\' ? 2 : 1; 83 | } 84 | 85 | static int set_len(const char *re, int re_len) { 86 | int len = 0; 87 | 88 | while (len < re_len && re[len] != ']') { 89 | len += op_len(re + len); 90 | } 91 | 92 | return len <= re_len ? len + 1 : -1; 93 | } 94 | 95 | static int get_op_len(const char *re, int re_len) { 96 | return re[0] == '[' ? set_len(re + 1, re_len - 1) + 1 : op_len(re); 97 | } 98 | 99 | static int is_quantifier(const char *re) { 100 | return re[0] == '*' || re[0] == '+' || re[0] == '?'; 101 | } 102 | 103 | static int toi(int x) { 104 | return isdigit(x) ? x - '0' : x - 'W'; 105 | } 106 | 107 | static int hextoi(const unsigned char *s) { 108 | return (toi(tolower(s[0])) << 4) | toi(tolower(s[1])); 109 | } 110 | 111 | static int match_op(const unsigned char *re, const unsigned char *s, 112 | struct regex_info *info) { 113 | int result = 0; 114 | switch (*re) { 115 | case '\\': 116 | /* Metacharacters */ 117 | switch (re[1]) { 118 | case 'S': FAIL_IF(isspace(*s), SLRE_NO_MATCH); result++; break; 119 | case 's': FAIL_IF(!isspace(*s), SLRE_NO_MATCH); result++; break; 120 | case 'd': FAIL_IF(!isdigit(*s), SLRE_NO_MATCH); result++; break; 121 | case 'b': FAIL_IF(*s != '\b', SLRE_NO_MATCH); result++; break; 122 | case 'f': FAIL_IF(*s != '\f', SLRE_NO_MATCH); result++; break; 123 | case 'n': FAIL_IF(*s != '\n', SLRE_NO_MATCH); result++; break; 124 | case 'r': FAIL_IF(*s != '\r', SLRE_NO_MATCH); result++; break; 125 | case 't': FAIL_IF(*s != '\t', SLRE_NO_MATCH); result++; break; 126 | case 'v': FAIL_IF(*s != '\v', SLRE_NO_MATCH); result++; break; 127 | 128 | case 'x': 129 | /* Match byte, \xHH where HH is hexadecimal byte representaion */ 130 | FAIL_IF(hextoi(re + 2) != *s, SLRE_NO_MATCH); 131 | result++; 132 | break; 133 | 134 | default: 135 | /* Valid metacharacter check is done in bar() */ 136 | FAIL_IF(re[1] != s[0], SLRE_NO_MATCH); 137 | result++; 138 | break; 139 | } 140 | break; 141 | 142 | case '|': FAIL_IF(1, SLRE_INTERNAL_ERROR); break; 143 | case '$': FAIL_IF(1, SLRE_NO_MATCH); break; 144 | case '.': result++; break; 145 | 146 | default: 147 | if (info->flags & SLRE_IGNORE_CASE) { 148 | FAIL_IF(tolower(*re) != tolower(*s), SLRE_NO_MATCH); 149 | } else { 150 | FAIL_IF(*re != *s, SLRE_NO_MATCH); 151 | } 152 | result++; 153 | break; 154 | } 155 | 156 | return result; 157 | } 158 | 159 | static int match_set(const char *re, int re_len, const char *s, 160 | struct regex_info *info) { 161 | int len = 0, result = -1, invert = re[0] == '^'; 162 | 163 | if (invert) re++, re_len--; 164 | 165 | while (len <= re_len && re[len] != ']' && result <= 0) { 166 | /* Support character range */ 167 | if (re[len] != '-' && re[len + 1] == '-' && re[len + 2] != ']' && 168 | re[len + 2] != '\0') { 169 | result = info->flags & SLRE_IGNORE_CASE ? 170 | tolower(*s) >= tolower(re[len]) && tolower(*s) <= tolower(re[len + 2]) : 171 | *s >= re[len] && *s <= re[len + 2]; 172 | len += 3; 173 | } else { 174 | result = match_op((const unsigned char *) re + len, (const unsigned char *) s, info); 175 | len += op_len(re + len); 176 | } 177 | } 178 | return (!invert && result > 0) || (invert && result <= 0) ? 1 : -1; 179 | } 180 | 181 | static int doh(const char *s, int s_len, struct regex_info *info, int bi); 182 | 183 | static int bar(const char *re, int re_len, const char *s, int s_len, 184 | struct regex_info *info, int bi) { 185 | /* i is offset in re, j is offset in s, bi is brackets index */ 186 | int i, j, n, step; 187 | 188 | for (i = j = 0; i < re_len && j <= s_len; i += step) { 189 | 190 | /* Handle quantifiers. Get the length of the chunk. */ 191 | step = re[i] == '(' ? info->brackets[bi + 1].len + 2 : 192 | get_op_len(re + i, re_len - i); 193 | 194 | DBG(("%s [%.*s] [%.*s] re_len=%d step=%d i=%d j=%d\n", __func__, 195 | re_len - i, re + i, s_len - j, s + j, re_len, step, i, j)); 196 | 197 | FAIL_IF(is_quantifier(&re[i]), SLRE_UNEXPECTED_QUANTIFIER); 198 | FAIL_IF(step <= 0, SLRE_INVALID_CHARACTER_SET); 199 | 200 | if (i + step < re_len && is_quantifier(re + i + step)) { 201 | DBG(("QUANTIFIER: [%.*s]%c [%.*s]\n", step, re + i, 202 | re[i + step], s_len - j, s + j)); 203 | if (re[i + step] == '?') { 204 | int result = bar(re + i, step, s + j, s_len - j, info, bi); 205 | j += result > 0 ? result : 0; 206 | i++; 207 | } else if (re[i + step] == '+' || re[i + step] == '*') { 208 | int j2 = j, nj = j, n1, n2 = -1, ni, non_greedy = 0; 209 | 210 | /* Points to the regexp code after the quantifier */ 211 | ni = i + step + 1; 212 | if (ni < re_len && re[ni] == '?') { 213 | non_greedy = 1; 214 | ni++; 215 | } 216 | 217 | do { 218 | if ((n1 = bar(re + i, step, s + j2, s_len - j2, info, bi)) > 0) { 219 | j2 += n1; 220 | } 221 | if (re[i + step] == '+' && n1 < 0) break; 222 | 223 | if (ni >= re_len) { 224 | /* After quantifier, there is nothing */ 225 | nj = j2; 226 | } else if ((n2 = bar(re + ni, re_len - ni, s + j2, 227 | s_len - j2, info, bi)) >= 0) { 228 | /* Regex after quantifier matched */ 229 | nj = j2 + n2; 230 | } 231 | if (nj > j && non_greedy) break; 232 | } while (n1 > 0); 233 | 234 | /* 235 | * Even if we found one or more pattern, this branch will be executed, 236 | * changing the next captures. 237 | */ 238 | if (n1 < 0 && n2 < 0 && re[i + step] == '*' && 239 | (n2 = bar(re + ni, re_len - ni, s + j, s_len - j, info, bi)) > 0) { 240 | nj = j + n2; 241 | } 242 | 243 | DBG(("STAR/PLUS END: %d %d %d %d %d\n", j, nj, re_len - ni, n1, n2)); 244 | FAIL_IF(re[i + step] == '+' && nj == j, SLRE_NO_MATCH); 245 | 246 | /* If while loop body above was not executed for the * quantifier, */ 247 | /* make sure the rest of the regex matches */ 248 | FAIL_IF(nj == j && ni < re_len && n2 < 0, SLRE_NO_MATCH); 249 | 250 | /* Returning here cause we've matched the rest of RE already */ 251 | return nj; 252 | } 253 | continue; 254 | } 255 | 256 | if (re[i] == '[') { 257 | n = match_set(re + i + 1, re_len - (i + 2), s + j, info); 258 | DBG(("SET %.*s [%.*s] -> %d\n", step, re + i, s_len - j, s + j, n)); 259 | FAIL_IF(n <= 0, SLRE_NO_MATCH); 260 | j += n; 261 | } else if (re[i] == '(') { 262 | n = SLRE_NO_MATCH; 263 | bi++; 264 | FAIL_IF(bi >= info->num_brackets, SLRE_INTERNAL_ERROR); 265 | DBG(("CAPTURING [%.*s] [%.*s] [%s]\n", 266 | step, re + i, s_len - j, s + j, re + i + step)); 267 | 268 | if (re_len - (i + step) <= 0) { 269 | /* Nothing follows brackets */ 270 | n = doh(s + j, s_len - j, info, bi); 271 | } else { 272 | int j2; 273 | for (j2 = 0; j2 <= s_len - j; j2++) { 274 | if ((n = doh(s + j, s_len - (j + j2), info, bi)) >= 0 && 275 | bar(re + i + step, re_len - (i + step), 276 | s + j + n, s_len - (j + n), info, bi) >= 0) break; 277 | } 278 | } 279 | 280 | DBG(("CAPTURED [%.*s] [%.*s]:%d\n", step, re + i, s_len - j, s + j, n)); 281 | FAIL_IF(n < 0, n); 282 | if (info->caps != NULL && n > 0) { 283 | info->caps[bi - 1].ptr = s + j; 284 | info->caps[bi - 1].len = n; 285 | } 286 | j += n; 287 | } else if (re[i] == '^') { 288 | FAIL_IF(j != 0, SLRE_NO_MATCH); 289 | } else if (re[i] == '$') { 290 | FAIL_IF(j != s_len, SLRE_NO_MATCH); 291 | } else { 292 | FAIL_IF(j >= s_len, SLRE_NO_MATCH); 293 | n = match_op((const unsigned char *) (re + i), (const unsigned char *) (s + j), info); 294 | FAIL_IF(n <= 0, n); 295 | j += n; 296 | } 297 | } 298 | 299 | return j; 300 | } 301 | 302 | /* Process branch points */ 303 | static int doh(const char *s, int s_len, struct regex_info *info, int bi) { 304 | const struct bracket_pair *b = &info->brackets[bi]; 305 | int i = 0, len, result; 306 | const char *p; 307 | 308 | do { 309 | p = i == 0 ? b->ptr : info->branches[b->branches + i - 1].schlong + 1; 310 | len = b->num_branches == 0 ? b->len : 311 | i == b->num_branches ? (int) (b->ptr + b->len - p) : 312 | (int) (info->branches[b->branches + i].schlong - p); 313 | DBG(("%s %d %d [%.*s] [%.*s]\n", __func__, bi, i, len, p, s_len, s)); 314 | result = bar(p, len, s, s_len, info, bi); 315 | DBG(("%s <- %d\n", __func__, result)); 316 | } while (result <= 0 && i++ < b->num_branches); /* At least 1 iteration */ 317 | 318 | return result; 319 | } 320 | 321 | static int baz(const char *s, int s_len, struct regex_info *info) { 322 | int i, result = -1, is_anchored = info->brackets[0].ptr[0] == '^'; 323 | 324 | for (i = 0; i <= s_len; i++) { 325 | result = doh(s + i, s_len - i, info, 0); 326 | if (result >= 0) { 327 | result += i; 328 | break; 329 | } 330 | if (is_anchored) break; 331 | } 332 | 333 | return result; 334 | } 335 | 336 | static void setup_branch_points(struct regex_info *info) { 337 | int i, j; 338 | struct branch tmp; 339 | 340 | /* First, sort branches. Must be stable, no qsort. Use bubble algo. */ 341 | for (i = 0; i < info->num_branches; i++) { 342 | for (j = i + 1; j < info->num_branches; j++) { 343 | if (info->branches[i].bracket_index > info->branches[j].bracket_index) { 344 | tmp = info->branches[i]; 345 | info->branches[i] = info->branches[j]; 346 | info->branches[j] = tmp; 347 | } 348 | } 349 | } 350 | 351 | /* 352 | * For each bracket, set their branch points. This way, for every bracket 353 | * (i.e. every chunk of regex) we know all branch points before matching. 354 | */ 355 | for (i = j = 0; i < info->num_brackets; i++) { 356 | info->brackets[i].num_branches = 0; 357 | info->brackets[i].branches = j; 358 | while (j < info->num_branches && info->branches[j].bracket_index == i) { 359 | info->brackets[i].num_branches++; 360 | j++; 361 | } 362 | } 363 | } 364 | 365 | static int foo(const char *re, int re_len, const char *s, int s_len, 366 | struct regex_info *info) { 367 | int i, step, depth = 0; 368 | 369 | /* First bracket captures everything */ 370 | info->brackets[0].ptr = re; 371 | info->brackets[0].len = re_len; 372 | info->num_brackets = 1; 373 | 374 | /* Make a single pass over regex string, memorize brackets and branches */ 375 | for (i = 0; i < re_len; i += step) { 376 | step = get_op_len(re + i, re_len - i); 377 | 378 | if (re[i] == '|') { 379 | FAIL_IF(info->num_branches >= (int) ARRAY_SIZE(info->branches), 380 | SLRE_TOO_MANY_BRANCHES); 381 | info->branches[info->num_branches].bracket_index = 382 | info->brackets[info->num_brackets - 1].len == -1 ? 383 | info->num_brackets - 1 : depth; 384 | info->branches[info->num_branches].schlong = &re[i]; 385 | info->num_branches++; 386 | } else if (re[i] == '\\') { 387 | FAIL_IF(i >= re_len - 1, SLRE_INVALID_METACHARACTER); 388 | if (re[i + 1] == 'x') { 389 | /* Hex digit specification must follow */ 390 | FAIL_IF(re[i + 1] == 'x' && i >= re_len - 3, 391 | SLRE_INVALID_METACHARACTER); 392 | FAIL_IF(re[i + 1] == 'x' && !(isxdigit(re[i + 2]) && 393 | isxdigit(re[i + 3])), SLRE_INVALID_METACHARACTER); 394 | } else { 395 | FAIL_IF(!is_metacharacter((const unsigned char *) re + i + 1), 396 | SLRE_INVALID_METACHARACTER); 397 | } 398 | } else if (re[i] == '(') { 399 | FAIL_IF(info->num_brackets >= (int) ARRAY_SIZE(info->brackets), 400 | SLRE_TOO_MANY_BRACKETS); 401 | depth++; /* Order is important here. Depth increments first. */ 402 | info->brackets[info->num_brackets].ptr = re + i + 1; 403 | info->brackets[info->num_brackets].len = -1; 404 | info->num_brackets++; 405 | FAIL_IF(info->num_caps > 0 && info->num_brackets - 1 > info->num_caps, 406 | SLRE_CAPS_ARRAY_TOO_SMALL); 407 | } else if (re[i] == ')') { 408 | int ind = info->brackets[info->num_brackets - 1].len == -1 ? 409 | info->num_brackets - 1 : depth; 410 | info->brackets[ind].len = (int) (&re[i] - info->brackets[ind].ptr); 411 | DBG(("SETTING BRACKET %d [%.*s]\n", 412 | ind, info->brackets[ind].len, info->brackets[ind].ptr)); 413 | depth--; 414 | FAIL_IF(depth < 0, SLRE_UNBALANCED_BRACKETS); 415 | FAIL_IF(i > 0 && re[i - 1] == '(', SLRE_NO_MATCH); 416 | } 417 | } 418 | 419 | FAIL_IF(depth != 0, SLRE_UNBALANCED_BRACKETS); 420 | setup_branch_points(info); 421 | 422 | return baz(s, s_len, info); 423 | } 424 | 425 | int slre_match(const char *regexp, const char *s, int s_len, 426 | struct slre_cap *caps, int num_caps, int flags) { 427 | struct regex_info info; 428 | 429 | /* Initialize info structure */ 430 | info.flags = flags; 431 | info.num_brackets = info.num_branches = 0; 432 | info.num_caps = num_caps; 433 | info.caps = caps; 434 | 435 | DBG(("========================> [%s] [%.*s]\n", regexp, s_len, s)); 436 | return foo(regexp, (int) strlen(regexp), s, s_len, &info); 437 | } 438 | -------------------------------------------------------------------------------- /src/Internal/slre.901d42c/slre.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2013 Sergey Lyubka 3 | * Copyright (c) 2013 Cesanta Software Limited 4 | * All rights reserved 5 | * 6 | * This library is dual-licensed: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 as 8 | * published by the Free Software Foundation. For the terms of this 9 | * license, see . 10 | * 11 | * You are free to use this library under the terms of the GNU General 12 | * Public License, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the GNU General Public License for more details. 15 | * 16 | * Alternatively, you can license this library under a commercial 17 | * license, as set out in . 18 | */ 19 | 20 | /* 21 | * This is a regular expression library that implements a subset of Perl RE. 22 | * Please refer to README.md for a detailed reference. 23 | */ 24 | 25 | #ifndef CS_SLRE_SLRE_H_ 26 | #define CS_SLRE_SLRE_H_ 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | struct slre_cap { 33 | const char *ptr; 34 | int len; 35 | }; 36 | 37 | 38 | int slre_match(const char *regexp, const char *buf, int buf_len, 39 | struct slre_cap *caps, int num_caps, int flags); 40 | 41 | /* Possible flags for slre_match() */ 42 | enum { SLRE_IGNORE_CASE = 1 }; 43 | 44 | 45 | /* slre_match() failure codes */ 46 | #define SLRE_NO_MATCH -1 47 | #define SLRE_UNEXPECTED_QUANTIFIER -2 48 | #define SLRE_UNBALANCED_BRACKETS -3 49 | #define SLRE_INTERNAL_ERROR -4 50 | #define SLRE_INVALID_CHARACTER_SET -5 51 | #define SLRE_INVALID_METACHARACTER -6 52 | #define SLRE_CAPS_ARRAY_TOO_SMALL -7 53 | #define SLRE_TOO_MANY_BRANCHES -8 54 | #define SLRE_TOO_MANY_BRACKETS -9 55 | 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | 60 | #endif /* CS_SLRE_SLRE_H_ */ 61 | -------------------------------------------------------------------------------- /src/WioLTE.cpp: -------------------------------------------------------------------------------- 1 | #include "WioLTEConfig.h" 2 | #include "WioLTE.h" 3 | 4 | #include "Internal/Debug.h" 5 | #include "Internal/StringBuilder.h" 6 | #include "Internal/ArgumentParser.h" 7 | #if defined ARDUINO_ARCH_STM32F4 8 | #include "Internal/CMSIS/cmsis_gcc.h" 9 | #include "Internal/CMSIS/core_cm4.h" 10 | #elif defined ARDUINO_ARCH_STM32 11 | #include 12 | #endif 13 | #include "WioLTEHardware.h" 14 | #include 15 | #include 16 | 17 | #define RET_OK(val) (ReturnOk(val)) 18 | #define RET_ERR(val,err) (ReturnError(__LINE__, val, err)) 19 | 20 | #define CONNECT_ID_NUM (12) 21 | #define POLLING_INTERVAL (100) 22 | 23 | #define HTTP_USER_AGENT "QUECTEL_MODULE" 24 | #define HTTP_CONTENT_TYPE "application/json" 25 | 26 | #define LINEAR_SCALE(val, inMin, inMax, outMin, outMax) (((val) - (inMin)) / ((inMax) - (inMin)) * ((outMax) - (outMin)) + (outMin)) 27 | 28 | //////////////////////////////////////////////////////////////////////////////////////// 29 | // Helper functions 30 | 31 | #if defined ARDUINO_ARCH_STM32 32 | typedef uint32_t WiringPinMode; 33 | #endif // ARDUINO_ARCH_STM32 34 | 35 | static void PinModeAndDefault(int pin, WiringPinMode mode) 36 | { 37 | pinMode(pin, mode); 38 | } 39 | 40 | static void PinModeAndDefault(int pin, WiringPinMode mode, int value) 41 | { 42 | pinMode(pin, mode); 43 | if (mode == OUTPUT) digitalWrite(pin, value); 44 | } 45 | 46 | static int HexToInt(char c) 47 | { 48 | if ('0' <= c && c <= '9') return c - '0'; 49 | else if ('a' <= c && c <= 'f') return c - 'a' + 10; 50 | else if ('A' <= c && c <= 'F') return c - 'A' + 10; 51 | else return -1; 52 | } 53 | 54 | static bool ConvertHexToBytes(const char* hex, byte* data, int dataSize) 55 | { 56 | int high; 57 | int low; 58 | 59 | for (int i = 0; i < dataSize; i++) { 60 | high = HexToInt(hex[i * 2]); 61 | low = HexToInt(hex[i * 2 + 1]); 62 | if (high < 0 || low < 0) return false; 63 | data[i] = high * 16 + low; 64 | } 65 | 66 | return true; 67 | } 68 | 69 | static int Convert2DigitsToInt(const char* digits) 70 | { 71 | return (digits[0] - '0') * 10 + (digits[1] - '0'); 72 | } 73 | 74 | static bool SplitUrl(const char* url, const char** host, int* hostLength, const char** uri, int* uriLength) 75 | { 76 | if (strncmp(url, "http://", 7) == 0) { 77 | *host = &url[7]; 78 | } 79 | else if (strncmp(url, "https://", 8) == 0) { 80 | *host = &url[8]; 81 | } 82 | else { 83 | return false; 84 | } 85 | 86 | const char* ptr; 87 | for (ptr = *host; *ptr != '\0'; ptr++) { 88 | if (*ptr == '/') break; 89 | } 90 | *hostLength = ptr - *host; 91 | *uri = ptr; 92 | *uriLength = strlen(ptr); 93 | 94 | return true; 95 | } 96 | 97 | static bool SmAddressFieldToString(const byte* addressField, char* str, int strSize) 98 | { 99 | byte addressLength = addressField[0]; 100 | //byte typeOfAddress = addressField[1]; 101 | const byte* addressValue = &addressField[2]; 102 | 103 | if (addressLength + 1 > strSize) return false; 104 | 105 | for (int i = 0; i < addressLength; i++) 106 | { 107 | if (i % 2 == 0) 108 | { 109 | str[i] = '0' + (addressValue[i / 2] & 0x0f); 110 | } 111 | else 112 | { 113 | str[i] = '0' + (addressValue[i / 2] >> 4); 114 | } 115 | } 116 | str[addressLength] = '\0'; 117 | 118 | return true; 119 | } 120 | 121 | static double GnssCoordinateToDecimal(double dddmm) 122 | { 123 | int deg = (int)dddmm / 100; 124 | double min = dddmm - deg * 100.0; 125 | return deg + min / 60.0; 126 | } 127 | 128 | static void DelayArduino(int milliseconds) 129 | { 130 | delay(milliseconds); 131 | } 132 | 133 | //////////////////////////////////////////////////////////////////////////////////////// 134 | // WioLTE 135 | 136 | bool WioLTE::ReturnError(int lineNumber, bool value, WioLTE::ErrorCodeType errorCode) 137 | { 138 | _LastErrorCode = errorCode; 139 | 140 | char str[100]; 141 | sprintf(str, "%d", lineNumber); 142 | DEBUG_PRINT("ERROR! "); 143 | DEBUG_PRINTLN(str); 144 | 145 | return value; 146 | } 147 | 148 | int WioLTE::ReturnError(int lineNumber, int value, WioLTE::ErrorCodeType errorCode) 149 | { 150 | _LastErrorCode = errorCode; 151 | 152 | char str[100]; 153 | sprintf(str, "%d", lineNumber); 154 | DEBUG_PRINT("ERROR! "); 155 | DEBUG_PRINTLN(str); 156 | 157 | return value; 158 | } 159 | 160 | bool WioLTE::IsRespond() 161 | { 162 | Stopwatch sw; 163 | sw.Restart(); 164 | while (!_AtSerial.WriteCommandAndReadResponse("AT", "^OK$", 500, NULL)) { 165 | if (sw.ElapsedMilliseconds() >= 2000) return false; 166 | } 167 | 168 | return true; 169 | } 170 | 171 | bool WioLTE::Reset(long timeout) 172 | { 173 | digitalWrite(WioLTEHardwarePin::RESET_MODULE_PIN, LOW); 174 | _Delay(200); 175 | digitalWrite(WioLTEHardwarePin::RESET_MODULE_PIN, HIGH); 176 | _Delay(300); 177 | 178 | Stopwatch sw; 179 | sw.Restart(); 180 | while (!_AtSerial.ReadResponse("^RDY$", 100, NULL)) { 181 | DEBUG_PRINT("."); 182 | if (sw.ElapsedMilliseconds() >= timeout) return false; 183 | } 184 | DEBUG_PRINTLN(""); 185 | 186 | #ifdef WIO_DEBUG 187 | char dbg[100]; 188 | sprintf(dbg, "Elapsed time is %lu[msec.].", sw.ElapsedMilliseconds()); 189 | DEBUG_PRINTLN(dbg); 190 | #endif // WIO_DEBUG 191 | 192 | return true; 193 | } 194 | 195 | bool WioLTE::TurnOn(long timeout) 196 | { 197 | _Delay(100); 198 | digitalWrite(WioLTEHardwarePin::PWR_KEY_PIN, HIGH); 199 | _Delay(200); 200 | digitalWrite(WioLTEHardwarePin::PWR_KEY_PIN, LOW); 201 | 202 | Stopwatch sw; 203 | sw.Restart(); 204 | while (!_AtSerial.ReadResponse("^RDY$", 100, NULL)) { 205 | DEBUG_PRINT("."); 206 | if (sw.ElapsedMilliseconds() >= timeout) return false; 207 | } 208 | DEBUG_PRINTLN(""); 209 | 210 | #ifdef WIO_DEBUG 211 | char dbg[100]; 212 | sprintf(dbg, "Elapsed time is %lu[msec.].", sw.ElapsedMilliseconds()); 213 | DEBUG_PRINTLN(dbg); 214 | #endif // WIO_DEBUG 215 | 216 | return true; 217 | } 218 | 219 | int WioLTE::GetFirstIndexOfReceivedSMS() 220 | { 221 | std::string response; 222 | ArgumentParser parser; 223 | 224 | if (!_AtSerial.WriteCommandAndReadResponse("AT+CMGF=0", "^OK$", 500, NULL)) return -1; 225 | 226 | _AtSerial.WriteCommand("AT+CMGL=4"); // ALL 227 | 228 | int messageIndex = -1; 229 | while (true) { 230 | if (!_AtSerial.ReadResponse("^(OK|\\+CMGL: .*)$", 500, &response)) return -1; 231 | if (response == "OK") break; 232 | if (messageIndex < 0) { 233 | parser.Parse(&response.c_str()[7]); 234 | if (parser.Size() != 4) return -1; 235 | messageIndex = atoi(parser[0]); 236 | } 237 | 238 | if (!_AtSerial.ReadResponse("^.*$", 500, NULL)) return -1; 239 | } 240 | 241 | return messageIndex < 0 ? -2 : messageIndex; 242 | } 243 | 244 | bool WioLTE::HttpSetUrl(const char* url) 245 | { 246 | StringBuilder str; 247 | if (!str.WriteFormat("AT+QHTTPURL=%d", strlen(url))) return false; 248 | _AtSerial.WriteCommand(str.GetString()); 249 | if (!_AtSerial.ReadResponse("^CONNECT$", 500, NULL)) return false; 250 | 251 | _AtSerial.WriteBinary((const byte*)url, strlen(url)); 252 | if (!_AtSerial.ReadResponse("^OK$", 500, NULL)) return false; 253 | 254 | return true; 255 | } 256 | 257 | bool WioLTE::ReadResponseCallback(const char* response) 258 | { 259 | return false; 260 | 261 | if (strncmp(response, "+CGREG: ", 8) == 0) { 262 | DEBUG_PRINT("### Response Callback +CGREG ### "); 263 | DEBUG_PRINTLN(response); 264 | 265 | //ArgumentParser parser; 266 | //parser.Parse(&response[8]); 267 | //int stat; 268 | //if (parser.Size() == 2) { 269 | // stat = atoi(parser[1]); 270 | //} 271 | //else if (parser.Size() >= 1) { 272 | // stat = atoi(parser[0]); 273 | //} 274 | //else { 275 | // stat = -1; 276 | //} 277 | 278 | //switch (stat) 279 | //{ 280 | //case 0: // Not registered. MT is not currently searching 281 | //case 2: // Not registered, but MT is currently trying to attach or searching 282 | //case 3: // Registration denied. 283 | // _PacketGprsNetworkRegistration = false; 284 | // DEBUG_PRINTLN("NETWORK OFF"); 285 | // break; 286 | //case 1: // Registered, home network. 287 | //case 5: // Registered, roaming 288 | // _PacketGprsNetworkRegistration = true; 289 | // DEBUG_PRINTLN("NETWORK ON"); 290 | // break; 291 | //} 292 | 293 | return true; 294 | } 295 | else if (strncmp(response, "+CEREG: ", 8) == 0) { 296 | DEBUG_PRINT("### Response Callback +CEREG ### "); 297 | DEBUG_PRINTLN(response); 298 | 299 | //ArgumentParser parser; 300 | //parser.Parse(&response[8]); 301 | //int stat; 302 | //if (parser.Size() == 2) { 303 | // stat = atoi(parser[1]); 304 | //} 305 | //else if (parser.Size() >= 1) { 306 | // stat = atoi(parser[0]); 307 | //} 308 | //else { 309 | // stat = -1; 310 | //} 311 | 312 | //switch (stat) 313 | //{ 314 | //case 0: // Not registered. MT is not currently searching 315 | //case 2: // Not registered, but MT is currently trying to attach or searching 316 | //case 3: // Registration denied 317 | // _PacketEpsNetworkRegistration = false; 318 | // DEBUG_PRINTLN("NETWORK OFF"); 319 | // break; 320 | //case 1: // Registered, home network 321 | //case 5: // Registered, roaming 322 | // _PacketEpsNetworkRegistration = true; 323 | // DEBUG_PRINTLN("NETWORK ON"); 324 | // break; 325 | //} 326 | 327 | return true; 328 | } 329 | 330 | return false; 331 | } 332 | 333 | #if defined ARDUINO_ARCH_STM32F4 334 | WioLTE::WioLTE() : 335 | _SerialAPI(&SerialModule), 336 | _AtSerial(&_SerialAPI, this), 337 | _Led(1, WioLTEHardwarePin::RGB_LED_PIN), 338 | _LastErrorCode(E_OK), 339 | _Delay{ DelayArduino } 340 | { 341 | } 342 | #elif defined ARDUINO_ARCH_STM32 343 | WioLTE::WioLTE() : 344 | _SerialAPI(&SerialModule), 345 | _AtSerial(&_SerialAPI, this), 346 | _Led(), 347 | _LastErrorCode(E_OK), 348 | _Delay{ DelayArduino } 349 | { 350 | } 351 | #endif 352 | 353 | WioLTE::ErrorCodeType WioLTE::GetLastError() const 354 | { 355 | return _LastErrorCode; 356 | } 357 | 358 | void WioLTE::SetDelayFunction(std::function func) 359 | { 360 | _Delay = func; 361 | } 362 | 363 | void WioLTE::SetDoWorkInWaitForAvailableFunction(std::function func) 364 | { 365 | _AtSerial.SetDoWorkInWaitForAvailableFunction(func); 366 | } 367 | 368 | void WioLTE::Init() 369 | { 370 | // Power supply 371 | if (WioLTEHardwarePin::MODULE_PWR_PIN >= 0) PinModeAndDefault(WioLTEHardwarePin::MODULE_PWR_PIN, OUTPUT, LOW); 372 | if (WioLTEHardwarePin::ANT_PWR_PIN >= 0) PinModeAndDefault(WioLTEHardwarePin::ANT_PWR_PIN, OUTPUT, LOW); 373 | if (WioLTEHardwarePin::ENABLE_VCCB_PIN >= 0) PinModeAndDefault(WioLTEHardwarePin::ENABLE_VCCB_PIN, OUTPUT, LOW); 374 | if (WioLTEHardwarePin::RGB_LED_PWR_PIN >= 0) PinModeAndDefault(WioLTEHardwarePin::RGB_LED_PWR_PIN, OUTPUT, HIGH); 375 | if (WioLTEHardwarePin::SD_POWR_PIN >= 0) PinModeAndDefault(WioLTEHardwarePin::SD_POWR_PIN, OUTPUT, LOW); 376 | 377 | // Turn on/off Pins 378 | PinModeAndDefault(WioLTEHardwarePin::PWR_KEY_PIN, OUTPUT, LOW); 379 | PinModeAndDefault(WioLTEHardwarePin::RESET_MODULE_PIN, OUTPUT, HIGH); 380 | 381 | // Status Indication Pins 382 | if (WioLTEHardwarePin::STATUS_PIN >= 0) PinModeAndDefault(WioLTEHardwarePin::STATUS_PIN, INPUT); 383 | 384 | // UART Interface 385 | if (WioLTEHardwarePin::DTR_PIN >= 0) PinModeAndDefault(WioLTEHardwarePin::DTR_PIN, OUTPUT, LOW); 386 | 387 | // GPIO Pins 388 | if (WioLTEHardwarePin::WAKEUP_IN_PIN >= 0) PinModeAndDefault(WioLTEHardwarePin::WAKEUP_IN_PIN, OUTPUT, LOW); 389 | if (WioLTEHardwarePin::W_DISABLE_PIN >= 0) PinModeAndDefault(WioLTEHardwarePin::W_DISABLE_PIN, OUTPUT, HIGH); 390 | //if (WioLTEHardwarePin::AP_READY_PIN >= 0) PinModeAndDefault(WioLTEHardwarePin::AP_READY_PIN, OUTPUT); // NOT use 391 | 392 | _SerialAPI.Begin(115200); 393 | #if defined ARDUINO_ARCH_STM32F4 394 | _Led.begin(); 395 | #elif defined ARDUINO_ARCH_STM32 396 | if (WioLTEHardwarePin::RGB_LED_PIN >= 0) PinModeAndDefault(WioLTEHardwarePin::RGB_LED_PIN, OUTPUT, HIGH); 397 | #endif 398 | _LastErrorCode = E_OK; 399 | 400 | _PacketGprsNetworkRegistration = false; 401 | _PacketEpsNetworkRegistration = false; 402 | } 403 | 404 | void WioLTE::PowerSupplyLTE(bool on) 405 | { 406 | PowerSupplyCellular(on); 407 | } 408 | 409 | void WioLTE::PowerSupplyCellular(bool on) 410 | { 411 | if (WioLTEHardwarePin::MODULE_PWR_PIN >= 0) digitalWrite(WioLTEHardwarePin::MODULE_PWR_PIN, on ? HIGH : LOW); 412 | 413 | _LastErrorCode = E_OK; 414 | } 415 | 416 | void WioLTE::PowerSupplyGNSS(bool on) 417 | { 418 | if (WioLTEHardwarePin::ANT_PWR_PIN >= 0) digitalWrite(WioLTEHardwarePin::ANT_PWR_PIN, on ? HIGH : LOW); 419 | 420 | _LastErrorCode = E_OK; 421 | } 422 | 423 | void WioLTE::PowerSupplyLed(bool on) 424 | { 425 | if (WioLTEHardwarePin::RGB_LED_PWR_PIN >= 0) digitalWrite(WioLTEHardwarePin::RGB_LED_PWR_PIN, on ? HIGH : LOW); 426 | 427 | _LastErrorCode = E_OK; 428 | } 429 | 430 | void WioLTE::PowerSupplyGrove(bool on) 431 | { 432 | if (WioLTEHardwarePin::ENABLE_VCCB_PIN >= 0) digitalWrite(WioLTEHardwarePin::ENABLE_VCCB_PIN, on ? HIGH : LOW); 433 | 434 | _LastErrorCode = E_OK; 435 | } 436 | 437 | void WioLTE::PowerSupplySD(bool on) 438 | { 439 | if (WioLTEHardwarePin::SD_POWR_PIN >= 0) digitalWrite(WioLTEHardwarePin::SD_POWR_PIN, on ? HIGH : LOW); 440 | 441 | _LastErrorCode = E_OK; 442 | } 443 | 444 | void WioLTE::LedSetRGB(byte red, byte green, byte blue) 445 | { 446 | #if defined ARDUINO_ARCH_STM32F4 447 | _Led.WS2812SetRGB(0, red, green, blue); 448 | _Led.WS2812Send(); 449 | #elif defined ARDUINO_ARCH_STM32 450 | if (WioLTEHardwarePin::RGB_LED_PIN >= 0) 451 | { 452 | _Led.Reset(); 453 | _Led.SetSingleLED(red, green, blue); 454 | } 455 | #endif 456 | 457 | _LastErrorCode = E_OK; 458 | } 459 | 460 | bool WioLTE::TurnOnOrReset(long timeout) 461 | { 462 | std::string response; 463 | 464 | if (IsRespond()) { 465 | DEBUG_PRINTLN("Reset()"); 466 | if (!Reset(timeout)) return RET_ERR(false, E_UNABLE_TO_RECEIVE_RDY); 467 | } 468 | else { 469 | DEBUG_PRINTLN("TurnOn()"); 470 | if (!TurnOn(timeout)) return RET_ERR(false, E_UNABLE_TO_RECEIVE_RDY); 471 | } 472 | 473 | Stopwatch sw; 474 | sw.Restart(); 475 | while (!_AtSerial.WriteCommandAndReadResponse("AT", "^OK$", 500, NULL)) { 476 | DEBUG_PRINT("."); 477 | if (sw.ElapsedMilliseconds() >= 10000) return RET_ERR(false, E_NO_AT_RESPONSE); 478 | } 479 | DEBUG_PRINTLN(""); 480 | 481 | if (!_AtSerial.WriteCommandAndReadResponse("ATE0", "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 482 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QURCCFG=\"urcport\",\"uart1\"", "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 483 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QSCLK=1", "^(OK|ERROR)$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 484 | 485 | // TODO ReadResponseCallback 486 | //if (!_AtSerial.WriteCommandAndReadResponse("AT+CGREG=2", "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 487 | //if (!_AtSerial.WriteCommandAndReadResponse("AT+CEREG=2", "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 488 | //if (!_AtSerial.WriteCommandAndReadResponse("AT+CGREG?", "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 489 | //if (!_AtSerial.WriteCommandAndReadResponse("AT+CEREG?", "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 490 | 491 | sw.Restart(); 492 | bool cpinReady; 493 | while (true) { 494 | _AtSerial.WriteCommand("AT+CPIN?"); 495 | cpinReady = false; 496 | while (true) { 497 | if (!_AtSerial.ReadResponse("^(OK|\\+CPIN: READY|\\+CME ERROR: .*)$", 500, &response)) return RET_ERR(false, E_PIN); 498 | if (response == "+CPIN: READY") { 499 | cpinReady = true; 500 | continue; 501 | } 502 | break; 503 | } 504 | if (response == "OK" && cpinReady) break; 505 | 506 | if (sw.ElapsedMilliseconds() >= 10000) return RET_ERR(false, E_PIN); 507 | _Delay(POLLING_INTERVAL); 508 | } 509 | 510 | return RET_OK(true); 511 | } 512 | 513 | bool WioLTE::TurnOff(long timeout) 514 | { 515 | std::string response; 516 | 517 | Stopwatch sw; 518 | sw.Restart(); 519 | while (true) { 520 | _AtSerial.WriteCommand("AT+QPOWD"); 521 | if (!_AtSerial.ReadResponse("^(OK|ERROR)$", 500, &response)) return RET_ERR(false, E_TIMEOUT); 522 | if (response == "OK") break; 523 | if (sw.ElapsedMilliseconds() >= (unsigned long)timeout) return RET_ERR(false, E_TIMEOUT); 524 | _Delay(POLLING_INTERVAL); 525 | } 526 | 527 | if (!_AtSerial.ReadResponse("^POWERED DOWN$", 60000, NULL)) return RET_ERR(false, E_UNABLE_TO_RECEIVE_POWERED_DOWN); 528 | 529 | return RET_OK(true); 530 | } 531 | 532 | bool WioLTE::Sleep() 533 | { 534 | if (WioLTEHardwarePin::DTR_PIN >= 0) digitalWrite(WioLTEHardwarePin::DTR_PIN, HIGH); 535 | 536 | return RET_OK(true); 537 | } 538 | 539 | bool WioLTE::Wakeup() 540 | { 541 | if (WioLTEHardwarePin::DTR_PIN >= 0) digitalWrite(WioLTEHardwarePin::DTR_PIN, LOW); 542 | 543 | Stopwatch sw; 544 | sw.Restart(); 545 | while (!_AtSerial.WriteCommandAndReadResponse("AT", "^OK$", 500, NULL)) { 546 | DEBUG_PRINT("."); 547 | if (sw.ElapsedMilliseconds() >= 2000) return RET_ERR(false, E_NO_AT_RESPONSE); 548 | } 549 | DEBUG_PRINTLN(""); 550 | 551 | return RET_OK(true); 552 | } 553 | 554 | int WioLTE::GetRevision(char* revision, int revisionSize) 555 | { 556 | std::string response; 557 | std::string revisionStr; 558 | 559 | _AtSerial.WriteCommand("AT+CGMR"); 560 | while (true) { 561 | if (!_AtSerial.ReadResponse("^(OK|[0-9A-Z_]+)$", 500, &response)) return RET_ERR(-1, E_TIMEOUT); 562 | if (response == "OK") break; 563 | revisionStr = response; 564 | } 565 | 566 | if ((int)revisionStr.size() + 1 > revisionSize) return RET_ERR(-1, E_NOT_ENOUGH_SIZE); 567 | strcpy(revision, revisionStr.c_str()); 568 | 569 | return RET_OK((int)strlen(revision)); 570 | } 571 | 572 | int WioLTE::GetIMEI(char* imei, int imeiSize) 573 | { 574 | std::string response; 575 | std::string imeiStr; 576 | 577 | _AtSerial.WriteCommand("AT+GSN"); 578 | while (true) { 579 | if (!_AtSerial.ReadResponse("^(OK|[0-9]+)$", 500, &response)) return RET_ERR(-1, E_TIMEOUT); 580 | if (response == "OK") break; 581 | imeiStr = response; 582 | } 583 | 584 | if ((int)imeiStr.size() + 1 > imeiSize) return RET_ERR(-1, E_NOT_ENOUGH_SIZE); 585 | strcpy(imei, imeiStr.c_str()); 586 | 587 | return RET_OK((int)strlen(imei)); 588 | } 589 | 590 | int WioLTE::GetIMSI(char* imsi, int imsiSize) 591 | { 592 | std::string response; 593 | std::string imsiStr; 594 | 595 | _AtSerial.WriteCommand("AT+CIMI"); 596 | while (true) { 597 | if (!_AtSerial.ReadResponse("^(OK|[0-9]+)$", 500, &response)) return RET_ERR(-1, E_TIMEOUT); 598 | if (response == "OK") break; 599 | imsiStr = response; 600 | } 601 | 602 | if ((int)imsiStr.size() + 1 > imsiSize) return RET_ERR(-1, E_NOT_ENOUGH_SIZE); 603 | strcpy(imsi, imsiStr.c_str()); 604 | 605 | return RET_OK((int)strlen(imsi)); 606 | } 607 | 608 | int WioLTE::GetICCID(char* iccid, int iccidSize) 609 | { 610 | std::string response; 611 | 612 | _AtSerial.WriteCommand("AT+QCCID"); 613 | if (!_AtSerial.ReadResponse("^\\+QCCID: (.*)$", 500, &response)) return RET_ERR(-1, E_TIMEOUT); 614 | if (!_AtSerial.ReadResponse("^OK$", 500, NULL)) return RET_ERR(-1, E_TIMEOUT); 615 | response.erase(response.size() - 1, 1); 616 | 617 | if ((int)response.size() + 1 > iccidSize) return RET_ERR(-1, E_NOT_ENOUGH_SIZE); 618 | strcpy(iccid, response.c_str()); 619 | 620 | return RET_OK((int)strlen(iccid)); 621 | } 622 | 623 | int WioLTE::GetPhoneNumber(char* number, int numberSize) 624 | { 625 | std::string response; 626 | ArgumentParser parser; 627 | std::string numberStr; 628 | 629 | _AtSerial.WriteCommand("AT+CNUM"); 630 | while (true) { 631 | if (!_AtSerial.ReadResponse("^(OK|\\+CNUM: .*)$", 500, &response)) return RET_ERR(-1, E_TIMEOUT); 632 | if (response == "OK") break; 633 | 634 | if (numberStr.size() >= 1) continue; 635 | 636 | parser.Parse(response.c_str()); 637 | if (parser.Size() < 2) return RET_ERR(-1, E_INVALID_RESPONSE); 638 | numberStr = parser[1]; 639 | } 640 | 641 | if ((int)numberStr.size() + 1 > numberSize) return RET_ERR(-1, E_NOT_ENOUGH_SIZE); 642 | strcpy(number, numberStr.c_str()); 643 | 644 | return RET_OK((int)strlen(number)); 645 | } 646 | 647 | int WioLTE::GetReceivedSignalStrength() 648 | { 649 | std::string response; 650 | ArgumentParser parser; 651 | 652 | _AtSerial.WriteCommand("AT+CSQ"); 653 | if (!_AtSerial.ReadResponse("^\\+CSQ: (.*)$", 500, &response)) return RET_ERR(INT_MIN, E_TIMEOUT); 654 | 655 | parser.Parse(response.c_str()); 656 | if (parser.Size() != 2) return RET_ERR(INT_MIN, E_INVALID_RESPONSE); 657 | int rssi = atoi(parser[0]); 658 | 659 | if (!_AtSerial.ReadResponse("^OK$", 500, NULL)) return RET_ERR(INT_MIN, E_TIMEOUT); 660 | 661 | if (rssi == 0) return RET_OK(-113); 662 | else if (rssi == 1) return RET_OK(-111); 663 | else if (2 <= rssi && rssi <= 30) return RET_OK((int)LINEAR_SCALE((double)rssi, 2, 30, -109, -53)); 664 | else if (rssi == 31) return RET_OK(-51); 665 | else if (rssi == 99) return RET_OK(-999); 666 | else if (rssi == 100) return RET_OK(-116); 667 | else if (rssi == 101) return RET_OK(-115); 668 | else if (102 <= rssi && rssi <= 190) return RET_OK((int)LINEAR_SCALE((double)rssi, 102, 190, -114, -26)); 669 | else if (rssi == 191) return RET_OK(-25); 670 | else if (rssi == 199) return RET_OK(-999); 671 | 672 | return RET_OK(-999); 673 | } 674 | 675 | bool WioLTE::GetTime(struct tm* tim) 676 | { 677 | std::string response; 678 | 679 | _AtSerial.WriteCommand("AT+CCLK?"); 680 | if (!_AtSerial.ReadResponse("^\\+CCLK: (.*)$", 500, &response)) return RET_ERR(false, E_TIMEOUT); 681 | if (!_AtSerial.ReadResponse("^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 682 | 683 | if (strlen(response.c_str()) != 22) return RET_ERR(false, E_INVALID_RESPONSE); 684 | const char* parameter = response.c_str(); 685 | 686 | if (parameter[0] != '"') return RET_ERR(false, E_INVALID_RESPONSE); 687 | if (parameter[3] != '/') return RET_ERR(false, E_INVALID_RESPONSE); 688 | if (parameter[6] != '/') return RET_ERR(false, E_INVALID_RESPONSE); 689 | if (parameter[9] != ',') return RET_ERR(false, E_INVALID_RESPONSE); 690 | if (parameter[12] != ':') return RET_ERR(false, E_INVALID_RESPONSE); 691 | if (parameter[15] != ':') return RET_ERR(false, E_INVALID_RESPONSE); 692 | if (parameter[21] != '"') return RET_ERR(false, E_INVALID_RESPONSE); 693 | 694 | int yearOffset = atoi(¶meter[1]); 695 | tim->tm_year = (yearOffset >= 80 ? 1900 : 2000) + yearOffset - 1900; 696 | tim->tm_mon = atoi(¶meter[4]) - 1; 697 | tim->tm_mday = atoi(¶meter[7]); 698 | tim->tm_hour = atoi(¶meter[10]); 699 | tim->tm_min = atoi(¶meter[13]); 700 | tim->tm_sec = atoi(¶meter[16]); 701 | tim->tm_wday = 0; 702 | tim->tm_yday = 0; 703 | tim->tm_isdst = 0; 704 | 705 | // Update tm_wday and tm_yday 706 | mktime(tim); 707 | 708 | return RET_OK(true); 709 | } 710 | 711 | bool WioLTE::SendSMS(const char* dialNumber, const char* message) 712 | { 713 | if (!_AtSerial.WriteCommandAndReadResponse("AT+CMGF=1", "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 714 | 715 | StringBuilder str; 716 | if (!str.WriteFormat("AT+CMGS=\"%s\"", dialNumber)) return RET_ERR(false, E_UNKNOWN); 717 | _AtSerial.WriteCommand(str.GetString()); 718 | if (!_AtSerial.ReadResponse("^> ", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 719 | _AtSerial.WriteBinary((const byte*)message, strlen(message)); 720 | _AtSerial.WriteBinary((const byte*)"\x1a", 1); 721 | if (!_AtSerial.ReadResponse("^OK$", 120000, NULL)) return RET_ERR(false, E_TIMEOUT); 722 | 723 | return RET_OK(true); 724 | } 725 | 726 | int WioLTE::ReceiveSMS(char* message, int messageSize, char* dialNumber, int dialNumberSize) 727 | { 728 | int messageIndex = GetFirstIndexOfReceivedSMS(); 729 | if (messageIndex == -2) return RET_OK(0); 730 | if (messageIndex < 0) return RET_ERR(-1, E_INVALID_ARGUMENT); 731 | 732 | if (!_AtSerial.WriteCommandAndReadResponse("AT+CMGF=0", "^OK$", 500, NULL)) return RET_ERR(-1, E_TIMEOUT); 733 | 734 | StringBuilder str; 735 | if (!str.WriteFormat("AT+CMGR=%d", messageIndex)) return RET_ERR(-1, E_UNKNOWN); 736 | _AtSerial.WriteCommand(str.GetString()); 737 | 738 | if (!_AtSerial.ReadResponse("^\\+CMGR: .*$", 500, NULL)) return RET_ERR(-1, E_TIMEOUT); 739 | 740 | std::string response; 741 | if (!_AtSerial.ReadResponse("^(.*)$", 500, &response)) return RET_ERR(-1, E_TIMEOUT); 742 | const char* hex = response.c_str(); 743 | 744 | int hexSize = strlen(hex); 745 | if (hexSize % 2 != 0) return RET_ERR(-1, E_INVALID_RESPONSE); 746 | int dataSize = hexSize / 2; 747 | byte* data = (byte*)alloca(dataSize); 748 | if (!ConvertHexToBytes(hex, data, dataSize)) return RET_ERR(-1, E_INVALID_RESPONSE); 749 | byte* dataEnd = &data[dataSize]; 750 | 751 | // 3GPP TS 23.040 https://www.etsi.org/deliver/etsi_ts/123000_123099/123040/09.03.00_60/ts_123040v090300p.pdf 752 | // 3GPP TS 23.038 https://www.etsi.org/deliver/etsi_ts/123000_123099/123038/10.00.00_60/ts_123038v100000p.pdf 753 | byte* smscInfoSize = data; 754 | byte* tpMti = smscInfoSize + 1 + *smscInfoSize; 755 | if (tpMti >= dataEnd) return RET_ERR(-1, E_INVALID_RESPONSE); 756 | if ((*tpMti & 0x03) != 0x00) return RET_ERR(-1, E_INVALID_RESPONSE); // SMS-DELIVER 757 | bool tpUdhi = *tpMti & 0b01000000 ? true : false; 758 | byte* tpOaSize = tpMti + 1; 759 | if (tpOaSize >= dataEnd) return RET_ERR(-1, E_INVALID_RESPONSE); 760 | byte* tpPid = tpOaSize + 2 + *tpOaSize / 2 + *tpOaSize % 2; 761 | if (tpPid >= dataEnd) return RET_ERR(-1, E_INVALID_RESPONSE); 762 | byte* tpDcs = tpPid + 1; 763 | if (tpDcs >= dataEnd) return RET_ERR(-1, E_INVALID_RESPONSE); 764 | byte* tpScts = tpDcs + 1; 765 | if (tpScts >= dataEnd) return RET_ERR(-1, E_INVALID_RESPONSE); 766 | byte* tpUd = tpScts + 7; 767 | if (tpUd >= dataEnd) return RET_ERR(-1, E_INVALID_RESPONSE); 768 | 769 | if (dialNumber != NULL && dialNumberSize >= 1) 770 | { 771 | if (!SmAddressFieldToString(tpOaSize, dialNumber, dialNumberSize)) return RET_ERR(-1, E_INVALID_RESPONSE); 772 | } 773 | 774 | int smSize; 775 | byte* sm; 776 | if (!tpUdhi) 777 | { 778 | smSize = tpUd[0]; 779 | sm = tpUd + 1; 780 | } 781 | else 782 | { 783 | if (&tpUd[1] >= dataEnd) return RET_ERR(-1, E_INVALID_RESPONSE); 784 | smSize = tpUd[0] - (1 + tpUd[1]); 785 | sm = tpUd + 2 + tpUd[1]; 786 | } 787 | 788 | if (messageSize < smSize + 1) return RET_ERR(-1, E_INVALID_RESPONSE); 789 | for (int i = 0; i < smSize; i++) { 790 | int offset = i - i / 8; 791 | int shift = i % 8; 792 | if (shift == 0) { 793 | message[i] = sm[offset] & 0x7f; 794 | } 795 | else { 796 | message[i] = (sm[offset] * 256 + sm[offset - 1]) << shift >> 8 & 0x7f; 797 | } 798 | } 799 | message[smSize] = '\0'; 800 | 801 | if (!_AtSerial.ReadResponse("^OK$", 500, NULL)) return RET_ERR(-1, E_TIMEOUT); 802 | 803 | return RET_OK(smSize); 804 | } 805 | 806 | bool WioLTE::DeleteReceivedSMS() 807 | { 808 | int messageIndex = GetFirstIndexOfReceivedSMS(); 809 | if (messageIndex == -2) return RET_ERR(false, E_UNKNOWN); 810 | if (messageIndex < 0) return RET_ERR(false, E_UNKNOWN); 811 | 812 | StringBuilder str; 813 | if (!str.WriteFormat("AT+CMGD=%d", messageIndex)) return RET_ERR(false, E_UNKNOWN); 814 | if (!_AtSerial.WriteCommandAndReadResponse(str.GetString(), "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 815 | 816 | return RET_OK(true); 817 | } 818 | 819 | bool WioLTE::WaitForCSRegistration(long timeout) 820 | { 821 | std::string response; 822 | ArgumentParser parser; 823 | 824 | Stopwatch sw; 825 | sw.Restart(); 826 | while (true) { 827 | int status; 828 | 829 | _AtSerial.WriteCommand("AT+CREG?"); 830 | if (!_AtSerial.ReadResponse("^\\+CREG: (.*)$", 500, &response)) return RET_ERR(false, E_TIMEOUT); 831 | parser.Parse(response.c_str()); 832 | if (parser.Size() < 2) return RET_ERR(false, E_INVALID_RESPONSE); 833 | //resultCode = atoi(parser[0]); 834 | status = atoi(parser[1]); 835 | if (!_AtSerial.ReadResponse("^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 836 | if (status == 0) return RET_ERR(false, E_INVALID_RESPONSE); 837 | if (status == 1 || status == 5) break; 838 | 839 | if (sw.ElapsedMilliseconds() >= (unsigned long)timeout) return RET_ERR(false, E_TIMEOUT); 840 | _Delay(POLLING_INTERVAL); 841 | } 842 | 843 | return RET_OK(true); 844 | } 845 | 846 | bool WioLTE::WaitForPSRegistration(long timeout) 847 | { 848 | std::string response; 849 | ArgumentParser parser; 850 | 851 | Stopwatch sw; 852 | sw.Restart(); 853 | while (true) { 854 | int status; 855 | 856 | _AtSerial.WriteCommand("AT+CGREG?"); 857 | if (!_AtSerial.ReadResponse("^\\+CGREG: (.*)$", 500, &response)) return RET_ERR(false, E_TIMEOUT); 858 | parser.Parse(response.c_str()); 859 | if (parser.Size() < 2) return RET_ERR(false, E_INVALID_RESPONSE); 860 | //resultCode = atoi(parser[0]); 861 | status = atoi(parser[1]); 862 | if (!_AtSerial.ReadResponse("^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 863 | if (status == 0) return RET_ERR(false, E_INVALID_RESPONSE); 864 | if (status == 1 || status == 5) break; 865 | 866 | _AtSerial.WriteCommand("AT+CEREG?"); 867 | if (!_AtSerial.ReadResponse("^\\+CEREG: (.*)$", 500, &response)) return RET_ERR(false, E_TIMEOUT); 868 | parser.Parse(response.c_str()); 869 | if (parser.Size() < 2) return RET_ERR(false, E_INVALID_RESPONSE); 870 | //resultCode = atoi(parser[0]); 871 | status = atoi(parser[1]); 872 | if (!_AtSerial.ReadResponse("^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 873 | if (status == 0) return RET_ERR(false, E_INVALID_RESPONSE); 874 | if (status == 1 || status == 5) break; 875 | 876 | if (sw.ElapsedMilliseconds() >= (unsigned long)timeout) return RET_ERR(false, E_TIMEOUT); 877 | _Delay(POLLING_INTERVAL); 878 | } 879 | 880 | return RET_OK(true); 881 | } 882 | 883 | bool WioLTE::Activate(const char* accessPointName, const char* userName, const char* password, long waitForRegistTimeout) 884 | { 885 | std::string response; 886 | ArgumentParser parser; 887 | Stopwatch sw; 888 | 889 | if (!WaitForPSRegistration(0)) { 890 | StringBuilder str; 891 | if (!str.WriteFormat("AT+QICSGP=1,1,\"%s\",\"%s\",\"%s\",3", accessPointName, userName, password)) return RET_ERR(false, E_UNKNOWN); 892 | if (!_AtSerial.WriteCommandAndReadResponse(str.GetString(), "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 893 | 894 | sw.Restart(); 895 | 896 | if (!WaitForPSRegistration(waitForRegistTimeout)) return RET_ERR(false, E_UNKNOWN); 897 | 898 | // for debug. 899 | #ifdef WIO_DEBUG 900 | char dbg[100]; 901 | sprintf(dbg, "Elapsed time is %lu[msec.].", sw.ElapsedMilliseconds()); 902 | DEBUG_PRINTLN(dbg); 903 | 904 | _AtSerial.WriteCommandAndReadResponse("AT+CREG?", "^OK$", 500, NULL); 905 | _AtSerial.WriteCommandAndReadResponse("AT+CGREG?", "^OK$", 500, NULL); 906 | _AtSerial.WriteCommandAndReadResponse("AT+CEREG?", "^OK$", 500, NULL); 907 | #endif // WIO_DEBUG 908 | } 909 | 910 | sw.Restart(); 911 | while (true) { 912 | _AtSerial.WriteCommand("AT+QIACT=1"); 913 | if (!_AtSerial.ReadResponse("^(OK|ERROR)$", 150000, &response)) return RET_ERR(false, E_TIMEOUT); 914 | if (response == "OK") break; 915 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QIGETERROR", "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 916 | if (sw.ElapsedMilliseconds() >= 150000) return RET_ERR(false, E_TIMEOUT); 917 | _Delay(POLLING_INTERVAL); 918 | } 919 | 920 | // for debug. 921 | #ifdef WIO_DEBUG 922 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QIACT?", "^OK$", 150000, NULL)) return RET_ERR(false, E_TIMEOUT); 923 | #endif // WIO_DEBUG 924 | 925 | return RET_OK(true); 926 | } 927 | 928 | bool WioLTE::Deactivate() 929 | { 930 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QIDEACT=1", "^OK$", 40000, NULL)) return RET_ERR(false, E_TIMEOUT); 931 | 932 | return RET_OK(true); 933 | } 934 | 935 | bool WioLTE::SyncTime(const char* host) 936 | { 937 | StringBuilder str; 938 | std::string response; 939 | if (!str.WriteFormat("AT+QNTP=1,\"%s\"", host)) return RET_ERR(false, E_UNKNOWN); 940 | if (!_AtSerial.WriteCommandAndReadResponse(str.GetString(), "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 941 | if (!_AtSerial.ReadResponse("^\\+QNTP: (.*)$", 125000, &response)) return RET_ERR(false, E_TIMEOUT); 942 | if (strncmp(response.c_str(), "0,", 2) != 0) return RET_ERR(-1, E_INVALID_RESPONSE); // check whether the command finished successfully 943 | 944 | return RET_OK(true); 945 | } 946 | 947 | bool WioLTE::GetLocation(double* longitude, double* latitude) 948 | { 949 | std::string response; 950 | ArgumentParser parser; 951 | 952 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QLOCCFG=\"contextid\",1", "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 953 | 954 | _AtSerial.WriteCommand("AT+QCELLLOC"); 955 | if (!_AtSerial.ReadResponse("^(\\+QCELLLOC: .*|\\+CME ERROR: .*)$", 60000, &response)) return RET_ERR(false, E_TIMEOUT); 956 | if (strncmp(response.c_str(), "+QCELLLOC: ", 11) != 0) return RET_ERR(false, E_INVALID_RESPONSE); 957 | 958 | parser.Parse(&response.c_str()[11]); 959 | if (parser.Size() != 2) return RET_ERR(false, E_INVALID_RESPONSE); 960 | *longitude = atof(parser[0]); 961 | *latitude = atof(parser[1]); 962 | if (!_AtSerial.ReadResponse("^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 963 | 964 | return RET_OK(true); 965 | } 966 | 967 | int WioLTE::SocketOpen(const char* host, int port, SocketType type) 968 | { 969 | std::string response; 970 | ArgumentParser parser; 971 | 972 | if (host == NULL || host[0] == '\0') return RET_ERR(-1, E_INVALID_ARGUMENT); 973 | if (port < 0 || 65535 < port) return RET_ERR(-1, E_INVALID_ARGUMENT); 974 | 975 | const char* typeStr; 976 | switch (type) { 977 | case SOCKET_TCP: 978 | typeStr = "TCP"; 979 | break; 980 | case SOCKET_UDP: 981 | typeStr = "UDP"; 982 | break; 983 | default: 984 | return RET_ERR(-1, E_INVALID_ARGUMENT); 985 | } 986 | 987 | bool connectIdUsed[CONNECT_ID_NUM]; 988 | for (int i = 0; i < CONNECT_ID_NUM; i++) connectIdUsed[i] = false; 989 | 990 | _AtSerial.WriteCommand("AT+QISTATE?"); 991 | do { 992 | if (!_AtSerial.ReadResponse("^(OK|\\+QISTATE: .*)$", 10000, &response)) return RET_ERR(-1, E_TIMEOUT); 993 | if (strncmp(response.c_str(), "+QISTATE: ", 10) == 0) { 994 | parser.Parse(&response.c_str()[10]); 995 | if (parser.Size() >= 1) { 996 | int connectId = atoi(parser[0]); 997 | if (connectId < 0 || CONNECT_ID_NUM <= connectId) return RET_ERR(-1, E_INVALID_RESPONSE); 998 | connectIdUsed[connectId] = true; 999 | } 1000 | } 1001 | } while (response != "OK"); 1002 | 1003 | int connectId; 1004 | for (connectId = 0; connectId < CONNECT_ID_NUM; connectId++) { 1005 | if (!connectIdUsed[connectId]) break; 1006 | } 1007 | if (connectId >= CONNECT_ID_NUM) return RET_ERR(-1, E_NOT_ENOUGH_RESOURCE); 1008 | 1009 | StringBuilder str; 1010 | if (!str.WriteFormat("AT+QIOPEN=1,%d,\"%s\",\"%s\",%d", connectId, typeStr, host, port)) return RET_ERR(-1, E_UNKNOWN); 1011 | if (!_AtSerial.WriteCommandAndReadResponse(str.GetString(), "^OK$", 150000, NULL)) return RET_ERR(-1, E_TIMEOUT); 1012 | str.Clear(); 1013 | if (!str.WriteFormat("^\\+QIOPEN: %d,0$", connectId)) return RET_ERR(-1, E_UNKNOWN); 1014 | if (!_AtSerial.ReadResponse(str.GetString(), 150000, NULL)) return RET_ERR(-1, E_TIMEOUT); 1015 | 1016 | return RET_OK(connectId); 1017 | } 1018 | 1019 | bool WioLTE::SocketSend(int connectId, const byte* data, int dataSize) 1020 | { 1021 | if (connectId >= CONNECT_ID_NUM) return RET_ERR(false, E_INVALID_ARGUMENT); 1022 | if (dataSize > 1460) return RET_ERR(false, E_INVALID_ARGUMENT); 1023 | 1024 | StringBuilder str; 1025 | if (!str.WriteFormat("AT+QISEND=%d,%d", connectId, dataSize)) return RET_ERR(false, E_UNKNOWN); 1026 | _AtSerial.WriteCommand(str.GetString()); 1027 | if (!_AtSerial.ReadResponse("^>", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 1028 | _AtSerial.WriteBinary(data, dataSize); 1029 | if (!_AtSerial.ReadResponse("^SEND OK$", 5000, NULL)) return RET_ERR(false, E_TIMEOUT); 1030 | 1031 | return RET_OK(true); 1032 | } 1033 | 1034 | bool WioLTE::SocketSend(int connectId, const char* data) 1035 | { 1036 | return SocketSend(connectId, (const byte*)data, strlen(data)); 1037 | } 1038 | 1039 | int WioLTE::SocketReceive(int connectId, byte* data, int dataSize) 1040 | { 1041 | std::string response; 1042 | 1043 | if (connectId >= CONNECT_ID_NUM) return RET_ERR(-1, E_INVALID_ARGUMENT); 1044 | 1045 | StringBuilder str; 1046 | if (!str.WriteFormat("AT+QIRD=%d", connectId)) return RET_ERR(-1, E_UNKNOWN); 1047 | _AtSerial.WriteCommand(str.GetString()); 1048 | if (!_AtSerial.ReadResponse("^\\+QIRD: (.*)$", 500, &response)) return RET_ERR(-1, E_TIMEOUT); 1049 | int dataLength = atoi(response.c_str()); 1050 | if (dataLength >= 1) { 1051 | if (dataLength > dataSize) return RET_ERR(-1, E_NOT_ENOUGH_SIZE); 1052 | if (!_AtSerial.ReadBinary(data, dataLength, 500)) return RET_ERR(-1, E_TIMEOUT); 1053 | } 1054 | if (!_AtSerial.ReadResponse("^OK$", 500, NULL)) return RET_ERR(-1, E_TIMEOUT); 1055 | 1056 | return RET_OK(dataLength); 1057 | } 1058 | 1059 | int WioLTE::SocketReceive(int connectId, char* data, int dataSize) 1060 | { 1061 | int dataLength = SocketReceive(connectId, (byte*)data, dataSize - 1); 1062 | if (dataLength >= 0) data[dataLength] = '\0'; 1063 | 1064 | return dataLength; 1065 | } 1066 | 1067 | int WioLTE::SocketReceive(int connectId, byte* data, int dataSize, long timeout) 1068 | { 1069 | Stopwatch sw; 1070 | sw.Restart(); 1071 | int dataLength; 1072 | while ((dataLength = SocketReceive(connectId, data, dataSize)) == 0) { 1073 | if (sw.ElapsedMilliseconds() >= (unsigned long)timeout) return 0; 1074 | _Delay(POLLING_INTERVAL); 1075 | } 1076 | return dataLength; 1077 | } 1078 | 1079 | int WioLTE::SocketReceive(int connectId, char* data, int dataSize, long timeout) 1080 | { 1081 | Stopwatch sw; 1082 | sw.Restart(); 1083 | int dataLength; 1084 | while ((dataLength = SocketReceive(connectId, data, dataSize)) == 0) { 1085 | if (sw.ElapsedMilliseconds() >= (unsigned long)timeout) return 0; 1086 | _Delay(POLLING_INTERVAL); 1087 | } 1088 | return dataLength; 1089 | } 1090 | 1091 | bool WioLTE::SocketClose(int connectId) 1092 | { 1093 | if (connectId >= CONNECT_ID_NUM) return RET_ERR(false, E_INVALID_ARGUMENT); 1094 | 1095 | StringBuilder str; 1096 | if (!str.WriteFormat("AT+QICLOSE=%d", connectId)) return RET_ERR(false, E_UNKNOWN); 1097 | if (!_AtSerial.WriteCommandAndReadResponse(str.GetString(), "^OK$", 10000, NULL)) return RET_ERR(false, E_TIMEOUT); 1098 | 1099 | return RET_OK(true); 1100 | } 1101 | 1102 | int WioLTE::HttpGet(const char* url, char* data, int dataSize, long timeout) 1103 | { 1104 | WioLTEHttpHeader header; 1105 | header["Accept"] = "*/*"; 1106 | header["User-Agent"] = HTTP_USER_AGENT; 1107 | header["Connection"] = "close"; 1108 | 1109 | return HttpGet(url, data, dataSize, header, timeout); 1110 | } 1111 | 1112 | int WioLTE::HttpGet(const char* url, char* data, int dataSize, const WioLTEHttpHeader& header, long timeout) 1113 | { 1114 | std::string response; 1115 | ArgumentParser parser; 1116 | 1117 | int timeoutSec = timeout / 1000; 1118 | if (timeout % 1000 > 0) timeoutSec++; 1119 | 1120 | if (strncmp(url, "https:", 6) == 0) { 1121 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QHTTPCFG=\"sslctxid\",1" , "^OK$", 500, NULL)) return RET_ERR(-1, E_TIMEOUT); 1122 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QSSLCFG=\"sslversion\",1,4" , "^OK$", 500, NULL)) return RET_ERR(-1, E_TIMEOUT); 1123 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QSSLCFG=\"ciphersuite\",1,0XFFFF", "^OK$", 500, NULL)) return RET_ERR(-1, E_TIMEOUT); 1124 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QSSLCFG=\"seclevel\",1,0" , "^OK$", 500, NULL)) return RET_ERR(-1, E_TIMEOUT); 1125 | } 1126 | 1127 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QHTTPCFG=\"requestheader\",1", "^OK$", 500, NULL)) return RET_ERR(-1, E_TIMEOUT); 1128 | 1129 | if (!HttpSetUrl(url)) return RET_ERR(-1, E_UNKNOWN); 1130 | 1131 | const char* host; 1132 | int hostLength; 1133 | const char* uri; 1134 | int uriLength; 1135 | if (!SplitUrl(url, &host, &hostLength, &uri, &uriLength)) return RET_ERR(false, E_INVALID_ARGUMENT); 1136 | 1137 | StringBuilder headerSb; 1138 | headerSb.Write("GET "); 1139 | if (uriLength <= 0) { 1140 | headerSb.Write("/"); 1141 | } 1142 | else { 1143 | headerSb.Write(uri, uriLength); 1144 | } 1145 | headerSb.Write(" HTTP/1.1\r\n"); 1146 | headerSb.Write("Host: "); 1147 | headerSb.Write(host, hostLength); 1148 | headerSb.Write("\r\n"); 1149 | for (auto it = header.begin(); it != header.end(); it++) { 1150 | headerSb.Write(it->first.c_str()); 1151 | headerSb.Write(": "); 1152 | headerSb.Write(it->second.c_str()); 1153 | headerSb.Write("\r\n"); 1154 | } 1155 | headerSb.Write("\r\n"); 1156 | DEBUG_PRINTLN("=== header"); 1157 | DEBUG_PRINTLN(headerSb.GetString()); 1158 | DEBUG_PRINTLN("==="); 1159 | 1160 | StringBuilder str; 1161 | if (!str.WriteFormat("AT+QHTTPGET=%d,%d", timeoutSec, headerSb.Length())) return RET_ERR(false, E_UNKNOWN); 1162 | _AtSerial.WriteCommand(str.GetString()); 1163 | if (!_AtSerial.ReadResponse("^CONNECT$", 60000, NULL)) return RET_ERR(false, E_TIMEOUT); 1164 | const char* headerStr = headerSb.GetString(); 1165 | _AtSerial.WriteBinary((const byte*)headerStr, strlen(headerStr)); 1166 | if (!_AtSerial.ReadResponse("^OK$", 1000, NULL)) return RET_ERR(false, E_TIMEOUT); 1167 | if (!_AtSerial.ReadResponse("^\\+QHTTPGET: (.*)$", (timeoutSec + 1) * 1000, &response)) return RET_ERR(-1, E_TIMEOUT); 1168 | 1169 | parser.Parse(response.c_str()); 1170 | if (parser.Size() < 1) return RET_ERR(-1, E_INVALID_RESPONSE); 1171 | if (strcmp(parser[0], "0") != 0) return RET_ERR(-1, E_INVALID_RESPONSE); 1172 | int contentLength = parser.Size() >= 3 ? atoi(parser[2]) : -1; 1173 | 1174 | _AtSerial.WriteCommand("AT+QHTTPREAD"); 1175 | if (!_AtSerial.ReadResponse("^CONNECT$", 1000, NULL)) return RET_ERR(-1, E_TIMEOUT); 1176 | if (contentLength >= 0) { 1177 | if (contentLength + 1 > dataSize) return RET_ERR(-1, E_NOT_ENOUGH_SIZE); 1178 | if (!_AtSerial.ReadBinary((byte*)data, contentLength, 60000)) return RET_ERR(-1, E_TIMEOUT); 1179 | data[contentLength] = '\0'; 1180 | 1181 | if (!_AtSerial.ReadResponse("^OK$", 1000, NULL)) return RET_ERR(-1, E_TIMEOUT); 1182 | } 1183 | else { 1184 | if (!_AtSerial.ReadResponseQHTTPREAD(data, dataSize, 60000)) return RET_ERR(-1, E_TIMEOUT); 1185 | contentLength = strlen(data); 1186 | } 1187 | if (!_AtSerial.ReadResponse("^\\+QHTTPREAD: 0$", 1000, NULL)) return RET_ERR(-1, E_TIMEOUT); 1188 | 1189 | return RET_OK(contentLength); 1190 | } 1191 | 1192 | bool WioLTE::HttpPost(const char* url, const char* data, int* responseCode, long timeout) 1193 | { 1194 | WioLTEHttpHeader header; 1195 | header["Accept"] = "*/*"; 1196 | header["User-Agent"] = HTTP_USER_AGENT; 1197 | header["Connection"] = "close"; 1198 | header["Content-Type"] = HTTP_CONTENT_TYPE; 1199 | 1200 | return HttpPost(url, data, responseCode, header, timeout); 1201 | } 1202 | 1203 | bool WioLTE::HttpPost(const char* url, const char* data, int* responseCode, const WioLTEHttpHeader& header, long timeout) 1204 | { 1205 | std::string response; 1206 | ArgumentParser parser; 1207 | 1208 | int timeoutSec = timeout / 1000; 1209 | if (timeout % 1000 > 0) timeoutSec++; 1210 | 1211 | if (strncmp(url, "https:", 6) == 0) { 1212 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QHTTPCFG=\"sslctxid\",1" , "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 1213 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QSSLCFG=\"sslversion\",1,4" , "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 1214 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QSSLCFG=\"ciphersuite\",1,0XFFFF", "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 1215 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QSSLCFG=\"seclevel\",1,0" , "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 1216 | } 1217 | 1218 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QHTTPCFG=\"requestheader\",1", "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 1219 | 1220 | if (!HttpSetUrl(url)) return RET_ERR(false, E_UNKNOWN); 1221 | 1222 | const char* host; 1223 | int hostLength; 1224 | const char* uri; 1225 | int uriLength; 1226 | if (!SplitUrl(url, &host, &hostLength, &uri, &uriLength)) return RET_ERR(false, E_INVALID_ARGUMENT); 1227 | 1228 | StringBuilder headerSb; 1229 | headerSb.Write("POST "); 1230 | if (uriLength <= 0) { 1231 | headerSb.Write("/"); 1232 | } 1233 | else { 1234 | headerSb.Write(uri, uriLength); 1235 | } 1236 | headerSb.Write(" HTTP/1.1\r\n"); 1237 | headerSb.Write("Host: "); 1238 | headerSb.Write(host, hostLength); 1239 | headerSb.Write("\r\n"); 1240 | if (!headerSb.WriteFormat("Content-Length: %d\r\n", strlen(data))) return RET_ERR(false, E_UNKNOWN); 1241 | for (auto it = header.begin(); it != header.end(); it++) { 1242 | headerSb.Write(it->first.c_str()); 1243 | headerSb.Write(": "); 1244 | headerSb.Write(it->second.c_str()); 1245 | headerSb.Write("\r\n"); 1246 | } 1247 | headerSb.Write("\r\n"); 1248 | DEBUG_PRINTLN("=== header"); 1249 | DEBUG_PRINTLN(headerSb.GetString()); 1250 | DEBUG_PRINTLN("==="); 1251 | 1252 | StringBuilder str; 1253 | if (!str.WriteFormat("AT+QHTTPPOST=%d,%d,%d", headerSb.Length() + strlen(data), timeoutSec, timeoutSec)) return RET_ERR(false, E_UNKNOWN); 1254 | _AtSerial.WriteCommand(str.GetString()); 1255 | if (!_AtSerial.ReadResponse("^CONNECT$", 60000, NULL)) return RET_ERR(false, E_TIMEOUT); 1256 | const char* headerStr = headerSb.GetString(); 1257 | _AtSerial.WriteBinary((const byte*)headerStr, strlen(headerStr)); 1258 | _AtSerial.WriteBinary((const byte*)data, strlen(data)); 1259 | if (!_AtSerial.ReadResponse("^OK$", 1000, NULL)) return RET_ERR(false, E_TIMEOUT); 1260 | if (!_AtSerial.ReadResponse("^\\+QHTTPPOST: (.*)$", (timeoutSec + 1) * 1000, &response)) return RET_ERR(false, E_TIMEOUT); 1261 | parser.Parse(response.c_str()); 1262 | if (parser.Size() < 1) return RET_ERR(false, E_INVALID_RESPONSE); 1263 | if (strcmp(parser[0], "0") != 0) return RET_ERR(false, E_INVALID_RESPONSE); 1264 | if (parser.Size() < 2) { 1265 | *responseCode = -1; 1266 | } 1267 | else { 1268 | *responseCode = atoi(parser[1]); 1269 | } 1270 | 1271 | return RET_OK(true); 1272 | } 1273 | 1274 | bool WioLTE::EnableGNSS(long timeout) 1275 | { 1276 | std::string response; 1277 | 1278 | Stopwatch sw; 1279 | sw.Restart(); 1280 | while (true) { 1281 | _AtSerial.WriteCommand("AT+QGPS=1"); 1282 | if (!_AtSerial.ReadResponse("^(OK|ERROR)$", 500, &response)) return RET_ERR(false, E_TIMEOUT); 1283 | if (response == "OK") break; 1284 | if (sw.ElapsedMilliseconds() >= (unsigned long)timeout) return RET_ERR(false, E_TIMEOUT); 1285 | _Delay(POLLING_INTERVAL); 1286 | } 1287 | 1288 | return RET_OK(true); 1289 | } 1290 | 1291 | bool WioLTE::DisableGNSS() 1292 | { 1293 | if (!_AtSerial.WriteCommandAndReadResponse("AT+QGPSEND", "^OK$", 500, NULL)) return RET_ERR(false, E_TIMEOUT); 1294 | 1295 | return RET_OK(true); 1296 | } 1297 | 1298 | bool WioLTE::GetGNSSLocation(double* longitude, double* latitude, double* altitude, struct tm* tim) 1299 | { 1300 | std::string response; 1301 | std::string locStr; 1302 | 1303 | _AtSerial.WriteCommand("AT+QGPSLOC?"); 1304 | while (true) { 1305 | if (!_AtSerial.ReadResponse("^(OK|\\+QGPSLOC: .*|\\+CME ERROR: .*)$", 500, &response)) return RET_ERR(false, E_TIMEOUT); 1306 | if (response == "OK") break; 1307 | if (strncmp(response.c_str(), "+CME ERROR: ", 12) == 0) { 1308 | if (strcmp(&response.c_str()[12], "516") == 0) { // Not fixed now 1309 | return RET_ERR(false, E_GNSS_NOT_FIXED); 1310 | } 1311 | else { 1312 | return RET_ERR(false, E_INVALID_RESPONSE); 1313 | } 1314 | } 1315 | locStr = response; 1316 | } 1317 | 1318 | // parse the response: utc time, latitude, longitude, horizontal precision, altitude 1319 | if (strlen(locStr.c_str()) < 10) return RET_ERR(false, E_INVALID_RESPONSE); 1320 | ArgumentParser parser; 1321 | parser.Parse(&locStr.c_str()[10]); 1322 | if (parser.Size() < 5) return RET_ERR(false, E_INVALID_RESPONSE); 1323 | 1324 | // latitude 1325 | if (latitude != NULL) { 1326 | *latitude = GnssCoordinateToDecimal(atof(parser[1])); 1327 | 1328 | if (parser[1][strlen(parser[1]) - 1] != 'N') { 1329 | *latitude = - *latitude; 1330 | } 1331 | } 1332 | 1333 | // longitude 1334 | if (longitude != NULL) { 1335 | *longitude = GnssCoordinateToDecimal(atof(parser[2])); 1336 | 1337 | if (parser[2][strlen(parser[2]) - 1] != 'E') { 1338 | *longitude = - *longitude; 1339 | } 1340 | } 1341 | 1342 | // altitude 1343 | if (altitude != NULL) { 1344 | *altitude = atof(parser[4]); 1345 | } 1346 | 1347 | // utc time 1348 | if (tim != NULL) { 1349 | if (parser.Size() < 10) return RET_ERR(false, E_INVALID_RESPONSE); 1350 | 1351 | const char* ymd = parser[9]; // date. ddmmyy 1352 | const char* hms = parser[0]; // time. hhmmss.s 1353 | 1354 | if (strlen(ymd) != 6) return RET_ERR(false, E_INVALID_RESPONSE); 1355 | if (strlen(hms) < 6) return RET_ERR(false, E_INVALID_RESPONSE); 1356 | 1357 | int yearOffset = Convert2DigitsToInt(&ymd[4]); 1358 | tim->tm_year = (yearOffset >= 80 ? 1900 : 2000) + yearOffset - 1900; 1359 | tim->tm_mon = Convert2DigitsToInt(&ymd[2]) - 1; 1360 | tim->tm_mday = Convert2DigitsToInt(&ymd[0]); 1361 | tim->tm_hour = Convert2DigitsToInt(&hms[0]); 1362 | tim->tm_min = Convert2DigitsToInt(&hms[2]); 1363 | tim->tm_sec = Convert2DigitsToInt(&hms[4]); 1364 | tim->tm_wday = 0; 1365 | tim->tm_yday = 0; 1366 | tim->tm_isdst = 0; 1367 | 1368 | // Update tm_wday and tm_yday 1369 | mktime(tim); 1370 | } 1371 | 1372 | return RET_OK(true); 1373 | } 1374 | 1375 | void WioLTE::SystemReset() 1376 | { 1377 | NVIC_SystemReset(); 1378 | } 1379 | 1380 | //////////////////////////////////////////////////////////////////////////////////////// 1381 | -------------------------------------------------------------------------------- /src/WioLTE.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "WioLTEConfig.h" 4 | #include "Internal/AtSerial.h" 5 | #if defined ARDUINO_ARCH_STM32F4 6 | #include 7 | #elif defined ARDUINO_ARCH_STM32 8 | #include "Internal/WioSK6812.h" 9 | #endif 10 | #include 11 | #include 12 | #include "WioLTEHttpHeader.h" 13 | 14 | #define WIOLTE_TCP (WioLTE::SOCKET_TCP) 15 | #define WIOLTE_UDP (WioLTE::SOCKET_UDP) 16 | 17 | #define WIOLTE_D38 (WioLTE::D38) 18 | #define WIOLTE_D39 (WioLTE::D39) 19 | #define WIOLTE_D20 (WioLTE::D20) 20 | #define WIOLTE_D19 (WioLTE::D19) 21 | #define WIOLTE_A6 (WioLTE::A6) 22 | #define WIOLTE_A7 (WioLTE::A7) 23 | #define WIOLTE_A4 (WioLTE::A4) 24 | #define WIOLTE_A5 (WioLTE::A5) 25 | 26 | #define WIO_TCP (WioLTE::SOCKET_TCP) 27 | #define WIO_UDP (WioLTE::SOCKET_UDP) 28 | 29 | #define WIO_D38 (WioLTE::D38) 30 | #define WIO_D39 (WioLTE::D39) 31 | #define WIO_D20 (WioLTE::D20) 32 | #define WIO_D19 (WioLTE::D19) 33 | #define WIO_A6 (WioLTE::A6) 34 | #define WIO_A7 (WioLTE::A7) 35 | #define WIO_A4 (WioLTE::A4) 36 | #define WIO_A5 (WioLTE::A5) 37 | 38 | class WioLTE 39 | { 40 | public: 41 | enum ErrorCodeType { 42 | E_OK = 0, 43 | E_UNKNOWN, 44 | E_TIMEOUT, 45 | E_GNSS_NOT_FIXED, 46 | E_UNABLE_TO_RECEIVE_RDY, 47 | E_NO_AT_RESPONSE, 48 | E_PIN, 49 | E_UNABLE_TO_RECEIVE_POWERED_DOWN, 50 | E_RESPONSE_TOO_LONG, 51 | E_NOT_ENOUGH_SIZE, 52 | E_INVALID_RESPONSE, 53 | E_INVALID_ARGUMENT, 54 | E_NOT_ENOUGH_RESOURCE, 55 | }; 56 | 57 | enum SocketType { 58 | SOCKET_TCP, 59 | SOCKET_UDP, 60 | }; 61 | 62 | public: 63 | // D38 connector 64 | static const int D38 = 38; 65 | static const int D39 = 39; 66 | 67 | // D20 connector 68 | static const int D20 = 20; 69 | static const int D19 = 19; 70 | 71 | // A6 connector 72 | static const int A6 = 6; 73 | static const int A7 = 7; 74 | 75 | // A4 connector 76 | static const int A4 = 4; 77 | static const int A5 = 5; 78 | 79 | private: 80 | SerialAPI _SerialAPI; 81 | AtSerial _AtSerial; 82 | #if defined ARDUINO_ARCH_STM32F4 83 | WS2812 _Led; 84 | #elif defined ARDUINO_ARCH_STM32 85 | WioSK6812 _Led; 86 | #endif 87 | ErrorCodeType _LastErrorCode; 88 | std::function_Delay; 89 | 90 | bool _PacketGprsNetworkRegistration; 91 | bool _PacketEpsNetworkRegistration; 92 | 93 | private: 94 | bool ReturnOk(bool value) 95 | { 96 | _LastErrorCode = E_OK; 97 | return value; 98 | } 99 | int ReturnOk(int value) 100 | { 101 | _LastErrorCode = E_OK; 102 | return value; 103 | } 104 | bool ReturnError(int lineNumber, bool value, ErrorCodeType errorCode); 105 | int ReturnError(int lineNumber, int value, ErrorCodeType errorCode); 106 | 107 | bool IsRespond(); 108 | bool Reset(long timeout); 109 | bool TurnOn(long timeout); 110 | 111 | int GetFirstIndexOfReceivedSMS(); 112 | 113 | bool HttpSetUrl(const char* url); 114 | 115 | public: 116 | bool ReadResponseCallback(const char* response); // Internal use only. 117 | 118 | public: 119 | WioLTE(); 120 | ErrorCodeType GetLastError() const; 121 | void SetDelayFunction(std::function func); 122 | void SetDoWorkInWaitForAvailableFunction(std::function func); 123 | void Init(); 124 | void PowerSupplyLTE(bool on); // Keep compatibility 125 | void PowerSupplyCellular(bool on); 126 | void PowerSupplyGNSS(bool on); 127 | void PowerSupplyLed(bool on); 128 | void PowerSupplyGrove(bool on); 129 | void PowerSupplySD(bool on); 130 | void LedSetRGB(byte red, byte green, byte blue); 131 | bool TurnOnOrReset(long timeout = 12000); 132 | bool TurnOff(long timeout = 60000); 133 | bool Sleep(); 134 | bool Wakeup(); 135 | 136 | int GetRevision(char* revision, int revisionSize); 137 | int GetIMEI(char* imei, int imeiSize); 138 | int GetIMSI(char* imsi, int imsiSize); 139 | int GetICCID(char* iccid, int iccidSize); 140 | int GetPhoneNumber(char* number, int numberSize); 141 | int GetReceivedSignalStrength(); 142 | bool GetTime(struct tm* tim); 143 | 144 | //bool Call(const char* dialNumber); 145 | //void IsRinging(); 146 | //void Answer(); 147 | //bool HangUp(); 148 | 149 | bool SendSMS(const char* dialNumber, const char* message); 150 | int ReceiveSMS(char* message, int messageSize, char* dialNumber = NULL, int dialNumberSize = 0); 151 | bool DeleteReceivedSMS(); 152 | 153 | bool WaitForCSRegistration(long timeout = 120000); 154 | bool WaitForPSRegistration(long timeout = 120000); 155 | bool Activate(const char* accessPointName, const char* userName, const char* password, long waitForRegistTimeout = 120000); 156 | bool Deactivate(); 157 | 158 | bool SyncTime(const char* host); 159 | bool GetLocation(double* longitude, double* latitude); 160 | 161 | int SocketOpen(const char* host, int port, SocketType type); 162 | bool SocketSend(int connectId, const byte* data, int dataSize); 163 | bool SocketSend(int connectId, const char* data); 164 | int SocketReceive(int connectId, byte* data, int dataSize); 165 | int SocketReceive(int connectId, char* data, int dataSize); 166 | int SocketReceive(int connectId, byte* data, int dataSize, long timeout); 167 | int SocketReceive(int connectId, char* data, int dataSize, long timeout); 168 | bool SocketClose(int connectId); 169 | 170 | int HttpGet(const char* url, char* data, int dataSize, long timeout = 60000); 171 | int HttpGet(const char* url, char* data, int dataSize, const WioLTEHttpHeader& header, long timeout = 60000); 172 | bool HttpPost(const char* url, const char* data, int* responseCode, long timeout = 60000); 173 | bool HttpPost(const char* url, const char* data, int* responseCode, const WioLTEHttpHeader& header, long timeout = 60000); 174 | 175 | // GNSS functionality (may not work on JP boards) 176 | bool EnableGNSS(long timeout = 60000); 177 | bool DisableGNSS(); 178 | bool GetGNSSLocation(double* longitude, double* latitude, double* altitude = NULL, struct tm* tim = NULL); 179 | 180 | public: 181 | static void SystemReset(); 182 | 183 | }; 184 | 185 | typedef WioLTE WioCellular; 186 | -------------------------------------------------------------------------------- /src/WioLTEClient.cpp: -------------------------------------------------------------------------------- 1 | #include "WioLTEConfig.h" 2 | #include "WioLTEClient.h" 3 | 4 | #define RECEIVE_MAX_LENGTH (1500) 5 | 6 | #define CONNECT_SUCCESS (1) 7 | #define CONNECT_TIMED_OUT (-1) 8 | #define CONNECT_INVALID_SERVER (-2) 9 | #define CONNECT_TRUNCATED (-3) 10 | #define CONNECT_INVALID_RESPONSE (-4) 11 | 12 | WioLTEClient::WioLTEClient(WioLTE* wio) 13 | { 14 | _Wio = wio; 15 | _ConnectId = -1; 16 | _ReceiveBuffer = new byte[RECEIVE_MAX_LENGTH]; 17 | } 18 | 19 | WioLTEClient::~WioLTEClient() 20 | { 21 | delete [] _ReceiveBuffer; 22 | } 23 | 24 | int WioLTEClient::connect(IPAddress ip, uint16_t port) 25 | { 26 | if (connected()) return CONNECT_INVALID_RESPONSE; // Already connected. 27 | 28 | String ipStr = String(ip[0]); 29 | ipStr += "."; 30 | ipStr += String(ip[1]); 31 | ipStr += "."; 32 | ipStr += String(ip[2]); 33 | ipStr += "."; 34 | ipStr += String(ip[3]); 35 | int connectId = _Wio->SocketOpen(ipStr.c_str(), port, WioLTE::SOCKET_TCP); 36 | if (connectId < 0) return CONNECT_INVALID_SERVER; 37 | _ConnectId = connectId; 38 | 39 | return CONNECT_SUCCESS; 40 | } 41 | 42 | int WioLTEClient::connect(const char* host, uint16_t port) 43 | { 44 | if (connected()) return CONNECT_INVALID_RESPONSE; // Already connected. 45 | 46 | int connectId = _Wio->SocketOpen(host, port, WioLTE::SOCKET_TCP); 47 | if (connectId < 0) return CONNECT_INVALID_SERVER; 48 | _ConnectId = connectId; 49 | 50 | return CONNECT_SUCCESS; 51 | } 52 | 53 | size_t WioLTEClient::write(uint8_t data) 54 | { 55 | if (!connected()) return 0; 56 | 57 | if (!_Wio->SocketSend(_ConnectId, &data, 1)) return 0; 58 | 59 | return 1; 60 | } 61 | 62 | size_t WioLTEClient::write(const uint8_t* buf, size_t size) 63 | { 64 | if (!connected()) return 0; 65 | 66 | if (!_Wio->SocketSend(_ConnectId, buf, size)) return 0; 67 | 68 | return size; 69 | } 70 | 71 | int WioLTEClient::available() 72 | { 73 | if (!connected()) return 0; 74 | 75 | int receiveSize = _Wio->SocketReceive(_ConnectId, _ReceiveBuffer, RECEIVE_MAX_LENGTH); 76 | for (int i = 0; i < receiveSize; i++) _ReceiveQueue.push(_ReceiveBuffer[i]); 77 | 78 | return _ReceiveQueue.size(); 79 | } 80 | 81 | int WioLTEClient::read() 82 | { 83 | if (!connected()) return -1; 84 | 85 | int actualSize = available(); 86 | if (actualSize <= 0) return -1; // None is available. 87 | 88 | byte data = _ReceiveQueue.front(); 89 | _ReceiveQueue.pop(); 90 | 91 | return data; 92 | } 93 | 94 | int WioLTEClient::read(uint8_t* buf, size_t size) 95 | { 96 | if (!connected()) return 0; 97 | 98 | int actualSize = available(); 99 | if (actualSize <= 0) return 0; // None is available. 100 | 101 | int popSize = (unsigned)actualSize <= size ? actualSize : size; 102 | for (int i = 0; i < popSize; i++) { 103 | buf[i] = _ReceiveQueue.front(); 104 | _ReceiveQueue.pop(); 105 | } 106 | 107 | return popSize; 108 | } 109 | 110 | int WioLTEClient::peek() 111 | { 112 | if (!connected()) return 0; 113 | 114 | int actualSize = available(); 115 | if (actualSize <= 0) return -1; // None is available. 116 | 117 | return _ReceiveQueue.front(); 118 | } 119 | 120 | void WioLTEClient::flush() 121 | { 122 | // Nothing to do. 123 | } 124 | 125 | void WioLTEClient::stop() 126 | { 127 | if (!connected()) return; 128 | 129 | _Wio->SocketClose(_ConnectId); 130 | _ConnectId = -1; 131 | while (!_ReceiveQueue.empty()) _ReceiveQueue.pop(); 132 | } 133 | 134 | uint8_t WioLTEClient::connected() 135 | { 136 | return _ConnectId >= 0 ? true : false; 137 | } 138 | 139 | WioLTEClient::operator bool() 140 | { 141 | return _ConnectId >= 0 ? true : false; 142 | } 143 | -------------------------------------------------------------------------------- /src/WioLTEClient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "WioLTE.h" 4 | #include 5 | #include 6 | 7 | class WioLTEClient : public Client { 8 | 9 | protected: 10 | WioLTE* _Wio; 11 | int _ConnectId; 12 | std::queue _ReceiveQueue; 13 | byte* _ReceiveBuffer; 14 | 15 | public: 16 | WioLTEClient(WioLTE* wio); 17 | virtual ~WioLTEClient(); 18 | 19 | virtual int connect(IPAddress ip, uint16_t port); 20 | virtual int connect(const char* host, uint16_t port); 21 | virtual size_t write(uint8_t data); 22 | virtual size_t write(const uint8_t* buf, size_t size); 23 | virtual int available(); 24 | virtual int read(); 25 | virtual int read(uint8_t* buf, size_t size); 26 | virtual int peek(); 27 | virtual void flush(); 28 | virtual void stop(); 29 | virtual uint8_t connected(); 30 | virtual operator bool(); 31 | 32 | }; 33 | 34 | typedef WioLTEClient WioCellularClient; 35 | -------------------------------------------------------------------------------- /src/WioLTEConfig.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | -------------------------------------------------------------------------------- /src/WioLTEHardware.cpp: -------------------------------------------------------------------------------- 1 | #include "WioLTEConfig.h" 2 | #include "WioLTEHardware.h" 3 | 4 | #if defined ARDUINO_ARCH_STM32F4 5 | 6 | HardwareSerial& SerialModule = Serial1; 7 | 8 | HardwareSerial& SerialUART = Serial; 9 | TwoWire& WireI2C = Wire; 10 | 11 | #elif defined ARDUINO_ARCH_STM32 12 | 13 | HardwareSerial SerialModule(WioLTEHardwarePin::MODULE_UART_RX_PIN, WioLTEHardwarePin::MODULE_UART_TX_PIN); 14 | 15 | #if defined Serial 16 | HardwareSerial& SerialUART = Serial; 17 | #endif // Serial 18 | TwoWire& WireI2C = Wire; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/WioLTEHardware.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "WioLTEConfig.h" 4 | 5 | #if __has_include("WioLTEHardwarePinCustom.h") 6 | #include "WioLTEHardwarePinCustom.h" 7 | #else 8 | #include "WioLTEHardwarePin.h" 9 | #endif 10 | 11 | #include 12 | 13 | #if defined ARDUINO_ARCH_STM32F4 14 | 15 | extern HardwareSerial& SerialModule; 16 | 17 | extern HardwareSerial& SerialUART; 18 | extern TwoWire& WireI2C; 19 | 20 | #elif defined ARDUINO_ARCH_STM32 21 | 22 | extern HardwareSerial SerialModule; 23 | 24 | #if defined Serial 25 | extern HardwareSerial& SerialUART; 26 | #endif // Serial 27 | extern TwoWire& WireI2C; 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/WioLTEHardwarePin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class WioLTEHardwarePin 4 | { 5 | public: 6 | WioLTEHardwarePin() = delete; 7 | 8 | public: 9 | static constexpr int MODULE_UART_TX_PIN = 2; // Required - PA2 Note: Fixed to PA2 by ARDUINO_ARCH_STM32F4 10 | static constexpr int MODULE_UART_RX_PIN = 3; // Required - PA3 Note: Fixed to PA3 by ARDUINO_ARCH_STM32F4 11 | static constexpr int PWR_KEY_PIN = 36; // Required - PC4 12 | static constexpr int RESET_MODULE_PIN = 35; // Required - PC3 13 | static constexpr int STATUS_PIN = 31; // Optional - PB15 14 | static constexpr int DTR_PIN = 1; // Optional - PA1 15 | static constexpr int WAKEUP_IN_PIN = 32; // Optional - PC0 16 | static constexpr int W_DISABLE_PIN = 34; // Optional - PC2 17 | static constexpr int AP_READY_PIN = 33; // Optional - PC1 18 | 19 | static constexpr int RGB_LED_PIN = 17; // Optional - PB1 Note: Fixed to PB1 by ARDUINO_ARCH_STM32 20 | 21 | static constexpr int MODULE_PWR_PIN = 21; // Optional - PB5 22 | static constexpr int ANT_PWR_PIN = 28; // Optional - PB12 23 | static constexpr int ENABLE_VCCB_PIN = 26; // Optional - PB10 24 | static constexpr int SD_POWR_PIN = 15; // Optional - PA15 25 | static constexpr int RGB_LED_PWR_PIN = 8; // Optional - PA8 26 | }; 27 | -------------------------------------------------------------------------------- /src/WioLTEHttpHeader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "WioLTEConfig.h" 4 | 5 | #include 6 | 7 | class WioLTEHttpHeader : public std::map 8 | { 9 | }; 10 | -------------------------------------------------------------------------------- /src/WioLTEforArduino.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "WioLTEHardware.h" 4 | #include "WioLTE.h" 5 | --------------------------------------------------------------------------------