LoRaPHY project, based upon SX1276Lib, hardware with NUCLEO-F103EB/L053R8 and other boards as well as multiple Radio modules of SX1272/1276/1278. The code contains MACRO definitions and can be configured as TX/RX only, PINGPONG and consider to be a code base of RTTY.

Dependencies:   SX1276Lib mbed

About LoRaPHY

This project has two major goals:

  1. Setup and verify low cost LoRa RF shields for Arduino compatible boards, Nucleo/Freedom, as well as various mini-core-boards. Share common hardware as possible as we can.
  2. Design competitive MAC layer based upon LoRa PHY layer radio link (LoRaPHY), with modified ALOHA algorithm for CSMA/CA, RTS/CTS control packets.

The first goal is very important for an extremely budget limited project, including this project, 100% personal self-sponsored and no support at all.

The second goal is to ease the pain of developing without a LoRaWAN gateway at hand. Sometimes SX1278/1272 single band module can be used to build a simple LoRaWAN gateway, or even more generic gateway. Yeap, it is also related to the budget as well as network coverage in your region.

We may derivate extra hardware/firmware/software products beyond above goals.

- Generic USB/UART dongle for LoRa with SX1278/SX1272/SX1276; - Verify Semtech IEEE488 SCPI as genernal equipment for LoRa; - Data Link Layer and IPv6 over LoRaPHY and ALOHA MAC....... - Cloud services.

Hardware

We delivery LoRa shield for Arduino/Nucleo/Freedom boards based upon mature RF modules. In order to avoid sourcing issues, we selected carefully and added solder jumpers to support multiple modules, therefore the developers can get constant supplies. Up to now, we have verified several SX1278 modules, and we will move on to verified SX1276 and SX1272 to cover EU/US bands.

Since we also develop based upon these boards, we added solder jumper for 3V3 VCC, so you can measure the power consumption of RF module. Additionally, we added some test pins, so you can use a logic analyzer to probe the SPI bus . This interface is very handy, I have removed some firmware bugs with this interface.

In this next version, we added I2C EEPROM. However since we can use internal Flash ROM to emulate EEPROM and some parts even have on-chip NVM, so it is still under evaluation.

RFM100L Arduino shield

Fig1, RFM100L with NPLINK SX1278, can plug into Arduino/Nucleo/Freedom boards

mbed Logo

Fig 2, RFM100L with AT SX1278 Ra-01 and NUCLEO-F103RB

mbed Logo

Fig 3, Schematics of RFM100L, check out the solder jumpers.

And we will continue to introduce more adapters for pin to pin compatible modules, as well as breakout boards for mini boards. Keep tuned.

MAC & Higher Layers

Since LoRa RFIC is a half duplex design, so we can not use CSMA/CD (Conflict Detect), we can use CSMA/CA(Conflict Avoidance). We will leverage wideband RSSI and CAD preamble detection as Carrier Sensing method. This part will borrow from LoRaWAN codebase.

In order to avoid conflict, we use RTS/CTS with timestamp information before real packet transaction. So other nodes will know how long the channel will be occupied. Then we will define packet structure. And X.25 over LoRa, and then IP based upon X.25.......

More discussion on Stacks.

Firmware

Most of the LoRa applications follow LoRaWAN specifications. LoRaWAN is suitable for fixed location IoT DAQ system. In some applications like people positioning system, we may need different MAC layer design due to different topology, which is similiar to early age of radio communications, HAM or walkie talkie. Therefore peer to peer and competitive MAC layer is required, instead of hybird MAC like LoRaWAN, which is competitive for uplink and time scheduler for downlink.

LoRaWAN firmware

Since LoRaWAN is a major fork for device firmware, we will verified the LoRaWAN device stack on our hardware.

MODEM firmware

In order to make it a MODEM, we will define AT command set to interface via UART/USB CDC. To make it easy to develop LoRa in a regular PC or Raspberry Pi/Android/Router.

SCPI firmware

We can reuse the same hardware for testing purposes by using Semtech's SCPI project.

Host Software

The software running on host will be written in Python as well as Java, including CPython/Jython, Java for Android and Processing.

Bugs

Please refer Bugs for detail information.

Ordering

There are three products available right now:

- RFM100L, NPLINK/AiThinker SX1278 modules, Arduino Shield - RFM110L, HPD/HopeRF SX1272/1276/1278 modules, Arduino Shield, with 24CL64 FeRAM, uFL/SMA connector. - RFM1100A, clone version of Adafruit LoRa module, with uFL/SMA connector and modified BOM for LDO. - LRD110L, HPD/HopeRF SX1272/1276/1278 modules with STM32F103C8/CB mini board, the lowest cost dongle.

So far our first batch (20170201) of prototypes are only available via taobao.com in China. But we will arrange channels on tindie soon.

Please contact me (allankliu(at)163.com) if you are interested in this project.

Committer:
allankliu
Date:
Wed Feb 22 00:04:36 2017 +0000
Revision:
0:90252f6ec3d0
Init code, tested on F103RB, ported to L053R8.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
allankliu 0:90252f6ec3d0 1 #include "mbed.h"
allankliu 0:90252f6ec3d0 2 #include "main.h"
allankliu 0:90252f6ec3d0 3 #include "sx1276-hal.h"
allankliu 0:90252f6ec3d0 4 #include "debug.h"
allankliu 0:90252f6ec3d0 5
allankliu 0:90252f6ec3d0 6 /* Set this flag to '1' to display debug messages on the console */
allankliu 0:90252f6ec3d0 7 #define DEBUG_MESSAGE 0
allankliu 0:90252f6ec3d0 8
allankliu 0:90252f6ec3d0 9 /* Set this flag to '1' to use the LoRa modulation or to '0' to use FSK modulation */
allankliu 0:90252f6ec3d0 10 #define USE_MODEM_LORA 1
allankliu 0:90252f6ec3d0 11 #define USE_MODEM_FSK !USE_MODEM_LORA
allankliu 0:90252f6ec3d0 12
allankliu 0:90252f6ec3d0 13 //#define RF868 1
allankliu 0:90252f6ec3d0 14
allankliu 0:90252f6ec3d0 15 #ifdef RF868
allankliu 0:90252f6ec3d0 16
allankliu 0:90252f6ec3d0 17 #define RF_FREQUENCY 868000000 // Hz
allankliu 0:90252f6ec3d0 18 #define TX_OUTPUT_POWER 14 // 14 dBm
allankliu 0:90252f6ec3d0 19
allankliu 0:90252f6ec3d0 20 #else
allankliu 0:90252f6ec3d0 21
allankliu 0:90252f6ec3d0 22 #define RF_FREQUENCY 433000000 // Hz
allankliu 0:90252f6ec3d0 23 #define TX_OUTPUT_POWER 14 // 26 dBm
allankliu 0:90252f6ec3d0 24
allankliu 0:90252f6ec3d0 25 #endif
allankliu 0:90252f6ec3d0 26
allankliu 0:90252f6ec3d0 27 #if USE_MODEM_LORA == 1
allankliu 0:90252f6ec3d0 28 #define LORA_BANDWIDTH 0
allankliu 0:90252f6ec3d0 29 #define LORA_SPREADING_FACTOR 10
allankliu 0:90252f6ec3d0 30 #define LORA_CODINGRATE 2
allankliu 0:90252f6ec3d0 31
allankliu 0:90252f6ec3d0 32 //#define LORA_BANDWIDTH 2 // [0: 125 kHz,
allankliu 0:90252f6ec3d0 33 // 1: 250 kHz,
allankliu 0:90252f6ec3d0 34 // 2: 500 kHz,
allankliu 0:90252f6ec3d0 35 // 3: Reserved]
allankliu 0:90252f6ec3d0 36 //#define LORA_SPREADING_FACTOR 7 // [SF7..SF12]
allankliu 0:90252f6ec3d0 37 //#define LORA_CODINGRATE 1 // [1: 4/5,
allankliu 0:90252f6ec3d0 38 // 2: 4/6,
allankliu 0:90252f6ec3d0 39 // 3: 4/7,
allankliu 0:90252f6ec3d0 40 // 4: 4/8]
allankliu 0:90252f6ec3d0 41 #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx
allankliu 0:90252f6ec3d0 42 #define LORA_SYMBOL_TIMEOUT 5 // Symbols
allankliu 0:90252f6ec3d0 43 #define LORA_FIX_LENGTH_PAYLOAD_ON false
allankliu 0:90252f6ec3d0 44 #define LORA_FHSS_ENABLED false
allankliu 0:90252f6ec3d0 45 #define LORA_NB_SYMB_HOP 4
allankliu 0:90252f6ec3d0 46 #define LORA_IQ_INVERSION_ON false
allankliu 0:90252f6ec3d0 47 #define LORA_CRC_ENABLED true
allankliu 0:90252f6ec3d0 48
allankliu 0:90252f6ec3d0 49 #elif USE_MODEM_FSK == 1
allankliu 0:90252f6ec3d0 50
allankliu 0:90252f6ec3d0 51 #define FSK_FDEV 25000 // Hz
allankliu 0:90252f6ec3d0 52 #define FSK_DATARATE 19200 // bps
allankliu 0:90252f6ec3d0 53 #define FSK_BANDWIDTH 50000 // Hz
allankliu 0:90252f6ec3d0 54 #define FSK_AFC_BANDWIDTH 83333 // Hz
allankliu 0:90252f6ec3d0 55 #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx
allankliu 0:90252f6ec3d0 56 #define FSK_FIX_LENGTH_PAYLOAD_ON false
allankliu 0:90252f6ec3d0 57 #define FSK_CRC_ENABLED true
allankliu 0:90252f6ec3d0 58
allankliu 0:90252f6ec3d0 59 #else
allankliu 0:90252f6ec3d0 60 #error "Please define a modem in the compiler options."
allankliu 0:90252f6ec3d0 61 #endif
allankliu 0:90252f6ec3d0 62
allankliu 0:90252f6ec3d0 63 #define RX_TIMEOUT_VALUE 3500000 // in us
allankliu 0:90252f6ec3d0 64 #define BUFFER_SIZE 32 // Define the payload size here
allankliu 0:90252f6ec3d0 65
allankliu 0:90252f6ec3d0 66 #if( defined ( TARGET_KL25Z ) || defined ( TARGET_LPC11U6X ) )
allankliu 0:90252f6ec3d0 67 DigitalOut led(LED2);
allankliu 0:90252f6ec3d0 68 #else
allankliu 0:90252f6ec3d0 69 //DigitalOut led(LED1);
allankliu 0:90252f6ec3d0 70 //DigitalOut led2(LED2);
allankliu 0:90252f6ec3d0 71 //DigitalOut led3(LED3);
allankliu 0:90252f6ec3d0 72 //DigitalOut led4(LED4);
allankliu 0:90252f6ec3d0 73 DigitalOut debugled(D6);
allankliu 0:90252f6ec3d0 74 DigitalOut debugled2(D7);
allankliu 0:90252f6ec3d0 75
allankliu 0:90252f6ec3d0 76 #endif
allankliu 0:90252f6ec3d0 77
allankliu 0:90252f6ec3d0 78 DigitalIn role(USER_BUTTON); // PC_13 in Mini 103RC mini board
allankliu 0:90252f6ec3d0 79 Timer tx_tmr;
allankliu 0:90252f6ec3d0 80
allankliu 0:90252f6ec3d0 81 #define UART_ENABLE
allankliu 0:90252f6ec3d0 82
allankliu 0:90252f6ec3d0 83 #ifdef UART_ENABLE
allankliu 0:90252f6ec3d0 84 //Serial pc(USBTX, USBRX);
allankliu 0:90252f6ec3d0 85 Serial pc(SERIAL_TX, SERIAL_RX);
allankliu 0:90252f6ec3d0 86 #endif
allankliu 0:90252f6ec3d0 87
allankliu 0:90252f6ec3d0 88 Ticker nwk_ticker;
allankliu 0:90252f6ec3d0 89
allankliu 0:90252f6ec3d0 90 bool channelOccupied = false;
allankliu 0:90252f6ec3d0 91
allankliu 0:90252f6ec3d0 92 #define NWK_SLEEP 0
allankliu 0:90252f6ec3d0 93 #define NWK_TX 1
allankliu 0:90252f6ec3d0 94 #define NWK_TX_NOK 2
allankliu 0:90252f6ec3d0 95 #define NWK_RX_OK 3
allankliu 0:90252f6ec3d0 96 #define NWK_RX_NOK 4
allankliu 0:90252f6ec3d0 97
allankliu 0:90252f6ec3d0 98 //#define PINGPONG
allankliu 0:90252f6ec3d0 99
allankliu 0:90252f6ec3d0 100 void nwk_toggle()
allankliu 0:90252f6ec3d0 101 {
allankliu 0:90252f6ec3d0 102 debugled = !debugled;
allankliu 0:90252f6ec3d0 103 debugled2 = !debugled2;
allankliu 0:90252f6ec3d0 104 }
allankliu 0:90252f6ec3d0 105
allankliu 0:90252f6ec3d0 106 void nwk_setmode(uint8_t mode)
allankliu 0:90252f6ec3d0 107 {
allankliu 0:90252f6ec3d0 108 switch(mode){
allankliu 0:90252f6ec3d0 109 case NWK_TX:
allankliu 0:90252f6ec3d0 110 case NWK_RX_OK:
allankliu 0:90252f6ec3d0 111 nwk_ticker.attach(&nwk_toggle, 1);
allankliu 0:90252f6ec3d0 112 break;
allankliu 0:90252f6ec3d0 113 case NWK_TX_NOK:
allankliu 0:90252f6ec3d0 114 case NWK_RX_NOK:
allankliu 0:90252f6ec3d0 115 nwk_ticker.attach(&nwk_toggle, 0.1);
allankliu 0:90252f6ec3d0 116 break;
allankliu 0:90252f6ec3d0 117 case NWK_SLEEP:
allankliu 0:90252f6ec3d0 118 default:
allankliu 0:90252f6ec3d0 119 debugled = 0;
allankliu 0:90252f6ec3d0 120 debugled2 = 0;
allankliu 0:90252f6ec3d0 121 nwk_ticker.detach();
allankliu 0:90252f6ec3d0 122 break;
allankliu 0:90252f6ec3d0 123 }
allankliu 0:90252f6ec3d0 124 }
allankliu 0:90252f6ec3d0 125
allankliu 0:90252f6ec3d0 126 /*
allankliu 0:90252f6ec3d0 127 * Global variables declarations
allankliu 0:90252f6ec3d0 128 */
allankliu 0:90252f6ec3d0 129 typedef enum
allankliu 0:90252f6ec3d0 130 {
allankliu 0:90252f6ec3d0 131 ST_LOWPOWER = 0,
allankliu 0:90252f6ec3d0 132 ST_IDLE,
allankliu 0:90252f6ec3d0 133
allankliu 0:90252f6ec3d0 134 ST_RX,
allankliu 0:90252f6ec3d0 135 ST_RX_TIMEOUT,
allankliu 0:90252f6ec3d0 136 ST_RX_ERROR,
allankliu 0:90252f6ec3d0 137
allankliu 0:90252f6ec3d0 138 ST_TX,
allankliu 0:90252f6ec3d0 139 ST_TX_TIMEOUT,
allankliu 0:90252f6ec3d0 140
allankliu 0:90252f6ec3d0 141 ST_CAD,
allankliu 0:90252f6ec3d0 142 ST_CAD_DONE
allankliu 0:90252f6ec3d0 143 }AppStates_t;
allankliu 0:90252f6ec3d0 144
allankliu 0:90252f6ec3d0 145 volatile AppStates_t State = ST_LOWPOWER;
allankliu 0:90252f6ec3d0 146
allankliu 0:90252f6ec3d0 147 /*!
allankliu 0:90252f6ec3d0 148 * Radio events function pointer
allankliu 0:90252f6ec3d0 149 */
allankliu 0:90252f6ec3d0 150 static RadioEvents_t RadioEvents;
allankliu 0:90252f6ec3d0 151
allankliu 0:90252f6ec3d0 152 /*
allankliu 0:90252f6ec3d0 153 * Global variables declarations
allankliu 0:90252f6ec3d0 154 */
allankliu 0:90252f6ec3d0 155 SX1276MB1xAS Radio( NULL );
allankliu 0:90252f6ec3d0 156
allankliu 0:90252f6ec3d0 157 const uint8_t PingMsg[] = "PING";
allankliu 0:90252f6ec3d0 158 const uint8_t PongMsg[] = "PONG";
allankliu 0:90252f6ec3d0 159 const uint8_t TestMsg[] = "LoRa Test";
allankliu 0:90252f6ec3d0 160
allankliu 0:90252f6ec3d0 161 uint16_t BufferSize = BUFFER_SIZE;
allankliu 0:90252f6ec3d0 162 uint8_t Buffer[BUFFER_SIZE];
allankliu 0:90252f6ec3d0 163
allankliu 0:90252f6ec3d0 164 //int16_t RssiValue = 0.0;
allankliu 0:90252f6ec3d0 165 //int8_t SnrValue = 0.0;
allankliu 0:90252f6ec3d0 166
allankliu 0:90252f6ec3d0 167 int16_t RssiValue = 0;
allankliu 0:90252f6ec3d0 168 int8_t SnrValue = 0;
allankliu 0:90252f6ec3d0 169
allankliu 0:90252f6ec3d0 170 #define REG_SIZE 0x70 // see below
allankliu 0:90252f6ec3d0 171 #define REG_IDX_SIZE 39
allankliu 0:90252f6ec3d0 172
allankliu 0:90252f6ec3d0 173 static int my_strncmp(const char *, const char *, int);
allankliu 0:90252f6ec3d0 174 static void my_strcpy(char * , const char *);
allankliu 0:90252f6ec3d0 175
allankliu 0:90252f6ec3d0 176 int my_strncmp(const char * s1, const char * s2, int size)
allankliu 0:90252f6ec3d0 177 {
allankliu 0:90252f6ec3d0 178 int n = size;
allankliu 0:90252f6ec3d0 179 for ( ; n > 0; s1++, s2++, --n)
allankliu 0:90252f6ec3d0 180 if (*s1 != *s2)
allankliu 0:90252f6ec3d0 181 return ((*(unsigned char *)s1 < *(unsigned char *)s2) ? -1 : +1);
allankliu 0:90252f6ec3d0 182 else if (*s1 == '\0')
allankliu 0:90252f6ec3d0 183 return 0;
allankliu 0:90252f6ec3d0 184 return 0;
allankliu 0:90252f6ec3d0 185 }
allankliu 0:90252f6ec3d0 186
allankliu 0:90252f6ec3d0 187 void my_strcpy(char * s1, const char * s2)
allankliu 0:90252f6ec3d0 188 {
allankliu 0:90252f6ec3d0 189 char *s = s1;
allankliu 0:90252f6ec3d0 190 while ((*s++ = *s2++) != 0)
allankliu 0:90252f6ec3d0 191 ;
allankliu 0:90252f6ec3d0 192 }
allankliu 0:90252f6ec3d0 193
allankliu 0:90252f6ec3d0 194 void Sender ( void )
allankliu 0:90252f6ec3d0 195 {
allankliu 0:90252f6ec3d0 196 int i;
allankliu 0:90252f6ec3d0 197 my_strcpy( ( char* )Buffer, ( char* )PingMsg );
allankliu 0:90252f6ec3d0 198 for( i = 4; i < BufferSize; i++ ){
allankliu 0:90252f6ec3d0 199 Buffer[i] = i - 4;
allankliu 0:90252f6ec3d0 200 }
allankliu 0:90252f6ec3d0 201 Radio.Send( Buffer, BufferSize );
allankliu 0:90252f6ec3d0 202 }
allankliu 0:90252f6ec3d0 203
allankliu 0:90252f6ec3d0 204 int main()
allankliu 0:90252f6ec3d0 205 {
allankliu 0:90252f6ec3d0 206 uint8_t i;
allankliu 0:90252f6ec3d0 207 uint8_t regval;
allankliu 0:90252f6ec3d0 208 bool isMaster = true;
allankliu 0:90252f6ec3d0 209 int begin, end;
allankliu 0:90252f6ec3d0 210
allankliu 0:90252f6ec3d0 211 uint32_t rand;
allankliu 0:90252f6ec3d0 212 debugled = 1;
allankliu 0:90252f6ec3d0 213 debugled2 = 1;
allankliu 0:90252f6ec3d0 214
allankliu 0:90252f6ec3d0 215 isMaster = role.read();
allankliu 0:90252f6ec3d0 216
allankliu 0:90252f6ec3d0 217 //debug( "\n\n\r SX1276 Ping Pong Demo Application \n\n\r" );
allankliu 0:90252f6ec3d0 218
allankliu 0:90252f6ec3d0 219 // Initialize Radio driver
allankliu 0:90252f6ec3d0 220 RadioEvents.TxDone = OnTxDone;
allankliu 0:90252f6ec3d0 221 RadioEvents.RxDone = OnRxDone;
allankliu 0:90252f6ec3d0 222 RadioEvents.RxError = OnRxError;
allankliu 0:90252f6ec3d0 223 RadioEvents.TxTimeout = OnTxTimeout;
allankliu 0:90252f6ec3d0 224 RadioEvents.RxTimeout = OnRxTimeout;
allankliu 0:90252f6ec3d0 225 Radio.Init( &RadioEvents );
allankliu 0:90252f6ec3d0 226
allankliu 0:90252f6ec3d0 227 #ifdef UART_ENABLE
allankliu 0:90252f6ec3d0 228 regval = Radio.Read(REG_VERSION);
allankliu 0:90252f6ec3d0 229 pc.printf("%s", TestMsg);
allankliu 0:90252f6ec3d0 230 pc.printf("IC Version: %02X\r\n", regval);
allankliu 0:90252f6ec3d0 231 regval = Radio.Read(REG_OPMODE);
allankliu 0:90252f6ec3d0 232 pc.printf("OPMODE: %02X\r\n", regval);
allankliu 0:90252f6ec3d0 233 #endif
allankliu 0:90252f6ec3d0 234
allankliu 0:90252f6ec3d0 235 debugled = 0;
allankliu 0:90252f6ec3d0 236 debugled2 = 0;
allankliu 0:90252f6ec3d0 237
allankliu 0:90252f6ec3d0 238 // verify the connection with the board
allankliu 0:90252f6ec3d0 239 while( Radio.Read( REG_VERSION ) == 0x00 )
allankliu 0:90252f6ec3d0 240 {
allankliu 0:90252f6ec3d0 241 //debug( "Radio could not be detected!\n\r", NULL );
allankliu 0:90252f6ec3d0 242 wait( 1 );
allankliu 0:90252f6ec3d0 243 }
allankliu 0:90252f6ec3d0 244
allankliu 0:90252f6ec3d0 245 //debug_if( ( DEBUG_MESSAGE & ( Radio.DetectBoardType( ) == SX1276MB1LAS ) ) , "\n\r > Board Type: SX1276MB1LAS < \n\r" );
allankliu 0:90252f6ec3d0 246 //debug_if( ( DEBUG_MESSAGE & ( Radio.DetectBoardType( ) == SX1276MB1MAS ) ) , "\n\r > Board Type: SX1276MB1MAS < \n\r" );
allankliu 0:90252f6ec3d0 247
allankliu 0:90252f6ec3d0 248 Radio.SetChannel( RF_FREQUENCY );
allankliu 0:90252f6ec3d0 249
allankliu 0:90252f6ec3d0 250 #if USE_MODEM_LORA == 1
allankliu 0:90252f6ec3d0 251
allankliu 0:90252f6ec3d0 252 //debug_if( LORA_FHSS_ENABLED, "\n\n\r > LORA FHSS Mode < \n\n\r");
allankliu 0:90252f6ec3d0 253 //debug_if( !LORA_FHSS_ENABLED, "\n\n\r > LORA Mode < \n\n\r");
allankliu 0:90252f6ec3d0 254
allankliu 0:90252f6ec3d0 255 Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
allankliu 0:90252f6ec3d0 256 LORA_SPREADING_FACTOR, LORA_CODINGRATE,
allankliu 0:90252f6ec3d0 257 LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
allankliu 0:90252f6ec3d0 258 LORA_CRC_ENABLED, LORA_FHSS_ENABLED, LORA_NB_SYMB_HOP,
allankliu 0:90252f6ec3d0 259 LORA_IQ_INVERSION_ON, 2000000 );
allankliu 0:90252f6ec3d0 260
allankliu 0:90252f6ec3d0 261 Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
allankliu 0:90252f6ec3d0 262 LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
allankliu 0:90252f6ec3d0 263 LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, 0,
allankliu 0:90252f6ec3d0 264 LORA_CRC_ENABLED, LORA_FHSS_ENABLED, LORA_NB_SYMB_HOP,
allankliu 0:90252f6ec3d0 265 LORA_IQ_INVERSION_ON, true );
allankliu 0:90252f6ec3d0 266
allankliu 0:90252f6ec3d0 267 #elif USE_MODEM_FSK == 1
allankliu 0:90252f6ec3d0 268
allankliu 0:90252f6ec3d0 269 //debug("\n\n\r > FSK Mode < \n\n\r");
allankliu 0:90252f6ec3d0 270 Radio.SetTxConfig( MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, 0,
allankliu 0:90252f6ec3d0 271 FSK_DATARATE, 0,
allankliu 0:90252f6ec3d0 272 FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON,
allankliu 0:90252f6ec3d0 273 FSK_CRC_ENABLED, 0, 0, 0, 2000000 );
allankliu 0:90252f6ec3d0 274
allankliu 0:90252f6ec3d0 275 Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE,
allankliu 0:90252f6ec3d0 276 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH,
allankliu 0:90252f6ec3d0 277 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, FSK_CRC_ENABLED,
allankliu 0:90252f6ec3d0 278 0, 0, false, true );
allankliu 0:90252f6ec3d0 279
allankliu 0:90252f6ec3d0 280 #else
allankliu 0:90252f6ec3d0 281
allankliu 0:90252f6ec3d0 282 #error "Please define a modem in the compiler options."
allankliu 0:90252f6ec3d0 283
allankliu 0:90252f6ec3d0 284 #endif
allankliu 0:90252f6ec3d0 285
allankliu 0:90252f6ec3d0 286 //debug_if( DEBUG_MESSAGE, "Starting Ping-Pong loop\r\n" );
allankliu 0:90252f6ec3d0 287
allankliu 0:90252f6ec3d0 288 rand = Radio.Random();
allankliu 0:90252f6ec3d0 289 rand = rand%1000;
allankliu 0:90252f6ec3d0 290 wait_ms((uint16_t)rand);
allankliu 0:90252f6ec3d0 291
allankliu 0:90252f6ec3d0 292 #ifdef PINGPONG
allankliu 0:90252f6ec3d0 293 Radio.Rx( RX_TIMEOUT_VALUE );
allankliu 0:90252f6ec3d0 294
allankliu 0:90252f6ec3d0 295
allankliu 0:90252f6ec3d0 296 while( 1 )
allankliu 0:90252f6ec3d0 297 {
allankliu 0:90252f6ec3d0 298 switch( State )
allankliu 0:90252f6ec3d0 299 {
allankliu 0:90252f6ec3d0 300 case ST_RX:
allankliu 0:90252f6ec3d0 301 if( isMaster == true )
allankliu 0:90252f6ec3d0 302 {
allankliu 0:90252f6ec3d0 303 if( BufferSize > 0 )
allankliu 0:90252f6ec3d0 304 {
allankliu 0:90252f6ec3d0 305 #ifdef UART_ENABLE
allankliu 0:90252f6ec3d0 306 pc.printf("Received message:\r\n");
allankliu 0:90252f6ec3d0 307 pc.printf("%s",Buffer);
allankliu 0:90252f6ec3d0 308 #endif
allankliu 0:90252f6ec3d0 309 //if( strncmp( ( const char* )Buffer, ( const char* )PongMsg, 4 ) == 0 )
allankliu 0:90252f6ec3d0 310 if( my_strncmp( ( const char* )Buffer, ( const char* )PongMsg, 4 ) == 0 )
allankliu 0:90252f6ec3d0 311 {
allankliu 0:90252f6ec3d0 312 nwk_setmode(NWK_NORMAL);
allankliu 0:90252f6ec3d0 313 //debug( "...Pong\r\n" );
allankliu 0:90252f6ec3d0 314 // Send the next PING frame
allankliu 0:90252f6ec3d0 315 my_strcpy( ( char* )Buffer, ( char* )PingMsg );
allankliu 0:90252f6ec3d0 316 //_strcpy( ( char* )Buffer, ( char* )PingMsg );
allankliu 0:90252f6ec3d0 317 // We fill the buffer with numbers for the payload
allankliu 0:90252f6ec3d0 318 for( i = 4; i < BufferSize; i++ )
allankliu 0:90252f6ec3d0 319 {
allankliu 0:90252f6ec3d0 320 Buffer[i] = i - 4;
allankliu 0:90252f6ec3d0 321 }
allankliu 0:90252f6ec3d0 322 wait_ms( 10 );
allankliu 0:90252f6ec3d0 323 Radio.Send( Buffer, BufferSize );
allankliu 0:90252f6ec3d0 324 }
allankliu 0:90252f6ec3d0 325 else if( my_strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 )
allankliu 0:90252f6ec3d0 326 { // A master already exists then become a slave
allankliu 0:90252f6ec3d0 327 debug( "...Ping\r\n" );
allankliu 0:90252f6ec3d0 328 //nwk_setmode(NWK_NORMAL);
allankliu 0:90252f6ec3d0 329 //led = !led;
allankliu 0:90252f6ec3d0 330 isMaster = false;
allankliu 0:90252f6ec3d0 331 // Send the next PONG frame
allankliu 0:90252f6ec3d0 332 my_strcpy( ( char* )Buffer, ( char* )PongMsg );
allankliu 0:90252f6ec3d0 333 // We fill the buffer with numbers for the payload
allankliu 0:90252f6ec3d0 334 for( i = 4; i < BufferSize; i++ )
allankliu 0:90252f6ec3d0 335 {
allankliu 0:90252f6ec3d0 336 Buffer[i] = i - 4;
allankliu 0:90252f6ec3d0 337 }
allankliu 0:90252f6ec3d0 338 wait_ms( 10 );
allankliu 0:90252f6ec3d0 339 Radio.Send( Buffer, BufferSize );
allankliu 0:90252f6ec3d0 340 }
allankliu 0:90252f6ec3d0 341 else // valid reception but neither a PING or a PONG message
allankliu 0:90252f6ec3d0 342 { // Set device as master ans start again
allankliu 0:90252f6ec3d0 343 isMaster = true;
allankliu 0:90252f6ec3d0 344 Radio.Rx( RX_TIMEOUT_VALUE );
allankliu 0:90252f6ec3d0 345 }
allankliu 0:90252f6ec3d0 346 }
allankliu 0:90252f6ec3d0 347 }
allankliu 0:90252f6ec3d0 348 else
allankliu 0:90252f6ec3d0 349 {
allankliu 0:90252f6ec3d0 350 if( BufferSize > 0 )
allankliu 0:90252f6ec3d0 351 {
allankliu 0:90252f6ec3d0 352 #ifdef UART_ENABLE
allankliu 0:90252f6ec3d0 353 pc.printf("Received message:\r\n");
allankliu 0:90252f6ec3d0 354 pc.printf("%s",Buffer);
allankliu 0:90252f6ec3d0 355 #endif
allankliu 0:90252f6ec3d0 356
allankliu 0:90252f6ec3d0 357 if( my_strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 )
allankliu 0:90252f6ec3d0 358 {
allankliu 0:90252f6ec3d0 359 nwk_setmode(NWK_NORMAL);
allankliu 0:90252f6ec3d0 360 //led = !led;
allankliu 0:90252f6ec3d0 361 //debug( "...Ping\r\n" );
allankliu 0:90252f6ec3d0 362 // Send the reply to the PING string
allankliu 0:90252f6ec3d0 363 my_strcpy( ( char* )Buffer, ( char* )PongMsg );
allankliu 0:90252f6ec3d0 364 // We fill the buffer with numbers for the payload
allankliu 0:90252f6ec3d0 365 for( i = 4; i < BufferSize; i++ )
allankliu 0:90252f6ec3d0 366 {
allankliu 0:90252f6ec3d0 367 Buffer[i] = i - 4;
allankliu 0:90252f6ec3d0 368 }
allankliu 0:90252f6ec3d0 369 wait_ms( 10 );
allankliu 0:90252f6ec3d0 370 Radio.Send( Buffer, BufferSize );
allankliu 0:90252f6ec3d0 371 }
allankliu 0:90252f6ec3d0 372 else // valid reception but not a PING as expected
allankliu 0:90252f6ec3d0 373 { // Set device as master and start again
allankliu 0:90252f6ec3d0 374 isMaster = true;
allankliu 0:90252f6ec3d0 375 Radio.Rx( RX_TIMEOUT_VALUE );
allankliu 0:90252f6ec3d0 376 }
allankliu 0:90252f6ec3d0 377 }
allankliu 0:90252f6ec3d0 378 }
allankliu 0:90252f6ec3d0 379 State = ST_LOWPOWER;
allankliu 0:90252f6ec3d0 380 break;
allankliu 0:90252f6ec3d0 381 case ST_TX:
allankliu 0:90252f6ec3d0 382 //nwk_setmode(NWK_NORMAL);
allankliu 0:90252f6ec3d0 383 //led = !led;
allankliu 0:90252f6ec3d0 384 if( isMaster == true )
allankliu 0:90252f6ec3d0 385 {
allankliu 0:90252f6ec3d0 386 //debug( "Ping...\r\n" );
allankliu 0:90252f6ec3d0 387 }
allankliu 0:90252f6ec3d0 388 else
allankliu 0:90252f6ec3d0 389 {
allankliu 0:90252f6ec3d0 390 //debug( "Pong...\r\n" );
allankliu 0:90252f6ec3d0 391 }
allankliu 0:90252f6ec3d0 392 Radio.Rx( RX_TIMEOUT_VALUE );
allankliu 0:90252f6ec3d0 393 State = ST_LOWPOWER;
allankliu 0:90252f6ec3d0 394 break;
allankliu 0:90252f6ec3d0 395 case ST_RX_TIMEOUT:
allankliu 0:90252f6ec3d0 396 //debugled = !debugled;
allankliu 0:90252f6ec3d0 397 //debugled2 = !debugled2;
allankliu 0:90252f6ec3d0 398 nwk_setmode(NWK_ERR);
allankliu 0:90252f6ec3d0 399 if( isMaster == true )
allankliu 0:90252f6ec3d0 400 {
allankliu 0:90252f6ec3d0 401 // Send the next PING frame
allankliu 0:90252f6ec3d0 402 my_strcpy( ( char* )Buffer, ( char* )PingMsg );
allankliu 0:90252f6ec3d0 403 for( i = 4; i < BufferSize; i++ )
allankliu 0:90252f6ec3d0 404 {
allankliu 0:90252f6ec3d0 405 Buffer[i] = i - 4;
allankliu 0:90252f6ec3d0 406 }
allankliu 0:90252f6ec3d0 407 wait_ms( 10 );
allankliu 0:90252f6ec3d0 408 Radio.Send( Buffer, BufferSize );
allankliu 0:90252f6ec3d0 409 }
allankliu 0:90252f6ec3d0 410 else
allankliu 0:90252f6ec3d0 411 {
allankliu 0:90252f6ec3d0 412 Radio.Rx( RX_TIMEOUT_VALUE );
allankliu 0:90252f6ec3d0 413 }
allankliu 0:90252f6ec3d0 414 State = ST_LOWPOWER;
allankliu 0:90252f6ec3d0 415 break;
allankliu 0:90252f6ec3d0 416 case ST_RX_ERROR:
allankliu 0:90252f6ec3d0 417 // We have received a Packet with a CRC error, send reply as if packet was correct
allankliu 0:90252f6ec3d0 418 nwk_setmode(NWK_ERR);
allankliu 0:90252f6ec3d0 419 if( isMaster == true )
allankliu 0:90252f6ec3d0 420 {
allankliu 0:90252f6ec3d0 421 // Send the next PING frame
allankliu 0:90252f6ec3d0 422 my_strcpy( ( char* )Buffer, ( char* )PingMsg );
allankliu 0:90252f6ec3d0 423 for( i = 4; i < BufferSize; i++ )
allankliu 0:90252f6ec3d0 424 {
allankliu 0:90252f6ec3d0 425 Buffer[i] = i - 4;
allankliu 0:90252f6ec3d0 426 }
allankliu 0:90252f6ec3d0 427 wait_ms( 10 );
allankliu 0:90252f6ec3d0 428 Radio.Send( Buffer, BufferSize );
allankliu 0:90252f6ec3d0 429 }
allankliu 0:90252f6ec3d0 430 else
allankliu 0:90252f6ec3d0 431 {
allankliu 0:90252f6ec3d0 432 // Send the next PONG frame
allankliu 0:90252f6ec3d0 433 my_strcpy( ( char* )Buffer, ( char* )PongMsg );
allankliu 0:90252f6ec3d0 434 for( i = 4; i < BufferSize; i++ )
allankliu 0:90252f6ec3d0 435 {
allankliu 0:90252f6ec3d0 436 Buffer[i] = i - 4;
allankliu 0:90252f6ec3d0 437 }
allankliu 0:90252f6ec3d0 438 wait_ms( 10 );
allankliu 0:90252f6ec3d0 439 Radio.Send( Buffer, BufferSize );
allankliu 0:90252f6ec3d0 440 }
allankliu 0:90252f6ec3d0 441 State = ST_LOWPOWER;
allankliu 0:90252f6ec3d0 442 break;
allankliu 0:90252f6ec3d0 443 case ST_TX_TIMEOUT:
allankliu 0:90252f6ec3d0 444 nwk_setmode(NWK_ERR);
allankliu 0:90252f6ec3d0 445 Radio.Rx( RX_TIMEOUT_VALUE );
allankliu 0:90252f6ec3d0 446 State = ST_LOWPOWER;
allankliu 0:90252f6ec3d0 447 break;
allankliu 0:90252f6ec3d0 448 case ST_CAD:
allankliu 0:90252f6ec3d0 449 break;
allankliu 0:90252f6ec3d0 450 case ST_CAD_DONE:
allankliu 0:90252f6ec3d0 451 if(channelOccupied){
allankliu 0:90252f6ec3d0 452 State = ST_LOWPOWER;
allankliu 0:90252f6ec3d0 453 }else{
allankliu 0:90252f6ec3d0 454 // start to transmit here.
allankliu 0:90252f6ec3d0 455 }
allankliu 0:90252f6ec3d0 456 break;
allankliu 0:90252f6ec3d0 457 case ST_LOWPOWER:
allankliu 0:90252f6ec3d0 458 break;
allankliu 0:90252f6ec3d0 459 default:
allankliu 0:90252f6ec3d0 460 nwk_setmode(0xFF);
allankliu 0:90252f6ec3d0 461 State = ST_LOWPOWER;
allankliu 0:90252f6ec3d0 462 break;
allankliu 0:90252f6ec3d0 463 }
allankliu 0:90252f6ec3d0 464 }
allankliu 0:90252f6ec3d0 465
allankliu 0:90252f6ec3d0 466 #else
allankliu 0:90252f6ec3d0 467
allankliu 0:90252f6ec3d0 468 if(isMaster == true){
allankliu 0:90252f6ec3d0 469 tx_tmr.start();
allankliu 0:90252f6ec3d0 470 begin = tx_tmr.read_ms();
allankliu 0:90252f6ec3d0 471 }else{
allankliu 0:90252f6ec3d0 472 Radio.Rx( RX_TIMEOUT_VALUE );
allankliu 0:90252f6ec3d0 473 }
allankliu 0:90252f6ec3d0 474
allankliu 0:90252f6ec3d0 475 while(1){
allankliu 0:90252f6ec3d0 476 switch(State){
allankliu 0:90252f6ec3d0 477 case ST_RX:
allankliu 0:90252f6ec3d0 478 //nwk_setmode(NWK_RX_OK);
allankliu 0:90252f6ec3d0 479 Radio.Rx( RX_TIMEOUT_VALUE );
allankliu 0:90252f6ec3d0 480 State = ST_LOWPOWER;
allankliu 0:90252f6ec3d0 481 #ifdef UART_ENABLE
allankliu 0:90252f6ec3d0 482 //pc.printf("\r\nRX OK\tRSSI:%f SNR:%f \r\n",float(RssiValue),float(SnrValue));
allankliu 0:90252f6ec3d0 483 pc.printf("\r\nRX OK\tRSSI:%d SNR:%d \r\n",RssiValue,SnrValue);
allankliu 0:90252f6ec3d0 484 pc.printf("\r\nRSSI: %02X SNR: %01X\r\n", RssiValue, SnrValue);
allankliu 0:90252f6ec3d0 485 #endif
allankliu 0:90252f6ec3d0 486 break;
allankliu 0:90252f6ec3d0 487 case ST_TX:
allankliu 0:90252f6ec3d0 488 nwk_setmode(NWK_TX);
allankliu 0:90252f6ec3d0 489 State = ST_LOWPOWER;
allankliu 0:90252f6ec3d0 490 #ifdef UART_ENABLE
allankliu 0:90252f6ec3d0 491 pc.printf("\r\nTX Done.\r\n");
allankliu 0:90252f6ec3d0 492 #endif
allankliu 0:90252f6ec3d0 493 break;
allankliu 0:90252f6ec3d0 494 case ST_RX_TIMEOUT:
allankliu 0:90252f6ec3d0 495 case ST_RX_ERROR:
allankliu 0:90252f6ec3d0 496 //nwk_setmode(NWK_RX_NOK);
allankliu 0:90252f6ec3d0 497 Radio.Rx( RX_TIMEOUT_VALUE );
allankliu 0:90252f6ec3d0 498 State = ST_LOWPOWER;
allankliu 0:90252f6ec3d0 499 #ifdef UART_ENABLE
allankliu 0:90252f6ec3d0 500 pc.printf("\r\nRX TIMEOUT or ERROR.\r\n");
allankliu 0:90252f6ec3d0 501 #endif
allankliu 0:90252f6ec3d0 502 break;
allankliu 0:90252f6ec3d0 503 case ST_TX_TIMEOUT:
allankliu 0:90252f6ec3d0 504 State = ST_LOWPOWER;
allankliu 0:90252f6ec3d0 505 break;
allankliu 0:90252f6ec3d0 506 case ST_LOWPOWER:
allankliu 0:90252f6ec3d0 507 if (isMaster){
allankliu 0:90252f6ec3d0 508 end = tx_tmr.read_ms();
allankliu 0:90252f6ec3d0 509 if ((end-begin) >= 2000){
allankliu 0:90252f6ec3d0 510 Sender();
allankliu 0:90252f6ec3d0 511 tx_tmr.stop();
allankliu 0:90252f6ec3d0 512 tx_tmr.start();
allankliu 0:90252f6ec3d0 513 begin = tx_tmr.read_ms();
allankliu 0:90252f6ec3d0 514 }
allankliu 0:90252f6ec3d0 515 }
allankliu 0:90252f6ec3d0 516 break;
allankliu 0:90252f6ec3d0 517 default:
allankliu 0:90252f6ec3d0 518 State = ST_LOWPOWER;
allankliu 0:90252f6ec3d0 519 break;
allankliu 0:90252f6ec3d0 520 }
allankliu 0:90252f6ec3d0 521 }
allankliu 0:90252f6ec3d0 522 #endif
allankliu 0:90252f6ec3d0 523
allankliu 0:90252f6ec3d0 524 }
allankliu 0:90252f6ec3d0 525
allankliu 0:90252f6ec3d0 526
allankliu 0:90252f6ec3d0 527 void OnTxDone( void )
allankliu 0:90252f6ec3d0 528 {
allankliu 0:90252f6ec3d0 529 Radio.Sleep( );
allankliu 0:90252f6ec3d0 530 State = ST_TX;
allankliu 0:90252f6ec3d0 531 //debug_if( DEBUG_MESSAGE, "> OnTxDone\n\r" );
allankliu 0:90252f6ec3d0 532 }
allankliu 0:90252f6ec3d0 533
allankliu 0:90252f6ec3d0 534 void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr)
allankliu 0:90252f6ec3d0 535 {
allankliu 0:90252f6ec3d0 536 Radio.Sleep( );
allankliu 0:90252f6ec3d0 537 BufferSize = size;
allankliu 0:90252f6ec3d0 538 memcpy( Buffer, payload, BufferSize );
allankliu 0:90252f6ec3d0 539 RssiValue = rssi;
allankliu 0:90252f6ec3d0 540 SnrValue = snr;
allankliu 0:90252f6ec3d0 541 State = ST_RX;
allankliu 0:90252f6ec3d0 542 nwk_setmode(NWK_RX_OK);
allankliu 0:90252f6ec3d0 543 //debug_if( DEBUG_MESSAGE, "> OnRxDone\n\r" );
allankliu 0:90252f6ec3d0 544 }
allankliu 0:90252f6ec3d0 545
allankliu 0:90252f6ec3d0 546 void OnTxTimeout( void )
allankliu 0:90252f6ec3d0 547 {
allankliu 0:90252f6ec3d0 548 Radio.Sleep( );
allankliu 0:90252f6ec3d0 549 State = ST_TX_TIMEOUT;
allankliu 0:90252f6ec3d0 550 //debug_if( DEBUG_MESSAGE, "> OnTxTimeout\n\r" );
allankliu 0:90252f6ec3d0 551 }
allankliu 0:90252f6ec3d0 552
allankliu 0:90252f6ec3d0 553 void OnRxTimeout( void )
allankliu 0:90252f6ec3d0 554 {
allankliu 0:90252f6ec3d0 555 Radio.Sleep( );
allankliu 0:90252f6ec3d0 556 Buffer[ BufferSize ] = 0;
allankliu 0:90252f6ec3d0 557 State = ST_RX_TIMEOUT;
allankliu 0:90252f6ec3d0 558 nwk_setmode(NWK_RX_NOK);
allankliu 0:90252f6ec3d0 559 //debug_if( DEBUG_MESSAGE, "> OnRxTimeout\n\r" );
allankliu 0:90252f6ec3d0 560 }
allankliu 0:90252f6ec3d0 561
allankliu 0:90252f6ec3d0 562 void OnRxError( void )
allankliu 0:90252f6ec3d0 563 {
allankliu 0:90252f6ec3d0 564 Radio.Sleep( );
allankliu 0:90252f6ec3d0 565 State = ST_RX_ERROR;
allankliu 0:90252f6ec3d0 566 //debug_if( DEBUG_MESSAGE, "> OnRxError\n\r" );
allankliu 0:90252f6ec3d0 567 }
allankliu 0:90252f6ec3d0 568
allankliu 0:90252f6ec3d0 569 // Added by allankliu
allankliu 0:90252f6ec3d0 570 void OnCadDone( bool channelActivityDetected )
allankliu 0:90252f6ec3d0 571 {
allankliu 0:90252f6ec3d0 572 Radio.Sleep();
allankliu 0:90252f6ec3d0 573 channelOccupied = channelActivityDetected;
allankliu 0:90252f6ec3d0 574 State = ST_CAD_DONE;
allankliu 0:90252f6ec3d0 575 }