diff --git a/Software/PC_Application/Application b/Software/PC_Application/Application index 0faca95..7a9407d 100755 Binary files a/Software/PC_Application/Application and b/Software/PC_Application/Application differ diff --git a/Software/PC_Application/Device/device.cpp b/Software/PC_Application/Device/device.cpp index f360fcd..a09dd93 100644 --- a/Software/PC_Application/Device/device.cpp +++ b/Software/PC_Application/Device/device.cpp @@ -157,6 +157,30 @@ bool Device::SendFirmwareChunk(Protocol::FirmwarePacket &fw) } } +bool Device::SendCommandWithoutPayload(Protocol::PacketType type) +{ + if(m_connected) { + unsigned char buffer[32]; + Protocol::PacketInfo p; + p.type = type; + unsigned int length = Protocol::EncodePacket(p, buffer, sizeof(buffer)); + if(!length) { + qCritical() << "Failed to encode packet"; + return false; + } + int actual_length; + auto ret = libusb_bulk_transfer(m_handle, EP_Data_Out_Addr, buffer, length, &actual_length, 0); + if(ret < 0) { + qCritical() << "Error sending data: " + << libusb_strerror((libusb_error) ret); + return false; + } + return true; + } else { + return false; + } +} + std::vector Device::GetDevices() { std::vector serials; diff --git a/Software/PC_Application/Device/device.h b/Software/PC_Application/Device/device.h index 2037cfe..c94fef3 100644 --- a/Software/PC_Application/Device/device.h +++ b/Software/PC_Application/Device/device.h @@ -48,6 +48,7 @@ public: bool Configure(Protocol::SweepSettings settings); bool SetManual(Protocol::ManualControl manual); bool SendFirmwareChunk(Protocol::FirmwarePacket &fw); + bool SendCommandWithoutPayload(Protocol::PacketType type); // Returns serial numbers of all connected devices static std::vector GetDevices(); QString serial() const; diff --git a/Software/PC_Application/Device/firmwareupdatedialog.cpp b/Software/PC_Application/Device/firmwareupdatedialog.cpp index 1dbbbb6..e1b020b 100644 --- a/Software/PC_Application/Device/firmwareupdatedialog.cpp +++ b/Software/PC_Application/Device/firmwareupdatedialog.cpp @@ -62,7 +62,7 @@ void FirmwareUpdateDialog::on_bStart_clicked() } state = State::ErasingFLASH; addStatus("Erasing device memory..."); - // TODO issue write command + dev.SendCommandWithoutPayload(Protocol::PacketType::ClearFlash); timer.start(10000); } @@ -105,7 +105,7 @@ void FirmwareUpdateDialog::receivedAck() // complete file transferred addStatus("Triggering device update..."); state = State::TriggeringUpdate; - // TODO trigger update + dev.SendCommandWithoutPayload(Protocol::PacketType::PerformFirmwareUpdate); timer.start(5000); } sendNextFirmwareChunk(); @@ -113,7 +113,7 @@ void FirmwareUpdateDialog::receivedAck() break; case State::TriggeringUpdate: addStatus("Rebooting device..."); - // TODO listen for detected device + // TODO delete current device and listen for reconnect state = State::Idle; break; } @@ -124,4 +124,5 @@ void FirmwareUpdateDialog::sendNextFirmwareChunk() Protocol::FirmwarePacket fw; fw.address = transferredBytes; file->read((char*) &fw.data, Protocol::FirmwareChunkSize); + dev.SendFirmwareChunk(fw); } diff --git a/Software/VNA_embedded/Application/App.cpp b/Software/VNA_embedded/Application/App.cpp index 314a8ac..c8d9602 100644 --- a/Software/VNA_embedded/Application/App.cpp +++ b/Software/VNA_embedded/Application/App.cpp @@ -11,21 +11,22 @@ #include "USB/usb.h" #include "Flash.hpp" #include "Firmware.hpp" +#include "FreeRTOS.h" +#include "task.h" #define LOG_LEVEL LOG_LEVEL_INFO #define LOG_MODULE "App" #include "Log.h" -static volatile bool newResult; static Protocol::Datapoint result; -static volatile bool newSettings = false; static Protocol::SweepSettings settings; -static volatile bool newStatus = false; static FPGA::SamplingResult statusResult; -static volatile bool newManual = false; static Protocol::ManualControl manual; +static Protocol::PacketInfo packet; +static TaskHandle_t handle; + // TODO set proper values #define HW_REVISION 'A' #define FW_MAJOR 0 @@ -34,18 +35,34 @@ static Protocol::ManualControl manual; extern SPI_HandleTypeDef hspi1; static Flash flash = Flash(&hspi1, FLASH_CS_GPIO_Port, FLASH_CS_Pin); -void VNACallback(Protocol::Datapoint res) { +#define FLAG_USB_PACKET 0x01 +#define FLAG_DATAPOINT 0x02 +#define FLAG_STATUSRESULT 0x04 + +static void VNACallback(Protocol::Datapoint res) { result = res; - newResult = true; + BaseType_t woken = false; + xTaskNotifyFromISR(handle, FLAG_DATAPOINT, eSetBits, &woken); + portYIELD_FROM_ISR(woken); } -void VNAStatusCallback(FPGA::SamplingResult res) { +static void VNAStatusCallback(FPGA::SamplingResult res) { statusResult = res; - newStatus = true; + BaseType_t woken = false; + xTaskNotifyFromISR(handle, FLAG_STATUSRESULT, eSetBits, &woken); + portYIELD_FROM_ISR(woken); +} +static void USBPacketReceived(Protocol::PacketInfo p) { + packet = p; + BaseType_t woken = false; + xTaskNotifyFromISR(handle, FLAG_USB_PACKET, eSetBits, &woken); + portYIELD_FROM_ISR(woken); } void App_Start() { + handle = xTaskGetCurrentTaskHandle(); usb_init(communication_usb_input); Log_Init(); + Communication::SetCallback(USBPacketReceived); // Pass on logging output to USB Log_SetRedirect(usb_log); LOG_INFO("Start"); @@ -66,66 +83,143 @@ void App_Start() { if (!VNA::Init()) { LOG_CRIT("Initialization failed, unable to start"); } - // Allow USB enumeration -// USB_EN_GPIO_Port->BSRR = USB_EN_Pin; uint32_t lastNewPoint = HAL_GetTick(); bool sweepActive = false; while (1) { - if (newResult) { - Protocol::PacketInfo packet; - packet.type = Protocol::PacketType::Datapoint; - packet.datapoint = result; - Communication::Send(packet); - newResult = false; - lastNewPoint = HAL_GetTick(); - if(result.pointNum == settings.points - 1) { - // end of sweep - // read PLL temperatures - uint8_t tempSource, tempLO; - VNA::GetTemps(&tempSource, &tempLO); - LOG_INFO("PLL temperatures: %u/%u", tempSource, tempLO); - // Read ADC min/max - auto limits = FPGA::GetADCLimits(); -#define ADC_LIMIT 30000 - // Compile info packet - packet.type = Protocol::PacketType::DeviceInfo; - packet.info.FPGA_configured = 1; - if(limits.P1min < -ADC_LIMIT || limits.P1max > ADC_LIMIT - || limits.P2min < -ADC_LIMIT || limits.P2max > ADC_LIMIT - || limits.Rmin < -ADC_LIMIT || limits.Rmax > ADC_LIMIT) { - packet.info.ADC_overload = true; - } else { - packet.info.ADC_overload = false; - } - packet.info.FW_major = FW_MAJOR; - packet.info.FW_minor = FW_MINOR; - packet.info.HW_Revision = HW_REVISION; - auto status = FPGA::GetStatus(); - packet.info.LO1_locked = (status & (int) FPGA::Interrupt::LO1Unlock) ? 0 : 1; - packet.info.source_locked = (status & (int) FPGA::Interrupt::SourceUnlock) ? 0 : 1; - packet.info.extRefAvailable = 0; - packet.info.extRefInUse = 0; - packet.info.temperatures.LO1 = tempLO; - packet.info.temperatures.source = tempSource; - packet.info.temperatures.MCU = 0; + uint32_t notification; + if(xTaskNotifyWait(0x00, UINT32_MAX, ¬ification, 100) == pdPASS) { + // something happened + if(notification & FLAG_DATAPOINT) { + Protocol::PacketInfo packet; + packet.type = Protocol::PacketType::Datapoint; + packet.datapoint = result; Communication::Send(packet); + lastNewPoint = HAL_GetTick(); + if(result.pointNum == settings.points - 1) { + // end of sweep + // read PLL temperatures + uint8_t tempSource, tempLO; + VNA::GetTemps(&tempSource, &tempLO); + LOG_INFO("PLL temperatures: %u/%u", tempSource, tempLO); + // Read ADC min/max + auto limits = FPGA::GetADCLimits(); + #define ADC_LIMIT 30000 + // Compile info packet + packet.type = Protocol::PacketType::DeviceInfo; + packet.info.FPGA_configured = 1; + if(limits.P1min < -ADC_LIMIT || limits.P1max > ADC_LIMIT + || limits.P2min < -ADC_LIMIT || limits.P2max > ADC_LIMIT + || limits.Rmin < -ADC_LIMIT || limits.Rmax > ADC_LIMIT) { + packet.info.ADC_overload = true; + } else { + packet.info.ADC_overload = false; + } + packet.info.FW_major = FW_MAJOR; + packet.info.FW_minor = FW_MINOR; + packet.info.HW_Revision = HW_REVISION; + auto status = FPGA::GetStatus(); + packet.info.LO1_locked = (status & (int) FPGA::Interrupt::LO1Unlock) ? 0 : 1; + packet.info.source_locked = (status & (int) FPGA::Interrupt::SourceUnlock) ? 0 : 1; + packet.info.extRefAvailable = 0; + packet.info.extRefInUse = 0; + packet.info.temperatures.LO1 = tempLO; + packet.info.temperatures.source = tempSource; + packet.info.temperatures.MCU = 0; + Communication::Send(packet); + FPGA::ResetADCLimits(); + LOG_INFO("ADC limits: P1: %d/%d P2: %d/%d R: %d/%d", + limits.P1min, limits.P1max, limits.P2min, limits.P2max, + limits.Rmin, limits.Rmax); + // Start next sweep + FPGA::StartSweep(); + } + } + if(notification & FLAG_STATUSRESULT) { + Protocol::PacketInfo p; + p.type = Protocol::PacketType::Status; + memset(&p.status, 0, sizeof(p.status)); + uint16_t isr_flags = FPGA::GetStatus(); + if (!(isr_flags & 0x0002)) { + p.status.source_locked = 1; + } + if (!(isr_flags & 0x0001)) { + p.status.LO_locked = 1; + } + auto limits = FPGA::GetADCLimits(); FPGA::ResetADCLimits(); - LOG_INFO("ADC limits: P1: %d/%d P2: %d/%d R: %d/%d", - limits.P1min, limits.P1max, limits.P2min, limits.P2max, - limits.Rmin, limits.Rmax); - // Start next sweep + p.status.port1min = limits.P1min; + p.status.port1max = limits.P1max; + p.status.port2min = limits.P2min; + p.status.port2max = limits.P2max; + p.status.refmin = limits.Rmin; + p.status.refmax = limits.Rmax; + p.status.port1real = (float) statusResult.P1I / manual.Samples; + p.status.port1imag = (float) statusResult.P1Q / manual.Samples; + p.status.port2real = (float) statusResult.P2I / manual.Samples; + p.status.port2imag = (float) statusResult.P2Q / manual.Samples; + p.status.refreal = (float) statusResult.RefI / manual.Samples; + p.status.refimag = (float) statusResult.RefQ / manual.Samples; + VNA::GetTemps(&p.status.temp_source, &p.status.temp_LO); + Communication::Send(p); + // Trigger next status update FPGA::StartSweep(); } + if(notification & FLAG_USB_PACKET) { + switch(packet.type) { + case Protocol::PacketType::SweepSettings: + LOG_INFO("New settings received"); + settings = packet.settings; + VNA::ConfigureSweep(settings, VNACallback); + sweepActive = true; + lastNewPoint = HAL_GetTick(); + break; + case Protocol::PacketType::ManualControl: + sweepActive = false; + manual = packet.manual; + VNA::ConfigureManual(manual, VNAStatusCallback); + break; + case Protocol::PacketType::ClearFlash: + FPGA::AbortSweep(); + sweepActive = false; + LOG_DEBUG("Erasing FLASH in preparation for firmware update..."); + if(flash.eraseChip()) { + LOG_DEBUG("...FLASH erased") + Protocol::PacketInfo p; + p.type = Protocol::PacketType::Ack; + Communication::Send(p); + } else { + LOG_ERR("Failed to erase FLASH"); + } + break; + case Protocol::PacketType::FirmwarePacket: + LOG_INFO("Writing firmware packet at address %u", packet.firmware.address); + flash.write(packet.firmware.address, sizeof(packet.firmware.data), packet.firmware.data); + Protocol::PacketInfo p; + p.type = Protocol::PacketType::Ack; + Communication::Send(p); + break; + case Protocol::PacketType::PerformFirmwareUpdate: { + auto fw_info = Firmware::GetFlashContentInfo(&flash); + if(fw_info.valid) { + Protocol::PacketInfo p; + p.type = Protocol::PacketType::Ack; + Communication::Send(p); + // Some delay to allow communication to finish + vTaskDelay(1000); + Firmware::PerformUpdate(&flash); + // will never get here + } + } + break; + default: + // ignore all other packets + break; + } + } } - if (newSettings) { - LOG_INFO("New settings received"); - newSettings = false; - VNA::ConfigureSweep(settings, VNACallback); - sweepActive = true; - lastNewPoint = HAL_GetTick(); - } + if(sweepActive && HAL_GetTick() - lastNewPoint > 1000) { LOG_WARN("Timed out waiting for point, last received point was %d", result.pointNum); LOG_WARN("FPGA status: 0x%04x", FPGA::GetStatus()); @@ -134,52 +228,5 @@ void App_Start() { sweepActive = true; lastNewPoint = HAL_GetTick(); } - if (newManual) { - LOG_INFO("New manual control"); - sweepActive = false; - newManual = false; - VNA::ConfigureManual(manual, VNAStatusCallback); - } - if (newStatus) { - newStatus = false; - Protocol::PacketInfo p; - p.type = Protocol::PacketType::Status; - memset(&p.status, 0, sizeof(p.status)); - uint16_t isr_flags = FPGA::GetStatus(); - if (!(isr_flags & 0x0002)) { - p.status.source_locked = 1; - } - if (!(isr_flags & 0x0001)) { - p.status.LO_locked = 1; - } - auto limits = FPGA::GetADCLimits(); - FPGA::ResetADCLimits(); - p.status.port1min = limits.P1min; - p.status.port1max = limits.P1max; - p.status.port2min = limits.P2min; - p.status.port2max = limits.P2max; - p.status.refmin = limits.Rmin; - p.status.refmax = limits.Rmax; - p.status.port1real = (float) statusResult.P1I / manual.Samples; - p.status.port1imag = (float) statusResult.P1Q / manual.Samples; - p.status.port2real = (float) statusResult.P2I / manual.Samples; - p.status.port2imag = (float) statusResult.P2Q / manual.Samples; - p.status.refreal = (float) statusResult.RefI / manual.Samples; - p.status.refimag = (float) statusResult.RefQ / manual.Samples; - VNA::GetTemps(&p.status.temp_source, &p.status.temp_LO); - Communication::Send(p); - // Trigger next status update - FPGA::StartSweep(); - } } } - -void App::NewSettings(Protocol::SweepSettings s) { - settings = s; - newSettings = true; -} - -void App::SetManual(Protocol::ManualControl m) { - manual = m; - newManual = true; -} diff --git a/Software/VNA_embedded/Application/App.h b/Software/VNA_embedded/Application/App.h index 221aa97..b45ec9e 100644 --- a/Software/VNA_embedded/Application/App.h +++ b/Software/VNA_embedded/Application/App.h @@ -3,13 +3,6 @@ #ifdef __cplusplus #include "Protocol.hpp" -namespace App { - -void NewSettings(Protocol::SweepSettings s); -void SetManual(Protocol::ManualControl m); - -} - extern "C" { #endif diff --git a/Software/VNA_embedded/Application/Communication/Communication.cpp b/Software/VNA_embedded/Application/Communication/Communication.cpp index 65a1091..9b9b64e 100644 --- a/Software/VNA_embedded/Application/Communication/Communication.cpp +++ b/Software/VNA_embedded/Application/Communication/Communication.cpp @@ -9,10 +9,12 @@ static uint8_t inputBuffer[1024]; uint16_t inputCnt = 0; static uint8_t outputBuffer[1024]; -//#include "usbd_def.h" -//#include "usbd_cdc_if.h" +static Communication::Callback callback = nullptr; + +void Communication::SetCallback(Callback cb) { + callback = cb; +} -//extern USBD_HandleTypeDef hUsbDeviceFS; void Communication::Input(const uint8_t *buf, uint16_t len) { if (inputCnt + len < sizeof(inputBuffer)) { @@ -33,13 +35,10 @@ void Communication::Input(const uint8_t *buf, uint16_t len) { memmove(inputBuffer, &inputBuffer[handled_len], remaining); inputCnt = remaining; } - switch(packet.type) { - case Protocol::PacketType::SweepSettings: - App::NewSettings(packet.settings); - break; - case Protocol::PacketType::ManualControl: - App::SetManual(packet.manual); - break; + if(packet.type != Protocol::PacketType::None) { + if(callback) { + callback(packet); + } } } while (handled_len > 0); } @@ -63,3 +62,4 @@ bool Communication::Send(Protocol::PacketInfo packet) { void communication_usb_input(const uint8_t *buf, uint16_t len) { Communication::Input(buf, len); } + diff --git a/Software/VNA_embedded/Application/Communication/Communication.h b/Software/VNA_embedded/Application/Communication/Communication.h index 543fa44..d7fbd4d 100644 --- a/Software/VNA_embedded/Application/Communication/Communication.h +++ b/Software/VNA_embedded/Application/Communication/Communication.h @@ -8,6 +8,9 @@ namespace Communication { +using Callback = void(*)(Protocol::PacketInfo); + +void SetCallback(Callback cb); void Input(const uint8_t *buf, uint16_t len); bool Send(Protocol::PacketInfo packet); diff --git a/Software/VNA_embedded/Application/Communication/Protocol.cpp b/Software/VNA_embedded/Application/Communication/Protocol.cpp index 6fe0587..cfd0a6f 100644 --- a/Software/VNA_embedded/Application/Communication/Protocol.cpp +++ b/Software/VNA_embedded/Application/Communication/Protocol.cpp @@ -401,6 +401,8 @@ uint16_t Protocol::DecodeBuffer(uint8_t *buf, uint16_t len, PacketInfo *info) { info->firmware = DecodeFirmwarePacket(&data[4]); break; case PacketType::Ack: + case PacketType::PerformFirmwareUpdate: + case PacketType::ClearFlash: // no payload, nothing to do break; case PacketType::None: @@ -432,6 +434,8 @@ uint16_t Protocol::EncodePacket(PacketInfo packet, uint8_t *dest, uint16_t dests payload_size = EncodeFirmwarePacket(packet.firmware, &dest[4], destsize - 8); break; case PacketType::Ack: + case PacketType::PerformFirmwareUpdate: + case PacketType::ClearFlash: // no payload, nothing to do break; case PacketType::None: diff --git a/Software/VNA_embedded/Application/Communication/Protocol.hpp b/Software/VNA_embedded/Application/Communication/Protocol.hpp index c2949d0..f30449b 100644 --- a/Software/VNA_embedded/Application/Communication/Protocol.hpp +++ b/Software/VNA_embedded/Application/Communication/Protocol.hpp @@ -91,14 +91,16 @@ using FirmwarePacket = struct _firmwarePacket { }; enum class PacketType : uint8_t { - None, - Datapoint, - SweepSettings, - Status, - ManualControl, - DeviceInfo, - FirmwarePacket, - Ack, + None = 0, + Datapoint = 1, + SweepSettings = 2, + Status = 3, + ManualControl = 4, + DeviceInfo = 5, + FirmwarePacket = 6, + Ack = 7, + ClearFlash = 8, + PerformFirmwareUpdate = 9, }; using PacketInfo = struct _packetinfo { diff --git a/Software/VNA_embedded/Application/Drivers/Flash.hpp b/Software/VNA_embedded/Application/Drivers/Flash.hpp index b7dbdf3..f315610 100644 --- a/Software/VNA_embedded/Application/Drivers/Flash.hpp +++ b/Software/VNA_embedded/Application/Drivers/Flash.hpp @@ -21,7 +21,7 @@ public: bool eraseChip(); // Starts the reading process without actually reading any bytes void initiateRead(uint32_t address); - const SPI_HandleTypeDef* const& getSpi() const { + const SPI_HandleTypeDef* const getSpi() const { return spi; }