summaryrefslogtreecommitdiff
path: root/loragw_hal/src
diff options
context:
space:
mode:
authorSylvain Miermont <smiermont@semtech.com>2013-09-02 16:13:41 +0200
committerSylvain Miermont <smiermont@semtech.com>2013-10-23 11:36:29 +0200
commit33ade9eb698f594e95076a5e4056a70163f14278 (patch)
treea8fb4a31cf79f49ba8c3e517b0c8956eea3966c6 /loragw_hal/src
parentddac0aa483dd5f7bca31b0c042949eca370a8fdc (diff)
downloadlora_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.c2
-rw-r--r--loragw_hal/src/loragw_hal.c35
-rw-r--r--loragw_hal/src/loragw_reg.c2
-rw-r--r--loragw_hal/src/loragw_spi.ftdi.c285
-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;}