/* * Copyright (C) 2016 Unwired Devices * 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. * @author José Ignacio Alamos * @author Alexandre Abadie * @} */ #include #include #include #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 " " " " " ""); 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 "); return -1; } if (strstr(argv[1], "get") != NULL) { if (argc < 3) { puts("usage: register get "); 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 "); 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 "); return -1; } return 0; } int send_cmd(int argc, char **argv) { if (argc <= 1) { puts("usage: send "); 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 "); 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 "); 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 "); 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; }