From b1eaaeca6fdcb38d9a247e2deabe1da788a1e1f0 Mon Sep 17 00:00:00 2001 From: Harsh Sharma Date: Thu, 3 Mar 2022 14:44:44 -0600 Subject: LoRa updates with MTAC-003 --- src/AccessoryCards/Mtac15Fpga.cpp | 803 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 803 insertions(+) create mode 100644 src/AccessoryCards/Mtac15Fpga.cpp (limited to 'src/AccessoryCards/Mtac15Fpga.cpp') diff --git a/src/AccessoryCards/Mtac15Fpga.cpp b/src/AccessoryCards/Mtac15Fpga.cpp new file mode 100644 index 0000000..151ff77 --- /dev/null +++ b/src/AccessoryCards/Mtac15Fpga.cpp @@ -0,0 +1,803 @@ +/********************************************************************** + * COPYRIGHT 2020 MULTI-TECH SYSTEMS, INC. + * + * ALL RIGHTS RESERVED BY AND FOR THE EXCLUSIVE BENEFIT OF + * MULTI-TECH SYSTEMS, INC. + * + * MULTI-TECH SYSTEMS, INC. - CONFIDENTIAL AND PROPRIETARY + * INFORMATION AND/OR TRADE SECRET. + * + * NOTICE: ALL CODE, PROGRAM, INFORMATION, SCRIPT, INSTRUCTION, + * DATA, AND COMMENT HEREIN IS AND SHALL REMAIN THE CONFIDENTIAL + * INFORMATION AND PROPERTY OF MULTI-TECH SYSTEMS, INC. + * USE AND DISCLOSURE THEREOF, EXCEPT AS STRICTLY AUTHORIZED IN A + * WRITTEN AGREEMENT SIGNED BY MULTI-TECH SYSTEMS, INC. IS PROHIBITED. + * + ***********************************************************************/ + +#include "Fpga.h" + +/* -------------------------------------------------------------------------- */ +/* --- Flash opcodes ---------------------------------------------------------*/ +#define WR_STATUS_REG 0x01 /* Write Status Register */ +#define PAGE_PROGRAM 0x02 /* Write up to a Page of the Memory */ +#define READ_DATA 0x03 /* Read from the Memory */ +#define WRITE_DISABLE 0x04 /* Disable Writing to the Memory */ +#define RD_STATUS_REG_1 0x05 /* Read Status Register-1 */ +#define WRITE_ENABLE 0x06 /* Enable Writing to the Memory */ +#define FAST_READ_DATA 0x0B /* Fast Read from the Memory */ +#define SECTOR_ERASE 0x20 /* Erase a Sector (4kb) */ u +#define RD_STATUS_REG_2 0x35 /* Read Status Register-2 */ +#define UNIQUE_ID 0x4B /* Read Unique ID */ +#define WE_STATUS_REG 0x50 /* Write Enable for Status Registers */ +#define BLOCK_ERASE_32 0x52 /* Erase a Block (32kb) */ +#define CHIP_ERASE 0x60 /* Erase Entire Chip */ +#define MNFTR_DEV_ID 0x90 /* Read Manufacturer ID followed by Device ID */ +#define JEDEC_ID 0x9F /* Read JEDEC ID */ +#define CHIP_RELEASE 0xAB /* Release chip from power down */ +#define BLOCK_ERASE_64 0xD8 /* Erase a Block (64kb) */ + +static const uint8_t fpga_version[] = {28, 31, 33, 35, 37}; +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 CONSTANTS ---------------------------------------------------- */ + +static const char + *valid_hashes[3][4] = + { + { + "d9f811fcab57947db3c2323242885a32a7f095a069d3386a148466e7f3da53" + "53", /* mtcdt v28*/ + "903c1199df46d38683b1aa9fc88310abe2f317c01c3aefa77987990874aba4" + "20", /* mtcdt v31*/ + "7c190506b969aea6198daffb6c9b47685f3a4dc3ce18565c66542bac27d6f2" + "4e", /* mtcdt v33*/ + "72bcdfda72bf8677d585330caa3d609615d08d4ca6d7951f0ebbcb5a93306b" + "3c" /* mtcdt v35*/ + }, + { + "54e41b186b2c91f1bcf249648c50357165d361101fc4fe20ee9b8f0c40dce2" + "5d" /* mtcdt3 v35*/ + }, + { + "07317fe9ca59393c074215c9d923d8d01025654883291a5e89b27d21668e22" + "63", /* mtcap v28*/ + "f208ef5cae03e703951bb8799172a5eaadb74ddb90bf3e65c32030c008a88e" + "75", /* mtcap v31*/ + "aaecd468b187703dbbf76022b00268dba2a5f25300da6486d420f476c83638" + "5c", /* mtcap v33*/ + "876cc5683f612c09f96bacb27fff170358c90f3bd76a5c61ec41504eabba83" + "13" /* mtcap v35*/ + }, +}; + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DEFINITION ------------------------------------------ + */ + +/* hash outputBuffer */ +void Mtac15Fpga::sha256_hash_string(unsigned 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; + printInfo("OutputBuffer hash: %s", outputBuffer); +} + +/* Initialize, update and finalize sha256 */ +void Mtac15Fpga::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; + printInfo("OutputBuffer finalized: %s", outputBuffer); +} + +/* Open input file and verify sha256 with verified list */ +int Mtac15Fpga::sha256_file(const char *path) { + printInfo("Checking hash on input file: %s", path); + + FILE *file = fopen(path, "rb"); + if (!file) { + printError("File %s not found", path); + return -1; + } else { + printInfo("Checking file %s", path); + } + + unsigned int i; + char file_hash[65]; + unsigned char hash[SHA256_DIGEST_LENGTH]; + SHA256_CTX sha256; + SHA256_Init(&sha256); + const int bufSize = 32768; + unsigned char *buffer = (unsigned char *)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); + + printInfo("Calculated input file hash: %s", file_hash); + for (i = 0; i < sizeof(valid_hashes[hardwareType]) / + sizeof(valid_hashes[hardwareType][0]); + ++i) { + if (!strcmp(valid_hashes[hardwareType][i], file_hash)) { + printInfo("File verified"); + return 0; + } + } + printError("Invalid input file"); + return -1; +} + +int Mtac15Fpga::spiOpen() { + int *spi_device = NULL; + int dev; + int a = 0, b = 0; + int i; + + /* allocate memory for the device descriptor */ + spi_device = (int *)malloc(sizeof(int)); + if (spi_device == NULL) { + printError("Malloc failed"); + return -1; + } + + /* open SPI device */ + dev = open(spiPath.c_str(), O_RDWR); + if (dev < 0) { + printError("Failed to open SPI device %s", spiPath.c_str()); + return -1; + } + + /* 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)) { + printError("SPI port failed to set IOC MODE 0"); + close(dev); + free(spi_device); + return -1; + } + + /* 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)) { + printError("SPI port failed to set MAX SPEED"); + close(dev); + free(spi_device); + return -1; + } + + /* 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)) { + printError("SPI port failed to set MSB FIRST"); + close(dev); + free(spi_device); + return -1; + } + + /* 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) || (b < 0)) { + printError("SPI port failed to set 8 bits-per-word"); + close(dev); + return -1; + } + + *spi_device = dev; + spi_target_ptr = (void *)spi_device; + return 0; +} + +int Mtac15Fpga::spiRead(uint8_t spi_mux_target, uint8_t address, + uint8_t *data) { + int spi_device; + uint8_t out_buf[3]; + uint8_t in_buf[ARRAY_SIZE(out_buf)]; + uint8_t command_size; + struct spi_ioc_transfer k; + int a; + + spi_device = + *(int *)spi_target_ptr; /* spi_target cannot be null beforehand */ + + /* prepare frame to be sent */ + out_buf[0] = spi_mux_target; + out_buf[1] = READ_ACCESS | (address & 0x7F); + out_buf[2] = 0x00; + command_size = 3; + + /* I/O transaction */ + memset(&k, 0, sizeof(k)); /* clear k */ + k.tx_buf = (unsigned long)out_buf; + k.rx_buf = (unsigned long)in_buf; + k.len = command_size; + k.cs_change = 1; + a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); + + /* determine return code */ + if (a != (int)k.len) { + printError("SPI read failure"); + return -1; + } else { + *data = in_buf[command_size - 1]; + return 0; + } +} + +/* Simple spi write to fpga*/ +int Mtac15Fpga::spiWrite(uint8_t spi_mux_target, uint8_t address, + uint8_t data) { + int spi_device; + uint8_t out_buf[3]; + uint8_t command_size; + struct spi_ioc_transfer k; + int a; + + spi_device = + *(int *)spi_target_ptr; /* spi_target cannot be null beforehand */ + + /* prepare frame to be sent */ + out_buf[0] = spi_mux_target; + out_buf[1] = WRITE_ACCESS | (address & 0x7F); + out_buf[2] = data; + command_size = 3; + + /* I/O transaction */ + memset(&k, 0, sizeof(k)); /* clear k */ + k.tx_buf = (unsigned long)out_buf; + k.len = command_size; + k.speed_hz = SPI_SPEED; + k.cs_change = 1; + k.bits_per_word = 8; + a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); + + /* determine return code */ + if (a != (int)k.len) { + printError("SPI write failure"); + return -1; + } else { + printDebug("SPI write success"); + return 0; + } +} + +int Mtac15Fpga::spiClose() { + int spi_device; + int a; + + /* close file & deallocate file descriptor */ + spi_device = *(int *)spi_target_ptr; /* check that spi_target is not null */ + a = close(spi_device); + free(spi_target_ptr); + + /* determine return code */ + if (a < 0) { + printError("SPI port failed to close"); + return -1; + } else { + return 0; + } +} + +/* write to creset pin */ +int Mtac15Fpga::cresetWrite(char num) { + std::string cresetPath = SYSFS_PLATFORM + port + CRESET; + int fd = open(cresetPath.c_str(), O_WRONLY); + if (fd < 0) { + printError("Unable to lock file, are you root?"); + return -1; + } + write(fd, &num, 1); + close(fd); + return 0; +} + +/* + Release Power-down instruction releases the device from + said state allowing device communication +*/ +int Mtac15Fpga::releaseDevice() { + int mtac_ret; + int spi_device; + struct spi_ioc_transfer k; + int ret; + size_t command_size = 5; + char out_buf[command_size]; + char in_buf[command_size]; + + /* prepare frame to be sent */ + out_buf[0] = CHIP_RELEASE; + out_buf[1] = 0; + out_buf[2] = 0; + out_buf[3] = 0; + out_buf[4] = 0; + + /* I/O transaction */ + mtac_ret = spiOpen(); + spi_device = + *(int *)spi_target_ptr; /* spi_target cannot be null beforehand */ + memset(&k, 0, sizeof(k)); /* clear k */ + k.tx_buf = (unsigned long)out_buf; + k.rx_buf = (unsigned long)in_buf; + k.len = command_size; + k.speed_hz = SPI_SPEED; + k.cs_change = 1; + k.bits_per_word = 8; + ret = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); + mtac_ret = spiClose(); + + /* determine return code */ + if (ret != (int)k.len) { + printError("Release failed"); + mtac_ret = -1; + } else { + usleep(1000); + mtac_ret = 0; + } + return mtac_ret; +} + +/* + Write enable instruction sets the write enable latch + in the status register to 1. It needs to be set before + a page can be programmed or chip erased +*/ +int Mtac15Fpga::writeEnable() { + int mtac_ret; + int spi_device; + struct spi_ioc_transfer k; + int ret; + size_t command_size = 1; + char out_buf[command_size]; + char in_buf[command_size]; + + /* prepare frame to be sent */ + out_buf[0] = 0x06; + + /* I/O transaction */ + mtac_ret = spiOpen(); + spi_device = + *(int *)spi_target_ptr; /* spi_target cannot be null beforehand */ + memset(&k, 0, sizeof(k)); /* clear k */ + k.tx_buf = (unsigned long)out_buf; + k.rx_buf = (unsigned long)in_buf; + k.len = command_size; + k.speed_hz = SPI_SPEED; + k.cs_change = 0; + k.bits_per_word = 8; + ret = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); + mtac_ret = spiClose(); + + /* determine return code */ + if (ret != (int)k.len) { + printError("Write Enable failed"); + mtac_ret = -1; + } else { + usleep(1000); + printDebug("Write Enable successful"); + mtac_ret = 0; + } + return mtac_ret; +} + +/* + Verify that the chip erase was successful +*/ +int Mtac15Fpga::chipEraseVerify() { + int mtac_ret; + int spi_device; + struct spi_ioc_transfer k; + int a, ret; + uint16_t command_size = 256 + 5; + char out_buf[command_size]; + char in_buf[command_size]; + + /* prepare frame to be sent */ + out_buf[0] = 0x0B; + out_buf[1] = 0x00; + out_buf[2] = 0x00; + out_buf[3] = 0x00; + out_buf[4] = 0x00; + + /* I/O transaction */ + mtac_ret = spiOpen(); + spi_device = + *(int *)spi_target_ptr; /* spi_target cannot be null beforehand */ + memset(&k, 0, sizeof(k)); /* clear k */ + k.tx_buf = (unsigned long)out_buf; + k.rx_buf = (unsigned long)in_buf; + k.len = command_size; + k.speed_hz = SPI_SPEED; + k.cs_change = 1; + k.bits_per_word = 8; + ret = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); + + /* determine return code */ + if (ret != (int)k.len) { + printError("Chip transfer failed"); + mtac_ret = -1; + } else { + printDebug("Chip transfer successful"); + mtac_ret = 0; + } + mtac_ret = spiClose(); + /* verify that the chip was erased */ + for (a = 5; a < command_size; a++) { + if (in_buf[a] != 0xFF) { + mtac_ret = spiClose(); + return mtac_ret; + } + } + return mtac_ret; +} + +/* + Chip erase instruction sets all memory within + the device to the erased state of all 1s (FFh) +*/ +int Mtac15Fpga::chipErase() { + int mtac_ret; + int spi_device; + struct spi_ioc_transfer k; + int ret; + size_t command_size = 1; + char out_buf[command_size]; + char in_buf[command_size]; + + /* prepare frame to be sent */ + out_buf[0] = CHIP_ERASE; + + /* I/O transaction */ + mtac_ret = spiOpen(); + spi_device = + *(int *)spi_target_ptr; /* spi_target cannot be null beforehand */ + memset(&k, 0, sizeof(k)); /* clear k */ + k.tx_buf = (unsigned long)out_buf; + k.rx_buf = (unsigned long)in_buf; + k.len = command_size; + k.speed_hz = SPI_SPEED; + k.cs_change = 0; + k.bits_per_word = 8; + ret = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); + sleep(5); + mtac_ret = spiClose(); + + /* determine return code */ + if (ret != (int)k.len) { + printError("Chip Erase transfer failed"); + mtac_ret = -1; + } else { + printDebug("Chip Erase transfer successful"); + chipEraseVerify(); + mtac_ret = 0; + } + return mtac_ret; +} + +/* erase entire flash */ +int Mtac15Fpga::mtacErase() { + int ret; + printInfo("Erasing flash"); + /* pull device out of powerdown state */ + ret = releaseDevice(); + if (ret != 0) { + return ret; + } + + /* enable writing to flash */ + ret = writeEnable(); + if (ret != 0) { + return ret; + } + + /* send chip erase command to flash */ + ret = chipErase(); + if (ret != 0) { + return ret; + } + /* pull device out of powerdown state */ + ret = releaseDevice(); + if (ret != 0) { + return ret; + } + return 0; +} + +/* + Page Program instruction allows writing upto 256 bytes (a page) of + data to be programmed at previously erased memory locations Write + enable must be issued first +*/ +int Mtac15Fpga::pageProgram(uint8_t adr_lower, uint8_t adr_higher, + uint32_t data[256]) { + int mtac_ret; + int spi_device; + struct spi_ioc_transfer k; + int a, h; + size_t command_size = 260; + char out_buf[command_size]; + char in_buf[command_size]; + + /* prepare frame to be sent */ + out_buf[0] = PAGE_PROGRAM; + out_buf[1] = adr_higher; + out_buf[2] = adr_lower; + out_buf[3] = 0x00; + for (h = 0; h < 256; h++) { + out_buf[h + 4] = data[h]; + } + + /* I/O transaction */ + mtac_ret = spiOpen(); + spi_device = + *(int *)spi_target_ptr; /* spi_target cannot be null beforehand */ + memset(&k, 0, sizeof(k)); /* clear k */ + k.tx_buf = (unsigned long)out_buf; + k.rx_buf = (unsigned long)in_buf; + k.len = command_size; + k.speed_hz = SPI_SPEED; + k.cs_change = 1; + k.bits_per_word = 8; + a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); + printDebug("Writing Page %x%x to MTAC\r", adr_higher, adr_lower); + usleep(10000); + + mtac_ret = spiClose(); + + /* determine return code */ + if (a != (int)k.len) { + printError("SPI write failure"); + mtac_ret = -1; + } else { + printDebug("SPI write success"); + mtac_ret = 0; + } + return mtac_ret; +} + +/* write to mtac card with input file */ +int Mtac15Fpga::mtacProgram(const char input_file[]) { + FILE *f; + struct stat st; + size_t file_size; + int ret = 0; + uint32_t i = 0, index, result, 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 = writeEnable(); + if (ret != 0) { + 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 = pageProgram(adr_lower, adr_higher, page_data); + if (ret != 0) { + free(p_array); + break; + } + /* release device from page program powerdown */ + ret = releaseDevice(); + if (ret != 0) { + free(p_array); + break; + } + } + free(p_array); + return ret; +} + +/* Make sure no device is using the spidev bus to prevent contention*/ +int Mtac15Fpga::busContention() { + char number[1024]; + FILE *f = popen("lsof", "r"); + while (fgets(number, 1024, f) != NULL) { + if (strstr(number, "spidev") != NULL) { + printError("The accessory card is being used by another process: " + "\n %sPlease " + "close all LoRaWAN processes and try again", + number); + pclose(f); + return -1; + } + } + pclose(f); + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ + +/* Constructor used fpga upgrade utility */ +Mtac15Fpga::Mtac15Fpga(std::string inputFile, std::string forcedPath) { + FILE *fp = fopen(DEVICE_INFO_FILE, "r"); + char buf[0XFFFF]; + rapidjson::FileReadStream input(fp, buf, sizeof(buf)); + deviceInfo.ParseStream(input); + fclose(fp); + + if (!deviceInfo.HasMember("hardwareVersion")) { + printError("%s does not have hardware version info, exiting", + DEVICE_INFO_FILE); + return; + } + std::string hwVersion = deviceInfo["hardwareVersion"].GetString(); + + if (deviceInfo.HasMember("accessoryCards") && + deviceInfo["accessoryCards"].IsArray() && + deviceInfo["accessoryCards"].Size() > 0) { + if (hwVersion.find("MTCDT3") != std::string::npos) { + hardwareType = HARDWARE_MTCDT3; + } else if (hwVersion.find("MTCDT") != std::string::npos) { + hardwareType = HARDWARE_MTCDT; + } else { + return; + } + if (inputFile.empty()) { + input_file = MTCDT_DEFAULT_FILE; + } else { + input_file = inputFile; + } + port = deviceInfo["accessoryCards"][0]["port"].GetString(); + if (port.back() == '2') { + spiPath = "/dev/spidev1.2"; + } else { + spiPath = "/dev/spidev0.2"; + } + getFpgaVersion(); + printInfo("Current FPGA version: %d", fpgaVersion); + } else if (hwVersion.find("MTCAP") != std::string::npos) { + hardwareType = HARDWARE_MTCAP; + if (inputFile.empty()) { + input_file = MTCAP_DEFAULT_FILE; + } else { + input_file = inputFile; + } + spiPath = "/dev/spidev0.0"; + getFpgaVersion(); + printInfo("Current FPGA version: %d", fpgaVersion); + } +} + +/* Constructor used by device_info.json generator */ +Mtac15Fpga::Mtac15Fpga(const std::string path) { spiPath = path; } + +int Mtac15Fpga::FpgaVersion() { return fpgaVersion; } + +/* Open spi device and get fpga version from register */ +int Mtac15Fpga::getFpgaVersion() { + int ret = spiOpen(); + if (ret != 0) { + printError("Could not open SPI port %s", spiPath.c_str()); + } else { + /* detect if the gateway has an FPGA with SPI mux header support */ + ret = spiRead(MTAC_FPGA, loregs[MTAC_VERSION].addr, &fpgaVersion); + if (ret != 0) { + printError("Could not read FPGA version"); + } + spiClose(); + } + spi_target_ptr = NULL; + return ret; +} + +/* setup and upgrade the mtac card with the file specified */ +int Mtac15Fpga::upgradeFpga() { + if (hardwareType == HARDWARE_INVALID) { + printError("Invalid hardware"); + return -1; + } + + int ret; + + if (input_file.empty()) { + printError("Invalid input file %s", input_file.c_str()); + return -1; + } + /* check that no other device is using the bus */ + ret = busContention(); + if (ret != 0) { + return ret; + } + /* check MTAC Hardware Compatibility */ + printInfo("Checking hardware compatibility"); + + /* check input file checksum */ + ret = sha256_file(input_file.c_str()); + if (ret != 0) { + return ret; + } + + /* pull creset down to access spi flash */ + ret = cresetWrite('0'); + if (ret != 0) { + return ret; + } + sleep(1); + + /* erase chip before flashing new firmware */ + ret = mtacErase(); + if (ret != 0) { + return ret; + } + + /* program user specified firmware */ + printInfo("Programming flash"); + ret = mtacProgram(input_file.c_str()); + if (ret != 0) { + return ret; + } else { + printInfo("Write Complete. Resetting FPGA"); + } + + /* pull creset up to access FPGA */ + ret = cresetWrite('1'); + if (ret != 0) { + return ret; + } + sleep(5); + printInfo("Reading New FPGA configuration"); + ret = getFpgaVersion(); + if (ret != 0) { + return ret; + } + printInfo("New FPGA version: %d", fpgaVersion); + return 0; +} -- cgit v1.2.3