├── 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 |
--------------------------------------------------------------------------------