diff --git a/.gitignore b/.gitignore index ba428357..57f7c3af 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,7 @@ lib/ obj/ *.so* -build/ +build*/ testing/ # documentation output diff --git a/device/Makefile b/device/Makefile index 8317dd2f..ee0b4efc 100644 --- a/device/Makefile +++ b/device/Makefile @@ -17,7 +17,7 @@ BOARD = DISCO_F407VG DEVICE = STMicroelectronics:stm32:Disco FQBN = $(DEVICE):pnum=$(BOARD),usb=CDCgen,upload_method=dfuMethod,xusb=FS,opt=o3std else -$(error Unknown device $(DEV), allowed devices are F401 (default), F411, and F407) +$(error Unknown device $(DEV), allowed devices are F401, F411 (default), and F407) endif diff --git a/device/PowerSensor/PowerSensor.ino b/device/PowerSensor/PowerSensor.ino index 6c0fd33a..21860a69 100644 --- a/device/PowerSensor/PowerSensor.ino +++ b/device/PowerSensor/PowerSensor.ino @@ -84,7 +84,7 @@ uint8_t serialData[(SENSORS + 1) * 2]; // 16b per sensor and 16b for timestamp bool sendData = false; bool streamValues = false; bool sendSingleValue = false; -bool sendMarkerNext = false; +uint32_t sendMarkers = 0; bool allSensorsInactive = false; // include device-specific code for setting up the ADC and DMA @@ -233,7 +233,7 @@ void serialEvent() { break; case 'M': // marker character, places a marker in the output file - sendMarkerNext = true; + sendMarkers++; break; case 'I': // Send single set of sensor values. does nothing if streaming is enabled @@ -251,6 +251,11 @@ void serialEvent() { case 'T': // Disable streaming of data and unpause display // in demo mode the display is always enabled so no need to reinitialize it here + // if streaming was enabled, first wait until all markers are sent + if (streamValues) { + while (sendMarkers > 0) delay(1); + while (!sendData) delay(1); + } streamValues = false; #if !defined NODISPLAY && !defined DEMO displayPaused = false; @@ -259,6 +264,11 @@ void serialEvent() { break; case 'X': // Shutdown and unpause display, shuts off IO thread on host + // if streaming was enabled, first wait until all markers are sent + if (streamValues) { + while (sendMarkers > 0) delay(1); + while (!sendData) delay(1); + } #ifndef NODISPLAY displayPaused = false; displayInitialValues(); diff --git a/device/PowerSensor/device_specific/BLACKPILL_F401CC_F411CE.hpp b/device/PowerSensor/device_specific/BLACKPILL_F401CC_F411CE.hpp index 1ce8308d..975d38c8 100644 --- a/device/PowerSensor/device_specific/BLACKPILL_F401CC_F411CE.hpp +++ b/device/PowerSensor/device_specific/BLACKPILL_F401CC_F411CE.hpp @@ -124,6 +124,12 @@ extern "C" void DMA2_Stream0_IRQHandler() { // store in sensorValues for display purposes sensorLevels[i] = level; #endif + // determine whether or not to send marker + // marker is always sent with sensor 0 + bool sendMarkerNext = (i == 0) && (sendMarkers > 0); + if (sendMarkerNext) { + sendMarkers--; + } // add metadata to remaining bits: 2 bytes available with 10b sensor value // First byte: 1 iii aaaa // where iii is the sensor id, a are the upper 4 bits of the level diff --git a/device/PowerSensor/device_specific/DISCO_F407VG.hpp b/device/PowerSensor/device_specific/DISCO_F407VG.hpp index 30327e7a..2f55ceb1 100644 --- a/device/PowerSensor/device_specific/DISCO_F407VG.hpp +++ b/device/PowerSensor/device_specific/DISCO_F407VG.hpp @@ -118,6 +118,12 @@ extern "C" void DMA2_Stream0_IRQHandler() { // store in sensorValues for display purposes sensorLevels[i] = level; #endif + // determine whether or not to send marker + // marker is always sent with sensor 0 + bool sendMarkerNext = (i == 0) && (sendMarkers > 0); + if (sendMarkerNext) { + sendMarkers--; + } // add metadata to remaining bits: 2 bytes available with 10b sensor value // First byte: 1 iii aaaa // where iii is the sensor id, a are the upper 4 bits of the level diff --git a/host/include/PowerSensor.hpp b/host/include/PowerSensor.hpp index 8ed417a6..90bcb522 100644 --- a/host/include/PowerSensor.hpp +++ b/host/include/PowerSensor.hpp @@ -55,7 +55,6 @@ class PowerSensor { void dump(const std::string dumpFileName); // dumpFileName == 0 --> stop dumping void mark(char name); - void mark(const State &startState, const State &stopState, const std::string name = 0, unsigned int tag = 0) const; void reset(bool dfuMode); void writeSensorsToEEPROM(); @@ -83,6 +82,7 @@ class PowerSensor { int openDevice(std::string device); std::queue markers; void writeMarker(); + void waitForMarkers(int timeout=500); void initializeSensorPairs(); void updateSensorPairs(); diff --git a/host/src/PowerSensor.cc b/host/src/PowerSensor.cc index bb950309..58108cdb 100644 --- a/host/src/PowerSensor.cc +++ b/host/src/PowerSensor.cc @@ -348,25 +348,26 @@ void PowerSensor::mark(char name) { * */ void PowerSensor::writeMarker() { - std::unique_lock lock(dumpFileMutex); - *dumpFile << "M " << markers.front() << std::endl; - markers.pop(); + if (dumpFile != nullptr) { + std::unique_lock lock(dumpFileMutex); + *dumpFile << "M " << markers.front() << std::endl; + markers.pop(); + } } /** - * @brief Write custom marker to dump file + * @brief Wait for all markers to be written to the dump file * - * @param startState State used to get start time - * @param stopState State used to get end time - * @param name name of the marker (string) - * @param tag id of the marker (int) + * @param timeout maximum waiting time in milliseconds */ -void PowerSensor::mark(const State &startState, const State &stopState, std::string name, unsigned int tag) const { - if (dumpFile != nullptr) { - std::unique_lock lock(dumpFileMutex); - *dumpFile << "M " << elapsedSeconds(startTime, startState.timeAtRead) << ' ' \ - << elapsedSeconds(startTime, stopState.timeAtRead) << ' ' \ - << tag << " \"" << name << '"' << std::endl; +void PowerSensor::waitForMarkers(int timeout) { + auto tstart = std::chrono::high_resolution_clock::now(); + while (markers.size() != 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + auto elapsed = std::chrono::high_resolution_clock::now() - tstart; + if (elapsed.count() > timeout) { + break; + } } } @@ -431,6 +432,8 @@ void PowerSensor::startIOThread() { * */ void PowerSensor::stopIOThread() { + // first ensure there are no markers still to be sent from the device + waitForMarkers(); if (thread != nullptr) { writeCharToDevice('X'); thread->join(); @@ -445,6 +448,11 @@ void PowerSensor::stopIOThread() { * @param dumpFileName */ void PowerSensor::dump(std::string dumpFileName) { + // if dumping should be stopped, first wait until all markers are written + if (dumpFileName.empty()) { + waitForMarkers(); + } + std::unique_lock lock(dumpFileMutex); dumpFile = std::unique_ptr(dumpFileName.empty() ? nullptr: new std::ofstream(dumpFileName)); if (!dumpFileName.empty()) { @@ -462,6 +470,9 @@ void PowerSensor::dump(std::string dumpFileName) { * */ void PowerSensor::dumpCurrentWattToFile() { + if (dumpFile == nullptr) { + return; + } std::unique_lock lock(dumpFileMutex); double totalWatt = 0; auto time = std::chrono::high_resolution_clock::now();