├── README.md ├── examples ├── BridgeSerial │ └── BridgeSerial.ino ├── LoRaPingPong │ └── LoRaPingPong.ino ├── LoRaWANABP │ └── LoRaWANABP.ino ├── LoRaWANOTAA │ └── LoRaWANOTAA.ino └── getInfo │ └── getInfo.ino ├── keywords.txt ├── library.properties └── src ├── LoRaRadio.cpp ├── LoRaRadio.h ├── LoRaWANNode.cpp ├── LoRaWANNode.h ├── atcmd_modem.h ├── debug.h ├── hw.h ├── hw_usart.cpp ├── hw_usart.h ├── i_nucleo_lrwan1_wm_sg_sm_xx.c ├── i_nucleo_lrwan1_wm_sg_sm_xx.h ├── lora_driver.c ├── lora_driver.h ├── tiny_sscanf.c ├── tiny_sscanf.h ├── tiny_vsnprintf.c └── tiny_vsnprintf.h /README.md: -------------------------------------------------------------------------------- 1 | # I-NUCLEO-LRWAN1 2 | 3 | Arduino library to support I-NUCLEO-LRWAN1 LoRa® expansion board based on USI® 4 | LoRaWAN™ technology module. 5 | 6 | ## API 7 | 8 | This library provides an Arduino API to manage the I-NUCLEO-LRWAN1 expansion 9 | board as a LoRaWAN™ node. 10 | 11 | * You will be able to choose the ABP or OTAA mode and set the corresponding keys. 12 | * Send and receive some data. 13 | * Select the EU or US band. 14 | * Enable or disable the duty cycle (must be enabled in EU band). 15 | * Enable the adaptative data rate and configure the data rate. 16 | * Put the device in sleep mode. 17 | 18 | This library provides also an API to manage the I-NUCLEO-LRWAN1 expansion board 19 | as a simple LoRa® radio module. 20 | 21 | * Configure the radio parameters (frequency, tx power, spreading factor, band width, ...) 22 | * Send/receive data 23 | * LoRaWAN stack disabled 24 | 25 | ## Known limitations 26 | 27 | * The module supports only class A. 28 | * Sleep mode is not supported in OTAA mode with the version 2.6 of the firmware. 29 | * Important note for Nucleo64: 30 | 31 | By default, D0/D1 of CN9 board connector are respectively not connected to 32 | PA3 and PA2 (SB62 and SB63 opened). 33 | Those pins are connected to STLink USART thanks to SB13, SB14. 34 | 35 | To use the shield: 36 | - Connect shield D0(Tx) to a free U(S)ARTn Rx pin 37 | - Connect shield D1(Rx) to a free U(S)ARTn Tx pin 38 | 39 | Where 'n' are the same U(S)ART number. 40 | 41 | - Update the Serial instance definition used for LoRa using the chosen Rx/Tx 42 | 43 | or 44 | 45 | - Close SB62 and SB63 to connect D0/D1 of CN9 connector to PA3 and PA2 46 | - Open SB13 and SB14 to disconnect PA3 and PA2 from STLink UART 47 | 48 | but in this case, you will have to wire STLink Rx/Tx of CN3 connector to 49 | another pins and update Serial instance before call `Serial.begin(115200);` 50 | using: 51 | ``` 52 | Serial.setRx(Rx pin); 53 | Serial.setTx(Tx pin); 54 | ``` 55 | 56 | See [UM1724](https://www.st.com/resource/en/user_manual/dm00105823.pdf), §6.8 section for more information. 57 | 58 | ## Examples 59 | 60 | * **getInfo**: display several info about LoRa shield (Firmware version, device EUI,...) 61 | * **LoRaWANABP**: send/receive data in ABP mode. 62 | * **LoRaWANOTAA**: send/receive data in OTAA mode. 63 | * **LoRaPingPong**: P2P exchange in LoRa®. 64 | * **BridgeSerial**: Send/Receive AT command from/to PC terminal to/from shield (console mode). 65 | 66 | ## Advice 67 | 68 | LoRaWAN default configuration: 69 | 70 | * Join accept delay is set to 5000 ms (LoRaWAN default value). 71 | * The network type is public by default. Use `setPublicNwkMode()` to set the network 72 | type in private. 73 | * RX1 window delay is 1000 ms by default. Use `setRx1Delay()` to set a new value. 74 | 75 | In case of high latency between the gateway and the network server, it is recommended 76 | to increase the delay time of the RX1 window. 77 | 78 | ## Version 79 | 80 | This library is based on the STM32CubeExpansion_LRWAN_V1.1.2 driver. 81 | This library has been validated with the version 2.6 and 3.6 of the firmware. 82 | 83 | ## Documentation 84 | 85 | You can find the source files at 86 | https://github.com/stm32duino/I-NUCLEO-LRWAN1 87 | 88 | The I-NUCLEO-LRWAN1 module datasheet is available at 89 | https://github.com/USILoRaModule/USI_I-NUCLEO-LRWAN1 90 | 91 | LoRaWAN standard 92 | https://www.lora-alliance.org 93 | -------------------------------------------------------------------------------- /examples/BridgeSerial/BridgeSerial.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Allows to relay UART data from/to a PC terminal to/from LORA shield. 3 | 4 | Shield uses a LPUART interface as the AT command console, the D0 and D1 pin 5 | is the LPUART TX and LPUART RX, and the default configuration is 115200,N,8,1 6 | 7 | Important note for Nucleo64: 8 | by default, D0/D1 of CN9 board connector are respectively not connected to 9 | PA3 and PA2 (SB62 and SB63 opened). 10 | Those pins are connected to STLink USART thanks to SB13, SB14. 11 | 12 | To use the shield: 13 | - Connect shield D0(Tx) to a free U(S)ARTn Rx pin 14 | - Connect shield D1(Rx) to a free U(S)ARTn Tx pin 15 | Where 'n' are the same U(S)ART number 16 | - Update the below 'SerialLora' instance definition using the chosen Rx/Tx 17 | 18 | or 19 | - Close SB62 and SB63 to connect D0/D1 of CN9 connector to PA3 and PA2 20 | - Open SB13 and SB14 to disconnect PA3 and PA2 from STLink UART 21 | but in this case, you will have to wire STLink Rx/Tx of CN3 connector to 22 | another pins and update Serial instance before call `Serial.begin(115200);` 23 | using: 24 | Serial.setRx(Rx pin); 25 | Serial.setTx(Tx pin); 26 | */ 27 | HardwareSerial SerialLora(D0, D1); 28 | 29 | void setup() 30 | { 31 | Serial.begin(115200); 32 | SerialLora.begin(115200); 33 | } 34 | 35 | // The loop function runs over and over again forever 36 | void loop() 37 | { 38 | char c; 39 | 40 | if (SerialLora.available() > 0) 41 | { 42 | c = SerialLora.read(); 43 | Serial.print(c); 44 | } 45 | if (Serial.available() > 0) 46 | { 47 | c = Serial.read(); 48 | SerialLora.print(c); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/LoRaPingPong/LoRaPingPong.ino: -------------------------------------------------------------------------------- 1 | /* 2 | LoRaPingPong.ino 3 | 4 | Provides an example to use the shield as a simple LoRa radio. 5 | Data are exchange between two boards. The first receiving the PING message 6 | becomes slave and will just send a PONG answer. 7 | 8 | */ 9 | 10 | #include "LoRaRadio.h" 11 | 12 | #define SEND_PERIOD_MS 1000 //send period every second. 13 | 14 | // Serial port use to communicate with the USI shield. 15 | // By default, use D0 (Rx) and D1(Tx). 16 | // For Nucleo64, see "Known limitations" chapter in the README.md 17 | HardwareSerial SerialLora(D0, D1); 18 | 19 | // Messages to exchange 20 | uint8_t PingMsg[] = "PING"; 21 | uint8_t PongMsg[] = "PONG"; 22 | 23 | bool isMaster = true; 24 | bool next = true; 25 | int timer = 0; 26 | 27 | void setup() 28 | { 29 | Serial.begin(9600); 30 | Serial.println("-- LoRa Ping Pong sketch --"); 31 | 32 | while(!loraRadio.begin(&SerialLora)) { 33 | Serial.println("LoRa module not ready"); 34 | delay(1000); 35 | } 36 | 37 | Serial.println("LoRa module ready\n"); 38 | } 39 | 40 | void loop() 41 | { 42 | uint8_t rcvData[64]; 43 | 44 | if((isMaster == true) && (next == true)) { 45 | next = false; 46 | loraRadio.write(PingMsg, 4); 47 | timer = millis(); 48 | } 49 | 50 | if(loraRadio.read(rcvData) > 0) { 51 | if(memcmp(rcvData, PongMsg, 4) == 0) { 52 | Serial.println((char *)PongMsg); 53 | } else if(memcmp(rcvData, PingMsg, 4) == 0) { 54 | isMaster = false; 55 | loraRadio.write(PongMsg, 4); 56 | Serial.println((char *)PingMsg); 57 | } 58 | memset(rcvData, 0, 5); 59 | } 60 | 61 | if(((millis() - timer) >= SEND_PERIOD_MS) && (isMaster == true)){ 62 | next = true; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /examples/LoRaWANABP/LoRaWANABP.ino: -------------------------------------------------------------------------------- 1 | /* 2 | LoRaABP.ino 3 | 4 | Establish a connection on a LoRaWAN network in ABP mode. 5 | Exchange data to/from the network. 6 | 7 | Extract of the LoRaWAN standard: 8 | 9 | Activation by personalization directly ties an end-device to a specific network by-passing the join request 10 | - join accept procedure. 11 | 12 | Activating an end-device by personalization means that the DevAddr and the two session 13 | keys NwkSKey and AppSKey are directly stored into the end-device instead of the DevEUI, 14 | AppEUI and the AppKey. The end-device is equipped with the required information for 15 | participating in a specific LoRa network when started. 16 | 17 | */ 18 | 19 | #include "LoRaWANNode.h" 20 | 21 | #define FRAME_DELAY 300000 // in ms. Every 5 minutes by default. 22 | 23 | // Serial port use to communicate with the USI shield. 24 | // By default, use D0 (Rx) and D1(Tx). 25 | // For Nucleo64, see "Known limitations" chapter in the README.md 26 | HardwareSerial SerialLora(D0, D1); 27 | 28 | // Device address, network & application keys 29 | const char devAddr[] = "ef00cb01"; 30 | const char nwkSKey[] = "abcdef0123456789abcdef0123456789"; 31 | const char appSKey[] = "0123456789abcdef0123456789abcdef"; 32 | 33 | // Data send 34 | char frameTx[] = "Hello world!"; 35 | 36 | void setup() 37 | { 38 | Serial.begin(9600); 39 | Serial.println("-- LoRaWAN ABP sketch --"); 40 | 41 | // Enable the USI module and set the radio band. 42 | while(!loraNode.begin(&SerialLora, LORA_BAND_EU_868)) { 43 | Serial.println("Lora module not ready"); 44 | delay(1000); 45 | } 46 | 47 | // Set the network keys of the module 48 | while(!loraNode.joinABP(devAddr, nwkSKey, appSKey)) { 49 | Serial.println("joinABP failed!!"); 50 | delay(1000); 51 | } 52 | 53 | Serial.println("Lora module ready\n"); 54 | 55 | String str = "Device address: "; 56 | loraNode.getDevAddr(&str); 57 | Serial.println(str); 58 | str = "NwkSKey: "; 59 | loraNode.getNwkSKey(&str); 60 | Serial.println(str); 61 | str = "AppSKey: "; 62 | loraNode.getAppSKey(&str); 63 | Serial.println(str); 64 | } 65 | 66 | void loop() 67 | { 68 | receive(); 69 | transmit(); 70 | delay(FRAME_DELAY); 71 | } 72 | 73 | void receive(void) { 74 | uint8_t frameRx[64]; 75 | uint8_t len; 76 | uint8_t port; 77 | 78 | // Check if data received from a gateway 79 | if(loraNode.receiveFrame(frameRx, &len, &port)) { 80 | uint8_t n = 0; 81 | Serial.print("frame received: 0x"); 82 | while(len > 0) { 83 | Serial.print(frameRx[n], HEX); 84 | Serial.print(','); 85 | len--; 86 | n++; 87 | } 88 | Serial.print(" on port "); Serial.println(port); 89 | } else { 90 | Serial.println("No data"); 91 | } 92 | } 93 | 94 | void transmit(void) { 95 | // Send unconfirmed data to a gateway (port 1 by default) 96 | int status = loraNode.sendFrame(frameTx, sizeof(frameTx), UNCONFIRMED); 97 | if(status == LORA_SEND_ERROR) { 98 | Serial.println("Send frame failed!!!"); 99 | } else if(status == LORA_SEND_DELAYED) { 100 | Serial.println("Module busy or duty cycle"); 101 | } else { 102 | Serial.println("Frame sent"); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /examples/LoRaWANOTAA/LoRaWANOTAA.ino: -------------------------------------------------------------------------------- 1 | /* 2 | LoRaOTAA.ino 3 | 4 | Establish a connection on a LoRaWAN network in OTAA mode. 5 | Send a join request and wait the join accept. 6 | Exchange data to/from the network. 7 | 8 | Extract of the LoRaWAN standard: 9 | 10 | For Over The Air Activation, end-devices must follow a join procedure prior to participating in 11 | data exchanges with the network server. An end-device has to go through a new join 12 | procedure every time it has lost the session context information. 13 | 14 | The join procedure requires the end-device to be personalized with the following information 15 | before its starts the join procedure: a globally unique end-device identifier (DevEUI), the 16 | application identifier (AppEUI), and an AES-128 key (AppKey). 17 | 18 | USI will burn the unique IEEE EUI64 at factory. 19 | 20 | */ 21 | 22 | #include "LoRaWANNode.h" 23 | 24 | #define FRAME_DELAY 300000 // in ms. Every 5 minutes by default. 25 | 26 | // Serial port use to communicate with the USI shield. 27 | // By default, use D0 (Rx) and D1(Tx). 28 | // For Nucleo64, see "Known limitations" chapter in the README.md 29 | HardwareSerial SerialLora(D0, D1); 30 | 31 | // AppKey and AppEUI. 32 | const char appKey[] = "0123456789abcdef0123456789abcdef"; 33 | const char appEUI[] = "0101010101010101"; 34 | 35 | // Data send 36 | char frameTx[] = "Hello world!"; 37 | 38 | void setup() 39 | { 40 | Serial.begin(9600); 41 | Serial.println("-- LoRaWAN OTAA sketch --"); 42 | 43 | // Enable the USI module and set the radio band. 44 | while(!loraNode.begin(&SerialLora, LORA_BAND_EU_868)) { 45 | Serial.println("Lora module not ready"); 46 | delay(1000); 47 | } 48 | 49 | // Send a join request and wait the join accept 50 | while(!loraNode.joinOTAA(appKey, appEUI)) { 51 | Serial.println("joinOTAA failed!!"); 52 | delay(1000); 53 | } 54 | 55 | Serial.println("Lora module ready, join accepted.\n"); 56 | 57 | String str = "Device EUI: "; 58 | loraNode.getDevEUI(&str); 59 | Serial.println(str); 60 | str = "Application key: "; 61 | loraNode.getAppKey(&str); 62 | Serial.println(str); 63 | str = "Application EUI: "; 64 | loraNode.getAppEUI(&str); 65 | Serial.println(str); 66 | } 67 | 68 | void loop() 69 | { 70 | receive(); 71 | transmit(); 72 | delay(FRAME_DELAY); 73 | } 74 | 75 | void receive(void) { 76 | uint8_t frameRx[64]; 77 | uint8_t len; 78 | uint8_t port; 79 | 80 | // Check if data received from a gateway 81 | if(loraNode.receiveFrame(frameRx, &len, &port)) { 82 | uint8_t n = 0; 83 | Serial.print("frame received: 0x"); 84 | while(len > 0) { 85 | Serial.print(frameRx[n], HEX); 86 | Serial.print(','); 87 | len--; 88 | n++; 89 | } 90 | Serial.print(" on port "); Serial.println(port); 91 | } else { 92 | Serial.println("No data"); 93 | } 94 | } 95 | 96 | void transmit(void) { 97 | // Send unconfirmed data to a gateway (port 1 by default) 98 | int status = loraNode.sendFrame(frameTx, sizeof(frameTx), UNCONFIRMED); 99 | if(status == LORA_SEND_ERROR) { 100 | Serial.println("Send frame failed!!!"); 101 | } else if(status == LORA_SEND_DELAYED) { 102 | Serial.println("Module busy or duty cycle"); 103 | } else { 104 | Serial.println("Frame sent"); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /examples/getInfo/getInfo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | getInfo.ino 3 | 4 | Display several information about the module. The devEUI of the USI module 5 | can't be modified. It is useful to read it to configure the module in a 6 | LoRaWAN network when asked by the network server. 7 | */ 8 | 9 | #include "LoRaWANNode.h" 10 | 11 | // Serial port use to communicate with the USI shield. 12 | // By default, use D0 (Rx) and D1(Tx). 13 | // For Nucleo64, see "Known limitations" chapter in the README.md 14 | HardwareSerial SerialLora(D0, D1); 15 | 16 | void setup() 17 | { 18 | Serial.begin(115200); 19 | Serial.println("-- Get Info sketch --"); 20 | 21 | // Enable the USI module and set the radio band. 22 | while (!loraNode.begin(&SerialLora, LORA_BAND_EU_868)) { 23 | Serial.println("Lora module not ready"); 24 | delay(1000); 25 | } 26 | 27 | // Get the DevEUI 28 | String str = "Firmware version: "; 29 | loraNode.getFWVersion(&str); 30 | Serial.println(str); 31 | 32 | str = "LoRa stack version: "; 33 | loraNode.getVersion(&str); 34 | Serial.println(str); 35 | 36 | str = "Unique DevEUI: 0x"; 37 | loraNode.getDevEUI(&str); 38 | Serial.println(str); 39 | 40 | str = "Application EUI: 0x"; 41 | loraNode.getAppEUI(&str); 42 | Serial.println(str); 43 | 44 | str = "Application key: 0x"; 45 | loraNode.getAppKey(&str); 46 | Serial.println(str); 47 | 48 | str = "Network session Key: 0x"; 49 | loraNode.getNwkSKey(&str); 50 | Serial.println(str); 51 | 52 | str = "Application session key: 0x"; 53 | loraNode.getAppSKey(&str); 54 | Serial.println(str); 55 | 56 | str = "Device address: 0x"; 57 | loraNode.getDevAddr(&str); 58 | Serial.println(str); 59 | } 60 | 61 | void loop() 62 | { 63 | //empty loop 64 | } 65 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For I-NUCLEO-LRWAN1 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | LoRaWANNodeClass KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | begin KEYWORD2 16 | reset KEYWORD2 17 | sleep KEYWORD2 18 | wakeup KEYWORD2 19 | 20 | joinABP KEYWORD2 21 | joinOTAA KEYWORD2 22 | 23 | receiveFrame KEYWORD2 24 | sendFrame KEYWORD2 25 | 26 | getFWVersion KEYWORD2 27 | getVersion KEYWORD2 28 | getDevAddr KEYWORD2 29 | getAppSKey KEYWORD2 30 | getNwkSKey KEYWORD2 31 | getAppEUI KEYWORD2 32 | getAppKey KEYWORD2 33 | getDevEUI KEYWORD2 34 | 35 | getBand KEYWORD2 36 | setBand KEYWORD2 37 | getDutyCycle KEYWORD2 38 | setDutyCycle KEYWORD2 39 | getAdaptativeDataRate KEYWORD2 40 | setAdaptativeDataRate KEYWORD2 41 | getDataRate KEYWORD2 42 | setDataRate KEYWORD2 43 | getPublicNwkMode KEYWORD2 44 | setPublicNwkMode KEYWORD2 45 | getRx1Delay KEYWORD2 46 | setRx1Delay KEYWORD2 47 | getJoinRx1Delay KEYWORD2 48 | setJoinRx1Delay KEYWORD2 49 | 50 | IS_BAND KEYWORD2 51 | IS_CLASS KEYWORD2 52 | 53 | ####################################### 54 | # Instances (KEYWORD1) 55 | ####################################### 56 | 57 | loraNode KEYWORD1 58 | 59 | ####################################### 60 | # Constants (LITERAL1) 61 | ####################################### 62 | 63 | LORA_BAND_EU_868 LITERAL1 64 | LORA_BAND_US_915 LITERAL1 65 | LORA_SEND_DELAYED LITERAL1 66 | LORA_SEND_ERROR LITERAL1 67 | UNCONFIRMED LITERAL1 68 | CONFIRMED LITERAL1 69 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=STM32duino I-NUCLEO-LRWAN1 2 | version=1.0.2 3 | author=STMicroelectronics, Wi6labs 4 | maintainer=stm32duino 5 | sentence=This library provides the LoRa® driver for the expansion board I-NUCLEO-LRWAN1. 6 | paragraph=The I-NUCLEO-LRWAN1 features the USI® LoRaWAN™ technology module, addressing low-cost and low-power wide area network (LPWAN) which comes with embedded AT-commands stack pre-loaded. The I-NUCLEO-LRWAN1 is LoRaWAN™ class A certified. 7 | category=Communication 8 | url=https://github.com/stm32duino/I-NUCLEO-LRWAN1 9 | architectures=stm32 10 | -------------------------------------------------------------------------------- /src/LoRaRadio.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file LoRaRadio.cpp 4 | * @author WI6LABS 5 | * @version V1.0.0 6 | * @date 14-December-2017 7 | * @brief LoRa radio API. This API allows to manage the I-NUCLEO-LRWAN1 module 8 | * at the radio level. You will be able to configure the radio 9 | * parameters and send/receive frame. In this case the LoRaWAN stack 10 | * is not available. 11 | ****************************************************************************** 12 | * @attention 13 | * 14 | *

© COPYRIGHT(c) 2017 STMicroelectronics

15 | * 16 | * Redistribution and use in source and binary forms, with or without modification, 17 | * are permitted provided that the following conditions are met: 18 | * 1. Redistributions of source code must retain the above copyright notice, 19 | * this list of conditions and the following disclaimer. 20 | * 2. Redistributions in binary form must reproduce the above copyright notice, 21 | * this list of conditions and the following disclaimer in the documentation 22 | * and/or other materials provided with the distribution. 23 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 24 | * may be used to endorse or promote products derived from this software 25 | * without specific prior written permission. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 31 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 35 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | * 38 | ****************************************************************************** 39 | */ 40 | 41 | /* 42 | NOTE: This mode doesn't provide any duty cycle management. If you use an EU 43 | band you must respect the LoRa duty cycle indication. 44 | */ 45 | 46 | #include "LoRaRadio.h" 47 | #include "lora_driver.h" 48 | 49 | // Module mode 50 | #define IDLE_MODE 0 51 | #define TX_MODE 4 52 | #define RX_MODE 5 53 | 54 | LoraRadio::LoraRadio() 55 | { 56 | _power = 20; 57 | _freq = 868000000; 58 | _sf = 7; 59 | _bw = 0; 60 | _cr = 1; 61 | _crc = true; 62 | _preamble = 8; 63 | _invIQ = false; 64 | } 65 | 66 | /* 67 | * @brief Initializes the LoRa module. 68 | * @param pointer to the serial instance uses to communicate with the module 69 | * @retval Error code: false if initialization failed else true 70 | */ 71 | bool LoraRadio::begin(HardwareSerial *serialx) 72 | { 73 | uint8_t nbTry = 0; 74 | uint8_t enable = 0; 75 | 76 | if(serialx == NULL) { 77 | return false; 78 | } 79 | 80 | // Enable UART 81 | if(Modem_IO_Init(serialx) != AT_OK) { 82 | return false; 83 | } 84 | 85 | LoRa_DumyRequest(); 86 | 87 | // Local echo mode must be disabled 88 | Modem_AT_Cmd(AT_EXCEPT, AT_ATE, &enable); 89 | 90 | // Verbose response must be enabled for the AT parser 91 | enable = 1; 92 | if (Modem_AT_Cmd(AT_EXCEPT, AT_VERB, &enable) != AT_OK) { 93 | AT_VERB_cmd = false; 94 | } 95 | 96 | // Enable Lora module 97 | /* 98 | NOTE: Sometimes if the module is not ready when we call the previous command 99 | the first answer received by LoraInit() is not "OK" but "AT OK" (echo of the 100 | command sent). The driver doesn't understand this answer. So we use a loop 101 | to avoid this issue. 102 | */ 103 | while(Lora_Init() != MODULE_READY) { 104 | if((nbTry++) > 3) { 105 | return false; 106 | } 107 | } 108 | 109 | // Set radio configuration 110 | if(!setRadio()) { 111 | return false; 112 | } 113 | 114 | return true; 115 | } 116 | 117 | /* 118 | * @brief Stop LoRa radio. 119 | * @param none 120 | * @retval none 121 | */ 122 | void LoraRadio::end(void) 123 | { 124 | enableIdle(); 125 | Modem_IO_DeInit(); 126 | } 127 | 128 | /* 129 | * @brief Set radio frequency. 130 | * @param frequency in Hz: 860000000 - 1020000000 Hz. Default is 868000000Hz 131 | * @retval Error code: false if failed else true 132 | */ 133 | bool LoraRadio::setFrequency(uint32_t frequency) 134 | { 135 | if(IS_RADIO_FREQ(frequency)) { 136 | _freq = frequency; 137 | return setRadio(); 138 | } 139 | return false; 140 | } 141 | 142 | /* 143 | * @brief Set radio output power. 144 | * @param power in dbm: 5 - 20 dbm. Default is 20dbm. 145 | * @retval Error code: false if failed else true 146 | */ 147 | bool LoraRadio::setTxPower(uint8_t power) 148 | { 149 | if(IS_RADIO_POWER(power)) { 150 | _power = power; 151 | return setRadio(); 152 | } 153 | return false; 154 | } 155 | 156 | /* 157 | * @brief Set radio spreading factor. 158 | * @param sf: 6 - 12. Default is 7. 159 | * RADIO_SF6 = SF6 (64 symbol/chip rate) 160 | * RADIO_SF7 = SF7 (128 symbol/chip rate) 161 | * RADIO_SF8 = SF8 (256 symbol/chip rate) 162 | * RADIO_SF9 = SF9 (512 symbol/chip rate) 163 | * RADIO_SF10 = SF10 (1024 symbol/chip rate) 164 | * RADIO_SF11 = SF11 (2048 symbol/chip rate) 165 | * RADIO_SF12 = SF12 (4096 symbol/chip rate) 166 | * @retval Error code: false if failed else true 167 | */ 168 | bool LoraRadio::setSpreadingFactor(uint8_t sf) 169 | { 170 | if(IS_RADIO_SF(sf)) { 171 | _sf = sf; 172 | return setRadio(); 173 | } 174 | return false; 175 | } 176 | 177 | /* 178 | * @brief Set radio band width. 179 | * @param bw: 0 - 2. Default is 0. 180 | * RADIO_BW125 = 125KHz 181 | * RADIO_BW250 = 250KHz 182 | * RADIO_BW500 = 500KHz 183 | * @retval Error code: false if failed else true 184 | */ 185 | bool LoraRadio::setBandWidth(uint8_t bw) 186 | { 187 | if(IS_RADIO_BW(bw)) { 188 | _bw = bw; 189 | return setRadio(); 190 | } 191 | return false; 192 | } 193 | 194 | /* 195 | * @brief Set radio coding rate. 196 | * @param bw: 1 - 4. Default is 1. 197 | * RADIO_CR4_5 = 4/5 198 | * RADIO_CR4_6 = 4/6 199 | * RADIO_CR4_7 = 4/7 200 | * RADIO_CR4_8 = 4/8 201 | * @retval Error code: false if failed else true 202 | */ 203 | bool LoraRadio::setCodingRate(uint8_t cr) 204 | { 205 | if(IS_RADIO_CR(cr)) { 206 | _cr = cr; 207 | return setRadio(); 208 | } 209 | return false; 210 | } 211 | 212 | /* 213 | * @brief Enable CRC. 214 | * @param none 215 | * @retval Error code: false if failed else true 216 | */ 217 | bool LoraRadio::enableCRC(void) 218 | { 219 | _crc = true; 220 | return setRadio(); 221 | } 222 | 223 | /* 224 | * @brief Disable CRC. 225 | * @param none 226 | * @retval Error code: false if failed else true 227 | */ 228 | bool LoraRadio::disableCRC(void) 229 | { 230 | _crc = false; 231 | return setRadio(); 232 | } 233 | 234 | /* 235 | * @brief Set preambule length. 236 | * @param length: 5 - 65535. Default is 8. 237 | * @retval Error code: false if failed else true 238 | */ 239 | bool LoraRadio::setPreambuleLength(uint32_t length) 240 | { 241 | if(IS_RADIO_PREAMBLE_LENGTH(length)) { 242 | _preamble = length; 243 | return setRadio(); 244 | } 245 | return false; 246 | } 247 | 248 | /* 249 | * @brief Enable inverted IQ signal. 250 | * @param none 251 | * @retval Error code: false if failed else true 252 | */ 253 | bool LoraRadio::enableInvIQ(void) 254 | { 255 | _invIQ = true; 256 | return setRadio(); 257 | } 258 | 259 | /* 260 | * @brief Disable inverted IQ signal. 261 | * @param none 262 | * @retval Error code: false if failed else true 263 | */ 264 | bool LoraRadio::disableInvIQ(void) 265 | { 266 | _invIQ = false; 267 | return setRadio(); 268 | } 269 | 270 | /* 271 | * @brief Send data.Data are send in polling mode. 272 | * @param buffer: pointer to the bytes to send. 273 | * @param len: number of bytes to send. Limited to 64 bytes. 274 | * @retval number of data sent. 0 if failed. 275 | */ 276 | uint8_t LoraRadio::write(uint8_t *buffer, uint8_t len) 277 | { 278 | if((buffer != NULL) && (len > 0)) { 279 | if(len > MAX_PAYLOAD_LENGTH) { 280 | return 0; 281 | } 282 | sSendData_t frame = {1, buffer, len}; 283 | if(enableTx() == AT_OK) { 284 | if(Modem_AT_Cmd(AT_SET, AT_TXT, &frame) == AT_OK) { 285 | while(Modem_AT_Cmd(AT_ASYNC_EVENT, AT_TXT, NULL) != AT_OK) {} 286 | if(enableRx() == AT_OK) { 287 | return len; 288 | } 289 | } 290 | } 291 | } 292 | 293 | return 0; 294 | } 295 | 296 | /* 297 | * @brief Read received data. Data are read in polling mode. 298 | * @param buffer: pointer to the bytes read. 299 | * @retval number of bytes read. 300 | */ 301 | uint8_t LoraRadio::read(uint8_t *buffer) 302 | { 303 | uint8_t len = 0; 304 | uint8_t frame[128] = {0}; 305 | 306 | if(buffer != NULL) { 307 | if(parseRcvData(frame) == AT_OK) { 308 | keyCharToInt((char *)frame, buffer, strlen((char*)frame)); 309 | len = sizeof((char *)buffer); 310 | } 311 | } 312 | 313 | return len; 314 | } 315 | 316 | /* 317 | * @brief Put the LoRa module in sleep mode. 318 | * @param none 319 | * @retval Error code: false if failed else true 320 | */ 321 | bool LoraRadio::sleep(void) 322 | { 323 | if(Lora_SleepMode() == AT_OK) { 324 | //delay(500); 325 | if(Modem_AT_Cmd(AT_ASYNC_EVENT, AT, NULL ) == AT_OK) { 326 | return true; 327 | } 328 | } 329 | return false; 330 | } 331 | 332 | /* 333 | * @brief Wake up the LoRa module. 334 | * @param none 335 | * @retval Error code: false if failed else true 336 | */ 337 | bool LoraRadio::wakeup(void) 338 | { 339 | LoRa_DumyRequest(); 340 | if(Modem_AT_Cmd(AT_ASYNC_EVENT, AT, NULL ) == AT_OK) { 341 | return true; 342 | } 343 | return false; 344 | } 345 | 346 | /********************** Private class functions *******************************/ 347 | 348 | /* 349 | * @brief Enable the radio in Rx mode. 350 | * @param none 351 | * @retval Error code 352 | */ 353 | uint8_t LoraRadio::enableRx(void) 354 | { 355 | uint8_t mode = RX_MODE; 356 | return Modem_AT_Cmd(AT_SET, AT_DEFMODE, &mode); 357 | } 358 | 359 | /* 360 | * @brief Enable the radio in Tx mode. 361 | * @param none 362 | * @retval Error code 363 | */ 364 | uint8_t LoraRadio::enableTx(void) 365 | { 366 | uint8_t mode = TX_MODE; 367 | return Modem_AT_Cmd(AT_SET, AT_DEFMODE, &mode); 368 | } 369 | 370 | /* 371 | * @brief Enable the radio in Idle mode. 372 | * @param none 373 | * @retval Error code 374 | */ 375 | uint8_t LoraRadio::enableIdle(void) 376 | { 377 | uint8_t mode = IDLE_MODE; 378 | return Modem_AT_Cmd(AT_SET, AT_DEFMODE, &mode); 379 | } 380 | 381 | /* 382 | * @brief Set the radio parameters. 383 | * @param none 384 | * @retval Error code 385 | */ 386 | bool LoraRadio::setRadio(void) 387 | { 388 | uint8_t status = false; 389 | sRadioCtrlSet_t config = {_power, _freq, _sf, _bw, _cr, _crc, _preamble, _invIQ}; 390 | 391 | if(enableIdle() == AT_OK) { 392 | if(Modem_AT_Cmd(AT_SET, AT_RF, &config) == AT_OK) { 393 | if(enableRx() == AT_OK) { 394 | status = true; 395 | } 396 | } 397 | } 398 | 399 | return status; 400 | } 401 | 402 | /* 403 | * @brief Parse the received data. 404 | * @param none 405 | * @retval Error code 406 | */ 407 | uint8_t LoraRadio::parseRcvData(void *pdata) 408 | { 409 | uint8_t ResponseComplete = 0; 410 | int8_t i = 0; 411 | char *ptrChr; 412 | ATEerror_t RetCode; 413 | uint32_t msStart; 414 | char response[DATA_RX_MAX_BUFF_SIZE]; 415 | 416 | if(pdata == NULL) { 417 | return AT_END_ERROR; 418 | } 419 | 420 | // Cleanup the response buffer 421 | memset(response, 0x00, DATA_RX_MAX_BUFF_SIZE); 422 | 423 | while (!ResponseComplete) { 424 | msStart = millis(); 425 | while (!HW_UART_Modem_IsNewCharReceived()) { 426 | if((millis() - msStart) > RESPONSE_TIMEOUT) { 427 | return AT_UART_LINK_ERROR; 428 | } 429 | } 430 | 431 | // Process the response 432 | response[i] = HW_UART_Modem_GetNewChar(); 433 | 434 | // Wait up to carriage return OR the line feed marker 435 | if (/*(response[i] =='\r') || */(response[i] == '\n')) { 436 | DBG_PRINTF("LoRa radio rcv: %s\r\n", response); 437 | 438 | if (i!= 0) { // Trap the asynchronous event 439 | // First statement to get back the return value 440 | response[i] = '\0'; 441 | ptrChr = strchr(&response[0],'+'); // Skip the '\0''\r' 442 | if (strncmp(ptrChr, "+RCV", sizeof("+RCV")-1) == 0) { 443 | RetCode = AT_OK; 444 | if(AT_VERB_cmd) { 445 | ptrChr = strrchr(&response[1], ','); 446 | strcpy((char *)pdata, ptrChr+1); 447 | } else { 448 | ptrChr = strchr(&response[1],':'); 449 | strcpy((char *)pdata, ptrChr+2); 450 | } 451 | ResponseComplete = 1; 452 | } else { 453 | RetCode = AT_END_ERROR; 454 | } 455 | memset(response, 0x00, 16); 456 | i= -1; // Compensate the next index iteration and restart in [0] 457 | } 458 | } else { 459 | if (i == (DATA_RX_MAX_BUFF_SIZE-1)) { 460 | // Frame overflow 461 | i = 0; 462 | return (AT_TEST_PARAM_OVERFLOW); 463 | } 464 | } 465 | i++; 466 | } 467 | 468 | return RetCode; 469 | } 470 | 471 | LoraRadio loraRadio; 472 | -------------------------------------------------------------------------------- /src/LoRaRadio.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file LoRaRadio.cpp 4 | * @author WI6LABS 5 | * @version V1.0.0 6 | * @date 14-December-2017 7 | * @brief LoRa radio API header 8 | ****************************************************************************** 9 | * @attention 10 | * 11 | *

© COPYRIGHT(c) 2017 STMicroelectronics

12 | * 13 | * Redistribution and use in source and binary forms, with or without modification, 14 | * are permitted provided that the following conditions are met: 15 | * 1. Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright notice, 18 | * this list of conditions and the following disclaimer in the documentation 19 | * and/or other materials provided with the distribution. 20 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 21 | * may be used to endorse or promote products derived from this software 22 | * without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | * 35 | ****************************************************************************** 36 | */ 37 | 38 | #ifndef __LORA_RADIO_H_ 39 | #define __LORA_RADIO_H_ 40 | 41 | #include "hw.h" 42 | 43 | #define RADIO_MIN_FREQ 860000000 44 | #define RADIO_MAX_FREQ 1020000000 45 | 46 | #define IS_RADIO_FREQ(x) (((x) >= RADIO_MIN_FREQ) && ((x) <= RADIO_MAX_FREQ)) 47 | 48 | #define RADIO_MIN_POWER 5 49 | #define RADIO_MAX_POWER 20 50 | 51 | #define IS_RADIO_POWER(x) (((x) >= RADIO_MIN_POWER) && ((x) <= RADIO_MAX_POWER)) 52 | 53 | #define RADIO_SF6 6 54 | #define RADIO_SF7 7 55 | #define RADIO_SF8 8 56 | #define RADIO_SF9 9 57 | #define RADIO_SF10 10 58 | #define RADIO_SF11 11 59 | #define RADIO_SF12 12 60 | 61 | #define IS_RADIO_SF(x) (((x) == RADIO_SF6) || ((x) == RADIO_SF7) ||\ 62 | ((x) == RADIO_SF8) || ((x) == RADIO_SF9) ||\ 63 | ((x) == RADIO_SF10) || ((x) == RADIO_SF11) ||\ 64 | ((x) == RADIO_SF12)) 65 | 66 | #define RADIO_BW125 0 67 | #define RADIO_BW250 1 68 | #define RADIO_BW500 2 69 | 70 | #define IS_RADIO_BW(x) (((x) == RADIO_BW125) || ((x) == RADIO_BW250) ||\ 71 | ((x) == RADIO_BW500)) 72 | 73 | #define RADIO_CR4_5 1 74 | #define RADIO_CR4_6 2 75 | #define RADIO_CR4_7 3 76 | #define RADIO_CR4_8 4 77 | 78 | #define IS_RADIO_CR(x) (((x) == RADIO_CR4_5) || ((x) == RADIO_CR4_6) ||\ 79 | ((x) == RADIO_CR4_7) || ((x) == RADIO_CR4_8)) 80 | 81 | #define RADIO_MIN_PREAMBLE_LENGTH 5 82 | #define RADIO_MAX_PREAMBLE_LENGTH 65535 83 | 84 | #define IS_RADIO_PREAMBLE_LENGTH(x) (((x) >= RADIO_MIN_PREAMBLE_LENGTH) &&\ 85 | ((x) <= RADIO_MAX_PREAMBLE_LENGTH)) 86 | 87 | 88 | class LoraRadio { 89 | public: 90 | 91 | LoraRadio(); 92 | 93 | // Begin initialization function 94 | bool begin(HardwareSerial *serialx); 95 | void end(void); 96 | 97 | bool setFrequency(uint32_t freq); 98 | bool setTxPower(uint8_t power); 99 | bool setSpreadingFactor(uint8_t sf); 100 | bool setBandWidth(uint8_t bw); 101 | bool setCodingRate(uint8_t cr); 102 | bool enableCRC(void); 103 | bool disableCRC(void); 104 | bool setPreambuleLength(uint32_t length); 105 | bool enableInvIQ(void); 106 | bool disableInvIQ(void); 107 | 108 | uint8_t write(uint8_t *buffer, uint8_t len); 109 | uint8_t read(uint8_t *buffer); 110 | 111 | bool sleep(void); 112 | bool wakeup(void); 113 | 114 | private: 115 | uint8_t _power; 116 | uint32_t _freq; 117 | uint8_t _sf; 118 | uint8_t _bw; 119 | uint8_t _cr; 120 | bool _crc; 121 | uint16_t _preamble; 122 | bool _invIQ; 123 | 124 | uint8_t enableRx(void); 125 | uint8_t enableTx(void); 126 | uint8_t enableIdle(void); 127 | 128 | bool setRadio(void); 129 | 130 | uint8_t parseRcvData(void *pdata); 131 | }; 132 | 133 | extern LoraRadio loraRadio; 134 | 135 | #endif //__LORA_RADIO_H_ 136 | -------------------------------------------------------------------------------- /src/LoRaWANNode.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file LoRaWANNode.cpp 4 | * @author WI6LABS 5 | * @version V1.0.0 6 | * @date 28-november-2017 7 | * @brief LoRaWAN Arduino API for I-NUCLEO-LRWAN1 shield 8 | ****************************************************************************** 9 | * @attention 10 | * 11 | *

© COPYRIGHT(c) 2017 STMicroelectronics

12 | * 13 | * Redistribution and use in source and binary forms, with or without modification, 14 | * are permitted provided that the following conditions are met: 15 | * 1. Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright notice, 18 | * this list of conditions and the following disclaimer in the documentation 19 | * and/or other materials provided with the distribution. 20 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 21 | * may be used to endorse or promote products derived from this software 22 | * without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | * 35 | ****************************************************************************** 36 | */ 37 | 38 | #include "LoRaWANNode.h" 39 | #include "lora_driver.h" 40 | 41 | 42 | LoRaWANNodeClass::LoRaWANNodeClass() 43 | { 44 | 45 | } 46 | 47 | /* 48 | * @brief Initializes the LoRa module 49 | * @param pointer to the serial instance uses to communicate with the module 50 | * @param LoRaWAN frequency band: 868MHz (EU) or 915MHz (US) 51 | * @param LoRaWAN node class: A, B or C. NOTE: Classes B and C are not available. 52 | * @retval Error code: false if initialization failed else true 53 | */ 54 | bool LoRaWANNodeClass::begin(HardwareSerial *serialx, uint8_t band, uint8_t loraClass) 55 | { 56 | uint8_t nbTry = 0; 57 | uint8_t enable = 0; 58 | 59 | if(!IS_BAND(band) || !IS_CLASS(loraClass) || (serialx == NULL)) { 60 | return 0; 61 | } 62 | 63 | if(loraClass != LORA_CLASS_A) { 64 | DBG_PRINTF_CRITICAL("The firmware only supports Class A so far.\r\n"); 65 | return 0; 66 | } 67 | 68 | // Enable UART 69 | if(Modem_IO_Init(serialx) != AT_OK) { 70 | return 0; 71 | } 72 | 73 | LoRa_DumyRequest(); 74 | 75 | // Local echo mode must be disabled 76 | Modem_AT_Cmd(AT_EXCEPT, AT_ATE, &enable); 77 | 78 | // Verbose response must be enabled for the AT parser 79 | enable = 1; 80 | if (Modem_AT_Cmd(AT_EXCEPT, AT_VERB, &enable) != AT_OK) { 81 | AT_VERB_cmd = false; 82 | } 83 | 84 | // Enable Lora module 85 | /* 86 | NOTE: Sometimes if the module is not ready when we call the previous command 87 | the first answer received by LoraInit() is not "OK" but "AT OK" (echo of the 88 | command sent). The driver doesn't understand this answer. So we use a loop 89 | to avoid this issue. 90 | */ 91 | while(Lora_Init() != MODULE_READY) { 92 | if((nbTry++) > 3) { 93 | return 0; 94 | } 95 | } 96 | 97 | // Set band: EU or US. 98 | if(getBand() != band) { 99 | if(!setBand(band)) { 100 | return 0; 101 | } 102 | } 103 | 104 | // Enable duty cycle just in case it was disabled previously. 105 | if(!setDutyCycle(true)) { 106 | return 0; 107 | } 108 | 109 | /* Set class (A, B or C). 110 | NOTE: Class B & C not supported! This code always returns an error. 111 | We only keep this code as example or when another class will be supported. 112 | */ 113 | #if 0 114 | if(Lora_SetClass(loraClass) != AT_OK) { 115 | printf("Class failed\r\n"); 116 | return 0; 117 | } 118 | #endif 119 | 120 | // Enable adaptative data rate by default 121 | if(!setAdaptativeDataRate(true)) { 122 | return 0; 123 | } 124 | 125 | return 1; 126 | } 127 | 128 | /* 129 | * @brief Configures the module in ABP mode. 130 | * @param Device address: 4 hexadecimal bytes 131 | * @param Network session key: 16 hexadecimal bytes 132 | * @param Application session key: 16 hexadecimal bytes 133 | * @retval Error code: false if failed else true 134 | */ 135 | bool LoRaWANNodeClass::joinABP(const char *devAddr, const char *nwkSKey, const char *appSKey) 136 | { 137 | uint8_t key[16]; 138 | 139 | if((devAddr != NULL) && (nwkSKey != NULL) && (appSKey != NULL)) { 140 | keyCharToInt(devAddr, key, 4); 141 | if(LoRa_SetDeviceAddress((key[0] << 24) | (key[1] << 16) | (key[2] << 8) | key[3]) == AT_OK) { 142 | keyCharToInt(nwkSKey, key, 16); 143 | if(LoRa_SetKey(AT_NWKSKEY, key) == AT_OK) { 144 | keyCharToInt(appSKey, key, 16); 145 | if(LoRa_SetKey(AT_APPSKEY, key) == AT_OK) { 146 | if(Lora_Join(ABP_JOIN_MODE) == AT_OK) { 147 | return 1; 148 | } 149 | } 150 | } 151 | } 152 | } 153 | return 0; 154 | } 155 | 156 | /* 157 | * @brief Configures the module in OTAA mode. 158 | * @param Application key: 16 hexadecimal bytes 159 | * @param Application EUI: 16 hexadecimal bytes (optional: can be a NULL pointer) 160 | * @retval Error code: false if failed else true 161 | */ 162 | bool LoRaWANNodeClass::joinOTAA(const char *appKey, const char *appEui) 163 | { 164 | uint8_t key[16]; 165 | ATEerror_t ret; 166 | 167 | // HACK: remove duty cycle to be able to send again a Join Request 168 | setDutyCycle(false); 169 | 170 | // Can be optional 171 | if(appEui != NULL) { 172 | keyCharToInt(appEui, key, 16); 173 | if(LoRa_SetAppID(key) != AT_OK) { 174 | return 0; 175 | } 176 | } 177 | 178 | if(appKey != NULL) { 179 | keyCharToInt(appKey, key, 16); 180 | if(LoRa_SetKey(AT_APPKEY, key) == AT_OK) { 181 | ret = Lora_Join(OTAA_JOIN_MODE); 182 | if(ret == AT_OK) { // Device joined 183 | return 1; 184 | } else if(ret == AT_JOIN_SLEEP_TRANSITION) { 185 | uint32_t timeout = millis(); 186 | do { 187 | if((millis() - timeout) > DELAY_FOR_JOIN_STATUS_REQ) { 188 | return 0; 189 | } 190 | ret = Lora_JoinAccept(); 191 | } while(ret != AT_OK); 192 | // HACK: enable again duty cycle 193 | setDutyCycle(true); 194 | return 1; 195 | } 196 | } 197 | } 198 | return 0; 199 | } 200 | 201 | /* 202 | * @brief Send a LoRaWAN frame to the network. 203 | * @param pointer to the frame to send. Size is limited to 64 bytes. 204 | * @param Number of data to send. 205 | * @param If true the module requires a acknowledgment from the network. 206 | * @param The application port number. 207 | * @retval LoRa error code. 208 | */ 209 | int8_t LoRaWANNodeClass::sendFrame(char frame[], uint8_t length, bool confirmed, uint8_t port) 210 | { 211 | if((frame == NULL) || (length == 0)) { 212 | return LORA_SEND_ERROR; 213 | } 214 | 215 | // Payload length is limited to 64 bytes. 216 | if(length > MAX_PAYLOAD_LENGTH) { 217 | return LORA_SEND_ERROR; 218 | } 219 | 220 | sSendDataBinary_t dataString = {frame, length, port, confirmed}; 221 | ATEerror_t errorCode = Lora_SendDataBin(&dataString); 222 | if(errorCode == AT_OK) { 223 | return length; 224 | } else if(errorCode == AT_ERROR_WAN_SEND) { 225 | // Previous frame not sent yet (busy or duty cycle). Wait before to try again. 226 | return LORA_SEND_DELAYED; 227 | } 228 | return LORA_SEND_ERROR; 229 | } 230 | 231 | /* 232 | * @brief Receives a LoRaWAN frame from the network. Must be called before the 233 | * next call of sendFrame(). The receive delay depends on the Rx1 and Rx2 234 | * windows. 235 | * @param pointer to the received frame. 236 | * @param Number of data received. 237 | * @param The application port number. 238 | * @retval Error code: false if failed else true. 239 | */ 240 | bool LoRaWANNodeClass::receiveFrame(uint8_t *frame, uint8_t *length, uint8_t *port) 241 | { 242 | uint8_t data[128]; 243 | 244 | if((frame == NULL) || (length == NULL) || (port == NULL)) { 245 | return 0; 246 | } 247 | 248 | sReceivedDataBinary_t structData = {data, 0, 0}; 249 | *length = 0; 250 | if(Lora_AsyncDownLinkData(&structData) == AT_OK) { 251 | if(structData.DataSize > 0) { 252 | *length = structData.DataSize; 253 | *port = structData.Port; 254 | keyCharToInt((char *)data, frame, *length); 255 | return 1; 256 | } 257 | } 258 | return 0; 259 | } 260 | 261 | /* 262 | * @brief Read the LoRaWAN stack version. 263 | * @param pointer to version number (an Arduino string allocated by caller). 264 | * @retval None. 265 | */ 266 | void LoRaWANNodeClass::getVersion(String *str) 267 | { 268 | if(str != NULL) { 269 | char tmp[10] = {'\0'}; 270 | Lora_GetVersion((uint8_t *)tmp); 271 | str->concat(tmp); 272 | } 273 | } 274 | 275 | /* 276 | * @brief Read the firmware version. 277 | * @param pointer to version number (an Arduino string allocated by caller). 278 | * @retval None. 279 | */ 280 | void LoRaWANNodeClass::getFWVersion(String *str) 281 | { 282 | if(str != NULL) { 283 | char tmp[10]; 284 | Lora_GetFWVersion((uint8_t *)tmp); 285 | tmp[9] = '\0'; 286 | str->concat(tmp); 287 | } 288 | } 289 | 290 | /* 291 | * @brief Read the device address. 292 | * @param pointer to the device address (an Arduino string allocated by caller). 293 | * @retval None. 294 | */ 295 | void LoRaWANNodeClass::getDevAddr(String *str) 296 | { 297 | if(str != NULL) { 298 | uint32_t addr; 299 | char cAddr[9] = {'\0'}; 300 | char tmp[3]; 301 | LoRa_GetDeviceAddress(&addr); 302 | keyIntToChar(cAddr, (uint8_t*)&addr, 4); 303 | // Swap characters 304 | for(uint8_t i = 0; i < 4; i+=2) { 305 | strncpy(tmp, &cAddr[i], 2); 306 | strncpy(&cAddr[i], &cAddr[6-i], 2); 307 | strncpy(&cAddr[6-i], tmp, 2); 308 | } 309 | str->concat(cAddr); 310 | } 311 | } 312 | 313 | /* 314 | * @brief Read the network session key. 315 | * @param pointer to the NwkSKey (an Arduino string allocated by caller). 316 | * @retval None. 317 | */ 318 | void LoRaWANNodeClass::getNwkSKey(String *str) 319 | { 320 | if(str != NULL) { 321 | uint8_t iKey[16]; 322 | char cKey[33] = {'\0'}; 323 | LoRa_GetKey(AT_NWKSKEY, iKey); 324 | keyIntToChar(cKey, iKey, 16); 325 | str->concat(cKey); 326 | } 327 | } 328 | 329 | /* 330 | * @brief Read the application session key. 331 | * @param pointer to the AppSKey (an Arduino string allocated by caller). 332 | * @retval None. 333 | */ 334 | void LoRaWANNodeClass::getAppSKey(String *str) 335 | { 336 | if(str != NULL) { 337 | uint8_t iKey[16]; 338 | char cKey[33] = {'\0'}; 339 | LoRa_GetKey(AT_APPSKEY, iKey); 340 | keyIntToChar(cKey, iKey, 16); 341 | str->concat(cKey); 342 | } 343 | } 344 | 345 | /* 346 | * @brief Read the device EUI. The device EUI is unique and burnt at factory. 347 | * @param pointer to the devie EUI (an Arduino string allocated by caller). 348 | * @retval None. 349 | */ 350 | void LoRaWANNodeClass::getDevEUI(String *str) 351 | { 352 | if(str != NULL) { 353 | uint8_t iKey[8]; 354 | char cKey[17] = {'\0'}; 355 | LoRa_GetDeviceID(iKey); 356 | keyIntToChar(cKey, iKey, 8); 357 | str->concat(cKey); 358 | } 359 | } 360 | 361 | /* 362 | * @brief Read the application key. 363 | * @param pointer to the AppKey (an Arduino string allocated by caller). 364 | * @retval None. 365 | */ 366 | void LoRaWANNodeClass::getAppKey(String *str) 367 | { 368 | if(str != NULL) { 369 | uint8_t iKey[16]; 370 | char cKey[33] = {'\0'}; 371 | LoRa_GetKey(AT_APPKEY, iKey); 372 | keyIntToChar(cKey, iKey, 16); 373 | str->concat(cKey); 374 | } 375 | } 376 | 377 | /* 378 | * @brief Read the application EUI. 379 | * @param pointer to the appEUI (an Arduino string allocated by caller). 380 | * @retval None. 381 | */ 382 | void LoRaWANNodeClass::getAppEUI(String *str) 383 | { 384 | if(str != NULL) { 385 | uint8_t iKey[8]; 386 | char cKey[17] = {'\0'}; 387 | LoRa_GetAppID(iKey); 388 | keyIntToChar(cKey, iKey, 8); 389 | str->concat(cKey); 390 | } 391 | } 392 | 393 | /* 394 | * @brief Write the LoRaWAN band. The device will be restarted. 395 | * @param frequency band: LORA_BAND_EU_868 or LORA_BAND_US_915 396 | * @retval Error code: false if failed else true. 397 | */ 398 | bool LoRaWANNodeClass::setBand(uint8_t band) 399 | { 400 | if(IS_BAND(band)) { 401 | if(Lora_SetDeviceBand(band) == AT_OK) { 402 | if(Lora_UpdateConfigTable() == AT_OK) { 403 | Lora_Reset(); 404 | return 1; 405 | } 406 | } 407 | } 408 | return 0; 409 | } 410 | 411 | /* 412 | * @brief Read the LoRaWAN band. 413 | * @retval Band: LORA_BAND_EU_868 or LORA_BAND_US_915 414 | */ 415 | uint8_t LoRaWANNodeClass::getBand(void) 416 | { 417 | uint8_t band; 418 | Lora_GetDeviceBand(&band); 419 | return (band - 48); //Convert ascii to int 420 | } 421 | 422 | /* 423 | * @brief Enable/disable the duty cycle. Must be enabled for EU band. 424 | * @param true enables duty cycle, false disables it. 425 | * @retval Error code: false if failed else true. 426 | */ 427 | bool LoRaWANNodeClass::setDutyCycle(bool state) 428 | { 429 | if(Lora_SetDutyCycle(state) == AT_OK) { 430 | return 1; 431 | } 432 | return 0; 433 | } 434 | 435 | /* 436 | * @brief Read the duty cycle state. 437 | * @retval True if enabled else false. 438 | */ 439 | bool LoRaWANNodeClass::getDutyCycle(void) 440 | { 441 | uint8_t state; 442 | Lora_GetDutyCycle(&state); 443 | return (bool)(state - 48); //Convert ascii to int 444 | } 445 | 446 | /* 447 | * @brief Enable/disable the adaptative data rate. 448 | * @param true enables ADR, false disables it. 449 | * @retval Error code: false if failed else true. 450 | */ 451 | bool LoRaWANNodeClass::setAdaptativeDataRate(bool state) 452 | { 453 | if(Lora_SetAdaptiveDataRate((uint8_t)state) == AT_OK) { 454 | return 1; 455 | } 456 | return 0; 457 | } 458 | 459 | /* 460 | * @brief Read the adaptative data rate state. 461 | * @retval True if enabled else false. 462 | */ 463 | bool LoRaWANNodeClass::getAdaptativeDataRate(void) 464 | { 465 | uint8_t state; 466 | Lora_GetAdaptiveDataRate(&state); 467 | return (bool)(state - 48); //Convert ascii to int 468 | } 469 | 470 | /* 471 | * @brief Reset the device parameters and restart it. 472 | */ 473 | void LoRaWANNodeClass::reset(void) 474 | { 475 | Lora_RestoreConfigTable(); 476 | Lora_Reset(); 477 | } 478 | 479 | /* 480 | * @brief Write the data rate. 481 | * @param Data rate: 0 to 15. 482 | * @retval Error code: false if failed else true. 483 | */ 484 | bool LoRaWANNodeClass::setDataRate(uint8_t value) 485 | { 486 | if(value <= 15) { //DR0 - DR15 487 | if(Lora_SetDataRate(value) == AT_OK) { 488 | return 1; 489 | } 490 | } 491 | return 0; 492 | } 493 | 494 | /* 495 | * @brief Read the data rate. 496 | * @retval Returns the data rate: 0 to 15. If returns 256 the data rate can't be read. 497 | */ 498 | uint8_t LoRaWANNodeClass::getDataRate(void) 499 | { 500 | uint8_t value[16]; // 0 (default) 501 | 502 | if(Lora_GetDataRate(value) == AT_OK) { 503 | return (value[0] - 48); // convert ascii to int 504 | } 505 | return 0xFF; 506 | } 507 | 508 | /* 509 | * @brief Enable/disable the public network mode. 510 | * @param True to enable the public network else false to switch in private network. 511 | * @retval Error code: false if failed else true. 512 | */ 513 | bool LoRaWANNodeClass::setPublicNwkMode(bool value) 514 | { 515 | // 0 Private network - 1 Public network (default) 516 | if(Lora_SetPublicNetworkMode(value) == AT_OK) { 517 | return 1; 518 | } 519 | return 0; 520 | } 521 | 522 | /* 523 | * @brief Read the network mode. 524 | * @retval Returns the network mode: 0 = private, 1 = public 525 | * If returns 256 the mode can't be read. 526 | */ 527 | uint8_t LoRaWANNodeClass::getPublicNwkMode(void) 528 | { 529 | uint8_t value[16]; // 0 (default) 530 | 531 | if(Lora_GetPublicNetworkMode(value) == AT_OK) { 532 | return (value[0] - 48); // convert ascii to int 533 | } 534 | return 0xFF; 535 | } 536 | 537 | /* 538 | * @brief Force the device to enter in sleep mode. 539 | * @retval Error code: false if failed else true. 540 | */ 541 | bool LoRaWANNodeClass::sleep(void) 542 | { 543 | if(Lora_SleepMode() == AT_OK) { 544 | delay(500); 545 | if(Modem_AT_Cmd(AT_ASYNC_EVENT, AT, NULL ) == AT_OK) { 546 | return 1; 547 | } 548 | } 549 | return 0; 550 | } 551 | 552 | /* 553 | * @brief Force the device to exit the sleep mode. 554 | * @retval Error code: false if failed else true. 555 | */ 556 | bool LoRaWANNodeClass::wakeup(void) 557 | { 558 | LoRa_DumyRequest(); 559 | if(Modem_AT_Cmd(AT_ASYNC_EVENT, AT, NULL ) == AT_OK) { 560 | return 1; 561 | } 562 | return 0; 563 | } 564 | 565 | /* 566 | * @brief Set the delay time of RX window 1. 567 | * @Note Delay time of RX2 window is 1000ms larger than RX1 window. 568 | * @param delay in ms. Should be a value of the LoRaWAN. 569 | * @retval Error code: false if failed else true. 570 | */ 571 | bool LoRaWANNodeClass::setRx1Delay(uint32_t ms) 572 | { 573 | /* NOTE: RX2 window delay must be set before RX1 window delay if not RX1 delay 574 | is rejected. */ 575 | if(ms >= getRx1Delay()) { 576 | if((LoRa_SetDelayRxWind(AT_RX2DL, ms + 1000) == AT_OK) && 577 | (LoRa_SetDelayRxWind(AT_RX1DL, ms) == AT_OK)) { 578 | return 1; 579 | } 580 | } else { 581 | if((LoRa_SetDelayRxWind(AT_RX1DL, ms) == AT_OK) && 582 | (LoRa_SetDelayRxWind(AT_RX2DL, ms + 1000) == AT_OK)) { 583 | return 1; 584 | } 585 | } 586 | return 0; 587 | } 588 | 589 | /* 590 | * @brief Get the delay time of RX window 1. 591 | * @retval Returns the delay time of RX window 1 in ms. 592 | */ 593 | uint32_t LoRaWANNodeClass::getRx1Delay(void) 594 | { 595 | uint32_t value; 596 | 597 | if(LoRa_GetDelayRxWind(AT_RX1DL, &value) == AT_OK) { 598 | return value; 599 | } 600 | return 0xFFFFFFFF; 601 | } 602 | 603 | /* 604 | * @brief Set the join accept delay time of RX window 1. 605 | * @Note Join Accept delay time of RX2 window is 1000ms larger than Join 606 | * Accept RX1 window. 607 | * @param delay in ms. Should be a value of the LoRaWAN. 608 | * @retval Error code: false if failed else true. 609 | */ 610 | bool LoRaWANNodeClass::setJoinRx1Delay(uint32_t ms) 611 | { 612 | /* NOTE: RX2 window delay must be set before RX1 window delay if not RX1 delay 613 | is rejected. */ 614 | if(ms >= getJoinRx1Delay()) { 615 | if((LoRa_SetJoinDelayRxWind(AT_JN2DL, ms + 1000) == AT_OK) && 616 | (LoRa_SetJoinDelayRxWind(AT_JN1DL, ms) == AT_OK)) { 617 | return 1; 618 | } 619 | } else { 620 | if((LoRa_SetJoinDelayRxWind(AT_JN1DL, ms) == AT_OK) && 621 | (LoRa_SetJoinDelayRxWind(AT_JN2DL, ms + 1000) == AT_OK)) { 622 | return 1; 623 | } 624 | } 625 | return 0; 626 | } 627 | 628 | /* 629 | * @brief Get the join accept delay time of RX window 1. 630 | * @retval Returns the delay time of the join accept RX window 1 in ms. 631 | */ 632 | uint32_t LoRaWANNodeClass::getJoinRx1Delay(void) 633 | { 634 | uint32_t value; 635 | 636 | if(LoRa_GetJoinDelayRxWind(AT_JN1DL, &value) == AT_OK) { 637 | return value; 638 | } 639 | return 0xFFFFFFFF; 640 | } 641 | 642 | LoRaWANNodeClass loraNode; 643 | -------------------------------------------------------------------------------- /src/LoRaWANNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file LoRaWANNode.h 4 | * @author WI6LABS 5 | * @version V1.0.0 6 | * @date 28-november-2017 7 | * @brief LoRaWAN Arduino API for I-NUCLEO-LRWAN1 shield 8 | ****************************************************************************** 9 | * @attention 10 | * 11 | *

© COPYRIGHT(c) 2017 STMicroelectronics

12 | * 13 | * Redistribution and use in source and binary forms, with or without modification, 14 | * are permitted provided that the following conditions are met: 15 | * 1. Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright notice, 18 | * this list of conditions and the following disclaimer in the documentation 19 | * and/or other materials provided with the distribution. 20 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 21 | * may be used to endorse or promote products derived from this software 22 | * without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | * 35 | ****************************************************************************** 36 | */ 37 | 38 | #ifndef __LORAWAN_NODE_H_ 39 | #define __LORAWAN_NODE_H_ 40 | 41 | #include "hw.h" 42 | 43 | // LoRa band 44 | #define LORA_BAND_EU_868 0U 45 | #define LORA_BAND_US_915 1U 46 | 47 | #define IS_BAND(band) ((band == LORA_BAND_EU_868) || (band == LORA_BAND_US_915)) 48 | 49 | // Lorawan Class 50 | // NOTE: the USI module supports only the class A!!! 51 | #define LORA_CLASS_A 0U 52 | #define LORA_CLASS_B 1U 53 | #define LORA_CLASS_C 2U 54 | 55 | #define IS_CLASS(loraClass) ( (loraClass == LORA_CLASS_A) ||\ 56 | (loraClass == LORA_CLASS_B) ||\ 57 | (loraClass == LORA_CLASS_C) ) 58 | 59 | // Data acknowledgment 60 | #define UNCONFIRMED 0U 61 | #define CONFIRMED 1U 62 | 63 | // Send frame error flags 64 | #define LORA_SEND_DELAYED 0 // Busy or duty cycle 65 | #define LORA_SEND_ERROR (-1) // Send failed 66 | 67 | class LoRaWANNodeClass { 68 | public: 69 | 70 | LoRaWANNodeClass(); 71 | // Begin initialization function 72 | bool begin(HardwareSerial *serialx, uint8_t band, uint8_t loraClass = LORA_CLASS_A); 73 | 74 | bool joinOTAA(const char *appKey, const char *appEui = NULL); //function to configure the otaa parameters 75 | bool joinABP(const char *devAddr, const char *nwkSKey, const char *appSKey); //function to configure the ABP parameters 76 | 77 | int8_t sendFrame(char frame[], uint8_t length, bool confirmed, uint8_t port = 1); //function to send a frame 78 | bool receiveFrame(uint8_t *frame, uint8_t *length, uint8_t *port); 79 | 80 | // Lorawan stack & firmware version 81 | void getVersion(String *str); 82 | void getFWVersion(String *str); 83 | 84 | // ABP information 85 | void getDevAddr(String *str); 86 | void getNwkSKey(String *str); 87 | void getAppSKey(String *str); 88 | 89 | // OTAA information 90 | void getDevEUI(String *str); 91 | void getAppKey(String *str); 92 | void getAppEUI(String *str); 93 | 94 | // Set/Get Band 95 | bool setBand(uint8_t band); 96 | uint8_t getBand(void); 97 | 98 | // Set/get duty cycle 99 | bool setDutyCycle(bool state); 100 | bool getDutyCycle(void); 101 | 102 | // Set/get adaptative data rate 103 | bool setAdaptativeDataRate(bool state); 104 | bool getAdaptativeDataRate(void); 105 | 106 | // Set/get data rate (SF and band width) 107 | bool setDataRate(uint8_t value); 108 | uint8_t getDataRate(void); 109 | 110 | // Reset USI module 111 | void reset(void); 112 | 113 | // Set/get network type 114 | bool setPublicNwkMode(bool value); 115 | uint8_t getPublicNwkMode(void); 116 | 117 | // Enter/exit the sleep mode 118 | bool sleep(void); 119 | bool wakeup(void); 120 | 121 | // Set/get RX1 delay 122 | // NOTE: Delay time of RX2 window is 1000ms larger than RX1 window. 123 | bool setRx1Delay(uint32_t ms); 124 | uint32_t getRx1Delay(void); 125 | 126 | // Set/get Join Accept RX1 delay 127 | // NOTE: Delay time of Join Accept RX2 window is 1000ms larger than RX1 window. 128 | bool setJoinRx1Delay(uint32_t ms); 129 | uint32_t getJoinRx1Delay(void); 130 | 131 | private: 132 | 133 | }; 134 | 135 | extern LoRaWANNodeClass loraNode; 136 | 137 | #endif //__LORAWAN_NODE_H_ 138 | -------------------------------------------------------------------------------- /src/atcmd_modem.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * @file atcmd_modem.h based on V1.0.1 3 | * @author MCD Application Team 4 | * @brief Header for AT commands definition 5 | ****************************************************************************** 6 | * @attention 7 | * 8 | *

© COPYRIGHT(c) 2017 STMicroelectronics

9 | * 10 | * Redistribution and use in source and binary forms, with or without modification, 11 | * are permitted provided that the following conditions are met: 12 | * 1. Redistributions of source code must retain the above copyright notice, 13 | * this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright notice, 15 | * this list of conditions and the following disclaimer in the documentation 16 | * and/or other materials provided with the distribution. 17 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 18 | * may be used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | * 32 | ****************************************************************************** 33 | */ 34 | #ifndef __ATCMD_MODEM_H__ 35 | #define __ATCMD_MODEM_H__ 36 | 37 | #ifdef __cplusplus 38 | extern "C" { 39 | #endif 40 | 41 | /**********************************************************************/ 42 | /* AT commands specification for WM_SG_SM_42USI modem */ 43 | /* - set of commands */ 44 | /* - return code error */ 45 | /**********************************************************************/ 46 | 47 | #ifdef AT_CMD_INDEX 48 | /* 49 | * AT Command Index . In direct relationship with "CmdTab" static array 50 | * in atcmd.c file 51 | */ 52 | typedef enum ATCmd 53 | { 54 | AT, /* OK */ 55 | 56 | AT_FWVERSION, /* New one */ 57 | 58 | AT_RESET, /* OK */ 59 | 60 | AT_BAND, /* New one */ 61 | 62 | AT_JOIN, /* OK - Same than Murata with additional parameter ABP or OTAA */ 63 | 64 | AT_NJS, /* KO - there is not equivalent in USI */ 65 | 66 | AT_DEUI, /* OK - USI equivalent EUI */ 67 | 68 | AT_DADDR, /* OK */ 69 | 70 | AT_APPKEY, /* OK - USI equivalent AK */ 71 | 72 | AT_NWKSKEY, /* OK - USI equivalent NSK */ 73 | 74 | AT_APPSKEY, /* OK - USI equivalent ASK */ 75 | 76 | AT_APPEUI, /* OK */ 77 | 78 | AT_ADR, /* OK */ 79 | 80 | AT_TXP, /* OK */ 81 | 82 | AT_DR, /* OK */ 83 | 84 | AT_DCS, /* OK - USI equivalent DC */ 85 | 86 | AT_PNM, /* OK - USI equivalent NTYP */ 87 | 88 | AT_RX2FQ, /* ?? */ 89 | 90 | AT_RX2DR, /* OK */ 91 | 92 | AT_RX1DL, /*OK - USI equivalent RX1DT */ 93 | 94 | AT_RX2DL, /*OK - USI equivalent RX2DT*/ 95 | 96 | AT_JN1DL, /*OK - USI equivalent JRX1DT*/ 97 | 98 | AT_JN2DL, /*OK - USI equivalent JRX2DT*/ 99 | 100 | AT_NJM, /* Is replaced by the combo join ? */ 101 | 102 | AT_NWKID, /* ?? */ 103 | AT_FCU, /* ?? */ 104 | AT_FCD, /* ?? */ 105 | 106 | AT_CLASS, /* OK */ 107 | 108 | /* AT_SENDB,*/ 109 | AT_SEND, /* Just one send mode- binary with scalar format port,data,ack */ 110 | 111 | AT_TXT, /* New one -- to send text. look like AT_SEND for murata */ 112 | 113 | AT_RECVB, /* ?? */ 114 | AT_RECV, /* ?? */ 115 | AT_CFM, /* Include in the send command */ 116 | AT_CFS, /* ?? */ 117 | 118 | AT_BAT, /* OK */ 119 | 120 | AT_RSSI, /* OK */ 121 | 122 | AT_SNR, /* OK */ 123 | 124 | AT_VER, /* OK */ 125 | 126 | AT_WDCT, /* New one */ 127 | 128 | AT_DEFMODE, /* New one */ 129 | 130 | AT_WDG, /* New one */ 131 | 132 | AT_ATE, /* New one */ 133 | 134 | AT_SLEEP, /* New one */ 135 | 136 | AT_PS, /* New one */ 137 | 138 | AT_RF, /* New one */ 139 | 140 | AT_VERB, /* New since firmware 2.8 */ 141 | 142 | AT_END_AT 143 | } ATCmd_t; 144 | 145 | #endif 146 | 147 | #ifdef AT_CMD_STRING 148 | /* List of AT string cmd supported by the USI LoRa modem */ 149 | static char *CmdTab[] = { 150 | "", 151 | "I", /* Firmware version of USI loara module */ 152 | "Z", /* System Reset */ 153 | "+BAND", /* +BAND country band - default 868 band */ 154 | 155 | "+JOIN", /* +JOIN */ 156 | 157 | "+NJS", /* +NJS --> ?? */ 158 | 159 | "+EUI", /* +EUI device ID */ 160 | 161 | "+ADDR", /* +ADDR device Address */ 162 | 163 | "+AK", /* +AK application key */ 164 | 165 | "+NSK", /* +NSK Network session Key */ 166 | 167 | "+ASK", /* +ASK application Session key */ 168 | 169 | "+APPEUI", /* +APPEUI application Identifier */ 170 | 171 | "+ADR", /* +ADR adaptive data rate */ 172 | 173 | "+TXP", /* +TXP transmit Tx power */ 174 | 175 | "+DR", /* +DR data rate */ 176 | 177 | "+DC", /* +DC duty cycle settings */ 178 | 179 | "+NTYP", /* +NTYP (replace+PNM) public network */ 180 | 181 | "+RX2FQ", /* +RF2FQ Rx2 window frequency --> ?? */ 182 | 183 | "+RX2DR", /* +RX2DR data rate of Rx window */ 184 | 185 | "+RX1DT", /* +RX1DT Delay of the Rx1 window */ 186 | 187 | "+RX2DT", /* +RX2DT delay of the Rx2 window */ 188 | 189 | "+JRX1DT", /* +JRX1DT Join delay on Rx Wind 1 */ 190 | 191 | "+JRX2DT", /* +JRX2DT Join delay on Rx Wind 2 */ 192 | 193 | "+NJM", /* +NJM Nwk Join Mode */ 194 | "+NWKID", /* +NWKID Network ID */ 195 | "+FCU", /* +FCU uplink frame counter */ 196 | "+FCD", /* +FCD downlink frame counter */ 197 | 198 | "+CLASS", /* +CLASS LoRa class */ 199 | 200 | /*{"+SENDB"},*/ /* +SENDB send data binary format --> sendB replaced by Send */ 201 | "+SEND", /* +SEND send data in raw format --> no sendb anymore with USI */ 202 | 203 | "+TXT", /* +TXT transmit text packet */ 204 | 205 | "+RECVB", /* +RECVB received data in binary format */ 206 | "+RECV", /* +RECV received data in raw format */ 207 | "+CFM", /* +CFM confirmation mode */ 208 | "+CFS", /* +CFS confirm status */ 209 | 210 | "+BAT", /* +BAT battery level */ 211 | 212 | "+RSSI", /* +RSSI Signal strength indicator on received radio signal */ 213 | 214 | "+SNR", /* +SNR Signal to Noice ratio */ 215 | 216 | "+VER", /* LoRaWAN version, if fw >= 2.8 also contains fw version */ 217 | 218 | "+WDCT", /* Update the configuration table */ 219 | 220 | "+DEFMODE", /* Set the default operationmode - 6 = LoRA WAN mode */ 221 | 222 | "+WDG", /* Enabling/disabling the watchdog */ 223 | 224 | "E", /* Enabling/disabling local echo mode */ 225 | 226 | "+SLEEP", /* Enter immediatly in sleep mode (slave) following the power control setting */ 227 | 228 | "+PS", /* Read or set the MCU power control (Slave) */ 229 | 230 | "+RF", /* Change the radio-related settings */ 231 | 232 | "+VERB" /* for enabling/disabling verbose response fw >= 2.8 */ 233 | }; 234 | #endif 235 | 236 | #ifdef AT_ERROR_INDEX 237 | /* 238 | * AT Command Index errors. In direct relationship with ATE_RetCode static array 239 | * in atcmd.c file 240 | */ 241 | typedef enum eATEerror 242 | { 243 | AT_OK = 0, 244 | AT_ERROR_UNKNOW, /* = -1 is USI error code*/ 245 | AT_ERROR_UNKNOW_COMMAND, /* = -2 */ 246 | AT_ERROR_LESS_ARGUMENTS, /* = -3, */ 247 | AT_ERROR_MORE_ARGUMENETS, /* = -4, */ 248 | AT_ERROR_INVALID_ARGUMENTS, /* = -5, */ 249 | AT_ERROR_NOT_SUPPORTED, /* = -6, */ 250 | AT_ERROR_OUT_OF_RANGE, /* = -7, */ 251 | AT_ERROR_RX_TIMEOUT, /* = -8, */ 252 | AT_ERROR_RX_ERROR, /* = -9, */ 253 | AT_ERROR_TX_TIMEOUT, /* = -10, */ 254 | AT_ERROR_TX_ERROR, /* = -11, */ 255 | AT_ERROR_RF_BUSY, /* = -12, */ 256 | AT_ERROR_TIMEOUT, /* = -13, */ 257 | AT_ERROR_NO_ARGUMENETS_NEEDED, /* = -14, */ 258 | AT_ERROR_HAL_ERROR, /* = -15, */ 259 | AT_ERROR_INVALID_HEX_FORMAT, /* = -16, */ 260 | AT_ERROR_OUT_OF_ADDRESS, /* = -17, */ 261 | AT_ERROR_WAN_SEND, /* = -100,*/ 262 | AT_ERROR_WAN_GETPARAM, /* = -101,*/ 263 | AT_ERROR_WAN_SETPARAM, /* = -102,*/ 264 | AT_WAN_NON_JOINED, /* = -103,*/ 265 | AT_END_ERROR, 266 | /* Additional return code */ 267 | AT_UART_LINK_ERROR, /* To notify error on UART link */ 268 | AT_TEST_PARAM_OVERFLOW, /* To be compatible whatevery the device modem*/ 269 | AT_JOIN_SLEEP_TRANSITION, /* To manage the Join request transaction*/ 270 | } ATEerror_t; 271 | 272 | #endif 273 | 274 | #ifdef AT_ERROR_STRING 275 | /* RetCode used to compare the return code from modem */ 276 | static ATE_RetCode_t ATE_RetCode[] = { 277 | {"OK\r\n", sizeof("OK\r\n"), AT_OK}, 278 | {"ERROR_UNKNOW\r", sizeof("ERROR_UNKNOW\r"), AT_ERROR_UNKNOW}, 279 | {"\rERROR_UNKNOW_COMMAND\r", sizeof("\rERROR_UNKNOW_COMMAND\r"), AT_ERROR_UNKNOW_COMMAND}, 280 | {"ERROR_LESS_ARGUMENETS\r\n", sizeof("ERROR_LESS_ARGUMENETS\r\n"), AT_ERROR_LESS_ARGUMENTS}, 281 | {"ERROR_MORE_ARGUMENETS\r", sizeof("ERROR_MORE_ARGUMENETS\r"), AT_ERROR_MORE_ARGUMENETS}, 282 | {"ERROR_INVALID_ARGUMENTS\r", sizeof("ERROR_INVALID_ARGUMENTS\r"), AT_ERROR_INVALID_ARGUMENTS}, 283 | {"AT_ERROR_NOT_SUPPORTED\r", sizeof("AT_ERROR_NOT_SUPPORTED\r"), AT_ERROR_NOT_SUPPORTED}, 284 | {"ERROR_OUT_OF_RANGE\r", sizeof("ERROR_OUT_OF_RANGE\r"), AT_ERROR_OUT_OF_RANGE}, 285 | {"ERROR_RX_TIMEOUT\r", sizeof("ERROR_RX_TIMEOUT\r"), AT_ERROR_RX_TIMEOUT}, 286 | {"ERROR_RX_ERROR\r", sizeof("ERROR_RX_ERROR\r"), AT_ERROR_RX_ERROR}, 287 | {"ERROR_TX_TIMEOUT\r", sizeof("ERROR_TX_TIMEOUT\r"), AT_ERROR_TX_TIMEOUT}, 288 | {"ERROR_TX_ERROR\r", sizeof("ERROR_TX_ERROR\r"), AT_ERROR_TX_ERROR}, 289 | {"ERROR_RF_BUSY\r", sizeof("ERROR_RF_BUSY\r"), AT_ERROR_RF_BUSY}, 290 | {"ERROR_TIMEOUT\r", sizeof("ERROR_TIMEOUT\r"), AT_ERROR_TIMEOUT}, 291 | {"ERROR_NO_ARGUMENETS_NEEDED\r",sizeof("ERROR_NO_ARGUMENETS_NEEDED\r"), AT_ERROR_NO_ARGUMENETS_NEEDED}, 292 | {"AT_ERROR_HAL_ERROR\r", sizeof("AT_ERROR_HAL_ERROR\r"), AT_ERROR_HAL_ERROR}, 293 | {"ERROR_INVALID_HEX_FORMAT\r", sizeof("ERROR_INVALID_HEX_FORMAT\r"), AT_ERROR_INVALID_HEX_FORMAT}, 294 | {"ERROR_OUT_OF_ADDRESS\r", sizeof("ERROR_OUT_OF_ADDRESS\r"), AT_ERROR_OUT_OF_ADDRESS}, 295 | {"ERROR_WAN_SEND\r", sizeof("ERROR_WAN_SEND\r"), AT_ERROR_WAN_SEND}, 296 | {"ERROR_WAN_GETPARAM\r", sizeof("ERROR_WAN_GETPARAM\r"), AT_ERROR_WAN_GETPARAM}, 297 | {"ERROR_WAN_SETPARAM\r", sizeof("ERROR_WAN_SETPARAM\r"), AT_ERROR_WAN_SETPARAM}, 298 | {"ERROR_WAN_NON_JOINED\r", sizeof("ERROR_WAN_NON_JOINED\r"), AT_WAN_NON_JOINED}, 299 | {"unknown error\r", sizeof("unknown error\r"), AT_END_ERROR} 300 | }; 301 | #endif 302 | 303 | #ifdef AT_CMD_MARKER 304 | /* Marker to design the AT command string */ 305 | #define AT_HEADER "AT" 306 | #define AT_SET_MARKER "=" 307 | #define AT_GET_MARKER "" 308 | #define AT_NULL_MARKER "" 309 | #define AT_COLON ":" 310 | #define AT_COMMA "," 311 | #define AT_TAIL "\r" 312 | #define AT_SEPARATOR "" 313 | #define AT_FRAME_KEY "%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx" 314 | #define AT_FRAME_KEY_OFFSET 2 315 | 316 | #endif 317 | 318 | #ifdef __cplusplus 319 | } 320 | #endif 321 | 322 | #endif /*__ATCMD_MODEM_H__*/ 323 | 324 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 325 | -------------------------------------------------------------------------------- /src/debug.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file debug.h based on V1.1.2 3 | * @author MCD Application Team 4 | * @brief Header for driver debug.c module 5 | ****************************************************************************** 6 | * @attention 7 | * 8 | *

© Copyright (c) 2017 STMicroelectronics International N.V. 9 | * All rights reserved.

10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted, provided that the following conditions are met: 13 | * 14 | * 1. Redistribution of source code must retain the above copyright notice, 15 | * this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright notice, 17 | * this list of conditions and the following disclaimer in the documentation 18 | * and/or other materials provided with the distribution. 19 | * 3. Neither the name of STMicroelectronics nor the names of other 20 | * contributors to this software may be used to endorse or promote products 21 | * derived from this software without specific written permission. 22 | * 4. This software, including modifications and/or derivative works of this 23 | * software, must execute solely and exclusively on microcontroller or 24 | * microprocessor devices manufactured by or for STMicroelectronics. 25 | * 5. Redistribution and use of this software other than as permitted under 26 | * this license is void and will automatically terminate your rights under 27 | * this license. 28 | * 29 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 30 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 32 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 33 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 34 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 35 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 37 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 38 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 39 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 40 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | * 42 | ****************************************************************************** 43 | */ 44 | 45 | /* Define to prevent recursive inclusion -------------------------------------*/ 46 | #ifndef __DEBUG_H__ 47 | #define __DEBUG_H__ 48 | 49 | #ifdef __cplusplus 50 | extern "C" { 51 | #endif 52 | 53 | /* Exported macros -----------------------------------------------------------*/ 54 | 55 | #if defined(DEBUG) && defined(TRACE) 56 | 57 | #define DBG_PRINTF(...) printf(__VA_ARGS__) 58 | #define DBG_PRINTF_CRITICAL(...) printf(__VA_ARGS__) 59 | 60 | #else /* DEBUG && TRACE */ 61 | 62 | #define DBG_PRINTF(...) 63 | #define DBG_PRINTF_CRITICAL(...) 64 | 65 | #endif /* DEBUG && TRACE */ 66 | 67 | #ifdef __cplusplus 68 | } 69 | #endif 70 | 71 | #endif /* __DEBUG_H__*/ 72 | 73 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 74 | -------------------------------------------------------------------------------- /src/hw.h: -------------------------------------------------------------------------------- 1 | /* 2 | / _____) _ | | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ 5 | _____) ) ____| | | || |_| ____( (___| | | | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| 7 | (C)2013 Semtech 8 | 9 | Description: contains all hardware driver 10 | 11 | License: Revised BSD License, see LICENSE.TXT file include in the project 12 | 13 | Maintainer: Miguel Luis and Gregory Cristian 14 | */ 15 | /****************************************************************************** 16 | * @file hw.h 17 | * @author MCD Application Team 18 | * @version V1.1.2 19 | * @date 08-September-2017 20 | * @brief contains all hardware driver 21 | ****************************************************************************** 22 | * @attention 23 | * 24 | *

© Copyright (c) 2017 STMicroelectronics International N.V. 25 | * All rights reserved.

26 | * 27 | * Redistribution and use in source and binary forms, with or without 28 | * modification, are permitted, provided that the following conditions are met: 29 | * 30 | * 1. Redistribution of source code must retain the above copyright notice, 31 | * this list of conditions and the following disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above copyright notice, 33 | * this list of conditions and the following disclaimer in the documentation 34 | * and/or other materials provided with the distribution. 35 | * 3. Neither the name of STMicroelectronics nor the names of other 36 | * contributors to this software may be used to endorse or promote products 37 | * derived from this software without specific written permission. 38 | * 4. This software, including modifications and/or derivative works of this 39 | * software, must execute solely and exclusively on microcontroller or 40 | * microprocessor devices manufactured by or for STMicroelectronics. 41 | * 5. Redistribution and use of this software other than as permitted under 42 | * this license is void and will automatically terminate your rights under 43 | * this license. 44 | * 45 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 46 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 47 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 48 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 49 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 50 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 51 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 52 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 53 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 54 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 55 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 56 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57 | * 58 | ****************************************************************************** 59 | */ 60 | 61 | /* Define to prevent recursive inclusion -------------------------------------*/ 62 | #ifndef __HW_H__ 63 | #define __HW_H__ 64 | 65 | #include "hw_usart.h" 66 | 67 | #ifdef __cplusplus 68 | extern "C" { 69 | #endif 70 | /* Includes ------------------------------------------------------------------*/ 71 | #include 72 | #include 73 | #include 74 | #include "debug.h" 75 | 76 | /******************************************************************************/ 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | 82 | #endif /* __HW_H__ */ 83 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 84 | 85 | -------------------------------------------------------------------------------- /src/hw_usart.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file hw_usart.c 3 | * @author MCD Application Team 4 | * @version V1.1.2 5 | * @date 08-September-2017 6 | * @brief This file provides code for the configuration of the USART 7 | * instances. 8 | ****************************************************************************** 9 | * @attention 10 | * 11 | *

© Copyright (c) 2017 STMicroelectronics International N.V. 12 | * All rights reserved.

13 | * 14 | * Redistribution and use in source and binary forms, with or without 15 | * modification, are permitted, provided that the following conditions are met: 16 | * 17 | * 1. Redistribution of source code must retain the above copyright notice, 18 | * this list of conditions and the following disclaimer. 19 | * 2. Redistributions in binary form must reproduce the above copyright notice, 20 | * this list of conditions and the following disclaimer in the documentation 21 | * and/or other materials provided with the distribution. 22 | * 3. Neither the name of STMicroelectronics nor the names of other 23 | * contributors to this software may be used to endorse or promote products 24 | * derived from this software without specific written permission. 25 | * 4. This software, including modifications and/or derivative works of this 26 | * software, must execute solely and exclusively on microcontroller or 27 | * microprocessor devices manufactured by or for STMicroelectronics. 28 | * 5. Redistribution and use of this software other than as permitted under 29 | * this license is void and will automatically terminate your rights under 30 | * this license. 31 | * 32 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 33 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 34 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 35 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 36 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 37 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 38 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 39 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 40 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 41 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 42 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 43 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 44 | * 45 | ****************************************************************************** 46 | */ 47 | 48 | /* Includes ------------------------------------------------------------------*/ 49 | #include "hw_usart.h" 50 | 51 | static HardwareSerial *Serialx = NULL; 52 | 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | /* USART init function */ 58 | 59 | bool HW_UART_Modem_Init(void *serial, uint32_t BaudRate) 60 | { 61 | if(serial != NULL) { 62 | Serialx = (HardwareSerial*)serial; 63 | Serialx->begin(BaudRate); 64 | return (true); 65 | } 66 | return (false); 67 | } 68 | 69 | /* USART deinit function */ 70 | 71 | void HW_UART_Modem_DeInit(void) 72 | { 73 | if(Serialx != NULL) { 74 | Serialx->end(); 75 | Serialx = NULL; 76 | } 77 | } 78 | 79 | 80 | /****************************************************************************** 81 | * @brief To check if data has been received 82 | * @param none 83 | * @retval boolean: false no data / true data 84 | ******************************************************************************/ 85 | bool HW_UART_Modem_IsNewCharReceived(void) 86 | { 87 | bool status; 88 | 89 | if(Serialx != NULL) { 90 | if(Serialx->available()) { 91 | status = true; 92 | } else { 93 | status = false; 94 | } 95 | } else { 96 | status = false; 97 | } 98 | return status; 99 | } 100 | 101 | /****************************************************************************** 102 | * @brief Get the received character 103 | * @param none 104 | * @retval Return the data received 105 | ******************************************************************************/ 106 | uint8_t HW_UART_Modem_GetNewChar(void) 107 | { 108 | if(Serialx != NULL) { 109 | return Serialx->read(); 110 | } else { 111 | return 0; 112 | } 113 | } 114 | 115 | /****************************************************************************** 116 | * @brief Send an among of character 117 | * @param buffer: data to send 118 | * @param len: number of data to send 119 | * @retval Return the data number of data sent 120 | ******************************************************************************/ 121 | uint8_t HW_UART_Modem_Write(uint8_t *buffer, uint16_t len) 122 | { 123 | if(Serialx != NULL) { 124 | return Serialx->write(buffer, len); 125 | } else { 126 | return 0; 127 | } 128 | } 129 | 130 | /****************************************************************************** 131 | * @brief Flush serial buffer 132 | * @param none 133 | * @retval none 134 | ******************************************************************************/ 135 | void HW_UART_Modem_Flush(void) 136 | { 137 | if(Serialx != NULL) { 138 | while(Serialx->available()) { 139 | Serialx->read(); 140 | } 141 | } 142 | } 143 | 144 | #ifdef __cplusplus 145 | } 146 | #endif 147 | 148 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 149 | -------------------------------------------------------------------------------- /src/hw_usart.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file hw_usart.h 3 | * @author MCD Application Team 4 | * @version V1.1.2 5 | * @date 08-September-2017 6 | * @brief This file provides code for the configuration of the USART 7 | * instances. 8 | ****************************************************************************** 9 | * @attention 10 | * 11 | *

© Copyright (c) 2017 STMicroelectronics International N.V. 12 | * All rights reserved.

13 | * 14 | * Redistribution and use in source and binary forms, with or without 15 | * modification, are permitted, provided that the following conditions are met: 16 | * 17 | * 1. Redistribution of source code must retain the above copyright notice, 18 | * this list of conditions and the following disclaimer. 19 | * 2. Redistributions in binary form must reproduce the above copyright notice, 20 | * this list of conditions and the following disclaimer in the documentation 21 | * and/or other materials provided with the distribution. 22 | * 3. Neither the name of STMicroelectronics nor the names of other 23 | * contributors to this software may be used to endorse or promote products 24 | * derived from this software without specific written permission. 25 | * 4. This software, including modifications and/or derivative works of this 26 | * software, must execute solely and exclusively on microcontroller or 27 | * microprocessor devices manufactured by or for STMicroelectronics. 28 | * 5. Redistribution and use of this software other than as permitted under 29 | * this license is void and will automatically terminate your rights under 30 | * this license. 31 | * 32 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 33 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 34 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 35 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 36 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 37 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 38 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 39 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 40 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 41 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 42 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 43 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 44 | * 45 | ****************************************************************************** 46 | */ 47 | /* Define to prevent recursive inclusion -------------------------------------*/ 48 | #ifndef __usart_H 49 | #define __usart_H 50 | 51 | // We define a larger UART RX buffer size to remove reception error (lost data). 52 | #undef SERIAL_RX_BUFFER_SIZE 53 | #define SERIAL_RX_BUFFER_SIZE 256 54 | #include "Arduino.h" 55 | 56 | #ifdef __cplusplus 57 | extern "C" { 58 | #endif 59 | 60 | /* Includes ------------------------------------------------------------------*/ 61 | /* Private defines -----------------------------------------------------------*/ 62 | /* Exported constants --------------------------------------------------------*/ 63 | 64 | // Default baudrate for I-NUCLEO_LRWAN1 shield 65 | #define BAUD_RATE 115200 66 | 67 | /* External variables --------------------------------------------------------*/ 68 | /* Exported macros -----------------------------------------------------------*/ 69 | /* Exported functions ------------------------------------------------------- */ 70 | 71 | bool HW_UART_Modem_Init(void *serial, uint32_t BaudRate); 72 | void HW_UART_Modem_DeInit(void); 73 | 74 | bool HW_UART_Modem_IsNewCharReceived(void); 75 | 76 | uint8_t HW_UART_Modem_GetNewChar(void); 77 | 78 | uint8_t HW_UART_Modem_Write(uint8_t *buffer, uint16_t len); 79 | 80 | void HW_UART_Modem_Flush(void); 81 | 82 | 83 | #ifdef __cplusplus 84 | } 85 | #endif 86 | #endif /* __usart_H */ 87 | 88 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 89 | -------------------------------------------------------------------------------- /src/i_nucleo_lrwan1_wm_sg_sm_xx.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * @file i_nucleo_lrwan1_wm_sg_sm_xx.c based on V1.0.1 3 | * @author MCD Application Team 4 | * @brief driver I_NUCLEO_LRWAN1 for WM_SG_SM_XX modem board 5 | ****************************************************************************** 6 | * @attention 7 | * 8 | *

© COPYRIGHT(c) 2017 STMicroelectronics

9 | * 10 | * Redistribution and use in source and binary forms, with or without modification, 11 | * are permitted provided that the following conditions are met: 12 | * 1. Redistributions of source code must retain the above copyright notice, 13 | * this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright notice, 15 | * this list of conditions and the following disclaimer in the documentation 16 | * and/or other materials provided with the distribution. 17 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 18 | * may be used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | * 32 | ****************************************************************************** 33 | */ 34 | 35 | /* Includes ------------------------------------------------------------------*/ 36 | 37 | #ifdef __cplusplus 38 | extern "C" { 39 | #endif 40 | 41 | #include 42 | #include 43 | #include 44 | #include "i_nucleo_lrwan1_wm_sg_sm_xx.h" 45 | #include "hw.h" 46 | 47 | #include 48 | 49 | /* External variables --------------------------------------------------------*/ 50 | extern ATCmd_t gFlagException; /* Defined in lora_driver.c */ 51 | 52 | /* Private variables ---------------------------------------------------------*/ 53 | 54 | /* Buffer used for AT cmd transmission */ 55 | char LoRa_AT_Cmd_Buff[DATA_TX_MAX_BUFF_SIZE]; 56 | /* Write position needed for send command */ 57 | static uint16_t Offset = 0; 58 | /* 59 | * Buffer has to be the largest of the response not only for return code 60 | * but also for return value: exemple KEY 61 | */ 62 | static char response[DATA_RX_MAX_BUFF_SIZE]; 63 | 64 | /****************************************************************************/ 65 | /*here we have to include a list of AT cmd by the way of #include */ 66 | /*this file will be preprocessed for CmdTab and ATE_RetCode definition */ 67 | /****************************************************************************/ 68 | 69 | /* Avoid recursive include */ 70 | #undef __ATCMD_MODEM_H__ 71 | #define AT_CMD_STRING 72 | #define AT_ERROR_STRING 73 | #undef AT_CMD_INDEX 74 | #undef AT_ERROR_INDEX 75 | /* Include WM_SG_SM_42 specific string AT cmd definition */ 76 | #include "atcmd_modem.h" 77 | 78 | /* private functions ------------------------------------------------------- */ 79 | static uint8_t at_cmd_format(ATCmd_t Cmd, void *ptr, Marker_t Marker); 80 | 81 | static bool at_cmd_send(uint16_t len); 82 | 83 | static ATEerror_t at_cmd_receive(void *pdata); 84 | 85 | static ATEerror_t at_cmd_responseAnalysing(const char *ReturnResp); 86 | 87 | static ATEerror_t at_cmd_receive_async_event(void); 88 | 89 | static ATEerror_t at_cmd_AsyncEventAnalysing(const char *ReturnResp,int8_t *Flag); 90 | 91 | static ATEerror_t at_cmd_receive_async_event_downlink_data(void *ptr); 92 | 93 | /****************************************************************************** 94 | * @brief Configures modem UART interface. 95 | * @param None 96 | * @retval AT_OK in case of success 97 | * @retval AT_UART_LINK_ERROR in case of failure 98 | *****************************************************************************/ 99 | ATEerror_t Modem_IO_Init( void *serial ) 100 | { 101 | if (HW_UART_Modem_Init(serial, BAUD_RATE)) { 102 | return AT_OK; 103 | } else { 104 | return AT_UART_LINK_ERROR; 105 | } 106 | } 107 | 108 | /****************************************************************************** 109 | * @brief Deinitialise modem UART interface. 110 | * @param None 111 | * @retval None 112 | *****************************************************************************/ 113 | void Modem_IO_DeInit( void ) 114 | { 115 | HW_UART_Modem_DeInit(); 116 | } 117 | 118 | 119 | /****************************************************************************** 120 | * @brief Handle the AT cmd following their Groupp type 121 | * @param at_group AT group [control, set , get) 122 | * Cmd AT command 123 | * pdata pointer to the IN/OUT buffer 124 | * @retval module status 125 | *****************************************************************************/ 126 | ATEerror_t Modem_AT_Cmd(ATGroup_t at_group, ATCmd_t Cmd, void *pdata ) 127 | { 128 | ATEerror_t Status = AT_END_ERROR; 129 | uint16_t Len; 130 | 131 | /* Reset At_cmd buffer for each transmission */ 132 | memset(LoRa_AT_Cmd_Buff, 0x00, sizeof LoRa_AT_Cmd_Buff); 133 | 134 | switch (at_group) { 135 | case AT_CTRL: 136 | Len = at_cmd_format( Cmd, NULL, CTRL_MARKER); 137 | if(!at_cmd_send(Len)) { 138 | return (AT_UART_LINK_ERROR); 139 | } 140 | if(Cmd != AT_RESET) { 141 | Status = at_cmd_receive(NULL); 142 | } 143 | break; 144 | case AT_SET: 145 | Len = at_cmd_format(Cmd, pdata, SET_MARKER); 146 | if(!at_cmd_send(Len)) { 147 | return (AT_UART_LINK_ERROR); 148 | } 149 | Status = at_cmd_receive(NULL); 150 | break; 151 | case AT_GET: 152 | Len = at_cmd_format(Cmd, pdata, GET_MARKER); 153 | if(!at_cmd_send(Len)) { 154 | return (AT_UART_LINK_ERROR); 155 | } 156 | Status = at_cmd_receive(pdata); 157 | break; 158 | case AT_ASYNC_EVENT: 159 | if (( Cmd == AT_JOIN) || (Cmd == AT) || (Cmd == AT_TXT)) { 160 | Status = at_cmd_receive_async_event(); 161 | } else { 162 | Status = at_cmd_receive_async_event_downlink_data(pdata); 163 | } 164 | break; 165 | case AT_EXCEPT: 166 | Len = at_cmd_format(Cmd, pdata, SET_MARKER); 167 | if(!at_cmd_send(Len)) { 168 | return (AT_UART_LINK_ERROR); 169 | } else { 170 | Status = at_cmd_receive(NULL); 171 | } 172 | break; 173 | case AT_EXCEPT_1: 174 | Len = at_cmd_format(Cmd, NULL, SET_MARKER); 175 | if(!at_cmd_send(Len)) { 176 | return (AT_UART_LINK_ERROR); 177 | } else { 178 | Status = at_cmd_receive(NULL); 179 | } 180 | break; 181 | default: 182 | DBG_PRINTF("unknow group\n\r"); 183 | break; 184 | } /*end switch(at_group)*/ 185 | return Status; 186 | } 187 | 188 | /****************************************************************************** 189 | * @brief format the cmd in order to be send 190 | * @param Cmd AT command 191 | * ptr generic pointer to the IN/OUT buffer 192 | * Marker to discriminate the Set from the Get 193 | * @retval length of the formated frame to be send 194 | *****************************************************************************/ 195 | static uint8_t at_cmd_format(ATCmd_t Cmd, void *ptr, Marker_t Marker) 196 | { 197 | uint16_t len; /* Length of the formated command */ 198 | uint8_t *PtrValue; /* For IN/OUT buffer */ 199 | uint32_t value; /* For 32_02X and 32_D */ 200 | uint8_t value_8; /* For 8_D */ 201 | 202 | switch (Cmd){ 203 | case AT: /* Supported */ 204 | case AT_RESET: /* Supported */ 205 | case AT_SLEEP: /* Supported */ 206 | case AT_FWVERSION: /* Supported */ 207 | /* Format = FORMAT_VOID_PARAM; */ 208 | len = AT_VPRINTF("%s%s%s",AT_HEADER,CmdTab[Cmd],AT_TAIL); 209 | break; 210 | case AT_RECV: 211 | case AT_VER: 212 | /* Format = FORMAT_PLAIN_TEXT; */ 213 | if(Marker == SET_MARKER) { 214 | len = AT_VPRINTF("%s%s%s%d%s%s\r\n", AT_HEADER, CmdTab[Cmd], 215 | AT_SET_MARKER,((sSendDataString_t *)ptr)->Port, 216 | AT_COLON,((sSendDataString_t *)ptr)->Buffer); 217 | } else { 218 | len = AT_VPRINTF("%s%s%s%s", AT_HEADER, CmdTab[Cmd], 219 | AT_GET_MARKER,AT_TAIL); 220 | } 221 | break; 222 | case AT_SEND: /* Supported - sendB replaced by send - just one send mode on USI */ 223 | case AT_RECVB: /* Not supported*/ 224 | /* Format = FORMAT_BINARY_TEXT; */ 225 | if(Marker == SET_MARKER) { 226 | Offset = AT_VPRINTF("%s%s%s%d%s", AT_HEADER, CmdTab[Cmd], 227 | AT_SET_MARKER, ((sSendDataBinary_t *)ptr)->Port, 228 | AT_COMMA); 229 | for (uint32_t i = 0; i < ((sSendDataBinary_t *)ptr)->DataSize; i++) { 230 | Offset+=AT_VPRINTF("%02x", ((sSendDataBinary_t *)ptr)->Buffer[i]); 231 | } 232 | Offset+=AT_VPRINTF("%s%d%s", AT_COMMA, ((sSendDataBinary_t *)ptr)->Ack, 233 | AT_TAIL); 234 | len = Offset; 235 | Offset = 0; 236 | } else { 237 | len = AT_VPRINTF("%s%s%s%s", AT_HEADER, CmdTab[Cmd], AT_GET_MARKER, 238 | AT_TAIL); 239 | } 240 | break; 241 | case AT_TXT: 242 | /* Format = FORMAT_BINARY_TEXT; */ 243 | if(Marker == SET_MARKER) { 244 | Offset = AT_VPRINTF("%s%s%s%d%s", AT_HEADER, CmdTab[Cmd], AT_SET_MARKER, 245 | ((sSendData_t *)ptr)->NbRep, AT_COMMA); 246 | for (uint32_t i = 0; i < ((sSendData_t *)ptr)->DataSize; i++) { 247 | Offset+=AT_VPRINTF("%02x", ((sSendData_t *)ptr)->Buffer[i]); 248 | } 249 | Offset+=AT_VPRINTF("%s", AT_TAIL); 250 | len = Offset; 251 | Offset = 0; 252 | } else { 253 | len = 0; 254 | } 255 | break; 256 | case AT_APPKEY: /* Supported - USI equivalent AK */ 257 | case AT_NWKSKEY: /* Supported - USI equivalent NSK */ 258 | case AT_APPSKEY: /* Supported - USI equivalent ASK */ 259 | if(Marker == SET_MARKER) { 260 | /* Format = FORMAT_16_02X_PARAM; */ 261 | PtrValue = (uint8_t*) ptr; 262 | len = AT_VPRINTF( 263 | "%s%s%s%02x%s%02x%s%02x%s%02x%s%02x%s%02x%s%02x%s%02x%s%02x%s%02x%s%02x%s%02x%s%02x%s%02x%s%02x%s%02x%s", 264 | AT_HEADER, CmdTab[Cmd], AT_SET_MARKER, 265 | PtrValue[0], AT_SEPARATOR, PtrValue[1], AT_SEPARATOR, 266 | PtrValue[2], AT_SEPARATOR, PtrValue[3], AT_SEPARATOR, 267 | PtrValue[4], AT_SEPARATOR, PtrValue[5], AT_SEPARATOR, 268 | PtrValue[6], AT_SEPARATOR, PtrValue[7], AT_SEPARATOR, 269 | PtrValue[8], AT_SEPARATOR, PtrValue[9], AT_SEPARATOR, 270 | PtrValue[10], AT_SEPARATOR, PtrValue[11], AT_SEPARATOR, 271 | PtrValue[12], AT_SEPARATOR, PtrValue[13], AT_SEPARATOR, 272 | PtrValue[14], AT_SEPARATOR, PtrValue[15], AT_TAIL); 273 | } else { 274 | len = AT_VPRINTF("%s%s%s%s", AT_HEADER, CmdTab[Cmd], AT_GET_MARKER, 275 | AT_TAIL); 276 | } 277 | break; 278 | case AT_DADDR: /* Supported */ 279 | case AT_NWKID: /* N/A */ 280 | if(Marker == SET_MARKER) { 281 | /*Format = FORMAT_32_02X_PARAM;*/ 282 | value = *(uint32_t*)ptr; 283 | len = AT_VPRINTF("%s%s%s%02x%s%02x%s%02x%s%02x%s", AT_HEADER, 284 | CmdTab[Cmd], AT_SET_MARKER, 285 | (unsigned)((unsigned char *)(&value))[3], AT_SEPARATOR, 286 | (unsigned)((unsigned char *)(&value))[2], AT_SEPARATOR, 287 | (unsigned)((unsigned char *)(&value))[1], AT_SEPARATOR, 288 | (unsigned)((unsigned char *)(&value))[0], AT_TAIL); 289 | } else { 290 | len = AT_VPRINTF("%s%s%s%s", AT_HEADER, CmdTab[Cmd], AT_GET_MARKER, 291 | AT_TAIL); 292 | } 293 | break; 294 | case AT_APPEUI: /* Supported*/ 295 | case AT_DEUI: /* USI equivalent EUI - not relevant for SET since burned unique IEEE EUI64 at factory. */ 296 | if(Marker == SET_MARKER) { 297 | /* Format = FORMAT_8_02X_PARAM;*/ 298 | PtrValue = (uint8_t*)ptr; 299 | len = AT_VPRINTF( 300 | "%s%s%s%02x%s%02x%s%02x%s%02x%s%02x%s%02x%s%02x%s%02x%s", 301 | AT_HEADER,CmdTab[Cmd],AT_SET_MARKER, 302 | PtrValue[0], AT_SEPARATOR, PtrValue[1], AT_SEPARATOR, 303 | PtrValue[2], AT_SEPARATOR, PtrValue[3], AT_SEPARATOR, 304 | PtrValue[4], AT_SEPARATOR, PtrValue[5], AT_SEPARATOR, 305 | PtrValue[6], AT_SEPARATOR, PtrValue[7], AT_TAIL); 306 | } else { 307 | len = AT_VPRINTF("%s%s%s%s", AT_HEADER, CmdTab[Cmd], AT_GET_MARKER, 308 | AT_TAIL); 309 | } 310 | break; 311 | case AT_RX2FQ: /* N/A */ 312 | case AT_RX1DL: /* Supported - USI equivalent RX1DT */ 313 | case AT_RX2DL: /* Supported - USI equivalent RX2DT */ 314 | case AT_JN1DL: /* Supported - USI equivalent JRX1DT */ 315 | case AT_JN2DL: /* Supported - USI equivalent JRX2DT */ 316 | case AT_FCU: /* Not supported */ 317 | case AT_FCD: /* Not supported */ 318 | /* Format = FORMAT_32_D_PARAM; */ 319 | if(Marker == SET_MARKER) { 320 | value = *(uint32_t*)ptr; 321 | len = AT_VPRINTF("%s%s%s%u%s", AT_HEADER, CmdTab[Cmd], AT_SET_MARKER, 322 | value, AT_TAIL); 323 | } else { 324 | len = AT_VPRINTF("%s%s%s%s", AT_HEADER, CmdTab[Cmd], AT_GET_MARKER, 325 | AT_TAIL); 326 | } 327 | break; 328 | case AT_JOIN: /* Supported */ 329 | case AT_ATE: /* Supported */ 330 | case AT_DR: /* Supported */ 331 | case AT_RX2DR: /* Supported */ 332 | case AT_BAND: /* Supported */ 333 | case AT_TXP: /* N/A */ 334 | case AT_NJM: /* N/A */ 335 | case AT_PNM: /* Supported - USI equivalent NTYP */ 336 | case AT_DCS: /* Supported - USI equivalent DC - 337 | * Disabling duty cycle for testing only. 338 | * It should be enabled for shipping 339 | */ 340 | case AT_ADR: /* Supported */ 341 | case AT_CFM: /* N/A */ 342 | case AT_CFS: /* N/A */ 343 | case AT_BAT: /* Supported */ 344 | case AT_RSSI: /* Not supported by USI FW version */ 345 | case AT_SNR: /* Not supported by USI FW version */ 346 | case AT_NJS: /* N/A */ 347 | case AT_CLASS: /* Not supported on V2.5 USI FW version */ 348 | case AT_WDCT: /* Supported */ 349 | case AT_DEFMODE: 350 | case AT_VERB: /* Supported since V2.8 USI FW version */ 351 | /* Format = FORMAT_8_D_PARAM;*/ 352 | if(Marker == SET_MARKER) { 353 | value_8 = *(uint8_t*)ptr; 354 | len = AT_VPRINTF("%s%s%s%d%s", AT_HEADER, CmdTab[Cmd], AT_SET_MARKER, 355 | value_8, AT_TAIL); 356 | } else { 357 | len = AT_VPRINTF("%s%s%s%s", AT_HEADER, CmdTab[Cmd], AT_GET_MARKER, 358 | AT_TAIL); 359 | } 360 | break; 361 | case AT_PS: 362 | if(Marker == SET_MARKER) { 363 | len = AT_VPRINTF("%s%s%s%d,%d%s", AT_HEADER, CmdTab[Cmd], 364 | AT_SET_MARKER, ((sPowerCtrlSet_t *)ptr)->SetType, 365 | ((sPowerCtrlSet_t *)ptr)->Value, AT_TAIL); 366 | } else { 367 | len = AT_VPRINTF("%s%s%s%s", AT_HEADER, CmdTab[Cmd], AT_GET_MARKER, AT_TAIL); 368 | } 369 | break; 370 | case AT_RF: 371 | if(Marker == SET_MARKER) { 372 | len = AT_VPRINTF("%s%s%s%d,%d,%d,%d,%d,%d,%d,%d,%s", AT_HEADER, 373 | CmdTab[Cmd], AT_SET_MARKER, 374 | ((sRadioCtrlSet_t *)ptr)->power, 375 | ((sRadioCtrlSet_t *)ptr)->frequency, 376 | ((sRadioCtrlSet_t *)ptr)->sf, 377 | ((sRadioCtrlSet_t *)ptr)->bw, 378 | ((sRadioCtrlSet_t *)ptr)->codingRate, 379 | ((sRadioCtrlSet_t *)ptr)->crc, 380 | ((sRadioCtrlSet_t *)ptr)->preamble, 381 | ((sRadioCtrlSet_t *)ptr)->invIQ, AT_TAIL); 382 | } else { 383 | len = 0; 384 | } 385 | break; 386 | default: 387 | len = AT_VPRINTF("%s%s%s", AT_HEADER, CmdTab[Cmd], AT_TAIL); 388 | DBG_PRINTF ("format not yet supported \n\r"); 389 | break; 390 | } /* end switch(cmd)*/ 391 | return len; 392 | } 393 | 394 | 395 | /****************************************************************************** 396 | * @brief This function sends an AT cmd to the slave device 397 | * @param len: length of the AT cmd to be sent 398 | * @retval boolean 399 | ******************************************************************************/ 400 | static bool at_cmd_send(uint16_t len) 401 | { 402 | bool RetCode; 403 | uint16_t size; 404 | 405 | DBG_PRINTF("cmd: %s\r\n", LoRa_AT_Cmd_Buff); 406 | 407 | /* Transmit the command from master to slave */ 408 | size = HW_UART_Modem_Write((uint8_t*)LoRa_AT_Cmd_Buff, len); 409 | if(size == len ) { 410 | RetCode = true; 411 | } else { 412 | RetCode = false; 413 | } 414 | return RetCode; 415 | } 416 | 417 | /****************************************************************************** 418 | * @brief This function receives response from the slave device 419 | * @param pdata: pointeur to the value returned by the slave 420 | * @retval return code coming from slave 421 | ******************************************************************************/ 422 | static ATEerror_t at_cmd_receive(void *pdata) 423 | { 424 | uint8_t ResponseComplete = 0; 425 | int8_t i = 0; 426 | int8_t charnumber = 0; 427 | char *ptrChr; 428 | ATEerror_t RetCode; 429 | /* Discriminate the Get return code from return value */ 430 | uint8_t NoReturnCode = 1; 431 | uint32_t msStart; 432 | 433 | /* Cleanup the response buffer*/ 434 | memset(response, 0x00, DATA_RX_MAX_BUFF_SIZE); 435 | 436 | while (!ResponseComplete) { 437 | msStart = millis(); 438 | while (!HW_UART_Modem_IsNewCharReceived()) { 439 | if((millis() - msStart) > RESPONSE_TIMEOUT) { 440 | return AT_UART_LINK_ERROR; 441 | } 442 | } 443 | 444 | /* Process the response*/ 445 | response[i] = HW_UART_Modem_GetNewChar(); 446 | 447 | /* 448 | * Delete this first three characters: 449 | * "\r# " 450 | * to remove response analysing issue 451 | */ 452 | if((response[0] == '\r') && (response[1] == '#') && 453 | (response[2] == ' ')) { 454 | i = -1; 455 | } 456 | 457 | /* Wait up to carriage return OR the line feed marker*/ 458 | if (/*(response[i] =='\r') || */(response[i] == '\n')) { 459 | DBG_PRINTF("at_cmd_receive: %s\r\n", response); 460 | if(pdata == NULL) { 461 | /* Returned code following a SET cmd or simple AT cmd*/ 462 | i= 0; 463 | ResponseComplete = 1; 464 | RetCode = at_cmd_responseAnalysing(response); 465 | break; 466 | } else { 467 | /* Returned value following a GET cmd */ 468 | if (i!= 0 && NoReturnCode) { 469 | /* First statement to get back the return value */ 470 | response[i] = '\0'; 471 | if (gFlagException != AT_FWVERSION) { /* See comment in lora_driver.c */ 472 | ptrChr = strchr(&response[1],'='); /* Skip the '\0''\r' */ 473 | strcpy(pdata,ptrChr+1); 474 | } else { 475 | strcpy(pdata,&response[1]); 476 | gFlagException = AT_END_AT; 477 | } 478 | memset(response, 0x00, strlen(response)); 479 | i= -1; /* Compensate the next index iteration and restart in [0] */ 480 | NoReturnCode = 0; /*return code for the Get cmd*/ 481 | } else { 482 | if (i>1) { 483 | /*second statement to get back the return code*/ 484 | i= 0; 485 | ResponseComplete = 1; /*when value '=' return code have been trapped*/ 486 | RetCode = at_cmd_responseAnalysing(response); 487 | memset(response, 0x00, 16); 488 | break; 489 | } 490 | } 491 | } 492 | } else { 493 | if (i == (DATA_RX_MAX_BUFF_SIZE-1)) { 494 | /* Frame overflow */ 495 | i = 0; 496 | return (AT_TEST_PARAM_OVERFLOW); 497 | } 498 | } 499 | i++; 500 | charnumber++; 501 | } 502 | return RetCode; 503 | } 504 | 505 | /****************************************************************************** 506 | * @brief This function receives asynchronus event from the slave device 507 | * @param none 508 | * @retval return code coming from slave 509 | ******************************************************************************/ 510 | static ATEerror_t at_cmd_receive_async_event(void) 511 | { 512 | uint8_t ResponseComplete = 0; 513 | int8_t i = 0; 514 | int8_t charnumber = 0; 515 | char *ptrChr; 516 | ATEerror_t RetCode; 517 | /* Discriminate the Get return code from return value */ 518 | uint8_t NoReturnCode =1; 519 | uint32_t msStart; 520 | 521 | /* Cleanup the response buffer */ 522 | memset(response, 0x00, DATA_RX_MAX_BUFF_SIZE); 523 | 524 | while (!ResponseComplete) { 525 | msStart = millis(); 526 | while (!HW_UART_Modem_IsNewCharReceived()) { 527 | if((millis() - msStart) > RESPONSE_TIMEOUT) { 528 | return AT_UART_LINK_ERROR; 529 | } 530 | } 531 | 532 | /* Process the response */ 533 | response[i] = HW_UART_Modem_GetNewChar(); 534 | 535 | /* Wait up to carriage return OR the line feed marker */ 536 | if (/*(response[i] =='\r') || */(response[i] == '\n')) { 537 | DBG_PRINTF("at_cmd_receive_async_event: %s\r\n", response); 538 | 539 | if (i!= 0 && NoReturnCode) { /* Trap the asynchronous event*/ 540 | /* First statement to get back the return value */ 541 | response[i] = '\0'; 542 | ptrChr = strchr(&response[0], '+'); /* Skip the '\0''\r' */ 543 | RetCode = at_cmd_AsyncEventAnalysing(ptrChr, NULL); 544 | memset(response, 0x00, 16); 545 | i= -1; /* Compensate the next index iteration and restart in [0] */ 546 | NoReturnCode = 0; /* Return code for the Get cmd*/ 547 | break; 548 | } else { 549 | if (i>1) { 550 | /* Second statement to get back the return code */ 551 | i= 0; 552 | ResponseComplete = 1; /* When value + return code have been trapped */ 553 | RetCode = at_cmd_responseAnalysing(response); 554 | memset(response, 0x00, 16); 555 | break; 556 | } 557 | } 558 | } else { 559 | if (i == (DATA_RX_MAX_BUFF_SIZE-1)) { 560 | /* Frame overflow */ 561 | i = 0; 562 | return (AT_TEST_PARAM_OVERFLOW); 563 | } 564 | } 565 | i++; 566 | charnumber++; 567 | } 568 | return RetCode; 569 | } 570 | 571 | /****************************************************************************** 572 | * @brief This function receives asynchronus event from the slave device 573 | * @param none 574 | * @retval return code coming from slave 575 | ******************************************************************************/ 576 | static ATEerror_t at_cmd_receive_async_event_downlink_data(void *pdata) 577 | { 578 | int8_t i = 0; 579 | int8_t charnumber = 0; 580 | char *ptrChr; 581 | ATEerror_t RetCode = AT_OK; 582 | /* Discriminate the Get return code from return value */ 583 | uint8_t NoReturnCode =1; 584 | int8_t DlinkData_Complete = (0x1U); 585 | uint32_t msStart; 586 | 587 | /* Cleanup the response buffer */ 588 | memset(response, 0x00, DATA_RX_MAX_BUFF_SIZE); 589 | 590 | while (!(DlinkData_Complete & (0x1u <<2))) { /* Received sequence not complete */ 591 | msStart = millis(); 592 | while (!HW_UART_Modem_IsNewCharReceived()) { 593 | if((millis() - msStart) > ASYNC_EVENT_TIMEOUT) { 594 | return AT_UART_LINK_ERROR; 595 | } 596 | } 597 | 598 | /* Process the response */ 599 | response[i] = HW_UART_Modem_GetNewChar(); 600 | 601 | /* Wait up to carriage return OR the line feed marker */ 602 | if ((response[i] =='\r') || (response[i] == '\n')) { 603 | DBG_PRINTF("at_cmd_receive_async_event_downlink_data: %s\r\n", response); 604 | 605 | /* Trap the asynchronous events associated to network downlink data */ 606 | if (i!= 0 && NoReturnCode) { 607 | /* Sequence of events to be trapped: +RXPORT , +PAYLOADSIZE , +RCV */ 608 | response[i] = '\0'; 609 | /* 610 | * Here when we go out from low power mode the prefix is '\r' only. 611 | * We do not skip the '\0''\r' - USI behavior ... 612 | */ 613 | ptrChr = strchr(&response[0], '+'); 614 | RetCode = at_cmd_AsyncEventAnalysing(ptrChr,&DlinkData_Complete); 615 | if(RetCode == AT_OK) { 616 | ptrChr = strchr(&response[1],'='); /* Skip the '\0''\r' */ 617 | strcpy(pdata,ptrChr+1); 618 | pdata = (char*)pdata + strlen(ptrChr+1); 619 | if(!(DlinkData_Complete & (0x1u <<2))) { 620 | /* Introduce separator in order to discriminate port, size and data */ 621 | *((char*)pdata) = ','; 622 | pdata = (char*)pdata + 1; 623 | } 624 | } 625 | 626 | memset(response, 0x00, 16); 627 | i= -1; /* Compensate the next index iteration and restart in [0 ] */ 628 | } 629 | } else { 630 | if (i == (DATA_RX_MAX_BUFF_SIZE-1)) { 631 | /* Frame overflow */ 632 | i = 0; 633 | return (AT_TEST_PARAM_OVERFLOW); 634 | } 635 | } 636 | i++; 637 | charnumber++; 638 | } 639 | return RetCode; 640 | } 641 | 642 | /****************************************************************************** 643 | * @brief This function does analysis of the response received by the device 644 | * @param response: pointer to the received response 645 | * @retval ATEerror_t error type 646 | ******************************************************************************/ 647 | static ATEerror_t at_cmd_responseAnalysing(const char *ReturnResp) 648 | { 649 | ATEerror_t status; 650 | int i; 651 | status = AT_END_ERROR; 652 | 653 | for (i = 0; i < AT_END_ERROR; i++) { 654 | if (strncmp(ReturnResp, 655 | ATE_RetCode[i].RetCodeStr, 656 | (ATE_RetCode[i].SizeRetCodeStr-1)) == 0) { 657 | /* Command has been found found */ 658 | status = ATE_RetCode[i].RetCode; 659 | return status; 660 | } 661 | } 662 | return status; 663 | } 664 | 665 | /****************************************************************************** 666 | * @brief This function does analysis of the asynchronous event received by the device 667 | * @param response: pointer to the received response 668 | * @retval ATEerror_t error type 669 | ******************************************************************************/ 670 | static ATEerror_t at_cmd_AsyncEventAnalysing(const char *ReturnResp, int8_t *Flag) 671 | { 672 | ATEerror_t status; 673 | status = AT_END_ERROR; 674 | 675 | if (strncmp(ReturnResp, "+JoinAccepted\r", sizeof("+JoinAccepted\r")-1) == 0) { 676 | /* Event has been identified*/ 677 | status = AT_OK; 678 | } else { 679 | /* Following statements for network downlink data analysis */ 680 | if (strncmp(ReturnResp, "+RXPORT", sizeof("+RXPORT")-1) == 0) { 681 | /* Event has been identified */ 682 | *Flag <<= (0x0U); 683 | status = AT_OK; 684 | } else { 685 | /* Following statement for network downlink data */ 686 | if (strncmp(ReturnResp, "+PAYLOADSIZE", sizeof("+PAYLOADSIZE")-1) == 0) { 687 | /* event has been identified */ 688 | *Flag <<= (0x1U); 689 | status = AT_OK; 690 | } else { 691 | /* Following statement for network downlink data */ 692 | if (strncmp(ReturnResp, "+RCV", sizeof("+RCV")-1) == 0) { 693 | /* Event has been identified */ 694 | if(*Flag == 0x1U) { 695 | *Flag = (0x1U << 2); 696 | } else { 697 | *Flag <<= (0x1U); 698 | } 699 | status = AT_OK; 700 | } else { 701 | /* Following statement for network downlink data */ 702 | if (strncmp(ReturnResp, "+PS", sizeof("+PS")-1) == 0) { 703 | /* Event has been identified */ 704 | status = AT_OK; 705 | } else { 706 | /* Following statement for network downlink data */ 707 | if (strncmp(ReturnResp, "+TX: Done", sizeof("+TX: Done")-1) == 0) { 708 | /* Event has been identified */ 709 | status = AT_OK; 710 | } 711 | } 712 | } 713 | } 714 | } 715 | } 716 | return status; 717 | } 718 | 719 | /****************************************************************************** 720 | * @brief format the AT frame to be sent to the modem (slave) 721 | * @param pointer to the format string 722 | * @retval len of the string to be sent 723 | ******************************************************************************/ 724 | uint16_t at_cmd_vprintf(const char *format, ...) 725 | { 726 | va_list args; 727 | uint16_t len; 728 | 729 | va_start(args, format); 730 | 731 | len = tiny_vsnprintf_like(LoRa_AT_Cmd_Buff+Offset, 732 | sizeof(LoRa_AT_Cmd_Buff)-Offset, format, args); 733 | 734 | va_end(args); 735 | 736 | return len; 737 | } 738 | 739 | #ifdef __cplusplus 740 | } 741 | #endif 742 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 743 | -------------------------------------------------------------------------------- /src/i_nucleo_lrwan1_wm_sg_sm_xx.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * @file i_nucleo_lrwan1_wm_sg_sm_xx.h based on V1.0.1 3 | * @author MCD Application Team 4 | * @brief driver I_NUCLEO_LRWAN1 for WM_SG_SM_XX modem board 5 | ****************************************************************************** 6 | * @attention 7 | * 8 | *

© COPYRIGHT(c) 2017 STMicroelectronics

9 | * 10 | * Redistribution and use in source and binary forms, with or without modification, 11 | * are permitted provided that the following conditions are met: 12 | * 1. Redistributions of source code must retain the above copyright notice, 13 | * this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright notice, 15 | * this list of conditions and the following disclaimer in the documentation 16 | * and/or other materials provided with the distribution. 17 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 18 | * may be used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | * 32 | ****************************************************************************** 33 | */ 34 | /* Define to prevent recursive inclusion -------------------------------------*/ 35 | #ifndef __I_NUCLEO_LRWAN1_WM_SG_SM_XX_H__ 36 | #define __I_NUCLEO_LRWAN1_WM_SG_SM_XX_H__ 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | #include "tiny_sscanf.h" 43 | #include "tiny_vsnprintf.h" 44 | 45 | /* Includes ------------------------------------------------------------------*/ 46 | /* Exported types ------------------------------------------------------------*/ 47 | /* Exported constants --------------------------------------------------------*/ 48 | 49 | /* 50 | * Max size of the received buffer to optimize 51 | * what we can match with device key sizeof 52 | */ 53 | #define DATA_RX_MAX_BUFF_SIZE 128 54 | /* 55 | * Max size of the transmit buffer, 56 | * it is the worst-case when sending 57 | * a max payload equal to 64 bytes 58 | */ 59 | #define DATA_TX_MAX_BUFF_SIZE 78 60 | /* AT command response timeout in ms */ 61 | #define RESPONSE_TIMEOUT 1500 62 | /* 63 | * Delay before reception: 64 | * rx1 delay + rx2 delay + SF12 transmision time = 1s + 2s + 1.5s = 4.5s 65 | */ 66 | #define ASYNC_EVENT_TIMEOUT 5000 67 | 68 | /* Exported types ------------------------------------------------------------*/ 69 | 70 | typedef enum ATGroup 71 | { 72 | AT_CTRL = 0, 73 | AT_SET, 74 | AT_GET, 75 | AT_EXCEPT, 76 | AT_ASYNC_EVENT, 77 | AT_EXCEPT_1, 78 | } ATGroup_t; 79 | 80 | typedef enum Marker_s 81 | { 82 | CTRL_MARKER = 0, 83 | SET_MARKER, 84 | GET_MARKER, 85 | } Marker_t; 86 | 87 | /*****************************************************************************/ 88 | /* Here we have to include a list of AT cmd by the way of #include */ 89 | /* this file will be preprocessed for enum ATCmd, enum eATerror and AT marker*/ 90 | /* define */ 91 | /*****************************************************************************/ 92 | #define AT_ERROR_INDEX 93 | #define AT_CMD_INDEX 94 | #define AT_CMD_MARKER 95 | #include "atcmd_modem.h" /*to include WM_SG_SM_42 specific string AT cmd definition*/ 96 | 97 | /*! 98 | * \brief Modem driver definition 99 | */ 100 | typedef struct Modem_s 101 | { 102 | /*! 103 | * \brief Initializes the IO interface of the Modem 104 | */ 105 | ATEerror_t ( *IoInit )( void ); 106 | /*! 107 | * \brief DeInitializes the IO interface of the Modem 108 | */ 109 | void ( *IoDeInit )( void ); 110 | /*! 111 | * \brief Handler for Modem AT command 112 | */ 113 | ATEerror_t ( *ATCmd )( ATGroup_t at_group, ATCmd_t Cmd, void *pdata ); 114 | 115 | } sModem_t; 116 | 117 | /* Type definition for SEND command */ 118 | typedef struct sSendDataString 119 | { 120 | char *Buffer; 121 | uint8_t Port; 122 | }sSendDataString_t; 123 | 124 | /*type definition for RECV command */ 125 | typedef struct sReceivedDataString 126 | { 127 | uint8_t *Buffer; 128 | uint8_t Port; 129 | }sReceivedDataString_t; 130 | 131 | /* Type definition for SENDB command */ 132 | typedef struct sSendDataBinary 133 | { 134 | char *Buffer; 135 | uint8_t DataSize; 136 | uint8_t Port; 137 | uint8_t Ack; 138 | }sSendDataBinary_t; 139 | 140 | /* Type definition for RECVB command */ 141 | typedef struct sReceivedDataBinary 142 | { 143 | uint8_t *Buffer; 144 | uint32_t DataSize; 145 | uint8_t Port; 146 | }sReceivedDataBinary_t; 147 | 148 | /* Type definition for return code analysis */ 149 | typedef char* ATEerrorStr_t; 150 | 151 | typedef struct RetCode_s{ 152 | ATEerrorStr_t RetCodeStr; 153 | int SizeRetCodeStr; 154 | ATEerror_t RetCode; 155 | } ATE_RetCode_t; 156 | 157 | /* Type definition for the MCU power Control setting */ 158 | typedef struct sPowerCtrlSet{ 159 | uint8_t SetType; 160 | uint8_t Value; 161 | uint8_t AutoSleepTime; 162 | } sPowerCtrlSet_t; 163 | 164 | /* Type definition for the radio setting */ 165 | typedef struct sRadioCtrlSet{ 166 | uint8_t power; 167 | uint32_t frequency; 168 | uint8_t sf; 169 | uint8_t bw; 170 | uint8_t codingRate; 171 | bool crc; 172 | uint16_t preamble; 173 | bool invIQ; 174 | } sRadioCtrlSet_t; 175 | 176 | /* Type definition for the TXT command */ 177 | typedef struct sSendData{ 178 | uint16_t NbRep; 179 | uint8_t *Buffer; 180 | uint8_t DataSize; 181 | } sSendData_t; 182 | 183 | /* Type definition for AT cmd format identification */ 184 | typedef enum Fmt 185 | { 186 | FORMAT_VOID_PARAM, 187 | FORMAT_8_02X_PARAM, 188 | FORMAT_16_02X_PARAM, 189 | FORMAT_32_02X_PARAM, 190 | FORMAT_32_D_PARAM, 191 | FORMAT_8_D_PARAM, 192 | FORMAT_8_C_PARAM, 193 | FORMAT_PLAIN_TEXT, 194 | FORMAT_BINARY_TEXT 195 | } Fmt_t; 196 | 197 | /* Exported macros -----------------------------------------------------------*/ 198 | /* AT printf */ 199 | #define AT_VPRINTF(...) at_cmd_vprintf(__VA_ARGS__) 200 | 201 | #define AT_VSSCANF(...) tiny_sscanf(__VA_ARGS__) 202 | 203 | /* Exported functions ------------------------------------------------------- */ 204 | uint16_t at_cmd_vprintf(const char *format, ...); 205 | 206 | /****************************************************************************** 207 | * @brief Configures modem UART interface. 208 | * @param None 209 | * @retval AT_OK in case of success 210 | * @retval AT_UART_LINK_ERROR in case of failure 211 | *****************************************************************************/ 212 | ATEerror_t Modem_IO_Init( void *serial ) ; 213 | 214 | /****************************************************************************** 215 | * @brief Deinitialise modem UART interface. 216 | * @param None 217 | * @retval None 218 | *****************************************************************************/ 219 | void Modem_IO_DeInit( void ) ; 220 | 221 | /****************************************************************************** 222 | * @brief Handle the AT cmd following their Groupp type 223 | * @param at_group AT group [control, set , get) 224 | * Cmd AT command 225 | * pdata pointer to the IN/OUT buffer 226 | * @retval module status 227 | *****************************************************************************/ 228 | ATEerror_t Modem_AT_Cmd(ATGroup_t at_group, ATCmd_t Cmd, void *pdata ); 229 | 230 | #ifdef __cplusplus 231 | } 232 | #endif 233 | 234 | #endif /* __I_NUCLEO_LRWAN1_WM_SG_SM_XX_H__*/ 235 | 236 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 237 | -------------------------------------------------------------------------------- /src/lora_driver.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file lora_driver.h based on V1.1.2 3 | * @author MCD Application Team 4 | * @brief Header for lora driver module 5 | ****************************************************************************** 6 | * @attention 7 | * 8 | *

© Copyright (c) 2017 STMicroelectronics International N.V. 9 | * All rights reserved.

10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted, provided that the following conditions are met: 13 | * 14 | * 1. Redistribution of source code must retain the above copyright notice, 15 | * this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright notice, 17 | * this list of conditions and the following disclaimer in the documentation 18 | * and/or other materials provided with the distribution. 19 | * 3. Neither the name of STMicroelectronics nor the names of other 20 | * contributors to this software may be used to endorse or promote products 21 | * derived from this software without specific written permission. 22 | * 4. This software, including modifications and/or derivative works of this 23 | * software, must execute solely and exclusively on microcontroller or 24 | * microprocessor devices manufactured by or for STMicroelectronics. 25 | * 5. Redistribution and use of this software other than as permitted under 26 | * this license is void and will automatically terminate your rights under 27 | * this license. 28 | * 29 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 30 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 32 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 33 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 34 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 35 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 37 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 38 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 39 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 40 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | * 42 | ****************************************************************************** 43 | */ 44 | 45 | /* Define to prevent recursive inclusion -------------------------------------*/ 46 | #ifndef __LORA_DRIVER_H__ 47 | #define __LORA_DRIVER_H__ 48 | 49 | #ifdef __cplusplus 50 | extern "C" { 51 | #endif 52 | 53 | /* Includes ------------------------------------------------------------------*/ 54 | #include "i_nucleo_lrwan1_wm_sg_sm_xx.h" 55 | #include "hw.h" 56 | 57 | /* Exported types ------------------------------------------------------------*/ 58 | typedef enum RetCode 59 | { 60 | MODULE_READY, 61 | MODULE_NO_READY, 62 | MODULE_UART_ERROR, 63 | } RetCode_t; 64 | 65 | /* Exported constants --------------------------------------------------------*/ 66 | /* External variables --------------------------------------------------------*/ 67 | extern bool AT_VERB_cmd; 68 | /* Exported macros -----------------------------------------------------------*/ 69 | 70 | /* wait time to request Join status*/ 71 | #define DELAY_FOR_JOIN_STATUS_REQ 15000 72 | 73 | /* LoRa network join mode */ 74 | #define OTAA_JOIN_MODE 1 75 | #define ABP_JOIN_MODE 0 76 | 77 | /* Payload size limitation */ 78 | #define MAX_PAYLOAD_LENGTH 64U 79 | 80 | 81 | /* Exported functions ------------------------------------------------------- */ 82 | 83 | /************ connection management ************/ 84 | 85 | /************************************************************** 86 | * @brief Check if the LoRa module is working 87 | * @param void 88 | * @retval status of the module (ready or not ready) 89 | **************************************************************/ 90 | RetCode_t Lora_Init(void); 91 | 92 | /************************************************************** 93 | * @brief reset of the LoRa module 94 | * @param void 95 | * @retval void 96 | **************************************************************/ 97 | void Lora_Reset(void); 98 | 99 | /************************************************************** 100 | * @brief Do a request to establish a LoRa Connection with the gateway 101 | * @param Mode: by OTAA or by ABP 102 | * @retval LoRA return code 103 | **************************************************************/ 104 | ATEerror_t Lora_Join(uint8_t Mode); 105 | 106 | /************************************************************** 107 | * @brief Wait for join accept notification either in ABP or OTAA 108 | * @param void 109 | * @retval LoRA return code 110 | * @Nota this function supports either USI protocol or MDM32L07X01 protocol 111 | **************************************************************/ 112 | ATEerror_t Lora_JoinAccept(void); 113 | 114 | /************************************************************** 115 | * @brief Do a request to set the Network join Mode 116 | * @param Mode : OTA, ABP 117 | * @retval LoRa return code 118 | **************************************************************/ 119 | ATEerror_t Lora_SetJoinMode(uint8_t Mode); 120 | 121 | /************************************************************** 122 | * @brief Do a request to get the Network join Mode 123 | * @param pointer to the Join mode out value 124 | * @retval LoRa return code 125 | **************************************************************/ 126 | ATEerror_t Lora_GetJoinMode(uint8_t *Mode); 127 | 128 | /************ MiB management *******************/ 129 | 130 | /************************************************************** 131 | * @brief key configuration 132 | * @param KeyType : APPKEY, NWKSKE, APPSKEY 133 | * @retval LoRa return code 134 | **************************************************************/ 135 | ATEerror_t LoRa_SetKey(ATCmd_t KeyType, uint8_t *PtrKey); 136 | 137 | 138 | /************************************************************** 139 | * @brief Request the key type configuration 140 | * @param KeyType : APPKEY, NWKSKE, APPSKEY 141 | * @retval LoRa return code 142 | **************************************************************/ 143 | ATEerror_t LoRa_GetKey(ATCmd_t KeyType, uint8_t *PtrKey); 144 | 145 | 146 | /************************************************************** 147 | * @brief Set the Application Identifier 148 | * @param pointer to the APPEUI in value 149 | * @retval LoRa return code 150 | **************************************************************/ 151 | ATEerror_t LoRa_SetAppID(uint8_t *PtrAppID); 152 | 153 | 154 | /************************************************************** 155 | * @brief Request the Application Identifier 156 | * @param pointer to the APPEUI out value 157 | * @retval LoRa return code 158 | **************************************************************/ 159 | ATEerror_t LoRa_GetAppID(uint8_t *AppEui); 160 | 161 | 162 | /************************************************************** 163 | * @brief Set the device extended universal indentifier 164 | * @param pointer to the DEUI in value 165 | * @retval LoRa return code 166 | **************************************************************/ 167 | ATEerror_t LoRa_SetDeviceID(uint8_t *PtrDeviceID); 168 | 169 | 170 | /************************************************************** 171 | * @brief Request the device extended universal indentifier 172 | * @param pointer to the DEUI out value 173 | * @retval LoRa return code 174 | **************************************************************/ 175 | ATEerror_t LoRa_GetDeviceID(uint8_t *PtrDeviceID); 176 | 177 | 178 | /************************************************************** 179 | * @brief Set the device address 180 | * @param pointer to the DADDR in value 181 | * @retval LoRa return code 182 | **************************************************************/ 183 | ATEerror_t LoRa_SetDeviceAddress(uint32_t DeviceAddr); 184 | 185 | 186 | /************************************************************** 187 | * @brief Request the device address 188 | * @param pointer to the DADDR out value 189 | * @retval LoRa return code 190 | **************************************************************/ 191 | ATEerror_t LoRa_GetDeviceAddress(uint32_t *DeviceAddr); 192 | 193 | 194 | /************************************************************** 195 | * @brief Set the NetWork ID 196 | * @param NWKID in value 197 | * @retval LoRa return code 198 | **************************************************************/ 199 | ATEerror_t LoRa_SetNetworkID(uint32_t NetworkID); 200 | 201 | 202 | /************************************************************** 203 | * @brief Request the network ID 204 | * @param pointer to the NWKID out value 205 | * @retval LoRa return code 206 | **************************************************************/ 207 | ATEerror_t LoRa_GetNetworkID(uint32_t *NetworkID); 208 | 209 | /************ Network Management ***************/ 210 | 211 | /************************************************************** 212 | * @brief Do a request to set the adaptive data rate 213 | * @param ADR in value 0(off) / 1(on) 214 | * @retval LoRa return code 215 | **************************************************************/ 216 | ATEerror_t Lora_SetAdaptiveDataRate(uint8_t Rate); 217 | 218 | 219 | /************************************************************** 220 | * @brief Do a request to get the adaptive data rate 221 | * @param pointer to ADR out value 222 | * @retval LoRa return code 223 | **************************************************************/ 224 | ATEerror_t Lora_GetAdaptiveDataRate(uint8_t *Rate); 225 | 226 | 227 | /************************************************************** 228 | * @brief Do a request to set the LoRa Class 229 | * @param CLASS in value [0,1,2] 230 | * @retval LoRa return code 231 | **************************************************************/ 232 | ATEerror_t Lora_SetClass(uint8_t Class); 233 | 234 | 235 | /************************************************************** 236 | * @brief Do a request to get the LoRa class 237 | * @param pointer to CLASS out value 238 | * @retval LoRa return code 239 | **************************************************************/ 240 | ATEerror_t Lora_GetClass(uint8_t *Class); 241 | 242 | 243 | /************************************************************** 244 | * @brief Do a request to set the duty cycle 245 | * @brief only used in test mode 246 | * @param DCS in value 0(disable) / 1(enable) 247 | * @retval LoRa return code 248 | **************************************************************/ 249 | ATEerror_t Lora_SetDutyCycle(uint8_t DutyCycle); 250 | 251 | 252 | /************************************************************** 253 | * @brief Do a request to get the duty cycle 254 | * @param pointer to DR out value 255 | * @retval LoRa return code 256 | **************************************************************/ 257 | ATEerror_t Lora_GetDutyCycle(uint8_t *DutyCycle); 258 | 259 | 260 | /************************************************************** 261 | * @brief Do a request to set the data Rate 262 | * @param DR in value [0,1,2,3,4,5,6,7] 263 | * @retval LoRa return code 264 | **************************************************************/ 265 | ATEerror_t Lora_SetDataRate(uint8_t DataRate); 266 | 267 | 268 | /************************************************************** 269 | * @brief Do a request to get the data Rate 270 | * @param pointer to DR out value 271 | * @retval LoRa return code 272 | **************************************************************/ 273 | ATEerror_t Lora_GetDataRate(uint8_t *DataRate); 274 | 275 | 276 | /************************************************************** 277 | * @brief Do a request to set the frame counter 278 | * @param FrameCounterType : FCD, FCU 279 | * @retval LoRa return code 280 | **************************************************************/ 281 | ATEerror_t LoRa_SetFrameCounter(ATCmd_t FrameCounterType, 282 | uint32_t FrameCounternumber); 283 | 284 | 285 | /************************************************************** 286 | * @brief Request the frame counter number 287 | * @param frameCounterType : FCD, FCU 288 | * @retval LoRa return code 289 | **************************************************************/ 290 | ATEerror_t LoRa_GetFrameCounter(ATCmd_t FrameCounterType, 291 | uint32_t *FrameCounternumber); 292 | 293 | 294 | /************************************************************** 295 | * @brief Do a request to set the join accept delay between 296 | * @brief the end of the Tx and the join Rx#n window 297 | * @param RxWindowType : JN1DL, JN2DL 298 | * @retval LoRa return code 299 | **************************************************************/ 300 | ATEerror_t LoRa_SetJoinDelayRxWind(ATCmd_t RxWindowType, 301 | uint32_t JoinDelayInMs) ; 302 | 303 | /************************************************************** 304 | * @brief Do a request to get the join accept delay between 305 | * @brief the end of the Tx and the join Rx#n window 306 | * @param RxWindowType : JN1DL, JN2DL 307 | * @retval LoRa return code 308 | **************************************************************/ 309 | ATEerror_t LoRa_GetJoinDelayRxWind(ATCmd_t FrameCounterType, 310 | uint32_t *JoinDelayInMs); 311 | 312 | 313 | /************************************************************** 314 | * @brief Do a request to set the Public Network mode 315 | * @param PNM in value 0(off) / 1(on) 316 | * @retval LoRa return code 317 | **************************************************************/ 318 | ATEerror_t Lora_SetPublicNetworkMode(uint8_t NetworkMode); 319 | 320 | 321 | /************************************************************** 322 | * @brief Do a request to get the Public Network mode 323 | * @param pointer to PNM out value 324 | * @retval LoRa return code 325 | **************************************************************/ 326 | ATEerror_t Lora_GetPublicNetworkMode(uint8_t *NetworkMode); 327 | 328 | 329 | /************************************************************** 330 | * @brief Do a request to set the delay between the end of the Tx 331 | * @brief the end of the Tx and the join Rx#n window 332 | * @param RxWindowType : RX1DL, RX2DL 333 | * @retval LoRa return code 334 | **************************************************************/ 335 | ATEerror_t LoRa_SetDelayRxWind(ATCmd_t RxWindowType, uint32_t RxDelayInMs); 336 | 337 | 338 | /************************************************************** 339 | * @brief Do a request to get the delay between the end of the Tx 340 | * @brief the end of the Tx and the join Rx#n window 341 | * @param RxWindowType : RX1DL, RX2DL 342 | * @retval LoRa return code 343 | **************************************************************/ 344 | ATEerror_t LoRa_GetDelayRxWind(ATCmd_t RxWindowType,uint32_t *RxDelayInMs); 345 | 346 | 347 | /************************************************************** 348 | * @brief Set the frequency of the Rx2 window 349 | * @param pointer to the RX2FQ in value 350 | * @retval LoRa return code 351 | **************************************************************/ 352 | ATEerror_t LoRa_SetFreqRxWind2(uint32_t Rx2WindFrequency); 353 | 354 | 355 | /************************************************************** 356 | * @brief Request the frequency of the Rx2 window 357 | * @param pointer to the RX2FQ out value 358 | * @retval LoRa return code 359 | **************************************************************/ 360 | ATEerror_t LoRa_GetFreqRxWind2(uint32_t *Rx2WindFrequency); 361 | 362 | 363 | /************************************************************** 364 | * @brief Do a request to set the transmit Tx power 365 | * @param TXP in value [0,1,2,3,4,5] 366 | * @retval LoRa return code 367 | **************************************************************/ 368 | ATEerror_t Lora_SetTxPower(uint8_t TransmitTxPower); 369 | 370 | 371 | /************************************************************** 372 | * @brief Do a request to get the transmit Tx Power 373 | * @param pointer to TXP out value 374 | * @retval LoRa return code 375 | **************************************************************/ 376 | ATEerror_t Lora_GetTxPower(uint8_t *TransmitTxPower); 377 | 378 | 379 | 380 | /************************************************************** 381 | * @brief Do a request to set the data Rate of Rx2 window 382 | * @param RX2DR in value [0,1,2,3,4,5,6,7] 383 | * @retval LoRa return code 384 | **************************************************************/ 385 | ATEerror_t Lora_SetDataRateRxWind2(uint8_t DataRateRxWind2); 386 | 387 | 388 | /************************************************************** 389 | * @brief Do a request to get the data Rate of Rx2 window 390 | * @param pointer to RX2DR out value 391 | * @retval LoRa return code 392 | **************************************************************/ 393 | ATEerror_t Lora_GetDataRateRxWind2(uint8_t *DataRateRxWind2); 394 | 395 | 396 | /************ Data Path Management ***************/ 397 | 398 | /************************************************************** 399 | * @brief Send text data to a giving prot number 400 | * @param SEND in data struct (ptrString,port) 401 | * @retval LoRa return code 402 | **************************************************************/ 403 | ATEerror_t Lora_SendData(sSendDataString_t *PtrStructData); 404 | 405 | 406 | /************************************************************** 407 | * @brief Do a request to get the last data (in raw format) 408 | * @brief received by the Slave 409 | * @param pointer to RECV out value 410 | * @retval LoRa return code 411 | **************************************************************/ 412 | ATEerror_t Lora_ReceivedData(sReceivedDataString_t *PtrStructData); 413 | 414 | 415 | /************************************************************** 416 | * @brief Trap an asynchronous event coming from external modem (only USI device) 417 | * @param Pointer to RCV out value if any 418 | * @retval LoRa return code 419 | **************************************************************/ 420 | ATEerror_t Lora_AsyncDownLinkData(sReceivedDataBinary_t *PtrStructData); 421 | 422 | /************************************************************** 423 | * @brief Send binary data to a giving port number 424 | * @param SENDB in value 425 | * @retval LoRa return code 426 | **************************************************************/ 427 | ATEerror_t Lora_SendDataBin(sSendDataBinary_t *PtrStructData); 428 | 429 | 430 | /************************************************************** 431 | * @brief Do a request to get the last data (in binary format) 432 | * @brief received by the Slave 433 | * @param pointer to RECVB out value 434 | * @retval LoRa return code 435 | **************************************************************/ 436 | ATEerror_t Lora_ReceivedDataBin(sReceivedDataBinary_t *PtrStructData); 437 | 438 | /************************************************************** 439 | * @brief Do a request to set the confirmation mode 440 | * @param CFM in value 0(unconfirm) / 1(confirm) 441 | * @retval LoRa return code 442 | **************************************************************/ 443 | ATEerror_t Lora_SetSendMsgConfirm(uint8_t ConfirmMode); 444 | 445 | /************************************************************** 446 | * @brief Do a request to get the confirmation mode 447 | * @param pointer to CFM out value 448 | * @retval LoRa return code 449 | **************************************************************/ 450 | ATEerror_t Lora_GetSendMsgConfirm(uint8_t *ConfirmMode); 451 | 452 | 453 | /************************************************************** 454 | * @brief Do a request to get the msg status of the last send cmd 455 | * @param CFS in value 0(unconfirm) / 1(confirm) 456 | * @retval LoRa return code 457 | **************************************************************/ 458 | ATEerror_t Lora_GetSendMsgStatus(uint8_t *MsgStatus); 459 | 460 | /************************************************************** 461 | * @brief Do a request to get the battery level of the modem (slave) 462 | * @param BAT in value 463 | * 0: battery connected to external power supply 464 | * [1..254]: 1 being at minimum and 254 being at maximum 465 | * 255: not able to measure the battery level 466 | * @retval LoRa return code 467 | **************************************************************/ 468 | ATEerror_t Lora_GetBatLevel(uint32_t *BatLevel); 469 | 470 | 471 | /************************************************************** 472 | * @brief Do a request to get the RSSI of the last received packet 473 | * @param RSSI in value [in dbm] 474 | * @retval LoRa return code 475 | **************************************************************/ 476 | ATEerror_t Lora_GetRSSI(int32_t *SigStrengthInd); 477 | 478 | /************************************************************** 479 | * @brief Do a request to get the SNR of the last received packet 480 | * @param SNR in value [in db] 481 | * @retval LoRa return code 482 | **************************************************************/ 483 | ATEerror_t Lora_GetSNR(uint32_t *SigToNoice); 484 | 485 | 486 | /************************************************************** 487 | * @brief Do a request to set the country band code for LoRaWAN 488 | * @brief Need to write to DCT and Reset module to enable this setting 489 | * @param BAND in value 0(EU-868 Band) / 1(US-Band) 490 | * @retval LoRa return code 491 | **************************************************************/ 492 | ATEerror_t Lora_SetDeviceBand(uint8_t DeviceBand); 493 | 494 | 495 | /************************************************************** 496 | * @brief Do a request to get the country band code for LoRaWAN 497 | * @brief only used in test mode 498 | * @param pointer to BAND out value 499 | * @retval LoRa return code 500 | **************************************************************/ 501 | ATEerror_t Lora_GetDeviceBand(uint8_t *DeviceBand); 502 | 503 | 504 | /************************************************************** 505 | * @brief Do a request to get the firmware version of the modem (slave) 506 | * @param pointer to VER out value 507 | * @retval LoRa return code 508 | **************************************************************/ 509 | ATEerror_t Lora_GetVersion(uint8_t *PtrVersion); 510 | 511 | 512 | /************************************************************** 513 | * @brief Do a request to get the firmware version of the modem (slave) 514 | * @param pointer to FWVERSION out value 515 | * @retval LoRa return code 516 | **************************************************************/ 517 | ATEerror_t Lora_GetFWVersion(uint8_t *PtrFWVersion); 518 | 519 | 520 | /************************************************************** 521 | * @brief Do a request to enter the slave in sleep (MCU STOP mode) 522 | * @param Void 523 | * @retval LoRa return code 524 | **************************************************************/ 525 | ATEerror_t Lora_SleepMode(void); 526 | 527 | 528 | /************************************************************** 529 | * @brief Wait for mcu is going to sleep or is waked up 530 | * @param void 531 | * @retval LoRA return code 532 | **************************************************************/ 533 | ATEerror_t Lora_SleepStatus(void); 534 | 535 | 536 | /************************************************************** 537 | * @brief Do a request to set the power control settings of the MCU (slave) 538 | * @param Power control IN value 539 | * @retval LoRa return code 540 | **************************************************************/ 541 | ATEerror_t Lora_SetMCUPowerCtrl(sPowerCtrlSet_t *PtrStructData); 542 | 543 | /************************************************************** 544 | * @brief Do a Dumy request to resynchronize the Host and the modem 545 | * @note A simple AT cmd where we do not trap the return code 546 | * @param void 547 | * @retval LoRa return code 548 | **************************************************************/ 549 | ATEerror_t LoRa_DumyRequest(void); 550 | 551 | 552 | /************ DCT commands ***************/ 553 | 554 | /************************************************************** 555 | * @brief Do a request to restore DCT content table with default values 556 | * @param void 557 | * @retval LoRa return code 558 | **************************************************************/ 559 | ATEerror_t Lora_RestoreConfigTable(void); 560 | 561 | 562 | /************************************************************** 563 | * @brief Do a request to update the DCT content table with new values 564 | * @param void 565 | * @retval LoRa return code 566 | **************************************************************/ 567 | ATEerror_t Lora_UpdateConfigTable(void); 568 | 569 | /************************************************************** 570 | * @brief Convert keys from char to uint8_t 571 | * @param Key to convert. 572 | * @param Key converted. 573 | * @param length of the integer key. 574 | **************************************************************/ 575 | void keyCharToInt(const char *cKey, uint8_t *iKey, uint8_t length); 576 | 577 | /************************************************************** 578 | * @brief Convert keys from uint8_t to char 579 | * @param Key converted. 580 | * @param Key to convert. 581 | * @param length of the integer key. 582 | **************************************************************/ 583 | void keyIntToChar(char *cKey, const uint8_t *iKey, uint8_t length); 584 | 585 | #ifdef __cplusplus 586 | } 587 | #endif 588 | 589 | #endif /* __LORA_DRIVER_H__ */ 590 | 591 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 592 | -------------------------------------------------------------------------------- /src/tiny_sscanf.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file tiny_sscanf.c 3 | * @author MCD Application Team 4 | * @version V1.1.2 5 | * @date 08-September-2017 6 | * @brief Tiny implementation of sscanf 7 | ****************************************************************************** 8 | * @attention 9 | * 10 | *

© Copyright (c) 2017 STMicroelectronics International N.V. 11 | * All rights reserved.

12 | * 13 | * Copyright (c) 1990, 1993 14 | * The Regents of the University of California. All rights reserved. 15 | * 16 | * This code is derived from software contributed to Berkeley by 17 | * Chris Torek. 18 | * Redistribution and use in source and binary forms, with or without 19 | * modification, are permitted, provided that the following conditions are met: 20 | * 21 | * 1. Redistribution of source code must retain the above copyright notice, 22 | * this list of conditions and the following disclaimer. 23 | * 2. Redistributions in binary form must reproduce the above copyright notice, 24 | * this list of conditions and the following disclaimer in the documentation 25 | * and/or other materials provided with the distribution. 26 | * 3. Neither the name of STMicroelectronics nor the names of other 27 | * contributors to this software may be used to endorse or promote products 28 | * derived from this software without specific written permission. 29 | * 4. This software, including modifications and/or derivative works of this 30 | * software, must execute solely and exclusively on microcontroller or 31 | * microprocessor devices manufactured by or for STMicroelectronics. 32 | * 5. Redistribution and use of this software other than as permitted under 33 | * this license is void and will automatically terminate your rights under 34 | * this license. 35 | * 36 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 37 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 38 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 39 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 40 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 41 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 44 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 45 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 46 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 47 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | ****************************************************************************** 50 | */ 51 | /* $OpenBSD: sscanf.c,v 1.12 2005/08/08 08:05:36 espie Exp $ */ 52 | /*- 53 | * Copyright (c) 1990, 1993 54 | * The Regents of the University of California. All rights reserved. 55 | * 56 | * This code is derived from software contributed to Berkeley by 57 | * Chris Torek. 58 | * 59 | * Redistribution and use in source and binary forms, with or without 60 | * modification, are permitted provided that the following conditions 61 | * are met: 62 | * 1. Redistributions of source code must retain the above copyright 63 | * notice, this list of conditions and the following disclaimer. 64 | * 2. Redistributions in binary form must reproduce the above copyright 65 | * notice, this list of conditions and the following disclaimer in the 66 | * documentation and/or other materials provided with the distribution. 67 | * 3. Neither the name of the University nor the names of its contributors 68 | * may be used to endorse or promote products derived from this software 69 | * without specific prior written permission. 70 | * 71 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 72 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 73 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 74 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 75 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 76 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 77 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 78 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 79 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 80 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 81 | * SUCH DAMAGE. 82 | */ 83 | 84 | 85 | /* 86 | * This code is derived from 87 | * https://github.com/rapid7/metasploit-payloads/, in c/meterpreter/source/bionic/libc/stdio/sscanf.c 88 | * It has been derived in order to optimize code size. In this context 89 | * all the formats are not supported. Current supported formats are 90 | * %hx, %hhx, %ul, %d,... 91 | * when TINY_SSCANF is defined 92 | * 93 | * When TINY_NO_OX is defined, this is not possible to sscanf("%x") of "0xab", 94 | * only "ab" is possible 95 | * 96 | * When TINY_SPACE_NOT_SPECIALCASE is defined, "space" is not a special character. 97 | * That means that we expect a single space, and not any of ispace() character 98 | * (space, tabs,...) 99 | */ 100 | 101 | #ifdef __cplusplus 102 | extern "C" { 103 | #endif 104 | 105 | #include 106 | #include 107 | #include 108 | #include 109 | #include 110 | #include 111 | #include "tiny_sscanf.h" 112 | 113 | /* Private typedef -----------------------------------------------------------*/ 114 | /* Private define ------------------------------------------------------------*/ 115 | #define TINY_SSCANF 116 | #define TINY_NO_OX 117 | #define TINY_SPACE_NOT_SPECIALCASE 118 | 119 | /* Private macro -------------------------------------------------------------*/ 120 | /* Private variables ---------------------------------------------------------*/ 121 | /* Functions Definition ------------------------------------------------------*/ 122 | 123 | #ifdef FLOATING_POINT 124 | #include "floatio.h" 125 | #endif 126 | 127 | #define BUF 513 /* Maximum length of numeric string. */ 128 | 129 | /* 130 | * Flags used during conversion. 131 | */ 132 | #define LONG 0x00001 /* l: long or double */ 133 | #define SHORT 0x00004 /* h: short */ 134 | #define SHORTSHORT 0x00008 /* hh: 8 bit integer */ 135 | #define UNSIGNED 0x00800 /* %[oupxX] conversions */ 136 | #ifdef TINY_SSCANF 137 | #else 138 | #define LONGDBL 0x00002 /* L: long double; unimplemented */ 139 | #define LLONG 0x00010 /* ll: long long (+ deprecated q: quad) */ 140 | #define POINTER 0x00020 /* p: void * (as hex) */ 141 | #define SIZEINT 0x00040 /* z: (signed) size_t */ 142 | #define MAXINT 0x00080 /* j: intmax_t */ 143 | #define PTRINT 0x00100 /* t: ptrdiff_t */ 144 | #define NOSKIP 0x00200 /* [ or c: do not skip blanks */ 145 | #define SUPPRESS 0x00400 /* *: suppress assignment */ 146 | #endif 147 | 148 | /* 149 | * The following are used in numeric conversions only: 150 | * SIGNOK, HAVESIGN, NDIGITS, DPTOK, and EXPOK are for floating point; 151 | * SIGNOK, HAVESIGN, NDIGITS, PFXOK, and NZDIGITS are for integral. 152 | */ 153 | #define SIGNOK 0x01000 /* +/- is (still) legal */ 154 | #define HAVESIGN 0x02000 /* sign detected */ 155 | #define NDIGITS 0x04000 /* no digits detected */ 156 | 157 | #define DPTOK 0x08000 /* (float) decimal point is still legal */ 158 | #define EXPOK 0x10000 /* (float) exponent (e+3, etc) still legal */ 159 | 160 | #ifdef TINY_NO_OX 161 | #else 162 | #define PFXOK 0x08000 /* 0x prefix is (still) legal */ 163 | #define NZDIGITS 0x10000 /* no zero digits detected */ 164 | #endif 165 | 166 | /* 167 | * Conversion types. 168 | */ 169 | #define CT_INT 3 /* integer, i.e., strtoimax or strtoumax */ 170 | #define CT_FLOAT 4 /* floating, i.e., strtod */ 171 | 172 | #ifdef TINY_SSCANF 173 | #else 174 | #define CT_CHAR 0 /* %c conversion */ 175 | #define CT_CCL 1 /* %[...] conversion */ 176 | #define CT_STRING 2 /* %s conversion */ 177 | #endif 178 | 179 | #define u_char unsigned char 180 | #define u_long unsigned long 181 | 182 | #ifdef TINY_SSCANF 183 | #else 184 | static u_char *__sccl(char *, u_char *); 185 | #endif 186 | 187 | #define VFSCANF tiny_vfscanf 188 | 189 | #if !defined(VFSCANF) 190 | #define VFSCANF vfscanf 191 | #endif 192 | 193 | 194 | #define __srefill(_x) 1 195 | #define ungetc(_c, _fp) do { (_c), fp_p--; fp_r++; } while (0) 196 | 197 | /* 198 | * vfscanf 199 | */ 200 | static inline int 201 | VFSCANF(const char *str, const char *fmt0, va_list ap) 202 | { 203 | u_char *fmt = (u_char *)fmt0; 204 | int c; /* character from format, or conversion */ 205 | size_t width; /* field width, or 0 */ 206 | char *p; /* points into all kinds of strings */ 207 | int flags; /* flags as defined above */ 208 | int nassigned; /* number of fields assigned */ 209 | int nread; /* number of characters consumed from fp */ 210 | int base; /* base argument to strtoimax/strtouimax */ 211 | char buf[BUF]; /* buffer for numeric conversions */ 212 | const char *fp_p; 213 | int fp_r; 214 | uintmax_t value; 215 | int sign_minus; 216 | 217 | 218 | #ifdef TINY_SSCANF 219 | #else 220 | int n; /* handy integer */ 221 | char *p0; /* saves original value of p when necessary */ 222 | char ccltab[256]; /* character class table for %[...] */ 223 | #endif 224 | 225 | /* `basefix' is used to avoid `if' tests in the integer scanner */ 226 | #ifdef TINY_SSCANF 227 | /* basefix[] can be removed as we do not support %i */ 228 | #else 229 | static short basefix[17] = 230 | { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; 231 | #endif 232 | 233 | fp_p = str; 234 | fp_r = strlen(str); 235 | 236 | nassigned = 0; 237 | nread = 0; 238 | base = 0; /* XXX just to keep gcc happy */ 239 | for (;;) { 240 | c = *fmt++; 241 | if (c == 0) 242 | return (nassigned); 243 | #ifdef TINY_SPACE_NOT_SPECIALCASE 244 | #else 245 | if (isspace(c)) { 246 | while ((fp_r > 0 || __srefill(fp) == 0) && 247 | isspace(*fp_p)) 248 | nread++, fp_r--, fp_p++; 249 | continue; 250 | } 251 | #endif 252 | if (c != '%') 253 | goto literal; 254 | width = 0; 255 | flags = 0; 256 | /* 257 | * switch on the format. continue if done; 258 | * break once format type is derived. 259 | */ 260 | again: c = *fmt++; 261 | switch (c) { 262 | case '%': 263 | literal: 264 | if (fp_r <= 0 && __srefill(fp)) 265 | goto input_failure; 266 | if (*fp_p != c) 267 | goto match_failure; 268 | fp_r--, fp_p++; 269 | nread++; 270 | continue; 271 | 272 | #ifdef TINY_SSCANF 273 | #else 274 | case '*': 275 | flags |= SUPPRESS; 276 | goto again; 277 | case 'j': 278 | flags |= MAXINT; 279 | goto again; 280 | case 'L': 281 | flags |= LONGDBL; 282 | goto again; 283 | #endif 284 | case 'h': 285 | if (*fmt == 'h') { 286 | fmt++; 287 | flags |= SHORTSHORT; 288 | } else { 289 | flags |= SHORT; 290 | } 291 | goto again; 292 | case 'l': 293 | #ifdef TINY_SSCANF 294 | /* %ll not supported */ 295 | flags |= LONG; 296 | goto again; 297 | #else 298 | if (*fmt == 'l') { 299 | fmt++; 300 | flags |= LLONG; 301 | } else { 302 | flags |= LONG; 303 | } 304 | goto again; 305 | #endif 306 | 307 | #ifdef TINY_SSCANF 308 | #else 309 | case 'q': 310 | flags |= LLONG; /* deprecated */ 311 | goto again; 312 | case 't': 313 | flags |= PTRINT; 314 | goto again; 315 | case 'z': 316 | flags |= SIZEINT; 317 | goto again; 318 | #endif 319 | case '0': case '1': case '2': case '3': case '4': 320 | case '5': case '6': case '7': case '8': case '9': 321 | width = width * 10 + c - '0'; 322 | goto again; 323 | 324 | /* 325 | * Conversions. 326 | * Those marked `compat' are for 4.[123]BSD compatibility. 327 | * 328 | * (According to ANSI, E and X formats are supposed 329 | * to the same as e and x. Sorry about that.) 330 | */ 331 | case 'D': /* compat */ 332 | flags |= LONG; 333 | /* FALLTHROUGH */ 334 | case 'd': 335 | c = CT_INT; 336 | base = 10; 337 | break; 338 | 339 | #ifdef TINY_SSCANF 340 | /* 341 | * We do not support %i to remove potential base=8 in the following 342 | * Hence basefix can be removed 343 | */ 344 | #else 345 | case 'i': 346 | c = CT_INT; 347 | base = 0; 348 | break; 349 | #endif 350 | 351 | #ifdef TINY_SSCANF 352 | #else 353 | case 'O': /* compat */ 354 | flags |= LONG; 355 | /* FALLTHROUGH */ 356 | case 'o': 357 | c = CT_INT; 358 | flags |= UNSIGNED; 359 | base = 8; 360 | break; 361 | #endif 362 | 363 | case 'u': 364 | c = CT_INT; 365 | flags |= UNSIGNED; 366 | base = 10; 367 | break; 368 | 369 | case 'X': 370 | case 'x': 371 | #ifdef TINY_NO_OX 372 | #else 373 | flags |= PFXOK; /* enable 0x prefixing */ 374 | #endif 375 | c = CT_INT; 376 | flags |= UNSIGNED; 377 | base = 16; 378 | break; 379 | 380 | #ifdef FLOATING_POINT 381 | case 'E': 382 | case 'G': 383 | case 'e': 384 | case 'f': 385 | case 'g': 386 | c = CT_FLOAT; 387 | break; 388 | #endif 389 | 390 | #ifdef TINY_SSCANF 391 | #else 392 | case 's': 393 | c = CT_STRING; 394 | break; 395 | 396 | case '[': 397 | fmt = __sccl(ccltab, fmt); 398 | flags |= NOSKIP; 399 | c = CT_CCL; 400 | break; 401 | 402 | case 'c': 403 | flags |= NOSKIP; 404 | c = CT_CHAR; 405 | break; 406 | 407 | case 'p': /* pointer format is like hex */ 408 | flags |= POINTER | PFXOK; 409 | c = CT_INT; 410 | flags |= UNSIGNED; 411 | base = 16; 412 | break; 413 | 414 | case 'n': 415 | if (flags & SUPPRESS) 416 | continue; 417 | if (flags & SHORTSHORT) 418 | *va_arg(ap, char *) = nread; 419 | else if (flags & SHORT) 420 | *va_arg(ap, short *) = nread; 421 | else if (flags & LONG) 422 | *va_arg(ap, long *) = nread; 423 | else if (flags & SIZEINT) 424 | *va_arg(ap, size_t *) = nread; 425 | else if (flags & PTRINT) 426 | *va_arg(ap, ptrdiff_t *) = nread; 427 | else if (flags & LLONG) 428 | *va_arg(ap, long long *) = nread; 429 | else if (flags & MAXINT) 430 | *va_arg(ap, intmax_t *) = nread; 431 | else 432 | *va_arg(ap, int *) = nread; 433 | continue; 434 | #endif 435 | 436 | /* 437 | * Disgusting backwards compatibility hacks. XXX 438 | */ 439 | case '\0': /* compat */ 440 | return (EOF); 441 | 442 | default: /* compat */ 443 | #ifdef TINY_SSCANF 444 | #else 445 | if (isupper(c)) 446 | flags |= LONG; 447 | c = CT_INT; 448 | base = 10; 449 | #endif 450 | break; 451 | } 452 | 453 | /* 454 | * We have a conversion that requires input. 455 | */ 456 | if (fp_r <= 0 && __srefill(fp)) 457 | goto input_failure; 458 | 459 | 460 | /* 461 | * Consume leading white space, except for formats 462 | * that suppress this. 463 | */ 464 | #ifdef TINY_SSCANF 465 | #else 466 | if ((flags & NOSKIP) == 0) { 467 | while (isspace(*fp_p)) { 468 | nread++; 469 | if (--fp_r > 0) 470 | fp_p++; 471 | else if (__srefill(fp)) 472 | goto input_failure; 473 | } 474 | /* 475 | * Note that there is at least one character in 476 | * the buffer, so conversions that do not set NOSKIP 477 | * ca no longer result in an input failure. 478 | */ 479 | } 480 | #endif 481 | 482 | /* 483 | * Do the conversion. 484 | */ 485 | switch (c) { 486 | #ifdef TINY_SSCANF 487 | #else 488 | case CT_CHAR: 489 | /* scan arbitrary characters (sets NOSKIP) */ 490 | if (width == 0) 491 | width = 1; 492 | if (flags & SUPPRESS) { 493 | size_t sum = 0; 494 | for (;;) { 495 | if ((n = fp_r) < (int)width) { 496 | sum += n; 497 | width -= n; 498 | fp_p += n; 499 | if (__srefill(fp)) { 500 | if (sum == 0) 501 | goto input_failure; 502 | break; 503 | } 504 | } else { 505 | sum += width; 506 | fp_r -= width; 507 | fp_p += width; 508 | break; 509 | } 510 | } 511 | nread += sum; 512 | } else { 513 | size_t r = fread((void *)va_arg(ap, char *), 1, 514 | width, fp); 515 | 516 | if (r == 0) 517 | goto input_failure; 518 | nread += r; 519 | nassigned++; 520 | } 521 | break; 522 | #endif 523 | 524 | #ifdef TINY_SSCANF 525 | #else 526 | case CT_CCL: 527 | /* scan a (nonempty) character class (sets NOSKIP) */ 528 | if (width == 0) 529 | width = (size_t)~0; /* `infinity' */ 530 | /* take only those things in the class */ 531 | if (flags & SUPPRESS) { 532 | n = 0; 533 | while (ccltab[*fp_p]) { 534 | n++, fp_r--, fp_p++; 535 | if (--width == 0) 536 | break; 537 | if (fp_r <= 0 && __srefill(fp)) { 538 | if (n == 0) 539 | goto input_failure; 540 | break; 541 | } 542 | } 543 | if (n == 0) 544 | goto match_failure; 545 | } else { 546 | p0 = p = va_arg(ap, char *); 547 | while (ccltab[*fp_p]) { 548 | fp_r--; 549 | *p++ = *fp_p++; 550 | if (--width == 0) 551 | break; 552 | if (fp_r <= 0 && __srefill(fp)) { 553 | if (p == p0) 554 | goto input_failure; 555 | break; 556 | } 557 | } 558 | n = p - p0; 559 | if (n == 0) 560 | goto match_failure; 561 | *p = '\0'; 562 | nassigned++; 563 | } 564 | nread += n; 565 | break; 566 | #endif 567 | 568 | #ifdef TINY_SSCANF 569 | #else 570 | case CT_STRING: 571 | /* like CCL, but zero-length string OK, & no NOSKIP */ 572 | if (width == 0) 573 | width = (size_t)~0; 574 | if (flags & SUPPRESS) { 575 | n = 0; 576 | while (!isspace(*fp_p)) { 577 | n++, fp_r--, fp_p++; 578 | if (--width == 0) 579 | break; 580 | if (fp_r <= 0 && __srefill(fp)) 581 | break; 582 | } 583 | nread += n; 584 | } else { 585 | p0 = p = va_arg(ap, char *); 586 | while (!isspace(*fp_p)) { 587 | fp_r--; 588 | *p++ = *fp_p++; 589 | if (--width == 0) 590 | break; 591 | if (fp_r <= 0 && __srefill(fp)) 592 | break; 593 | } 594 | *p = '\0'; 595 | nread += p - p0; 596 | nassigned++; 597 | } 598 | continue; 599 | #endif 600 | 601 | case CT_INT: 602 | /* scan an integer as if by strtoimax/strtoumax */ 603 | #ifdef hardway 604 | if (width == 0 || width > sizeof(buf) - 1) 605 | width = sizeof(buf) - 1; 606 | #else 607 | /* size_t is unsigned, hence this optimisation */ 608 | if (--width > sizeof(buf) - 2) 609 | width = sizeof(buf) - 2; 610 | width++; 611 | #endif 612 | 613 | #ifdef TINY_NO_OX 614 | flags |= SIGNOK | NDIGITS; 615 | #else 616 | flags |= SIGNOK | NDIGITS | NZDIGITS; 617 | #endif 618 | 619 | sign_minus = 0; 620 | value = 0; 621 | for (p = buf; width; width--) { 622 | c = *fp_p; 623 | /* 624 | * Switch on the character; `goto ok' 625 | * if we accept it as a part of number. 626 | */ 627 | switch (c) { 628 | 629 | /* 630 | * The digit 0 is always legal, but is 631 | * special. For %i conversions, if no 632 | * digits (zero or nonzero) have been 633 | * scanned (only signs), we will have 634 | * base==0. In that case, we should set 635 | * it to 8 and enable 0x prefixing. 636 | * Also, if we have not scanned zero digits 637 | * before this, do not turn off prefixing 638 | * (someone else will turn it off if we 639 | * have scanned any nonzero digits). 640 | */ 641 | case '0': 642 | #ifdef TINY_NO_OX 643 | /* FALLTHROUGH */ 644 | #else 645 | #ifdef TINY_SSCANF 646 | #else 647 | if (base == 0) { 648 | base = 8; 649 | flags |= PFXOK; 650 | } 651 | #endif 652 | if (!(flags & NDIGITS)) { 653 | value = value * base; 654 | } 655 | 656 | if (flags & NZDIGITS) 657 | flags &= ~(SIGNOK|NZDIGITS|NDIGITS); 658 | else 659 | flags &= ~(SIGNOK|PFXOK|NDIGITS); 660 | goto ok; 661 | #endif 662 | 663 | #ifdef TINY_SSCANF 664 | /* we only support base 10 and 16 */ 665 | case '1': case '2': case '3': 666 | case '4': case '5': case '6': case '7': 667 | case '8': case '9': 668 | #ifdef TINY_NO_OX 669 | flags &= ~(SIGNOK | NDIGITS); 670 | #else 671 | flags &= ~(SIGNOK | PFXOK | NDIGITS); 672 | #endif 673 | value = value * base + c - '0'; 674 | goto ok; 675 | #else 676 | /* 1 through 7 always legal */ 677 | case '1': case '2': case '3': 678 | case '4': case '5': case '6': case '7': 679 | base = basefix[base]; 680 | flags &= ~(SIGNOK | PFXOK | NDIGITS); 681 | value = value * base + c - '0'; 682 | goto ok; 683 | 684 | /* digits 8 and 9 ok iff decimal or hex */ 685 | case '8': case '9': 686 | base = basefix[base]; 687 | if (base <= 8) 688 | break; /* not legal here */ 689 | flags &= ~(SIGNOK | PFXOK | NDIGITS); 690 | value = value * base + c - '0'; 691 | goto ok; 692 | #endif 693 | 694 | /* letters ok iff hex */ 695 | case 'A': case 'B': case 'C': 696 | case 'D': case 'E': case 'F': 697 | /* no need to fix base here */ 698 | if (base <= 10) 699 | break; /* not legal here */ 700 | #ifdef TINY_NO_OX 701 | flags &= ~(SIGNOK | NDIGITS); 702 | #else 703 | flags &= ~(SIGNOK | PFXOK | NDIGITS); 704 | #endif 705 | value = value * base + c - 'A' + 10; 706 | goto ok; 707 | 708 | case 'a': case 'b': case 'c': 709 | case 'd': case 'e': case 'f': 710 | /* no need to fix base here */ 711 | if (base <= 10) 712 | break; /* not legal here */ 713 | #ifdef TINY_NO_OX 714 | flags &= ~(SIGNOK | NDIGITS); 715 | #else 716 | flags &= ~(SIGNOK | PFXOK | NDIGITS); 717 | #endif 718 | value = value * base + c - 'a' + 10; 719 | goto ok; 720 | 721 | /* sign ok only as first character */ 722 | case '-': 723 | if (!(flags & HAVESIGN)) { 724 | sign_minus = 1; 725 | } 726 | /* FALLTHROUGH */ 727 | case '+': 728 | if (flags & SIGNOK) { 729 | flags &= ~SIGNOK; 730 | flags |= HAVESIGN; 731 | goto ok; 732 | } 733 | break; 734 | 735 | /* 736 | * x ok iff flag still set and 2nd char (or 737 | * 3rd char if we have a sign). 738 | */ 739 | #ifdef TINY_NO_OX 740 | #else 741 | case 'x': case 'X': 742 | if ((flags & PFXOK) && p == 743 | buf + 1 + !!(flags & HAVESIGN)) { 744 | base = 16; /* if %i */ 745 | flags &= ~PFXOK; 746 | goto ok; 747 | } 748 | break; 749 | #endif 750 | } 751 | 752 | /* 753 | * If we got here, c is not a legal character 754 | * for a number. Stop accumulating digits. 755 | */ 756 | break; 757 | ok: 758 | /* 759 | * c is legal: store it and look at the next. 760 | */ 761 | *p++ = c; 762 | if (--fp_r > 0) 763 | fp_p++; 764 | else if (__srefill(fp)) 765 | break; /* EOF */ 766 | } 767 | /* 768 | * If we had only a sign, it is no good; push 769 | * back the sign. If the number ends in `x', 770 | * it was [sign] '0' 'x', so push back the x 771 | * and treat it as [sign] '0'. 772 | */ 773 | if (flags & NDIGITS) { 774 | if (p > buf) 775 | { 776 | --c; 777 | --p; 778 | ungetc(c++, fp); 779 | /* There is a dummy post-increment to 780 | avoid an unused value warning */ 781 | } 782 | goto match_failure; 783 | } 784 | #ifdef TINY_NO_OX 785 | #else 786 | c = ((u_char *)p)[-1]; 787 | if (c == 'x' || c == 'X') { 788 | --p; 789 | ungetc(c, fp); 790 | } 791 | #endif 792 | 793 | #ifdef TINY_SSCANF 794 | { 795 | #else 796 | if ((flags & SUPPRESS) == 0) { 797 | #endif 798 | 799 | *p = '\0'; 800 | if (sign_minus) 801 | value = -value; 802 | 803 | #ifdef TINY_SSCANF 804 | #else 805 | if (flags & POINTER) 806 | *va_arg(ap, void **) = 807 | (void *)(uintptr_t)value; 808 | else if (flags & MAXINT) 809 | *va_arg(ap, intmax_t *) = value; 810 | else if (flags & LLONG) 811 | *va_arg(ap, long long *) = value; 812 | else if (flags & SIZEINT) 813 | *va_arg(ap, size_t *) = value; 814 | else if (flags & PTRINT) 815 | *va_arg(ap, ptrdiff_t *) = value; 816 | else 817 | #endif 818 | if (flags & LONG) 819 | *va_arg(ap, long *) = value; 820 | else if (flags & SHORT) 821 | *va_arg(ap, short *) = value; 822 | else if (flags & SHORTSHORT) 823 | *va_arg(ap, char *) = value; 824 | else 825 | *va_arg(ap, int *) = value; 826 | nassigned++; 827 | } 828 | nread += p - buf; 829 | break; 830 | 831 | #ifdef FLOATING_POINT 832 | case CT_FLOAT: 833 | /* scan a floating point number as if by strtod */ 834 | #ifdef hardway 835 | if (width == 0 || width > sizeof(buf) - 1) 836 | width = sizeof(buf) - 1; 837 | #else 838 | /* size_t is unsigned, hence this optimisation */ 839 | if (--width > sizeof(buf) - 2) 840 | width = sizeof(buf) - 2; 841 | width++; 842 | #endif 843 | flags |= SIGNOK | NDIGITS | DPTOK | EXPOK; 844 | for (p = buf; width; width--) { 845 | c = *fp->_p; 846 | /* 847 | * This code mimicks the integer conversion 848 | * code, but is much simpler. 849 | */ 850 | switch (c) { 851 | 852 | case '0': case '1': case '2': case '3': 853 | case '4': case '5': case '6': case '7': 854 | case '8': case '9': 855 | flags &= ~(SIGNOK | NDIGITS); 856 | goto fok; 857 | 858 | case '+': case '-': 859 | if (flags & SIGNOK) { 860 | flags &= ~SIGNOK; 861 | goto fok; 862 | } 863 | break; 864 | case '.': 865 | if (flags & DPTOK) { 866 | flags &= ~(SIGNOK | DPTOK); 867 | goto fok; 868 | } 869 | break; 870 | case 'e': case 'E': 871 | /* no exponent without some digits */ 872 | if ((flags&(NDIGITS|EXPOK)) == EXPOK) { 873 | flags = 874 | (flags & ~(EXPOK|DPTOK)) | 875 | SIGNOK | NDIGITS; 876 | goto fok; 877 | } 878 | break; 879 | } 880 | break; 881 | fok: 882 | *p++ = c; 883 | if (--fp->_r > 0) 884 | fp->_p++; 885 | else if (__srefill(fp)) 886 | break; /* EOF */ 887 | } 888 | /* 889 | * If no digits, might be missing exponent digits 890 | * (just give back the exponent) or might be missing 891 | * regular digits, but had sign and/or decimal point. 892 | */ 893 | if (flags & NDIGITS) { 894 | if (flags & EXPOK) { 895 | /* no digits at all */ 896 | while (p > buf) 897 | ungetc(*(u_char *)--p, fp); 898 | goto match_failure; 899 | } 900 | /* just a bad exponent (e and maybe sign) */ 901 | c = *(u_char *)--p; 902 | if (c != 'e' && c != 'E') { 903 | (void) ungetc(c, fp);/* sign */ 904 | c = *(u_char *)--p; 905 | } 906 | (void) ungetc(c, fp); 907 | } 908 | if ((flags & SUPPRESS) == 0) { 909 | double res; 910 | 911 | *p = '\0'; 912 | res = strtod(buf, (char **) NULL); 913 | if (flags & LONGDBL) 914 | *va_arg(ap, long double *) = res; 915 | else if (flags & LONG) 916 | *va_arg(ap, double *) = res; 917 | else 918 | *va_arg(ap, float *) = res; 919 | nassigned++; 920 | } 921 | nread += p - buf; 922 | break; 923 | #endif /* FLOATING_POINT */ 924 | } 925 | } 926 | input_failure: 927 | return (nassigned ? nassigned : -1); 928 | match_failure: 929 | return (nassigned); 930 | } 931 | 932 | #ifdef TINY_SSCANF 933 | #else 934 | /* 935 | * Fill in the given table from the scanset at the given format 936 | * (just after `['). Return a pointer to the character past the 937 | * closing `]'. The table has a 1 wherever characters should be 938 | * considered part of the scanset. 939 | */ 940 | static u_char * 941 | __sccl(char *tab, u_char *fmt) 942 | { 943 | int c, n, v; 944 | 945 | /* first `clear' the whole table */ 946 | c = *fmt++; /* first char hat => negated scanset */ 947 | if (c == '^') { 948 | v = 1; /* default => accept */ 949 | c = *fmt++; /* get new first char */ 950 | } else 951 | v = 0; /* default => reject */ 952 | /* should probably use memset here */ 953 | for (n = 0; n < 256; n++) 954 | tab[n] = v; 955 | if (c == 0) 956 | return (fmt - 1);/* format ended before closing ] */ 957 | 958 | /* 959 | * Now set the entries corresponding to the actual scanset 960 | * to the opposite of the above. 961 | * 962 | * The first character may be ']' (or '-') without being special; 963 | * the last character may be '-'. 964 | */ 965 | v = 1 - v; 966 | for (;;) { 967 | tab[c] = v; /* take character c */ 968 | doswitch: 969 | n = *fmt++; /* and examine the next */ 970 | switch (n) { 971 | 972 | case 0: /* format ended too soon */ 973 | return (fmt - 1); 974 | 975 | case '-': 976 | /* 977 | * A scanset of the form 978 | * [01+-] 979 | * is defined as `the digit 0, the digit 1, 980 | * the character +, the character -', but 981 | * the effect of a scanset such as 982 | * [a-zA-Z0-9] 983 | * is implementation defined. The V7 Unix 984 | * scanf treats `a-z' as `the letters a through 985 | * z', but treats `a-a' as `the letter a, the 986 | * character -, and the letter a'. 987 | * 988 | * For compatibility, the `-' is not considerd 989 | * to define a range if the character following 990 | * it is either a close bracket (required by ANSI) 991 | * or is not numerically greater than the character 992 | * we just stored in the table (c). 993 | */ 994 | n = *fmt; 995 | if (n == ']' || n < c) { 996 | c = '-'; 997 | break; /* resume the for(;;) */ 998 | } 999 | fmt++; 1000 | do { /* fill in the range */ 1001 | tab[++c] = v; 1002 | } while (c < n); 1003 | #if 1 /* XXX another disgusting compatibility hack */ 1004 | /* 1005 | * Alas, the V7 Unix scanf also treats formats 1006 | * such as [a-c-e] as `the letters a through e'. 1007 | * This too is permitted by the standard.... 1008 | */ 1009 | goto doswitch; 1010 | #else 1011 | c = *fmt++; 1012 | if (c == 0) 1013 | return (fmt - 1); 1014 | if (c == ']') 1015 | return (fmt); 1016 | #endif 1017 | break; 1018 | 1019 | case ']': /* end of scanset */ 1020 | return (fmt); 1021 | 1022 | default: /* just another character */ 1023 | c = n; 1024 | break; 1025 | } 1026 | } 1027 | /* NOTREACHED */ 1028 | } 1029 | #endif 1030 | 1031 | int 1032 | tiny_sscanf(const char *str, const char *fmt, ...) 1033 | { 1034 | int ret; 1035 | va_list ap; 1036 | 1037 | va_start(ap, fmt); 1038 | ret = tiny_vfscanf(str, fmt, ap); 1039 | va_end(ap); 1040 | return (ret); 1041 | } 1042 | 1043 | #ifdef __cplusplus 1044 | } 1045 | #endif 1046 | 1047 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 1048 | -------------------------------------------------------------------------------- /src/tiny_sscanf.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * @file tiny_sscanf.h 3 | * @author MCD Application Team 4 | * @version V1.1.2 5 | * @date 08-September-2017 6 | * @brief Header for driver tiny_sscanf.c module 7 | ****************************************************************************** 8 | * @attention 9 | * 10 | *

© Copyright (c) 2017 STMicroelectronics International N.V. 11 | * All rights reserved.

12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted, provided that the following conditions are met: 15 | * 16 | * 1. Redistribution of source code must retain the above copyright notice, 17 | * this list of conditions and the following disclaimer. 18 | * 2. Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 3. Neither the name of STMicroelectronics nor the names of other 22 | * contributors to this software may be used to endorse or promote products 23 | * derived from this software without specific written permission. 24 | * 4. This software, including modifications and/or derivative works of this 25 | * software, must execute solely and exclusively on microcontroller or 26 | * microprocessor devices manufactured by or for STMicroelectronics. 27 | * 5. Redistribution and use of this software other than as permitted under 28 | * this license is void and will automatically terminate your rights under 29 | * this license. 30 | * 31 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 32 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 34 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 35 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 36 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 37 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 39 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 40 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 41 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 42 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 43 | * 44 | ****************************************************************************** 45 | */ 46 | 47 | #ifndef __TINY_SSCANF_H__ 48 | #define __TINY_SSCANF_H__ 49 | 50 | #ifdef __cplusplus 51 | extern "C" { 52 | #endif 53 | 54 | /* Includes ------------------------------------------------------------------*/ 55 | /* Exported types ------------------------------------------------------------*/ 56 | /* Exported constants --------------------------------------------------------*/ 57 | /* External variables --------------------------------------------------------*/ 58 | /* Exported macros -----------------------------------------------------------*/ 59 | /* Exported functions ------------------------------------------------------- */ 60 | 61 | /** 62 | * @brief Read formatted data from string 63 | * 64 | * Reads data from s and stores them according to parameter format into the 65 | * locations given by the additional arguments, as if scanf was used, but 66 | * reading from s instead of the standard input (stdin). 67 | * 68 | * The additional arguments should point to already allocated objects of the 69 | * type specified by their corresponding format specifier within the format string. 70 | * 71 | * @param C string that the function processes as its source to retrieve the data. 72 | * @param C string that contains a format string that follows the same specifications 73 | * as format in scanf (see scanf for details). 74 | * @param Depending on the format string, the function may expect a sequence of 75 | * additional arguments, each containing a pointer to allocated storage 76 | * where the interpretation of the extracted characters is stored with 77 | * the appropriate type. 78 | * There should be at least as many of these arguments as the number of 79 | * values stored by the format specifiers. Additional arguments are 80 | * ignored by the function. 81 | * @retval The number of items in the argument list successfully filled. This 82 | * count can match the expected number of items or be less (even zero) 83 | * in the case of a matching failure 84 | * @note Current supported formats are %hx, %hhx, %ul, %d,... 85 | */ 86 | int tiny_sscanf(const char *str, const char *fmt, ...); 87 | 88 | #ifdef __cplusplus 89 | } 90 | #endif 91 | 92 | #endif /* __TINY_SSCANF_H__ */ 93 | 94 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 95 | -------------------------------------------------------------------------------- /src/tiny_vsnprintf.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file tiny_vsnprintf.c 3 | * @author MCD Application Team 4 | * @version V1.1.2 5 | * @date 08-September-2017 6 | * @brief Tiny implementation of vsnprintf like function 7 | ****************************************************************************** 8 | * @attention 9 | * 10 | *

© Copyright (c) 2017 STMicroelectronics International N.V. 11 | * All rights reserved.

12 | * 13 | * Copyright (c) 1990, 1993 14 | * The Regents of the University of California. All rights reserved. 15 | * 16 | * This code is derived from software contributed to Berkeley by 17 | * Chris Torek. 18 | * Redistribution and use in source and binary forms, with or without 19 | * modification, are permitted, provided that the following conditions are met: 20 | * 21 | * 1. Redistribution of source code must retain the above copyright notice, 22 | * this list of conditions and the following disclaimer. 23 | * 2. Redistributions in binary form must reproduce the above copyright notice, 24 | * this list of conditions and the following disclaimer in the documentation 25 | * and/or other materials provided with the distribution. 26 | * 3. Neither the name of STMicroelectronics nor the names of other 27 | * contributors to this software may be used to endorse or promote products 28 | * derived from this software without specific written permission. 29 | * 4. This software, including modifications and/or derivative works of this 30 | * software, must execute solely and exclusively on microcontroller or 31 | * microprocessor devices manufactured by or for STMicroelectronics. 32 | * 5. Redistribution and use of this software other than as permitted under 33 | * this license is void and will automatically terminate your rights under 34 | * this license. 35 | * 36 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 37 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 38 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 39 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 40 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 41 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 42 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 44 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 45 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 46 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 47 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | * 49 | ****************************************************************************** 50 | */ 51 | 52 | /* File : barebones/ee_printf.c 53 | This file contains an implementation of ee_printf that only requires a method to output a char to a UART without pulling in library code. 54 | This code is based on a file that contains the following: 55 | Copyright (C) 2002 Michael Ringgaard. All rights reserved. 56 | Redistribution and use in source and binary forms, with or without 57 | modification, are permitted provided that the following conditions 58 | are met: 59 | 60 | 1. Redistributions of source code must retain the above copyright 61 | notice, this list of conditions and the following disclaimer. 62 | 2. Redistributions in binary form must reproduce the above copyright 63 | notice, this list of conditions and the following disclaimer in the 64 | documentation and/or other materials provided with the distribution. 65 | 3. Neither the name of the project nor the names of its contributors 66 | may be used to endorse or promote products derived from this software 67 | without specific prior written permission. 68 | 69 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 70 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 71 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 72 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 73 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 74 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 75 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 76 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 77 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 78 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 79 | SUCH DAMAGE. 80 | */ 81 | 82 | /* 83 | * Following implementation is adapted from original one 84 | * https://github.com/jpbonn/coremark_lm32/blob/master/ee_printf.c 85 | */ 86 | 87 | #ifdef __cplusplus 88 | extern "C" { 89 | #endif 90 | 91 | #define TINY_PRINTF 92 | 93 | #include 94 | #include "tiny_vsnprintf.h" 95 | 96 | #define ZEROPAD (1<<0) /* Pad with zero */ 97 | #define SIGN (1<<1) /* Unsigned/signed long */ 98 | #define UPPERCASE (1<<6) /* 'ABCDEF' */ 99 | #ifdef TINY_PRINTF 100 | #else 101 | #define PLUS (1<<2) /* Show plus */ 102 | #define HEX_PREP (1<<5) /* 0x */ 103 | #define SPACE (1<<3) /* Spacer */ 104 | #define LEFT (1<<4) /* Left justified */ 105 | #endif 106 | 107 | #define is_digit(c) ((c) >= '0' && (c) <= '9') 108 | 109 | static char *lower_digits = "0123456789abcdefghijklmnopqrstuvwxyz"; 110 | static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 111 | #ifdef TINY_PRINTF 112 | #else 113 | static size_t strnlen(const char *s, size_t count); 114 | 115 | static size_t strnlen(const char *s, size_t count) 116 | { 117 | const char *sc; 118 | for (sc = s; *sc != '\0' && count--; ++sc); 119 | return sc - s; 120 | } 121 | #endif 122 | 123 | static int ee_skip_atoi(const char **s) 124 | { 125 | int i = 0; 126 | while (is_digit(**s)) i = i*10 + *((*s)++) - '0'; 127 | return i; 128 | } 129 | 130 | #define ASSIGN_STR(_c) do { *str++ = (_c); max_size--; if (max_size == 0) return str; } while (0) 131 | 132 | static char *ee_number(char *str, int max_size, long num, int base, int size, int precision, int type) 133 | { 134 | char c; 135 | char sign, tmp[66]; 136 | char *dig = lower_digits; 137 | int i; 138 | 139 | if (type & UPPERCASE) dig = upper_digits; 140 | #ifdef TINY_PRINTF 141 | #else 142 | if (type & LEFT) type &= ~ZEROPAD; 143 | #endif 144 | if (base < 2 || base > 36) return 0; 145 | 146 | c = (type & ZEROPAD) ? '0' : ' '; 147 | sign = 0; 148 | if (type & SIGN) 149 | { 150 | if (num < 0) 151 | { 152 | sign = '-'; 153 | num = -num; 154 | size--; 155 | } 156 | #ifdef TINY_PRINTF 157 | #else 158 | else if (type & PLUS) 159 | { 160 | sign = '+'; 161 | size--; 162 | } 163 | else if (type & SPACE) 164 | { 165 | sign = ' '; 166 | size--; 167 | } 168 | #endif 169 | } 170 | 171 | #ifdef TINY_PRINTF 172 | #else 173 | if (type & HEX_PREP) 174 | { 175 | if (base == 16) 176 | size -= 2; 177 | else if (base == 8) 178 | size--; 179 | } 180 | #endif 181 | 182 | i = 0; 183 | 184 | if (num == 0) 185 | tmp[i++] = '0'; 186 | else 187 | { 188 | while (num != 0) 189 | { 190 | tmp[i++] = dig[((unsigned long) num) % (unsigned) base]; 191 | num = ((unsigned long) num) / (unsigned) base; 192 | } 193 | } 194 | 195 | if (i > precision) precision = i; 196 | size -= precision; 197 | if (!(type & (ZEROPAD /* TINY option | LEFT */))) while (size-- > 0) ASSIGN_STR(' '); 198 | if (sign) ASSIGN_STR(sign); 199 | 200 | #ifdef TINY_PRINTF 201 | #else 202 | if (type & HEX_PREP) 203 | { 204 | if (base == 8) 205 | ASSIGN_STR('0'); 206 | else if (base == 16) 207 | { 208 | ASSIGN_STR('0'); 209 | ASSIGN_STR(lower_digits[33]); 210 | } 211 | } 212 | #endif 213 | 214 | #ifdef TINY_PRINTF 215 | while (size-- > 0) ASSIGN_STR(c); 216 | #else 217 | if (!(type & LEFT)) while (size-- > 0) ASSIGN_STR(c); 218 | #endif 219 | while (i < precision--) ASSIGN_STR('0'); 220 | while (i-- > 0) ASSIGN_STR(tmp[i]); 221 | while (size-- > 0) ASSIGN_STR(' '); 222 | 223 | return str; 224 | } 225 | 226 | #ifdef TINY_PRINTF 227 | #else 228 | static char *eaddr(char *str, unsigned char *addr, int size, int precision, int type) 229 | { 230 | char tmp[24]; 231 | char *dig = lower_digits; 232 | int i, len; 233 | 234 | if (type & UPPERCASE) dig = upper_digits; 235 | len = 0; 236 | for (i = 0; i < 6; i++) 237 | { 238 | if (i != 0) tmp[len++] = ':'; 239 | tmp[len++] = dig[addr[i] >> 4]; 240 | tmp[len++] = dig[addr[i] & 0x0F]; 241 | } 242 | 243 | if (!(type & LEFT)) while (len < size--) *str++ = ' '; 244 | for (i = 0; i < len; ++i) *str++ = tmp[i]; 245 | while (len < size--) *str++ = ' '; 246 | 247 | return str; 248 | } 249 | 250 | static char *iaddr(char *str, unsigned char *addr, int size, int precision, int type) 251 | { 252 | char tmp[24]; 253 | int i, n, len; 254 | 255 | len = 0; 256 | for (i = 0; i < 4; i++) 257 | { 258 | if (i != 0) tmp[len++] = '.'; 259 | n = addr[i]; 260 | 261 | if (n == 0) 262 | tmp[len++] = lower_digits[0]; 263 | else 264 | { 265 | if (n >= 100) 266 | { 267 | tmp[len++] = lower_digits[n / 100]; 268 | n = n % 100; 269 | tmp[len++] = lower_digits[n / 10]; 270 | n = n % 10; 271 | } 272 | else if (n >= 10) 273 | { 274 | tmp[len++] = lower_digits[n / 10]; 275 | n = n % 10; 276 | } 277 | 278 | tmp[len++] = lower_digits[n]; 279 | } 280 | } 281 | 282 | if (!(type & LEFT)) while (len < size--) *str++ = ' '; 283 | for (i = 0; i < len; ++i) *str++ = tmp[i]; 284 | while (len < size--) *str++ = ' '; 285 | 286 | return str; 287 | } 288 | #endif 289 | 290 | #ifdef HAS_FLOAT 291 | 292 | char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); 293 | char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); 294 | static void ee_bufcpy(char *d, char *s, int count); 295 | 296 | void ee_bufcpy(char *pd, char *ps, int count) { 297 | char *pe=ps+count; 298 | while (ps!=pe) 299 | *pd++=*ps++; 300 | } 301 | 302 | static void parse_float(double value, char *buffer, char fmt, int precision) 303 | { 304 | int decpt, sign, exp, pos; 305 | char *fdigits = NULL; 306 | char cvtbuf[80]; 307 | int capexp = 0; 308 | int magnitude; 309 | 310 | if (fmt == 'G' || fmt == 'E') 311 | { 312 | capexp = 1; 313 | fmt += 'a' - 'A'; 314 | } 315 | 316 | if (fmt == 'g') 317 | { 318 | fdigits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); 319 | magnitude = decpt - 1; 320 | if (magnitude < -4 || magnitude > precision - 1) 321 | { 322 | fmt = 'e'; 323 | precision -= 1; 324 | } 325 | else 326 | { 327 | fmt = 'f'; 328 | precision -= decpt; 329 | } 330 | } 331 | 332 | if (fmt == 'e') 333 | { 334 | fdigits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); 335 | 336 | if (sign) *buffer++ = '-'; 337 | *buffer++ = *fdigits; 338 | if (precision > 0) *buffer++ = '.'; 339 | ee_bufcpy(buffer, fdigits + 1, precision); 340 | buffer += precision; 341 | *buffer++ = capexp ? 'E' : 'e'; 342 | 343 | if (decpt == 0) 344 | { 345 | if (value == 0.0) 346 | exp = 0; 347 | else 348 | exp = -1; 349 | } 350 | else 351 | exp = decpt - 1; 352 | 353 | if (exp < 0) 354 | { 355 | *buffer++ = '-'; 356 | exp = -exp; 357 | } 358 | else 359 | *buffer++ = '+'; 360 | 361 | buffer[2] = (exp % 10) + '0'; 362 | exp = exp / 10; 363 | buffer[1] = (exp % 10) + '0'; 364 | exp = exp / 10; 365 | buffer[0] = (exp % 10) + '0'; 366 | buffer += 3; 367 | } 368 | else if (fmt == 'f') 369 | { 370 | fdigits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); 371 | if (sign) *buffer++ = '-'; 372 | if (*fdigits) 373 | { 374 | if (decpt <= 0) 375 | { 376 | *buffer++ = '0'; 377 | *buffer++ = '.'; 378 | for (pos = 0; pos < -decpt; pos++) *buffer++ = '0'; 379 | while (*fdigits) *buffer++ = *fdigits++; 380 | } 381 | else 382 | { 383 | pos = 0; 384 | while (*fdigits) 385 | { 386 | if (pos++ == decpt) *buffer++ = '.'; 387 | *buffer++ = *fdigits++; 388 | } 389 | } 390 | } 391 | else 392 | { 393 | *buffer++ = '0'; 394 | if (precision > 0) 395 | { 396 | *buffer++ = '.'; 397 | for (pos = 0; pos < precision; pos++) *buffer++ = '0'; 398 | } 399 | } 400 | } 401 | 402 | *buffer = '\0'; 403 | } 404 | 405 | static void decimal_point(char *buffer) 406 | { 407 | while (*buffer) 408 | { 409 | if (*buffer == '.') return; 410 | if (*buffer == 'e' || *buffer == 'E') break; 411 | buffer++; 412 | } 413 | 414 | if (*buffer) 415 | { 416 | int n = strnlen(buffer,256); 417 | while (n > 0) 418 | { 419 | buffer[n + 1] = buffer[n]; 420 | n--; 421 | } 422 | 423 | *buffer = '.'; 424 | } 425 | else 426 | { 427 | *buffer++ = '.'; 428 | *buffer = '\0'; 429 | } 430 | } 431 | 432 | static void cropzeros(char *buffer) 433 | { 434 | char *stop; 435 | 436 | while (*buffer && *buffer != '.') buffer++; 437 | if (*buffer++) 438 | { 439 | while (*buffer && *buffer != 'e' && *buffer != 'E') buffer++; 440 | stop = buffer--; 441 | while (*buffer == '0') buffer--; 442 | if (*buffer == '.') buffer--; 443 | while (buffer!=stop) 444 | *++buffer=0; 445 | } 446 | } 447 | 448 | static char *flt(char *str, double num, int size, int precision, char fmt, int flags) 449 | { 450 | char tmp[80]; 451 | char c, sign; 452 | int n, i; 453 | 454 | // Left align means no zero padding 455 | #ifdef TINY_PRINTF 456 | #else 457 | if (flags & LEFT) flags &= ~ZEROPAD; 458 | #endif 459 | 460 | // Determine padding and sign char 461 | c = (flags & ZEROPAD) ? '0' : ' '; 462 | sign = 0; 463 | if (flags & SIGN) 464 | { 465 | if (num < 0.0) 466 | { 467 | sign = '-'; 468 | num = -num; 469 | size--; 470 | } 471 | #ifdef TINY_PRINTF 472 | #else 473 | else if (flags & PLUS) 474 | { 475 | sign = '+'; 476 | size--; 477 | } 478 | else if (flags & SPACE) 479 | { 480 | sign = ' '; 481 | size--; 482 | } 483 | #endif 484 | } 485 | 486 | // Compute the precision value 487 | if (precision < 0) 488 | precision = 6; // Default precision: 6 489 | 490 | // Convert floating point number to text 491 | parse_float(num, tmp, fmt, precision); 492 | 493 | #ifdef TINY_PRINTF 494 | #else 495 | if ((flags & HEX_PREP) && precision == 0) decimal_point(tmp); 496 | #endif 497 | if (fmt == 'g' && !(flags & HEX_PREP)) cropzeros(tmp); 498 | 499 | n = strnlen(tmp,256); 500 | 501 | // Output number with alignment and padding 502 | size -= n; 503 | if (!(flags & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' '; 504 | if (sign) *str++ = sign; 505 | if (!(flags & LEFT)) while (size-- > 0) *str++ = c; 506 | for (i = 0; i < n; i++) *str++ = tmp[i]; 507 | while (size-- > 0) *str++ = ' '; 508 | 509 | return str; 510 | } 511 | 512 | #endif 513 | 514 | #define CHECK_STR_SIZE(_buf, _str, _size) \ 515 | if ((((_str) - (_buf)) >= ((_size)-1))) { break; } 516 | 517 | int tiny_vsnprintf_like(char *buf, const int size, const char *fmt, va_list args) 518 | { 519 | unsigned long num; 520 | int base; 521 | char *str; 522 | int len; 523 | int i; 524 | char *s; 525 | 526 | int flags; // Flags to number() 527 | 528 | int field_width; // Width of output field 529 | int precision; // Min. # of digits for integers; max number of chars for from string 530 | int qualifier; // 'h', 'l', or 'L' for integer fields 531 | 532 | if (size <= 0) 533 | { 534 | return 0; 535 | } 536 | 537 | for (str = buf; *fmt || ((str - buf) >= size-1); fmt++) 538 | { 539 | CHECK_STR_SIZE(buf, str, size); 540 | 541 | if (*fmt != '%') 542 | { 543 | *str++ = *fmt; 544 | continue; 545 | } 546 | 547 | // Process flags 548 | flags = 0; 549 | #ifdef TINY_PRINTF 550 | /* Support %0, but not %-, %+, %space and %# */ 551 | fmt++; 552 | if (*fmt == '0') 553 | { 554 | flags |= ZEROPAD; 555 | } 556 | #else 557 | repeat: 558 | fmt++; // This also skips first '%' 559 | switch (*fmt) 560 | { 561 | case '-': flags |= LEFT; goto repeat; 562 | case '+': flags |= PLUS; goto repeat; 563 | case ' ': flags |= SPACE; goto repeat; 564 | case '#': flags |= HEX_PREP; goto repeat; 565 | case '0': flags |= ZEROPAD; goto repeat; 566 | } 567 | #endif 568 | 569 | // Get field width 570 | field_width = -1; 571 | if (is_digit(*fmt)) 572 | field_width = ee_skip_atoi(&fmt); 573 | #ifdef TINY_PRINTF 574 | /* Does not support %* */ 575 | #else 576 | else if (*fmt == '*') 577 | { 578 | fmt++; 579 | field_width = va_arg(args, int); 580 | if (field_width < 0) 581 | { 582 | field_width = -field_width; 583 | flags |= LEFT; 584 | } 585 | } 586 | #endif 587 | 588 | // Get the precision 589 | precision = -1; 590 | #ifdef TINY_PRINTF 591 | /* Does not support %. */ 592 | #else 593 | if (*fmt == '.') 594 | { 595 | ++fmt; 596 | if (is_digit(*fmt)) 597 | precision = ee_skip_atoi(&fmt); 598 | else if (*fmt == '*') 599 | { 600 | ++fmt; 601 | precision = va_arg(args, int); 602 | } 603 | if (precision < 0) precision = 0; 604 | } 605 | #endif 606 | 607 | // Get the conversion qualifier 608 | qualifier = -1; 609 | #ifdef TINY_PRINTF 610 | /* Does not support %l and %L */ 611 | #else 612 | if (*fmt == 'l' || *fmt == 'L') 613 | { 614 | qualifier = *fmt; 615 | fmt++; 616 | } 617 | #endif 618 | 619 | // Default base 620 | base = 10; 621 | 622 | switch (*fmt) 623 | { 624 | case 'c': 625 | #ifdef TINY_PRINTF 626 | #else 627 | if (!(flags & LEFT)) 628 | #endif 629 | while (--field_width > 0) *str++ = ' '; 630 | *str++ = (unsigned char) va_arg(args, int); 631 | #ifdef TINY_PRINTF 632 | #else 633 | while (--field_width > 0) *str++ = ' '; 634 | #endif 635 | continue; 636 | 637 | case 's': 638 | s = va_arg(args, char *); 639 | if (!s) s = ""; 640 | #ifdef TINY_PRINTF 641 | len = strlen(s); 642 | #else 643 | len = strnlen(s, precision); 644 | if (!(flags & LEFT)) 645 | #endif 646 | while (len < field_width--) *str++ = ' '; 647 | for (i = 0; i < len; ++i) *str++ = *s++; 648 | #ifdef TINY_PRINTF 649 | #else 650 | while (len < field_width--) *str++ = ' '; 651 | #endif 652 | continue; 653 | 654 | #ifdef TINY_PRINTF 655 | /* Does not support %p, %A, %a, %o */ 656 | #else 657 | case 'p': 658 | if (field_width == -1) 659 | { 660 | field_width = 2 * sizeof(void *); 661 | flags |= ZEROPAD; 662 | } 663 | str = ee_number(str, (size - (str - buf)), (unsigned long) va_arg(args, void *), 16, field_width, precision, flags); 664 | continue; 665 | 666 | case 'A': 667 | flags |= UPPERCASE; 668 | 669 | case 'a': 670 | if (qualifier == 'l') 671 | str = eaddr(str, va_arg(args, unsigned char *), field_width, precision, flags); 672 | else 673 | str = iaddr(str, va_arg(args, unsigned char *), field_width, precision, flags); 674 | continue; 675 | 676 | // Integer number formats - set up the flags and "break" 677 | case 'o': 678 | base = 8; 679 | break; 680 | #endif 681 | 682 | case 'X': 683 | flags |= UPPERCASE; 684 | __attribute__ ((fallthrough)); 685 | 686 | case 'x': 687 | base = 16; 688 | break; 689 | 690 | case 'd': 691 | case 'i': 692 | flags |= SIGN; 693 | 694 | case 'u': 695 | break; 696 | 697 | #ifdef HAS_FLOAT 698 | 699 | case 'f': 700 | str = flt(str, va_arg(args, double), field_width, precision, *fmt, flags | SIGN); 701 | continue; 702 | 703 | #endif 704 | 705 | default: 706 | if (*fmt != '%') *str++ = '%'; 707 | CHECK_STR_SIZE(buf, str, size); 708 | if (*fmt) 709 | *str++ = *fmt; 710 | else 711 | --fmt; 712 | CHECK_STR_SIZE(buf, str, size); 713 | continue; 714 | } 715 | 716 | if (qualifier == 'l') 717 | num = va_arg(args, unsigned long); 718 | else if (flags & SIGN) 719 | num = va_arg(args, int); 720 | else 721 | num = va_arg(args, unsigned int); 722 | 723 | str = ee_number(str, ((size - 1) - (str - buf)), num, base, field_width, precision, flags); 724 | } 725 | 726 | *str = '\0'; 727 | return str - buf; 728 | } 729 | 730 | 731 | #ifdef __cplusplus 732 | } 733 | #endif 734 | -------------------------------------------------------------------------------- /src/tiny_vsnprintf.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file tiny_vsnprintf.h 3 | * @author MCD Application Team 4 | * @version V1.1.2 5 | * @date 08-September-2017 6 | * @brief Header for tiny_vsnprintf.c module 7 | ****************************************************************************** 8 | * @attention 9 | * 10 | *

© Copyright (c) 2017 STMicroelectronics International N.V. 11 | * All rights reserved.

12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted, provided that the following conditions are met: 15 | * 16 | * 1. Redistribution of source code must retain the above copyright notice, 17 | * this list of conditions and the following disclaimer. 18 | * 2. Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 3. Neither the name of STMicroelectronics nor the names of other 22 | * contributors to this software may be used to endorse or promote products 23 | * derived from this software without specific written permission. 24 | * 4. This software, including modifications and/or derivative works of this 25 | * software, must execute solely and exclusively on microcontroller or 26 | * microprocessor devices manufactured by or for STMicroelectronics. 27 | * 5. Redistribution and use of this software other than as permitted under 28 | * this license is void and will automatically terminate your rights under 29 | * this license. 30 | * 31 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 32 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 34 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 35 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 36 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 37 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 38 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 39 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 40 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 41 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 42 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 43 | * 44 | ****************************************************************************** 45 | */ 46 | /* Define to prevent recursive inclusion -------------------------------------*/ 47 | #ifndef __TINY_VSNPRINTF_H__ 48 | #define __TINY_VSNPRINTF_H__ 49 | 50 | #include "hw.h" 51 | 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | #include 56 | /* Includes ------------------------------------------------------------------*/ 57 | /* Exported types ------------------------------------------------------------*/ 58 | /* Exported constants --------------------------------------------------------*/ 59 | /* External variables --------------------------------------------------------*/ 60 | /* Exported functions ------------------------------------------------------- */ 61 | 62 | /** 63 | * @brief Tiny implementation of vsnprintf() like function 64 | * 65 | * It has been adapted so that: 66 | * - Tiny implementation, when defining TINY_PRINTF, is available. In such as case, 67 | * not all the format are available. Instead, only %02X, %x, %d, %u, %s and %c are available. 68 | * %f,, %+, %#, %- and others are excluded 69 | * - Provide a snprintf like implementation. The size of the buffer is provided, 70 | * and the length of the filled buffer is returned (not including the final '\0' char). 71 | * The string may be truncated 72 | * @param Pointer to a buffer where the resulting C-string is stored. The buffer should have a size of 73 | * at least n characters. 74 | * @param Maximum number of bytes to be used in the buffer. The generated string has a length of at 75 | * most n-1, leaving space for the additional terminating null character. 76 | * @param C string that contains a format string that follows the same specifications as format 77 | * in printf (see printf for details). 78 | * @param A value identifying a variable arguments list initialized with va_start. 79 | * @retval The number of written char (note that this is different from vsnprintf() 80 | */ 81 | int tiny_vsnprintf_like(char *buf, const int size, const char *fmt, va_list args); 82 | 83 | #ifdef __cplusplus 84 | } 85 | #endif 86 | 87 | #endif /* __TINY_VSNPRINTF_H__*/ 88 | 89 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 90 | --------------------------------------------------------------------------------