Blame view

RIOT/tests/driver_sx127x/main.c 10 KB
a752c7ab   elopes   add first test an...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
  /*
   * Copyright (C) 2016 Unwired Devices <info@unwds.com>
   *               2017 Inria Chile
   *               2017 Inria
   *
   * This file is subject to the terms and conditions of the GNU Lesser
   * General Public License v2.1. See the file LICENSE in the top level
   * directory for more details.
   */
  
  /**
   * @ingroup     tests
   * @{
   * @file
   * @brief       Test application for SX127X modem driver
   *
   * @author      Eugene P. <ep@unwds.com>
   * @author      José Ignacio Alamos <jose.alamos@inria.cl>
   * @author      Alexandre Abadie <alexandre.abadie@inria.fr>
   * @}
   */
  
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  
  #include "thread.h"
  #include "xtimer.h"
  #include "shell.h"
  #include "shell_commands.h"
  
  #include "net/gnrc/netdev.h"
  #include "net/netdev.h"
  
  #include "board.h"
  #include "periph/rtc.h"
  
  #include "sx127x_internal.h"
  #include "sx127x_params.h"
  #include "sx127x_netdev.h"
  
  #define SX127X_LORA_MSG_QUEUE   (16U)
  #define SX127X_STACKSIZE        (THREAD_STACKSIZE_DEFAULT)
  
  #define MSG_TYPE_ISR            (0x3456)
  
  static char stack[SX127X_STACKSIZE];
  static kernel_pid_t _recv_pid;
  
  static char message[32];
  static sx127x_t sx127x;
  static netdev_t *netdev;
  
  int lora_setup_cmd(int argc, char **argv) {
  
      if (argc < 4) {
          puts("usage: setup "
               "<bandwidth (125, 250, 500)> "
               "<spreading factor (7..12)> "
               "<code rate (5..8)>");
          return -1;
      }
  
      /* Check bandwidth value */
      int bw = atoi(argv[1]);
      uint8_t lora_bw;
      switch (bw) {
          case 125:
              puts("setup: setting 125KHz bandwidth");
              lora_bw = SX127X_BW_125_KHZ;
              break;
  
          case 250:
              puts("setup: setting 250KHz bandwidth");
              lora_bw = SX127X_BW_250_KHZ;
              break;
  
          case 500:
              puts("setup: setting 500KHz bandwidth");
              lora_bw = SX127X_BW_500_KHZ;
              break;
  
          default:
              puts("[Error] setup: invalid bandwidth value given, "
                   "only 125, 250 or 500 allowed.");
              return -1;
      }
  
      /* Check spreading factor value */
      uint8_t lora_sf = atoi(argv[2]);
      if (lora_sf < 7 || lora_sf > 12) {
          puts("[Error] setup: invalid spreading factor value given");
          return -1;
      }
  
      /* Check coding rate value */
      int cr = atoi(argv[3]);;
      if (cr < 5 || cr > 8) {
          puts("[Error ]setup: invalid coding rate value given");
          return -1;
      }
      uint8_t lora_cr = (uint8_t)(cr - 4);
  
      /* Configure radio device */
      netdev_t *netdev = (netdev_t*) &sx127x;
      netdev->driver->set(netdev, NETOPT_BANDWIDTH,
                          &lora_bw, sizeof(uint8_t));
      netdev->driver->set(netdev, NETOPT_SPREADING_FACTOR,
                          &lora_sf, 1);
      netdev->driver->set(netdev, NETOPT_CODING_RATE,
                          &lora_cr, sizeof(uint8_t));
  
      puts("[Info] setup: configuration set with success");
  
      return 0;
  }
  
  int random_cmd(int argc, char **argv)
  {
      printf("random: number from sx127x: %u\n",
             (unsigned int) sx127x_random((sx127x_t*) netdev));
  
      /* reinit the transceiver to default values */
      sx127x_init_radio_settings((sx127x_t*) netdev);
  
      return 0;
  }
  
  int register_cmd(int argc, char **argv)
  {
      if (argc < 2) {
          puts("usage: register <get | set>");
          return -1;
      }
  
      if (strstr(argv[1], "get") != NULL) {
          if (argc < 3) {
              puts("usage: register get <all | allinline | regnum>");
              return -1;
          }
          if (strcmp(argv[2], "all") == 0) {
              puts("- listing all registers -");
              uint8_t reg = 0, data = 0;
              /* Listing registers map */
              puts("Reg   0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
              for (unsigned i = 0; i <= 7; i++) {
                  printf("0x%02X ", i << 4);
  
                  for (unsigned j = 0; j <= 15; j++, reg++) {
                      data = sx127x_reg_read(&sx127x, reg);
                      printf("%02X ", data);
                  }
                  puts("");
              }
              puts("-done-");
              return 0;
          } else if (strcmp(argv[2], "allinline") == 0) {
              puts("- listing all registers in one line -");
              /* Listing registers map */
              for (uint16_t reg = 0; reg < 256; reg++) {
                  printf("%02X ", sx127x_reg_read(&sx127x, (uint8_t) reg));
              }
              puts("- done -");
              return 0;
          } else {
              long int num = 0;
              /* Register number in hex */
              if (strstr(argv[2], "0x") != NULL) {
                  num = strtol(argv[2], NULL, 16);
              } else {
                  num = atoi(argv[2]);
              }
              if (num >= 0 && num <= 255) {
                  printf("[regs] 0x%02X = 0x%02X\n",
                         (uint8_t) num,
                         sx127x_reg_read(&sx127x, (uint8_t) num));
              } else {
                  puts("regs: invalid register number specified");
                  return -1;
              }
          }
      } else if (strstr(argv[1], "set") != NULL) {
          if (argc < 4) {
              puts("usage: register set <regnum> <value>");
              return -1;
          }
  
          long num, val;
  
          /* Register number in hex */
          if (strstr(argv[2], "0x") != NULL) {
              num = strtol(argv[2], NULL, 16);
          } else {
              num = atoi(argv[2]);
          }
  
          /* Register value in hex */
          if (strstr(argv[3], "0x") != NULL) {
              val = strtol(argv[3], NULL, 16);
          } else {
              val = atoi(argv[3]);
          }
  
          sx127x_reg_write(&sx127x, (uint8_t) num, (uint8_t) val);
      }
      else {
          puts("usage: register get <all | allinline | regnum>");
          return -1;
      }
  
      return 0;
  }
  
  int send_cmd(int argc, char **argv)
  {
      if (argc <= 1) {
          puts("usage: send <payload>");
          return -1;
      }
  
      printf("sending \"%s\" payload (%d bytes)\n",
             argv[1], strlen(argv[1]) + 1);
  
      struct iovec vec[1];
      vec[0].iov_base = argv[1];
      vec[0].iov_len = strlen(argv[1]) + 1;
      if (netdev->driver->send(netdev, vec, 1) == -ENOTSUP) {
          puts("Cannot send: radio is still transmitting");
      }
  
      return 0;
  }
  
  int listen_cmd(int argc, char **argv)
  {
      /* Switch to continuous listen mode */
      netdev->driver->set(netdev, NETOPT_SINGLE_RECEIVE, false, sizeof(uint8_t));
      sx127x_set_rx(&sx127x);
  
      printf("Listen mode set\n");
  
      return 0;
  }
  
  int channel_cmd(int argc, char **argv)
  {
      if(argc < 2) {
          puts("usage: channel <get|set>");
          return -1;
      }
  
      uint32_t chan;
      if (strstr(argv[1], "get") != NULL) {
          netdev->driver->get(netdev, NETOPT_CHANNEL, &chan, sizeof(uint32_t));
          printf("Channel: %i\n", (int) chan);
          return 0;
      }
  
      if (strstr(argv[1], "set") != NULL) {
          if(argc < 3) {
              puts("usage: channel set <channel>");
              return -1;
          }
          chan = atoi(argv[2]);
          netdev->driver->set(netdev, NETOPT_CHANNEL, &chan, sizeof(uint32_t));
          printf("New channel set\n");
      }
      else {
          puts("usage: channel <get|set>");
          return -1;
      }
  
      return 0;
  }
  
  static const shell_command_t shell_commands[] = {
      { "setup",    "Initialize LoRa modulation settings",     lora_setup_cmd},
      { "random",   "Get random number from sx127x",           random_cmd },
      { "channel",  "Get/Set channel frequency (in Hz)",       channel_cmd },
      { "register", "Get/Set value(s) of registers of sx127x", register_cmd },
      { "send",     "Send raw payload string",                 send_cmd },
      { "listen",   "Start raw payload listener",              listen_cmd },
      { NULL, NULL, NULL }
  };
  
  static void _event_cb(netdev_t *dev, netdev_event_t event)
  {
      if (event == NETDEV_EVENT_ISR) {
          msg_t msg;
  
          msg.type = MSG_TYPE_ISR;
          msg.content.ptr = dev;
  
          if (msg_send(&msg, _recv_pid) <= 0) {
              puts("gnrc_netdev: possibly lost interrupt.");
          }
      }
      else {
          size_t len;
          netdev_sx127x_lora_packet_info_t packet_info;
          switch (event) {
              case NETDEV_EVENT_RX_COMPLETE:
                  len = dev->driver->recv(dev, NULL, 0, 0);
                  dev->driver->recv(dev, message, len, &packet_info);
                  printf("{Payload: \"%s\" (%d bytes), RSSI: %i, SNR: %i, TOA: %i}\n",
                         message, (int)len,
                         packet_info.rssi, (int)packet_info.snr,
                         (int)packet_info.time_on_air);
                  break;
              case NETDEV_EVENT_TX_COMPLETE:
                  sx127x_set_sleep(&sx127x);
                  puts("Transmission completed");
                  break;
              case NETDEV_EVENT_CAD_DONE:
                  break;
              case NETDEV_EVENT_TX_TIMEOUT:
                  sx127x_set_sleep(&sx127x);
                  break;
              default:
                  printf("Unexpected netdev event received: %d\n", event);
                  break;
          }
      }
  }
  
  void *_recv_thread(void *arg)
  {
      static msg_t _msg_q[SX127X_LORA_MSG_QUEUE];
      msg_init_queue(_msg_q, SX127X_LORA_MSG_QUEUE);
  
      while (1) {
          msg_t msg;
          msg_receive(&msg);
          if (msg.type == MSG_TYPE_ISR) {
              netdev_t *dev = msg.content.ptr;
              dev->driver->isr(dev);
          }
          else {
              puts("Unexpected msg type");
          }
      }
  }
  
  int main(void)
  {
      memcpy(&sx127x.params, sx127x_params, sizeof(sx127x_params));
      netdev = (netdev_t*) &sx127x;
      netdev->driver = &sx127x_driver;
      netdev->driver->init(netdev);
      netdev->event_callback = _event_cb;
  
      _recv_pid = thread_create(stack, sizeof(stack), THREAD_PRIORITY_MAIN - 1,
                                THREAD_CREATE_STACKTEST, _recv_thread, NULL,
                                "recv_thread");
  
      if (_recv_pid <= KERNEL_PID_UNDEF) {
          puts("Creation of receiver thread failed");
          return 1;
      }
  
      /* start the shell */
      puts("Initialization successful - starting the shell now");
      char line_buf[SHELL_DEFAULT_BUFSIZE];
      shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
  
      return 0;
  }