Host driver/HAL to build a LoRa Picocell Gateway which communicates through USB with a concentrator board based on Semtech SX1308 multi-channel modem and SX1257/SX1255 RF transceivers.
libloragw/src/loragw_mcu.c
- Committer:
- dgabino
- Date:
- 2018-04-11
- Revision:
- 0:102b50f941d0
File content as of revision 0:102b50f941d0:
/* / _____) _ | | ( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| (C)2017 Semtech-Cycleo Description: Wrapper to call MCU's HAL functions License: Revised BSD License, see LICENSE.TXT file include in the project */ /* -------------------------------------------------------------------------- */ /* --- DEPENDANCIES --------------------------------------------------------- */ #include <stdint.h> /* C99 types */ #include <stdio.h> /* printf fprintf */ #include <stdlib.h> /* malloc free */ #include <unistd.h> /* lseek, close */ #include <fcntl.h> /* open */ #include <string.h> /* memset */ #include <errno.h> /* Error number definitions */ #include <termios.h> /* POSIX terminal control definitions */ #include <sys/ioctl.h> #include <pthread.h> #include <time.h> #include <sys/select.h> #include "loragw_com.h" #include "loragw_mcu.h" #include "loragw_aux.h" /* -------------------------------------------------------------------------- */ /* --- PRIVATE MACROS ------------------------------------------------------- */ #if DEBUG_MCU == 1 #define DEBUG_MSG(str) fprintf(stderr, str) #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) #define CHECK_NULL(a) if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_COM_ERROR;} #else #define DEBUG_MSG(str) #define DEBUG_PRINTF(fmt, args...) #define CHECK_NULL(a) if(a==NULL){return LGW_COM_ERROR;} #endif /* -------------------------------------------------------------------------- */ /* --- PRIVATE SHARED VARIABLES (GLOBAL) ------------------------------------ */ extern void *lgw_com_target; /*! generic pointer to the COM device */ /* -------------------------------------------------------------------------- */ /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ int lgw_mcu_board_setconf(struct lgw_conf_board_s conf) { int i, x; lgw_com_cmd_t cmd; lgw_com_ans_t ans; uint8_t PADDING = 0; uint8_t data[4]; uint16_t size; /* struct to byte array */ data[0] = conf.lorawan_public; data[1] = conf.clksrc; data[2] = PADDING; data[3] = PADDING; size = sizeof(data) / sizeof(uint8_t); /* prepare command */ cmd.id = 'i'; cmd.len_msb = (uint8_t)((size >> 8) & 0xFF); cmd.len_lsb = (uint8_t)((size >> 0) & 0xFF); cmd.address = 0; for (i = 0; i < size; i++) { cmd.cmd_data[i] = data[i]; } /* send command to MCU */ x = lgw_com_send_command(lgw_com_target, cmd, &ans); if (x != LGW_COM_SUCCESS) { printf("ERROR: failed to configure board\n"); return LGW_MCU_ERROR; } /* check command acknoledge */ if (ans.status != ACK_OK) { printf("ERROR: failed to configure board, ACK failed\n"); return LGW_MCU_ERROR; } return LGW_MCU_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_mcu_rxrf_setconf(uint8_t rfchain, struct lgw_conf_rxrf_s conf) { int i, x; lgw_com_cmd_t cmd; lgw_com_ans_t ans; uint8_t PADDING = 0; uint8_t data[20]; uint16_t size; /* struct to byte array */ /* --- 64-bits start --- */ data[0] = conf.enable; data[1] = PADDING; data[2] = PADDING; data[3] = PADDING; data[4] = *(((uint8_t *)(&conf.freq_hz))); data[5] = *(((uint8_t *)(&conf.freq_hz)) + 1); data[6] = *(((uint8_t *)(&conf.freq_hz)) + 2); data[7] = *(((uint8_t *)(&conf.freq_hz)) + 3); /* --- 64-bits start --- */ data[8] = *(((uint8_t *)(&conf.rssi_offset))); data[9] = *(((uint8_t *)(&conf.rssi_offset)) + 1); data[10] = *(((uint8_t *)(&conf.rssi_offset)) + 2); data[11] = *(((uint8_t *)(&conf.rssi_offset)) + 3); data[12] = *(((uint8_t *)(&conf.type))); data[13] = PADDING; data[14] = PADDING; data[15] = PADDING; /* --- 64-bits start --- */ data[16] = *(((uint8_t *)(&conf.tx_enable))); data[17] = *(((uint8_t *)(&conf.tx_enable)) + 1); data[18] = *(((uint8_t *)(&conf.tx_enable)) + 2); data[19] = *(((uint8_t *)(&conf.tx_enable)) + 3); size = sizeof(data) / sizeof(uint8_t); /* prepare command */ cmd.id = 'c'; cmd.len_msb = (uint8_t)((size >> 8) & 0xFF); cmd.len_lsb = (uint8_t)((size >> 0) & 0xFF); cmd.address = rfchain; for (i = 0; i < size; i++) { cmd.cmd_data[i] = data[i]; } /* send command to MCU */ x = lgw_com_send_command(lgw_com_target, cmd, &ans); if (x != LGW_COM_SUCCESS) { printf("ERROR: failed to send rxrf configuration\n"); return LGW_MCU_ERROR; } /* check command acknoledge */ if (ans.status != ACK_OK) { printf("ERROR: rxrf configuration, ACK failed\n"); return LGW_MCU_ERROR; } return LGW_MCU_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_mcu_rxif_setconf(uint8_t ifchain, struct lgw_conf_rxif_s conf) { int i, x; lgw_com_cmd_t cmd; lgw_com_ans_t ans; uint8_t PADDING = 0; uint8_t data[32]; uint16_t size; /* struct to byte array */ /* --- 64-bits start --- */ data[0] = conf.enable; data[1] = *(((uint8_t *)(&conf.rf_chain))); data[2] = PADDING; data[3] = PADDING; data[4] = *(((uint8_t *)(&conf.freq_hz))); data[5] = *(((uint8_t *)(&conf.freq_hz)) + 1); data[6] = *(((uint8_t *)(&conf.freq_hz)) + 2); data[7] = *(((uint8_t *)(&conf.freq_hz)) + 3); /* --- 64-bits start --- */ data[8] = *(((uint8_t *)(&conf.bandwidth))); data[9] = PADDING; data[10] = PADDING; data[11] = PADDING; data[12] = *(((uint8_t *)(&conf.datarate))); data[13] = *(((uint8_t *)(&conf.datarate)) + 1); data[14] = *(((uint8_t *)(&conf.datarate)) + 2); data[15] = *(((uint8_t *)(&conf.datarate)) + 3); /* --- 64-bits start --- */ data[16] = *(((uint8_t *)(&conf.sync_word_size))); data[17] = PADDING; data[18] = PADDING; data[19] = PADDING; data[20] = PADDING; data[21] = PADDING; data[22] = PADDING; data[23] = PADDING; /* --- 64-bits start --- */ data[24] = *(((uint8_t *)(&conf.sync_word))); data[25] = *(((uint8_t *)(&conf.sync_word)) + 1); data[26] = *(((uint8_t *)(&conf.sync_word)) + 2); data[27] = *(((uint8_t *)(&conf.sync_word)) + 3); data[28] = *(((uint8_t *)(&conf.sync_word)) + 4); data[29] = *(((uint8_t *)(&conf.sync_word)) + 5); data[30] = *(((uint8_t *)(&conf.sync_word)) + 6); data[31] = *(((uint8_t *)(&conf.sync_word)) + 7); size = sizeof(data) / sizeof(uint8_t); /* prepare command */ cmd.id = 'd'; cmd.len_msb = (uint8_t)((size >> 8) & 0xFF); cmd.len_lsb = (uint8_t)((size >> 0) & 0xFF); cmd.address = ifchain; for (i = 0; i < size; i++) { cmd.cmd_data[i] = data[i]; } /* send command to MCU */ x = lgw_com_send_command(lgw_com_target, cmd, &ans); if (x != LGW_COM_SUCCESS) { printf("ERROR: failed to send rxif configuration\n"); return LGW_MCU_ERROR; } /* check command acknoledge */ if (ans.status != ACK_OK) { printf("ERROR: rxif configuration, ACK failed\n"); return LGW_MCU_ERROR; } return LGW_MCU_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_mcu_txgain_setconf(struct lgw_tx_gain_lut_s *conf) { int i, x; lgw_com_cmd_t cmd; lgw_com_ans_t ans; uint32_t u = 0; uint8_t data[(LGW_MULTI_NB * TX_GAIN_LUT_SIZE_MAX) + 4]; uint16_t size; /* struct to byte array */ for (u = 0; u < TX_GAIN_LUT_SIZE_MAX; u++) { data[0 + (5 * u)] = 0; data[1 + (5 * u)] = 0; data[2 + (5 * u)] = 0; data[3 + (5 * u)] = 0; data[4 + (5 * u)] = 0; } for (u = 0; u < conf->size; u++) { data[0 + (5 * u)] = conf->lut[u].dig_gain; data[1 + (5 * u)] = conf->lut[u].pa_gain; data[2 + (5 * u)] = conf->lut[u].dac_gain; data[3 + (5 * u)] = conf->lut[u].mix_gain; data[4 + (5 * u)] = conf->lut[u].rf_power; } data[(TX_GAIN_LUT_SIZE_MAX) * 5] = conf->size; size = ((TX_GAIN_LUT_SIZE_MAX) * 5) + 1; /* prepare command */ cmd.id = 'h'; cmd.len_msb = (uint8_t)((size >> 8) & 0xFF); cmd.len_lsb = (uint8_t)((size >> 0) & 0xFF); cmd.address = 0; for (i = 0; i < size; i++) { cmd.cmd_data[i] = data[i]; } /* send command to MCU */ x = lgw_com_send_command(lgw_com_target, cmd, &ans); if (x != LGW_COM_SUCCESS) { printf("ERROR: failed to send tx gain configuration\n"); return LGW_MCU_ERROR; } /* check command acknoledge */ if (ans.status != ACK_OK) { printf("ERROR: tx gain configuration, ACK failed\n"); return LGW_MCU_ERROR; } return LGW_MCU_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_mcu_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) { int i, j, x; int cptalc = 0; lgw_com_cmd_t cmd; lgw_com_ans_t ans; int nb_packet ; uint8_t data[LGW_PKT_RX_STRUCT_SIZE_ALIGNED * max_pkt]; uint16_t pkt_size; /* check input variables */ CHECK_NULL(pkt_data); /* Prepare command for fetching packets */ cmd.id = 'b'; cmd.len_msb = 0; cmd.len_lsb = 1; cmd.address = 0; cmd.cmd_data[0] = max_pkt; /* send command to MCU */ x = lgw_com_send_command(lgw_com_target, cmd, &ans); if ((x != LGW_COM_SUCCESS) || (ans.status != ACK_OK)) { DEBUG_MSG("ERROR: failed to receive packets from concentrator\n"); return 0; } /* check nb_packet variables */ nb_packet = ans.ans_data[0]; if ((nb_packet > LGW_PKT_FIFO_SIZE) || (nb_packet < 0)) { DEBUG_PRINTF("ERROR: NOT A VALID NUMBER OF RECEIVED PACKET (%d)\n", nb_packet); return 0; } //DEBUG_PRINTF("NOTE: Available packet %d %d\n", nb_packet, (ans.len_msb << 8) + ans.len_lsb); /* over the number of packets */ for (i = 0; i < nb_packet; i++) { /* for each packet */ pkt_size = (uint16_t)((uint8_t)(ans.ans_data[cptalc + 42] << 8) | (uint8_t)ans.ans_data[cptalc + 43]); for (j = 0; j < (LGW_PKT_RX_METADATA_SIZE_ALIGNED + pkt_size); j++) { data[(i * LGW_PKT_RX_STRUCT_SIZE_ALIGNED) + j] = ans.ans_data[j + cptalc + 1]; /* +1 because ans.ans_data[0] is nb_packet */ } cptalc += j; } /* byte array to struct - the following code is done to work both with 32 or 64 bits host */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-aliasing" for (i = 0; i < nb_packet; i++) { /* --- 64-bits start --- */ pkt_data[i].freq_hz = *((uint32_t*)(&data[0 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); pkt_data[i].if_chain = *((uint8_t*)(&data[4 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); pkt_data[i].status = *((uint8_t*)(&data[5 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); /* 1 BYTE PADDING FOR 64-bits ALIGNMENT */ /* 1 BYTE PADDING FOR 64-bits ALIGNMENT */ /* --- 64-bits start --- */ pkt_data[i].count_us = *((uint32_t*)(&data[8 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); pkt_data[i].rf_chain = *((uint8_t*)(&data[12 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); pkt_data[i].modulation = *((uint8_t*)(&data[13 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); pkt_data[i].bandwidth = *((uint8_t*)(&data[14 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); /* 1 BYTE PADDING FOR 64-bits ALIGNMENT */ /* --- 64-bits start --- */ pkt_data[i].datarate = *((uint32_t*)(&data[16 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); pkt_data[i].coderate = *((uint8_t*)(&data[20 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); /* --- 64-bits start --- */ pkt_data[i].rssi = *((float*)(&data[24 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); pkt_data[i].snr = *((float*)(&data[28 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); /* --- 64-bits start --- */ pkt_data[i].snr_min = *((float*)(&data[32 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); pkt_data[i].snr_max = *((float*)(&data[36 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); /* --- 64-bits start --- */ pkt_data[i].crc = *((uint16_t*)(&data[40 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); pkt_data[i].size = *((uint16_t*)(&data[42 + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); /* NO PADDING NEEDED HERE, END OF ARRAY */ for (j = 0; j < 256; j++) { (pkt_data[i].payload[j]) = *((uint8_t*)(&data[LGW_PKT_RX_METADATA_SIZE_ALIGNED + j + LGW_PKT_RX_STRUCT_SIZE_ALIGNED * i])); } } #pragma GCC diagnostic pop return nb_packet; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_mcu_send(struct lgw_pkt_tx_s pkt_data) { int i, x; lgw_com_cmd_t cmd; lgw_com_ans_t ans; uint8_t PADDING = 0; uint8_t data[LGW_PKT_TX_STRUCT_SIZE_ALIGNED]; uint16_t size; /* struct to byte array */ /* --- 64-bits start --- */ data[0] = *(((uint8_t *)(&pkt_data.freq_hz))); data[1] = *(((uint8_t *)(&pkt_data.freq_hz)) + 1); data[2] = *(((uint8_t *)(&pkt_data.freq_hz)) + 2); data[3] = *(((uint8_t *)(&pkt_data.freq_hz)) + 3); data[4] = *(((uint8_t *)(&pkt_data.tx_mode))); data[5] = PADDING; data[6] = PADDING; data[7] = PADDING; /* --- 64-bits start --- */ data[8] = *(((uint8_t *)(&pkt_data.count_us))); data[9] = *(((uint8_t *)(&pkt_data.count_us)) + 1); data[10] = *(((uint8_t *)(&pkt_data.count_us)) + 2); data[11] = *(((uint8_t *)(&pkt_data.count_us)) + 3); data[12] = *(((uint8_t *)(&pkt_data.rf_chain))); data[13] = *(((uint8_t *)(&pkt_data.rf_power))); data[14] = *(((uint8_t *)(&pkt_data.modulation))); data[15] = *(((uint8_t *)(&pkt_data.bandwidth))); /* --- 64-bits start --- */ data[16] = *(((uint8_t *)(&pkt_data.datarate))); data[17] = *(((uint8_t *)(&pkt_data.datarate)) + 1); data[18] = *(((uint8_t *)(&pkt_data.datarate)) + 2); data[19] = *(((uint8_t *)(&pkt_data.datarate)) + 3); data[20] = *(((uint8_t *)(&pkt_data.coderate))); data[21] = *(((uint8_t *)(&pkt_data.invert_pol))); data[22] = *(((uint8_t *)(&pkt_data.f_dev))); data[23] = PADDING; /* --- 64-bits start --- */ data[24] = *(((uint8_t *)(&pkt_data.preamble))); data[25] = *(((uint8_t *)(&pkt_data.preamble)) + 1); data[26] = *(((uint8_t *)(&pkt_data.no_crc))); data[27] = *(((uint8_t *)(&pkt_data.no_header))); data[28] = *(((uint8_t *)(&pkt_data.size))); data[29] = *(((uint8_t *)(&pkt_data.size)) + 1); /* NO PADDING NEEDED HERE, END OF ARRAY */ for (i = 0; i < 256; i++) { data[i + LGW_PKT_TX_METADATA_SIZE_ALIGNED] = *(((uint8_t *)(&pkt_data.payload)) + i); } size = sizeof(data) / sizeof(uint8_t); /* prepare command */ cmd.id = 'f'; cmd.len_msb = (uint8_t)((size >> 8) & 0xFF); cmd.len_lsb = (uint8_t)((size >> 0) & 0xFF); cmd.address = 0; for (i = 0; i < size; i++) { cmd.cmd_data[i] = data[i]; } /* send command to MCU */ x = lgw_com_send_command(lgw_com_target, cmd, &ans); if (x != LGW_COM_SUCCESS) { printf("ERROR: failed to send packet\n"); return LGW_MCU_ERROR; } /* check command acknoledge */ if (ans.status != ACK_OK) { printf("ERROR: failed to send packet, ACK failed\n"); return LGW_MCU_ERROR; } return LGW_MCU_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_mcu_get_trigcnt(uint32_t *data) { int x; lgw_com_cmd_t cmd; lgw_com_ans_t ans; /* check input variables */ CHECK_NULL(data); /* prepare command */ cmd.id = 'q'; cmd.len_msb = 0; cmd.len_lsb = 0; cmd.address = 0; /* send command to MCU */ x = lgw_com_send_command(lgw_com_target, cmd, &ans); if ((x != LGW_COM_SUCCESS) || (ans.status != ACK_OK)) { DEBUG_MSG("ERROR: failed to get concentrator internal counter\n"); return LGW_MCU_ERROR; } *data = (ans.ans_data[0] << 24) + (ans.ans_data[1] << 16) + (ans.ans_data[2] << 8) + (ans.ans_data[3]); DEBUG_PRINTF("Note: sx1301 counter %u\n", *data); return LGW_MCU_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_mcu_commit_radio_calibration(uint8_t idx_start, uint8_t idx_nb) { lgw_com_cmd_t cmd; lgw_com_ans_t ans; /* prepare command */ cmd.id = 'j'; cmd.len_msb = 0; cmd.len_lsb = 2; cmd.address = 0; cmd.cmd_data[0] = idx_start; cmd.cmd_data[1] = idx_nb; /* send command to MCU */ return lgw_com_send_command(lgw_com_target, cmd, &ans); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_mcu_reset(void) { lgw_com_cmd_t cmd; lgw_com_ans_t ans; /* prepare command */ cmd.id = 'm'; cmd.len_msb = 0; cmd.len_lsb = 0; cmd.address = 0; /* send command to MCU */ return lgw_com_send_command(lgw_com_target, cmd, &ans); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_mcu_get_unique_id(uint8_t *uid) { int i, x; int fwversion = STM32FWVERSION; lgw_com_cmd_t cmd; lgw_com_ans_t ans; /* prepare command */ cmd.id = 'l'; cmd.len_msb = 0; cmd.len_lsb = 4; cmd.address = 0; cmd.cmd_data[0] = (uint8_t)((fwversion >> 24) & (0x000000ff)); cmd.cmd_data[1] = (uint8_t)((fwversion >> 16) & (0x000000ff)); cmd.cmd_data[2] = (uint8_t)((fwversion >> 8) & (0x000000ff)); cmd.cmd_data[3] = (uint8_t)((fwversion) & (0x000000ff)); /* send command to MCU */ x = lgw_com_send_command(lgw_com_target, cmd, &ans); if (x != LGW_COM_SUCCESS) { DEBUG_MSG("ERROR: Failed to get MCU unique ID\n"); return LGW_MCU_ERROR; } /* Check MCU FW version */ if (ans.status == ACK_KO) { DEBUG_MSG("ERROR: Invalid MCU firmware version\n"); return LGW_MCU_ERROR; } /* Get MCU unique ID */ for (i = 0; i <= 7; i++) { uid[i] = ans.ans_data[i]; } return LGW_MCU_SUCCESS; } /* --- EOF ------------------------------------------------------------------ */