diff options
author | Sylvain Miermont <smiermont@semtech.com> | 2013-09-02 16:13:41 +0200 |
---|---|---|
committer | Sylvain Miermont <smiermont@semtech.com> | 2013-10-23 11:36:29 +0200 |
commit | 33ade9eb698f594e95076a5e4056a70163f14278 (patch) | |
tree | a8fb4a31cf79f49ba8c3e517b0c8956eea3966c6 /loragw_hal/src | |
parent | ddac0aa483dd5f7bca31b0c042949eca370a8fdc (diff) | |
download | lora_gateway-33ade9eb698f594e95076a5e4056a70163f14278.tar.gz lora_gateway-33ade9eb698f594e95076a5e4056a70163f14278.tar.bz2 lora_gateway-33ade9eb698f594e95076a5e4056a70163f14278.zip |
Beta 4v1.b4
- now supports 'native' Linux /dev/spi* interface and SPI-over-USB using FTDI bridge through libmpsse
- Flexible build system, with library.cfg file to set Makefile options
- removed 500 kHz bandwidth limitation on radios, pushed it to the nominal 800kHz usable bandwidth
- RSSI calibrated fo Lora multi-datarate channels
Diffstat (limited to 'loragw_hal/src')
-rw-r--r-- | loragw_hal/src/loragw_aux.c | 2 | ||||
-rw-r--r-- | loragw_hal/src/loragw_hal.c | 35 | ||||
-rw-r--r-- | loragw_hal/src/loragw_reg.c | 2 | ||||
-rw-r--r-- | loragw_hal/src/loragw_spi.ftdi.c | 285 | ||||
-rw-r--r-- | loragw_hal/src/loragw_spi.native.c (renamed from loragw_hal/src/loragw_spi.c) | 2 |
5 files changed, 308 insertions, 18 deletions
diff --git a/loragw_hal/src/loragw_aux.c b/loragw_hal/src/loragw_aux.c index 9adafe3..1c7e354 100644 --- a/loragw_hal/src/loragw_aux.c +++ b/loragw_hal/src/loragw_aux.c @@ -20,7 +20,7 @@ Description: /* -------------------------------------------------------------------------- */ /* --- PRIVATE MACROS ------------------------------------------------------- */ -#ifdef DEBUG +#if DEBUG_AUX == 1 #define DEBUG_MSG(str) fprintf(stderr, str) #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) #else diff --git a/loragw_hal/src/loragw_hal.c b/loragw_hal/src/loragw_hal.c index fc9e293..1738916 100644 --- a/loragw_hal/src/loragw_hal.c +++ b/loragw_hal/src/loragw_hal.c @@ -29,7 +29,7 @@ Description: /* --- PRIVATE MACROS ------------------------------------------------------- */ #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#ifdef DEBUG +#if DEBUG_HAL == 1 #define DEBUG_MSG(str) fprintf(stderr, str) #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%s:%d: "fmt, __FUNCTION__, __LINE__, args) #define DEBUG_ARRAY(a,b,c) for(a=0;a<b;++a) fprintf(stderr,"%x.",c[a]);fprintf(stderr,"end\n") @@ -54,6 +54,7 @@ const uint8_t ifmod_config[LGW_IF_CHAIN_NB] = LGW_IFMODEM_CONFIG; /* define hard const uint32_t rf_rx_lowfreq[LGW_RF_CHAIN_NB] = LGW_RF_RX_LOWFREQ; const uint32_t rf_rx_upfreq[LGW_RF_CHAIN_NB] = LGW_RF_RX_UPFREQ; +const uint32_t rf_rx_bandwidth[LGW_RF_CHAIN_NB] = LGW_RF_RX_BANDWIDTH; const uint32_t rf_tx_lowfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_LOWFREQ; const uint32_t rf_tx_upfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_UPFREQ; @@ -73,8 +74,8 @@ const uint32_t rf_tx_upfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_UPFREQ; #define SX1257_RX_ADC_TRIM 6 /* 0 to 7, 6 for 32MHz ref, 5 for 36MHz ref */ #define SX1257_RXBB_BW 2 -#define RSSI_OFFSET_LORA_MULTI -100.0 // TODO: need to find proper value with calibration -#define RSSI_OFFSET_LORA_STD -100.0 // TODO: need to find proper value with calibration +#define RSSI_OFFSET_LORA_MULTI -127.0 /* calibrated value */ +#define RSSI_OFFSET_LORA_STD 0.0 /* RSSI not working properly on that IF channel */ #define TX_METADATA_NB 16 #define RX_METADATA_NB 16 @@ -447,10 +448,14 @@ int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf) { if (ifmod_config[if_chain] == IF_UNDEFINED) { DEBUG_PRINTF("ERROR: IF CHAIN %d NOT CONFIGURABLE\n", if_chain); } - if ((conf.freq_hz + LGW_REF_BW/2) > LGW_RADIO_BW/2) { + if (conf.rf_chain >= LGW_RF_CHAIN_NB) { + DEBUG_MSG("ERROR: INVALID RF_CHAIN TO ASSOCIATE WITH A LORA_STD IF CHAIN\n"); + return LGW_HAL_ERROR; + } + if ((conf.freq_hz + LGW_REF_BW/2) > ((int32_t)rf_rx_bandwidth[conf.rf_chain] / 2)) { DEBUG_PRINTF("ERROR: IF FREQUENCY %d TOO HIGH\n", conf.freq_hz); return LGW_HAL_ERROR; - } else if ((conf.freq_hz - LGW_REF_BW/2) < -LGW_RADIO_BW/2) { + } else if ((conf.freq_hz - LGW_REF_BW/2) < -((int32_t)rf_rx_bandwidth[conf.rf_chain] / 2)) { DEBUG_PRINTF("ERROR: IF FREQUENCY %d TOO LOW\n", conf.freq_hz); return LGW_HAL_ERROR; } @@ -495,10 +500,6 @@ int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf) { break; case IF_LORA_MULTI: - if (conf.rf_chain >= LGW_RF_CHAIN_NB) { - DEBUG_MSG("ERROR: INVALID RF_CHAIN TO ASSOCIATE WITH A LORA_STD IF CHAIN\n"); - return LGW_HAL_ERROR; - } /* fill default parameters if needed */ if (conf.datarate == 0) { conf.datarate = DR_LORA_MULTI; @@ -755,10 +756,10 @@ int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) { p->snr_min = ((float)((int8_t)buff[s+3]))/4; p->snr_max = ((float)((int8_t)buff[s+4]))/4; if (ifmod == IF_LORA_MULTI) { - p->rssi = RSSI_OFFSET_LORA_MULTI + (float)buff[s+5]; //TODO: check formula + p->rssi = RSSI_OFFSET_LORA_MULTI + (float)buff[s+5]; p->bandwidth = BW_125KHZ; /* fixed in hardware */ } else { - p->rssi = RSSI_OFFSET_LORA_STD + (float)buff[s+5]; //TODO: check formula, might depend on bandwidth + p->rssi = RSSI_OFFSET_LORA_STD + (float)buff[s+5]; p->bandwidth = lora_rx_bw; /* get the parameter from the config variable */ } switch ((buff[s+1] >> 4) & 0x0F) { @@ -872,6 +873,11 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { return LGW_HAL_ERROR; } + /* reset TX command flags */ + lgw_reg_w(LGW_TX_TRIG_IMMEDIATE, 0); + lgw_reg_w(LGW_TX_TRIG_DELAYED, 0); + lgw_reg_w(LGW_TX_TRIG_GPS, 0); + /* metadata 0 to 2, TX PLL frequency */ part_int = pkt_data.freq_hz / LGW_SX1257_DENOMINATOR; /* integer part, gives the MSB and the middle byte */ part_frac = ((pkt_data.freq_hz % LGW_SX1257_DENOMINATOR) << 8) / LGW_SX1257_DENOMINATOR; /* fractional part, gives LSB */ @@ -962,21 +968,20 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { /* send data */ switch(pkt_data.tx_mode) { case IMMEDIATE: - lgw_reg_w(LGW_TX_TRIG_IMMEDIATE, 0); lgw_reg_w(LGW_TX_TRIG_IMMEDIATE, 1); break; case TIMESTAMPED: - lgw_reg_w(LGW_TX_TRIG_DELAYED, 0); lgw_reg_w(LGW_TX_TRIG_DELAYED, 1); break; case ON_GPS: - lgw_reg_w(LGW_TX_TRIG_GPS, 0); lgw_reg_w(LGW_TX_TRIG_GPS, 1); break; - default: DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.tx_mode); + default: + DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", pkt_data.tx_mode); + return LGW_HAL_ERROR; } return LGW_HAL_SUCCESS; diff --git a/loragw_hal/src/loragw_reg.c b/loragw_hal/src/loragw_reg.c index ab5a922..716c6c0 100644 --- a/loragw_hal/src/loragw_reg.c +++ b/loragw_hal/src/loragw_reg.c @@ -28,7 +28,7 @@ Description: /* --- PRIVATE MACROS ------------------------------------------------------- */ #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#ifdef DEBUG +#if DEBUG_REG == 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_REG_ERROR;} diff --git a/loragw_hal/src/loragw_spi.ftdi.c b/loragw_hal/src/loragw_spi.ftdi.c new file mode 100644 index 0000000..7b71901 --- /dev/null +++ b/loragw_hal/src/loragw_spi.ftdi.c @@ -0,0 +1,285 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + ©2013 Semtech-Cycleo + +Description: + Host specific functions to address the LoRa™ gateway registers through a + SPI interface. + Single-byte read/write and burst read/write. + Does not handle pagination. + Could be used with multiple SPI ports in parallel (explicit file descriptor) +*/ + + +/* -------------------------------------------------------------------------- */ +/* --- DEPENDANCIES --------------------------------------------------------- */ + +#include <stdint.h> /* C99 types */ +#include <stdio.h> /* printf fprintf */ +#include <stdlib.h> /* malloc free */ +#include <string.h> /* memcpy */ + +#include <mpsse.h> + +#include "loragw_spi.h" + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE MACROS ------------------------------------------------------- */ + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#if DEBUG_SPI == 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_SPI_ERROR;} +#else + #define DEBUG_MSG(str) + #define DEBUG_PRINTF(fmt, args...) + #define CHECK_NULL(a) if(a==NULL){return LGW_SPI_ERROR;} +#endif + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE CONSTANTS ---------------------------------------------------- */ + +#define READ_ACCESS 0x00 +#define WRITE_ACCESS 0x80 + +/* parameters for a FT2232H */ +#define VID 0x0403 +#define PID 0x6010 + +/* -------------------------------------------------------------------------- */ +/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ + +/* SPI initialization and configuration */ +int lgw_spi_open(void **spi_target_ptr) { + struct mpsse_context *mpsse = NULL; + + /* check input variables */ + CHECK_NULL(spi_target_ptr); /* cannot be null, must point on a void pointer (*spi_target_ptr can be null) */ + + /* try to open the first available FTDI device matching VID/PID parameters */ + mpsse = OpenIndex(VID,PID,SPI0, SIX_MHZ, MSB, IFACE_A, NULL, NULL, 0); + if (mpsse == NULL) { + DEBUG_MSG("ERROR: MPSSE OPEN FUNCTION RETURNED NULL\n"); + return LGW_SPI_ERROR; + } + if (mpsse->open != 1) { + DEBUG_MSG("ERROR: MPSSE OPEN FUNCTION FAILED\n"); + return LGW_SPI_ERROR; + } + + DEBUG_PRINTF("SPI port opened and configured ok\ndesc: %s\nPID: 0x%04X\nVID: 0x%04X\nclock: %d\nLibmpsse version: 0x%02X\n", GetDescription(mpsse), GetPid(mpsse), GetVid(mpsse), GetClock(mpsse), Version()); + *spi_target_ptr = (void *)mpsse; + return LGW_SPI_SUCCESS; +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* SPI release */ +int lgw_spi_close(void *spi_target) { + struct mpsse_context *mpsse = spi_target; + + /* check input variables */ + CHECK_NULL(spi_target); + + Close(mpsse); + + /* close return no status, assume success (0_o) */ + return LGW_SPI_SUCCESS; +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* Simple write */ +/* transaction time: .6 to 1 ms typically */ +int lgw_spi_w(void *spi_target, uint8_t address, uint8_t data) { + struct mpsse_context *mpsse = spi_target; + uint8_t out_buf[2]; + int a, b, c; + + /* check input variables */ + CHECK_NULL(spi_target); + if ((address & 0x80) != 0) { + DEBUG_MSG("WARNING: SPI address > 127\n"); + } + + /* prepare frame to be sent */ + out_buf[0] = WRITE_ACCESS | (address & 0x7F); + out_buf[1] = data; + + /* MPSSE transaction */ + a = Start(mpsse); + b = FastWrite(mpsse, (char *)out_buf, 2); + c = Stop(mpsse); + + /* determine return code */ + if ((a != MPSSE_OK) || (b != MPSSE_OK) || (c != MPSSE_OK)) { + DEBUG_MSG("ERROR: SPI WRITE FAILURE\n"); + return LGW_SPI_ERROR; + } else { + DEBUG_MSG("Note: SPI write success\n"); + return LGW_SPI_SUCCESS; + } +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* Simple read (using Transfer function) */ +/* transaction time: 1.1 to 2 ms typically */ +int lgw_spi_r(void *spi_target, uint8_t address, uint8_t *data) { + struct mpsse_context *mpsse = spi_target; + uint8_t out_buf[2]; + uint8_t *in_buf = NULL; + int a, b; + + /* check input variables */ + CHECK_NULL(spi_target); + if ((address & 0x80) != 0) { + DEBUG_MSG("WARNING: SPI address > 127\n"); + } + CHECK_NULL(data); + + /* prepare frame to be sent */ + out_buf[0] = READ_ACCESS | (address & 0x7F); + out_buf[1] = 0x00; + + /* MPSSE transaction */ + a = Start(mpsse); + in_buf = (uint8_t *)Transfer(mpsse, (char *)out_buf, 2); + b = Stop(mpsse); + + /* determine return code */ + if ((in_buf == NULL) || (a != MPSSE_OK) || (b != MPSSE_OK)) { + DEBUG_MSG("ERROR: SPI READ FAILURE\n"); + if (in_buf != NULL) { + free(in_buf); + } + return LGW_SPI_ERROR; + } else { + DEBUG_MSG("Note: SPI read success\n"); + *data = in_buf[1]; + free(in_buf); + return LGW_SPI_SUCCESS; + } +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* Burst (multiple-byte) write */ +/* transaction time: 3.7ms for 2500 data bytes @6MHz, 1kB chunks */ +/* transaction time: 0.5ms for 16 data bytes @6MHz, 1kB chunks */ +int lgw_spi_wb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size) { + struct mpsse_context *mpsse = spi_target; + uint8_t command; + uint8_t *out_buf = NULL; + int size_to_do, buf_size, chunk_size, offset; + int a, b, c; + int i; + + /* check input parameters */ + CHECK_NULL(spi_target); + if ((address & 0x80) != 0) { + DEBUG_MSG("WARNING: SPI address > 127\n"); + } + CHECK_NULL(data); + if (size == 0) { + DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); + return LGW_SPI_ERROR; + } + + /* prepare command byte */ + command = WRITE_ACCESS | (address & 0x7F); + size_to_do = size + 1; /* add a byte for the address */ + + /* allocate data buffer */ + buf_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; + out_buf = malloc(buf_size); + if (out_buf == NULL) { + DEBUG_MSG("ERROR: MALLOC FAIL\n"); + return LGW_SPI_ERROR; + } + + /* start MPSSE transaction */ + a = Start(mpsse); + for (i=0; size_to_do > 0; ++i) { + chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; + if (i == 0) { + /* first chunk, need to append the address */ + out_buf[0] = command; + memcpy(out_buf+1, data, chunk_size-1); + } else { + /* following chunks, just copy the data */ + offset = (i * LGW_BURST_CHUNK) - 1; + memcpy(out_buf, data + offset, chunk_size); + } + b = FastWrite(mpsse, (char *)out_buf, chunk_size); + size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ + } + c = Stop(mpsse); + + /* deallocate data buffer */ + free(out_buf); + + /* determine return code (only the last FastWrite is checked) */ + if ((a != MPSSE_OK) || (b != MPSSE_OK) || (c != MPSSE_OK)) { + DEBUG_MSG("ERROR: SPI BURST WRITE FAILURE\n"); + return LGW_SPI_ERROR; + } else { + DEBUG_MSG("Note: SPI burst write success\n"); + return LGW_SPI_SUCCESS; + } +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* Burst (multiple-byte) read (using FastWrite & FastRead functions) */ +/* transaction time: 7-12ms for 2500 data bytes @6MHz, 1kB chunks */ +/* transaction time: 2ms for 16 data bytes @6MHz, 1kB chunks */ +int lgw_spi_rb(void *spi_target, uint8_t address, uint8_t *data, uint16_t size) { + struct mpsse_context *mpsse = spi_target; + uint8_t command; + int size_to_do, chunk_size, offset; + int a, b, c, d; + int i; + + /* check input parameters */ + CHECK_NULL(spi_target); + if ((address & 0x80) != 0) { + DEBUG_MSG("WARNING: SPI address > 127\n"); + } + CHECK_NULL(data); + if (size == 0) { + DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); + return LGW_SPI_ERROR; + } + + /* prepare command byte */ + command = READ_ACCESS | (address & 0x7F); + size_to_do = size; + + /* start MPSSE transaction */ + a = Start(mpsse); + b = FastWrite(mpsse, (char *)&command, 1); + for (i=0; size_to_do > 0; ++i) { + chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; + offset = i * LGW_BURST_CHUNK; + c = FastRead(mpsse, (char *)(data + offset), chunk_size); + size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ + } + d = Stop(mpsse); + + /* determine return code (only the last FastRead is checked) */ + if ((a != MPSSE_OK) || (b != MPSSE_OK) || (c != MPSSE_OK) || (d != MPSSE_OK)) { + DEBUG_MSG("ERROR: SPI BURST READ FAILURE\n"); + return LGW_SPI_ERROR; + } else { + DEBUG_MSG("Note: SPI burst read success\n"); + return LGW_SPI_SUCCESS; + } +} + +/* --- EOF ------------------------------------------------------------------ */ diff --git a/loragw_hal/src/loragw_spi.c b/loragw_hal/src/loragw_spi.native.c index d6e3eb0..f5f0701 100644 --- a/loragw_hal/src/loragw_spi.c +++ b/loragw_hal/src/loragw_spi.native.c @@ -34,7 +34,7 @@ Description: /* --- PRIVATE MACROS ------------------------------------------------------- */ #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#ifdef DEBUG +#if DEBUG_SPI == 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_SPI_ERROR;} |