summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Klug <john.klug@multitech.com>2017-08-18 15:14:17 -0500
committerJohn Klug <john.klug@multitech.com>2017-08-18 15:14:17 -0500
commit3ff432faedee2ec0b93d163e4808f391d65f1ba2 (patch)
tree59df462ea8586a664a59d4cf62f1a58af6507f7e /src
parentc2da95882ea7a4218a4432ee5da8165aa61addfc (diff)
downloadmts-id-eeprom-3ff432faedee2ec0b93d163e4808f391d65f1ba2.tar.gz
mts-id-eeprom-3ff432faedee2ec0b93d163e4808f391d65f1ba2.tar.bz2
mts-id-eeprom-3ff432faedee2ec0b93d163e4808f391d65f1ba2.zip
mts-fpga-loader
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am7
-rw-r--r--src/README.md51
-rw-r--r--src/mts_error_codes.h24
-rw-r--r--src/mts_fpga_hash.c127
-rw-r--r--src/mts_fpga_hash.h14
-rw-r--r--src/mts_fpga_loader.c85
-rw-r--r--src/mts_fpga_reg.c406
-rw-r--r--src/mts_fpga_reg.h75
-rw-r--r--src/mts_fpga_spi.c513
-rw-r--r--src/mts_fpga_spi.h68
10 files changed, 1368 insertions, 2 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 12f084c..6884e1a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,12 +3,15 @@ AUTOMAKE_OPTIONS = gnu
AM_CFLAGS = -Wall
bin_PROGRAMS = mts-id-eeprom
-sbin_PROGRAMS = mts-hashpwd
+sbin_PROGRAMS = mts-hashpwd mts-fpga-loader
mts_hashpwd_SOURCES = hashpwd.cpp
mts_id_eeprom_SOURCES = eeprom_main.c
-noinst_HEADERS = eeprom.h
+noinst_HEADERS = eeprom.h log.h mts_error_codes.h mts_fpga_hash.h mts_fpga_reg.h mts_fpga_spi.h
mts_hashpwd_LDADD = -lcrypto
+mts_fpga_loader_SOURCES = mts_fpga_hash.c mts_fpga_reg.c mts_fpga_spi.c mts_fpga_loader.c
+mts_fpga_loader_LDADD = -lrt -lm -lssl -lcrypto
+
sbin_SCRIPTS = ubpasswd.sh
EXTRA_DIST =
diff --git a/src/README.md b/src/README.md
new file mode 100644
index 0000000..0d0eef5
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,51 @@
+# MTAC Upgrade Utility
+
+This Utility allows upgrading the FPGA firmware on the MTAC-LoRa 1.5 rev c cards.
+It currently supports the following versions:
+- v28 (TX Filter, Spectral Scan)
+- v31 (TX Filter, Spectral Scan)
+
+## Getting Started
+
+These instructions will get you to upgrade the FPGA on a MTAC-LoRa 1.5 rev c card.
+
+## Prerequisites
+
+MultiConnect Conduit and MTAC-LoRa 1.5 rev c card or MultiConnect Access Point.
+
+## Installing
+
+```
+scp <files> <device ip address>
+tar -xvf <files>
+ssh <device ip address>
+chmod +x mtac_upgrade
+```
+
+## Usage
+Please stop any processes that try to access the MTAC-LoRa card. For example, the LoRa Network Server and the LoRa Packet Forwarder or other third-party packet forwarders (e.g. Loriot, TTN, Actility, Senet, Orbiwise, etc.). The utility will check for open files on spidev and will not run if it finds any to prevent multiple access.
+
+### Example
+```
+./mtac_upgrade -h See all available options and examples
+./mtac_upgrade -c Check existing FPGA version
+./mtac_upgrade -i <upgrade file> Upgrade the FPGA on the default port using the file specified
+./mtac_upgrade -p 2 -i <upgrade file> Upgrade the FPGA on ap2 using the file specified
+./mtac_upgrade Upgrade the FPGA on the default port and upgrade file
+```
+### Options
+```
+ -c Check Existing MTAC Verson
+ -i Specify input file. Default is mtcdt-fpga-v31.hex for a MultiConnect Conduit & mtcap-fpga-v31.hex for MultiConnect Access Point
+ -p Specify port 1 or 2. Only required for a MultiConnect Conduit when dual cards are installed
+ -s Print Supported FPGA versions
+```
+
+## Authors
+
+* **Harsh Sharma** - Initial work
+
+## Acknowledgments
+
+* **Tim Barr** - Hardware design reference
+
diff --git a/src/mts_error_codes.h b/src/mts_error_codes.h
new file mode 100644
index 0000000..52346c7
--- /dev/null
+++ b/src/mts_error_codes.h
@@ -0,0 +1,24 @@
+#define MTAC_SUCCESS 0 /* Operation success */
+
+/* Hardware Errors */
+#define MTAC_INVALID_FPGA_VERSION 1 /* FPGA version check failed */
+#define MTAC_FILE_NOT_FOUND 2 /* Linked upgrade file not found */
+#define MTAC_INVALID_HARDWARE 3 /* MTAC Hardware does not support FPGA Upgrade */
+#define MTAC_HW_NOT_FOUND 4 /* MTAC Not found */
+#define MTAC_LOCK_FAILURE 5 /* Creset pin write failure */
+#define MTAC_OPEN_FILES 6
+
+/* SPI Errors */
+#define MTAC_SPI_OPEN_FAILURE 7 /* SPI open was not successful */
+#define MTAC_SPI_TRANSFER_FAILURE 8 /* IOCTL transfer failed */
+#define MTAC_SPI_CLOSE_FAILURE 9 /* SPI close was not successful */
+#define MTAC_SPI_ERROR 10 /* Generic SPI error */
+
+/* Register Errors*/
+#define MTAC_FPGA_REG_ERROR 11 /* Error reading FPGA Version */
+#define MTAC_SX1301_VERSION_FAILURE 12 /* Error reading SX1301 Version */
+#define MTAC_HASH_VERIFICATION_FAILURE 13 /* Input file's calculated hash did not match */
+
+/* Flashing Failures*/
+#define MTAC_CHIP_ERASE_FAILURE 14 /* Chip erase failure */
+#define MTAC_PROGRAM_FAILURE 15 /* Flashing mtac with firmware failed */
diff --git a/src/mts_fpga_hash.c b/src/mts_fpga_hash.c
new file mode 100644
index 0000000..7bd4da4
--- /dev/null
+++ b/src/mts_fpga_hash.c
@@ -0,0 +1,127 @@
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+#include <errno.h>
+#include <fcntl.h> /* open */
+#include <openssl/sha.h> /* generate hash */
+#include <stdio.h> /* printf fprintf */
+#include <stdlib.h> /* malloc free */
+#include <stdint.h> /* C99 types */
+#include <string.h> /* memset */
+#include "mts_error_codes.h" /* error codes*/
+#include "mts_fpga_reg.h" /* register functions*/
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_HASH == 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 MTAC_REG_ERROR; \
+ }
+#else
+#define DEBUG_MSG(str)
+#define DEBUG_PRINTF(fmt, args...)
+#define CHECK_NULL(a) \
+ if (a == NULL) { \
+ return MTAC_REG_ERROR; \
+ }
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+static const char *valid_mtcdt_hashes[] = {
+ "d9f811fcab57947db3c2323242885a32a7f095a069d3386a148466e7f3da5353", /* v28*/
+ "903c1199df46d38683b1aa9fc88310abe2f317c01c3aefa77987990874aba420", /* v31*/
+ "7c190506b969aea6198daffb6c9b47685f3a4dc3ce18565c66542bac27d6f24e"};/* v33*/
+static const char *valid_mtcap_hashes[] = {
+ "07317fe9ca59393c074215c9d923d8d01025654883291a5e89b27d21668e2263", /* v28*/
+ "f208ef5cae03e703951bb8799172a5eaadb74ddb90bf3e65c32030c008a88e75", /* v31*/
+ "aaecd468b187703dbbf76022b00268dba2a5f25300da6486d420f476c836385c"};/* v33*/
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ------------------------------------------ */
+
+/* hash outputBuffer */
+static void sha256_hash_string(char hash[SHA256_DIGEST_LENGTH],
+ char outputBuffer[65]) {
+ int i = 0;
+ for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
+ sprintf(outputBuffer + (i * 2), "%02x", (unsigned char)hash[i]);
+ }
+ outputBuffer[64] = 0;
+ DEBUG_PRINTF("OutputBuffer hash: %s\n", outputBuffer);
+}
+
+/* Initialize, update and finalize sha256 */
+static void sha256(char *string, char outputBuffer[65]) {
+ unsigned char hash[SHA256_DIGEST_LENGTH];
+ int len;
+ SHA256_CTX sha256;
+ SHA256_Init(&sha256);
+ len = strlen(string);
+ SHA256_Update(&sha256, string, len);
+ SHA256_Final(hash, &sha256);
+ int i = 0;
+ for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
+ sprintf(outputBuffer + (i * 2), "%02x", (unsigned char)hash[i]);
+ }
+ outputBuffer[64] = 0;
+ DEBUG_PRINTF("OutputBuffer finalized: %s\n", outputBuffer);
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+/* Open input file and verify sha256 with verified list */
+int sha256_file(char* hw, char *path) {
+ DEBUG_PRINTF("Checking hash on input file: %s\n", path);
+ FILE *file = fopen(path, "rb");
+ if (!file) {
+ printf("File %s not found\n", path);
+ return MTAC_FILE_NOT_FOUND;
+ }
+ else {
+ printf("Checking file %s\n", path);
+ }
+ char file_hash[65];
+ unsigned char hash[SHA256_DIGEST_LENGTH];
+ SHA256_CTX sha256;
+ SHA256_Init(&sha256);
+ const int bufSize = 32768;
+ unsigned char *buffer = malloc(bufSize);
+ int bytesRead = 0;
+ if (!buffer)
+ return ENOMEM;
+ while ((bytesRead = fread(buffer, 1, bufSize, file))) {
+ SHA256_Update(&sha256, buffer, bytesRead);
+ }
+ SHA256_Final(hash, &sha256);
+ sha256_hash_string(hash, file_hash);
+ fclose(file);
+ free(buffer);
+ DEBUG_PRINTF("Calculated input file hash: %s\n", file_hash);
+ int i;
+ if (strstr(hw, MTCAP)) {
+ for(i = 0; i < sizeof(valid_mtcap_hashes)/sizeof(valid_mtcap_hashes[0]); ++i) {
+ if(!strcmp(valid_mtcap_hashes[i], file_hash)) {
+ printf("File verified\n");
+ return MTAC_SUCCESS;
+ }
+ }
+ }
+ else if (strstr(hw, MTCDT)) {
+ for(i = 0; i < sizeof(valid_mtcdt_hashes)/sizeof(valid_mtcdt_hashes[0]); ++i) {
+ if(!strcmp(valid_mtcdt_hashes[i], file_hash)) {
+ printf("File verified\n");
+ return MTAC_SUCCESS;
+ }
+ }
+ }
+ printf("Invalid input file.\n");
+ return MTAC_HASH_VERIFICATION_FAILURE;
+} \ No newline at end of file
diff --git a/src/mts_fpga_hash.h b/src/mts_fpga_hash.h
new file mode 100644
index 0000000..a45df87
--- /dev/null
+++ b/src/mts_fpga_hash.h
@@ -0,0 +1,14 @@
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <openssl/sha.h> /* generate hash */
+#include <stdint.h> /* C99 types */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+static void sha256_hash_string(char hash[SHA256_DIGEST_LENGTH], char outputBuffer[65]);
+
+static void sha256(char *string, char outputBuffer[65]);
+
+int sha256_file(char* hw, char *path);
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/src/mts_fpga_loader.c b/src/mts_fpga_loader.c
new file mode 100644
index 0000000..3648eeb
--- /dev/null
+++ b/src/mts_fpga_loader.c
@@ -0,0 +1,85 @@
+#include <stdio.h> /* printf fprintf */
+#include <unistd.h> /* getopt */
+
+#include "mts_error_codes.h" /* list of utility error codes */
+#include "mts_fpga_reg.h" /* core utility functions a*/
+
+/* -------------------------------------------------------------------------- */
+/* --- MACROS & CONSTANTS --------------------------------------------------- */
+#define DEFAULT_PATH 0 /* default path, points to spidev0.0 */
+
+void usage(int argc, char *argv[]) {
+ printf("Usage: %s -option <argument>\n", argv[0]);
+ printf("Example\n");
+ printf(" %s -h See all available options and examples\n", argv[0]);
+ printf(" %s -c Check existing FPGA version\n", argv[0]);
+ printf(" %s -i <upgrade file> Upgrade the FPGA on the default port using the file specified\n", argv[0]);
+ printf(" %s -p 2 -i <upgrade file> Upgrade the FPGA on ap2 using the file specified\n", argv[0]);
+ printf(" %s Upgrade the FPGA on the default port and upgrade file\n", argv[0]);
+ printf("Options\n");
+ printf(" -c Check FPGA Version on MTAC card\n");
+ printf(" -i Specify input file. Default is mtcdt-fpga-v31.hex for a MultiConnect Conduit & mtcap-fpga-v31.hex for MultiConnect Access Point\n");
+ printf(" -p Specify port 1 or 2. Only required for a MultiConnect Conduit when dual cards are installed\n");
+ printf(" -s Print FPGA versions supported by the utility\n");
+}
+
+
+int main(int argc, char **argv) {
+ int index;
+ int c;
+ int ret;
+ char *upgrade_file;
+ int path = DEFAULT_PATH;
+ opterr = 0;
+ while ((c = getopt(argc, argv, "shp:ci:")) != -1)
+ switch (c) {
+ case 's':
+ print_supported_versions();
+ return 0;
+ case 'h':
+ usage(argc, argv);
+ return 0;
+ case 'p':
+ path = atoi(optarg);
+ if (path == 1) {
+ printf("Using ap1 - /dev/spidev32766.2\n");
+ }
+ else if (path == 2) {
+ printf("Using ap2 - /dev/spidev32765.2\n");
+ }
+ else {
+ fprintf(stderr, "Path %d must be set to 1(ap1) or 2(ap2)\n", path);
+ return 1;
+ }
+ break;
+ case 'i':
+ upgrade_file = optarg;
+ break;
+ case 'c':
+ ret = mtac_get_version(path);
+ if (ret != MTAC_SUCCESS) {
+ fprintf(stderr, "Version Check failed. Error Code: %d\n", ret);
+ return 1;
+ }
+ return 0;
+ case '?':
+ if (optopt == 'i')
+ fprintf(stderr, "Option -%c requires a file argument.\n", optopt);
+ else if (isprint(optopt))
+ fprintf(stderr, "Unknown option `-%c'.\n", optopt);
+ else
+ fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
+ return 1;
+ default:
+ usage(argc, argv);
+ }
+ ret = mtac_upgrade(upgrade_file, path);
+ if (ret != MTAC_SUCCESS) {
+ fprintf(stderr, "Upgrade Failed, Error Code: %d\n", ret);
+ return 1;
+ } else {
+ printf("FPGA Upgrade Sucessful\n");
+ return 0;
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/src/mts_fpga_reg.c b/src/mts_fpga_reg.c
new file mode 100644
index 0000000..6955219
--- /dev/null
+++ b/src/mts_fpga_reg.c
@@ -0,0 +1,406 @@
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <errno.h>
+#include <fcntl.h> /* open */
+#include <stdlib.h> /* malloc free */
+#include <string.h> /* memset */
+#include "mts_fpga_reg.h" /* register functions*/
+#include "mts_error_codes.h" /* error codes*/
+#include "mts_fpga_hash.h" /* compute fiel hash*/
+#include "mts_fpga_spi.h" /* spi interface commands*/
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#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 MTAC_REG_ERROR; \
+ }
+#else
+#define DEBUG_MSG(str)
+#define DEBUG_PRINTF(fmt, args...)
+#define CHECK_NULL(a) \
+ if (a == NULL) { \
+ return MTAC_REG_ERROR; \
+ }
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+const char *valid_hw[] = {MTCDT, MTCAP};
+static const uint8_t fpga_version[] = {28, 31, 33};
+static const struct mtac_reg_s loregs[3] = {
+ {-1, 0, 0, 0, 2, 0, 0}, /* PAGE_REG */
+ {-1, 0, 7, 0, 1, 0, 0}, /* SOFT_RESET */
+ {-1, 1, 0, 0, 8, 1, 103} /* VERSION */
+};
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+void *mtac_spi_target = NULL; /*! generic pointer to the SPI device */
+uint8_t mtac_spi_mux_mode = 0; /*! current SPI mux mode used */
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+void print_supported_versions() {
+ int i;
+ printf("Supported FPGA Versions: \n");
+ for (i = 0; i < (int)(sizeof fpga_version); i++) {
+ printf("%d\n", fpga_version[i]);
+ }
+}
+
+/* check the version of the fpga is within the supported list */
+bool check_fpga_version(uint8_t version) {
+ int i;
+ for (i = 0; i < (int)(sizeof fpga_version); i++) {
+ if (fpga_version[i] == version) {
+ printf("Valid FPGA version: %u\n", version);
+ return true;
+ }
+ }
+ printf("Invalid FPGA version: %u\n", version);
+ return false;
+}
+
+/* Make sure no device is using the spidev bus to prevent contention*/
+int bus_contention() {
+ char number[1024];
+ FILE *f = popen("lsof", "r");
+ while (fgets(number, 1024, f) != NULL) {
+ if (strstr(number, "spidev") != NULL) {
+ printf("The accesory card is being used by another process: \n %sPlease "
+ "close all LoRaWAN processes and try again.\n",
+ number);
+ pclose(f);
+ return MTAC_OPEN_FILES;
+ }
+ }
+ pclose(f);
+ return MTAC_SUCCESS;
+}
+
+/* write to creset pin */
+int mtac_creset_write(mts_hw *mts, char num) {
+ int fd = open(mts->creset, O_WRONLY);
+ if (fd < 0) {
+ printf("Unable to lock file, are you root?\n");
+ return MTAC_LOCK_FAILURE;
+ }
+ write(fd, &num, 1);
+ close(fd);
+ return MTAC_SUCCESS;
+}
+
+int hw_check(mts_hw *mts) {
+ FILE *fp;
+ fp = fopen(HW_FILE, "r");
+
+ if (fp == NULL) {
+ printf("Unable to lock file, are you root?\n");
+ return MTAC_LOCK_FAILURE;
+ }
+ fscanf(fp, "%[^\n]", mts->dev_hw);
+ fclose(fp);
+ if (strstr(mts->dev_hw, "MTCAP")) {
+ if (mts->path != 0) {
+ printf("Path argument is not supported on this device. Exiting.\n");
+ return MTAC_INVALID_HARDWARE;
+ } else {
+ strcpy(mts->spi_path, SPI_DEV_PATH_MTCAP);
+ strcpy(mts->mtac_hw, MTAC_HW_VERSION);
+ strcpy(mts->creset, CRESET);
+ return MTAC_SUCCESS;
+ }
+ } else if (strstr(mts->dev_hw, "MTCDT")) {
+ if (mts->path == 0) {
+ strcpy(mts->spi_path, SPI_DEV_PATH_MTCDT);
+ strcpy(mts->mtac_hw, MTAC_HW_VERSION);
+ strcpy(mts->creset, CRESET);
+ return MTAC_SUCCESS;
+ } else if (mts->path == 1) {
+ strcpy(mts->mtac_hw, MTAC_HW_VERSION_AP1);
+ strcpy(mts->spi_path, SPI_DEV_PATH_AP1);
+ strcpy(mts->creset, CRESET_AP1);
+ return MTAC_SUCCESS;
+ } else if (mts->path == 2) {
+ strcpy(mts->mtac_hw, MTAC_HW_VERSION_AP2);
+ strcpy(mts->spi_path, SPI_DEV_PATH_AP2);
+ strcpy(mts->creset, CRESET_AP2);
+ return MTAC_SUCCESS;
+ }
+ } else
+ printf("This software is licensed only for use on MultiTech products.\n");
+ return MTAC_INVALID_HARDWARE;
+}
+
+/* check mtac hardware compatibility */
+int mtac_check(mts_hw *mts) {
+ int i;
+ char buff[255];
+ FILE *fptr;
+ /* verify that the device to be flashed exists */
+ if ((fptr = fopen(mts->mtac_hw, "r")) == NULL) {
+ printf("Could not connect to hardware. Verify accessory port argument?\n");
+ return MTAC_HW_NOT_FOUND;
+ }
+ fscanf(fptr, "%s", &buff);
+ for (i = 0; i < (int)(sizeof valid_hw); i++) {
+ if (valid_hw[i] == buff) {
+ printf("Found Valid Hardware: %s\n", buff);
+ strcpy(mts->mtac_hw, buff);
+ fclose(fptr);
+ return MTAC_SUCCESS;
+ }
+ }
+ printf("\nInvalid Hardware: %s. Cannot Upgrade FPGA.\n", buff);
+ fclose(fptr);
+ return MTAC_INVALID_HARDWARE;
+}
+
+/* connect to the oncentrator to get the fpga version */
+int mtac_get_version(int path) {
+ uint8_t u = 0;
+ int ret;
+ mts_hw mts;
+ mts.path = path;
+ /* check MTAC Hardware Compatibility */
+ printf("Checking hardware compatibility\n");
+ ret = hw_check(&mts);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+
+ ret = mtac_check(&mts);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+
+ if (strstr(mts.mtac_hw, MTCAP)) {
+ strcpy(mts.spi_path, "/dev/spidev0.0");
+ }
+ /* open the SPI link */
+ ret = mtac_creset_write(&mts, '1');
+ sleep(2);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+ ret = mtac_spi_open(mts.spi_path, &mtac_spi_target);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+ /* detect if the gateway has an FPGA with SPI mux header support */
+ ret = mtac_spi_r(mtac_spi_target, MTAC_SPI_MUX_MODE1, MTAC_FPGA,
+ loregs[MTAC_VERSION].addr, &u);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+ if (check_fpga_version(u) != true) {
+ printf("INFO: no FPGA detected or version not supported (v%u)\n", u);
+ return MTAC_INVALID_FPGA_VERSION;
+ } else {
+ mtac_spi_mux_mode = MTAC_SPI_MUX_MODE1;
+ /* FPGA Soft Reset */
+ mtac_spi_w(mtac_spi_target, mtac_spi_mux_mode, MTAC_FPGA, 0, 1);
+ mtac_spi_w(mtac_spi_target, mtac_spi_mux_mode, MTAC_FPGA, 0, 0);
+ }
+
+ /* check SX1301 version */
+ ret = mtac_spi_r(mtac_spi_target, mtac_spi_mux_mode, MTAC_SX1301,
+ loregs[MTAC_VERSION].addr, &u);
+ if (ret != MTAC_SUCCESS) {
+ return MTAC_SX1301_VERSION_FAILURE;
+ }
+
+ /* write 0 to the page/reset register */
+ ret = mtac_spi_w(mtac_spi_target, mtac_spi_mux_mode, MTAC_SX1301,
+ loregs[MTAC_PAGE_REG].addr, 0);
+ if (ret != MTAC_SUCCESS) {
+ return MTAC_FPGA_REG_ERROR;
+ }
+ mtac_disconnect();
+ return MTAC_SUCCESS;
+}
+
+/* setup and upgrade the mtac card with the file specified */
+int mtac_upgrade(char *input_file, int path) {
+ int ret;
+ mts_hw mts;
+ mts.path = path;
+ /* check that no other device is using the bus */
+ ret = bus_contention();
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+ /* check MTAC Hardware Compatibility */
+ printf("Checking hardware compatibility\n");
+ ret = hw_check(&mts);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+
+ ret = mtac_check(&mts);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+ if (!input_file) {
+ if (strstr(mts.dev_hw, "MTCDT")) {
+ input_file = strdup(MTCDT_DEFAULT_FILE);
+ } else if (strstr(mts.mtac_hw, MTCAP)) {
+ input_file = strdup(MTCAP_DEFAULT_FILE);
+ }
+ }
+ /* check input file checksum */
+ ret = sha256_file(mts.mtac_hw, input_file);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+
+ /* check SPI link status */
+ if (mtac_spi_target != NULL) {
+ printf("WARNING: concentrator was connected\n");
+ mtac_spi_close(mtac_spi_target);
+ }
+
+ /* pull creset down to access spi flash */
+ ret = mtac_creset_write(&mts, '0');
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+ sleep(1);
+
+ /* erase chip before flashing new firmware */
+ ret = mtac_erase(&mts);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+
+ /* program user specified firmware */
+ printf("Programming flash\n");
+ ret = mtac_program(&mts, input_file);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ } else {
+ printf("Write Complete. Resetting FPGA\n");
+ }
+ /* pull creset up to access FPGA */
+ ret = mtac_creset_write(&mts, '1');
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+ sleep(5);
+ printf("Reading New FPGA configuration\n");
+ ret = mtac_get_version(path);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+ return MTAC_SUCCESS;
+}
+
+/* erase entire flash */
+int mtac_erase(mts_hw *mts) {
+ int ret;
+ printf("Erasing flash\n");
+ /* pull device out of powerdown state */
+ ret = mtac_release(mts->spi_path, mtac_spi_target);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+
+ /* enable writing to flash */
+ ret = write_enable(mts->spi_path, mtac_spi_target);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+
+ /* send chip erase command to flash */
+ ret = chip_erase(mts->spi_path, mtac_spi_target);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+ /* pull device out of powerdown state */
+ mtac_release(mts->spi_path, mtac_spi_target);
+ if (ret != MTAC_SUCCESS) {
+ return ret;
+ }
+ return MTAC_SUCCESS;
+}
+
+/* write to mtac card with input file */
+int mtac_program(mts_hw *mts, char input_file[]) {
+ FILE *f;
+ struct stat st;
+ size_t file_size;
+ int i = 0;
+ int ret = MTAC_SUCCESS;
+ int index, result;
+ uint32_t offset, page_address, no_pages, page_data[256];
+ uint8_t adr_lower, adr_higher;
+
+ /* get data array from file to be writen */
+ f = fopen(input_file, "r");
+ stat(input_file, &st);
+ file_size = st.st_size;
+ uint8_t *p_array;
+ p_array = (uint8_t *)malloc(sizeof(uint8_t) * file_size);
+ unsigned int data[file_size];
+ while ((result = fscanf(f, "%x ", data + i)) == 1) {
+ i++;
+ }
+ fclose(f);
+ no_pages = ceil(i / 256.0);
+
+ /* program one page at a time */
+ for (page_address = 0x00; page_address < no_pages; page_address++) {
+ /* mask page address */
+ adr_higher = (page_address >> 8) & 0xff;
+ adr_lower = page_address & 0xff;
+ /* calculate initial data offset */
+ offset = page_address * 256;
+ /* enable writing to flash */
+ ret = write_enable(mts->spi_path, mtac_spi_target);
+ if (ret != MTAC_SUCCESS) {
+ free(p_array);
+ break;
+ }
+ /* assign data for page to be written */
+ for (index = 0; index < 256; index++) {
+ page_data[index] = index + offset > i ? 0xff : data[index + offset];
+ }
+ /* program single page*/
+ ret = page_program(mts->spi_path, mtac_spi_target, adr_lower, adr_higher, page_data);
+ if (ret != MTAC_SUCCESS) {
+ free(p_array);
+ break;
+ }
+ /* release device from page program powerdown */
+ ret = mtac_release(mts->spi_path, mtac_spi_target);
+ if (ret != MTAC_SUCCESS) {
+ free(p_array);
+ break;
+ }
+ }
+ free(p_array);
+ return ret;
+}
+
+/* Concentrator disconnect */
+int mtac_disconnect(void) {
+ if (mtac_spi_target != NULL) {
+ mtac_spi_close(mtac_spi_target);
+ mtac_spi_target = NULL;
+ DEBUG_MSG("Note: success disconnecting the concentrator\n");
+ return MTAC_SUCCESS;
+ } else {
+ DEBUG_MSG("WARNING: concentrator was already disconnected\n");
+ return MTAC_SPI_CLOSE_FAILURE;
+ }
+} \ No newline at end of file
diff --git a/src/mts_fpga_reg.h b/src/mts_fpga_reg.h
new file mode 100644
index 0000000..d67a60c
--- /dev/null
+++ b/src/mts_fpga_reg.h
@@ -0,0 +1,75 @@
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+#include <stdbool.h> /* bool type */
+#include <stdint.h> /* C99 types */
+#include <stdio.h>
+
+/* -------------------------------------------------------------------------- */
+/* --- INTERNAL SHARED TYPES ------------------------------------------------ */
+
+struct mtac_reg_s {
+ int8_t page; /*!< page containing the register (-1 for all pages) */
+ uint8_t addr; /*!< base address of the register (7 bit) */
+ uint8_t offs; /*!< position of the register LSB (between 0 to 7) */
+ bool sign; /*!< 1 indicates the register is signed (2 complem.) */
+ uint8_t leng; /*!< number of bits in the register */
+ bool rdon; /*!< 1 indicates a read-only register */
+ int32_t dflt; /*!< register default value */
+};
+
+typedef struct mts {
+ char creset[60];
+ char mtac_hw[60];
+ char spi_path[60];
+ char dev_hw[40];
+ int path;
+} mts_hw;
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+#define MTAC_PAGE_REG 0
+#define MTAC_SOFT_RESET 1
+#define MTAC_VERSION 2
+#define SPI_DEV_PATH_AP1 "/dev/spidev32766.2"
+#define SPI_DEV_PATH_AP2 "/dev/spidev32765.2"
+#define SPI_DEV_PATH_MTCAP "/dev/spidev0.1"
+#define SPI_DEV_PATH_MTCDT "/dev/spidev0.0"
+#define MTCDT "MTAC-LORA-1.5"
+#define MTCAP "MTCAP-LORA-1.5"
+#define HW_FILE "/sys/devices/platform/mts-io/hw-version"
+#define MTCDT_DEFAULT_FILE "mtcdt-fpga-v31.hex"
+#define MTCAP_DEFAULT_FILE "mtcap-fpga-v31.hex"
+#define CRESET "/sys/devices/platform/mts-io/lora/creset"
+#define CRESET_AP1 "/sys/devices/platform/mts-io/ap1/creset"
+#define CRESET_AP2 "/sys/devices/platform/mts-io/ap2/creset"
+#define MTAC_HW_VERSION "/sys/devices/platform/mts-io/lora/hw-version"
+#define MTAC_HW_VERSION_AP1 "/sys/devices/platform/mts-io/ap1/hw-version"
+#define MTAC_HW_VERSION_AP2 "/sys/devices/platform/mts-io/ap2/hw-version"
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+int mtac_get_version(int path);
+
+int mtac_disconnect(void);
+
+int bus_contention(void);
+
+int mtac_reg_w(uint16_t register_id, int32_t reg_value);
+
+int mtac_reg_r(uint16_t register_id, int32_t *reg_value);
+
+int mtac_upgrade(char input_file[255], int path);
+
+int mtac_erase(mts_hw *mts);
+
+int mtac_program(mts_hw *mts, char input_file[]);
+
+int mtac_check(mts_hw *mts);
+
+int hw_check(mts_hw *mts);
+
+void print_supported_versions();
+
+int mtac_creset_write(mts_hw *mts, char num);
+/* --- EOF ------------------------------------------------------------------ */
diff --git a/src/mts_fpga_spi.c b/src/mts_fpga_spi.c
new file mode 100644
index 0000000..1d95ac1
--- /dev/null
+++ b/src/mts_fpga_spi.c
@@ -0,0 +1,513 @@
+#include "mts_error_codes.h"
+#include "mts_fpga_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 MTAC_SPI_ERROR; \
+ }
+#else
+#define DEBUG_MSG(str)
+#define DEBUG_PRINTF(fmt, args...)
+#define CHECK_NULL(a) \
+ if (a == NULL) { \
+ return MTAC_SPI_ERROR; \
+ }
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define READ_ACCESS 0x00
+#define WRITE_ACCESS 0x80
+#define SPI_SPEED 8000000
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+/*
+ SPI initialization and configuration
+*/
+int mtac_spi_open(char *spidev, void **spi_target_ptr) {
+ int *spi_device = NULL;
+ int dev;
+ int a = 0, b = 0;
+ int i;
+
+ /* check input variables */
+ CHECK_NULL(spi_target_ptr);
+
+ /* allocate memory for the device descriptor */
+ spi_device = malloc(sizeof(int));
+ if (spi_device == NULL) {
+ DEBUG_MSG("ERROR: MALLOC FAIL\n");
+ return MTAC_SPI_OPEN_FAILURE;
+ }
+
+ /* open SPI device */
+ dev = open(spidev, O_RDWR);
+ if (dev < 0) {
+ DEBUG_PRINTF("ERROR: failed to open SPI device %s\n", spidev);
+ return MTAC_SPI_OPEN_FAILURE;
+ }
+
+ /* setting SPI mode to 'mode 0' */
+ i = SPI_MODE_3;
+ a = ioctl(dev, SPI_IOC_WR_MODE, &i);
+ b = ioctl(dev, SPI_IOC_RD_MODE, &i);
+ if ((a < 0) || (b < 0)) {
+ DEBUG_MSG("ERROR: SPI PORT FAIL TO SET IN MODE 0\n");
+ close(dev);
+ free(spi_device);
+ return MTAC_SPI_OPEN_FAILURE;
+ }
+
+ /* setting SPI max clk (in Hz) */
+ i = SPI_SPEED;
+ a = ioctl(dev, SPI_IOC_WR_MAX_SPEED_HZ, &i);
+ b = ioctl(dev, SPI_IOC_RD_MAX_SPEED_HZ, &i);
+ if ((a < 0) || (b < 0)) {
+ DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MAX SPEED\n");
+ close(dev);
+ free(spi_device);
+ return MTAC_SPI_OPEN_FAILURE;
+ }
+
+ /* setting SPI to MSB first */
+ i = 0;
+ a = ioctl(dev, SPI_IOC_WR_LSB_FIRST, &i);
+ b = ioctl(dev, SPI_IOC_RD_LSB_FIRST, &i);
+ if ((a < 0) || (b < 0)) {
+ DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MSB FIRST\n");
+ close(dev);
+ free(spi_device);
+ return MTAC_SPI_OPEN_FAILURE;
+ }
+
+ /* setting SPI to 8 bits per word */
+ i = 0;
+ a = ioctl(dev, SPI_IOC_WR_BITS_PER_WORD, &i);
+ b = ioctl(dev, SPI_IOC_RD_BITS_PER_WORD, &i);
+ if ((a < 0)