From 517ab8bcfa38af46571892e91b707a6e194f7d9c Mon Sep 17 00:00:00 2001 From: Leon Oostrum Date: Fri, 15 Nov 2024 10:30:39 +0100 Subject: [PATCH 1/8] Ignore any build directories --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 038addb88a88ff702551674ccc280842e5a780b3 Mon Sep 17 00:00:00 2001 From: Leon Oostrum Date: Fri, 15 Nov 2024 11:56:49 +0100 Subject: [PATCH 2/8] Add waitForMakers function and avoid segfaults when writing to file. Use this to wait for any writing of markers to finish. Used when the dumping to file is stopped, and when the I/O thread is stopped. Sometimes a marker was written after closing the dump file. Check if the dumpfile is not nullptr both when writing a marker and when writing power data --- host/include/PowerSensor.hpp | 1 + host/src/PowerSensor.cc | 36 +++++++++++++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/host/include/PowerSensor.hpp b/host/include/PowerSensor.hpp index d70299f4..23f7da3c 100644 --- a/host/include/PowerSensor.hpp +++ b/host/include/PowerSensor.hpp @@ -82,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 1d665be5..dea502b0 100644 --- a/host/src/PowerSensor.cc +++ b/host/src/PowerSensor.cc @@ -336,9 +336,11 @@ 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(); + } } /** @@ -357,6 +359,24 @@ void PowerSensor::mark(const State &startState, const State &stopState, std::str } } +/** + * @brief Wait for all markers to be written to the dump file + * + * @param timeout maximum waiting time in milliseconds + */ +void PowerSensor::waitForMarkers(int timeout) { + std::chrono::duration elapsed; + auto tstart = std::chrono::high_resolution_clock::now(); + while (markers.size() != 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + elapsed = std::chrono::high_resolution_clock::now() - tstart; + if (elapsed.count() > timeout) { + break; + } + } + std::cout << "Marker waiting time: " << elapsed.count() << std::endl; +} + /** * @brief thread to continuously read sensor values from device * @@ -418,6 +438,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(); @@ -432,6 +454,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()) { @@ -449,6 +476,9 @@ void PowerSensor::dump(std::string dumpFileName) { * */ void PowerSensor::dumpCurrentWattToFile() { + if (dumpFile == nullptr) { + return; + } std::unique_lock lock(dumpFileMutex); double totalWatt = 0; double time = omp_get_wtime(); From a1b8cd1e32930a785bef0efb0c3df18a06dfc6b7 Mon Sep 17 00:00:00 2001 From: Leon Oostrum Date: Mon, 18 Nov 2024 11:47:37 +0100 Subject: [PATCH 3/8] Correct default device in Makefile error message --- device/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 73b6ddcc5c6d8c5acc4115cd2e68e71230aa87cb Mon Sep 17 00:00:00 2001 From: Leon Oostrum Date: Mon, 18 Nov 2024 11:48:25 +0100 Subject: [PATCH 4/8] Fix sending multiple markers in quick succession The device now keeps track of markers to send with a counter instead of boolean When a second marker request is received before the first one is sent, both are now sent with consecutive samples of sensor 0 --- device/PowerSensor/PowerSensor.ino | 4 ++-- .../PowerSensor/device_specific/BLACKPILL_F401CC_F411CE.hpp | 6 ++++++ device/PowerSensor/device_specific/DISCO_F407VG.hpp | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/device/PowerSensor/PowerSensor.ino b/device/PowerSensor/PowerSensor.ino index 6c0fd33a..4072a762 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 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 From bd3526682ca5f183f079e3854971b876cfa6e2a1 Mon Sep 17 00:00:00 2001 From: Leon Oostrum Date: Mon, 18 Nov 2024 11:49:37 +0100 Subject: [PATCH 5/8] Ensure markers are sent before stopping the data stream First wait for all markers to be processed, then wait for final packet to be sent to avoid missing last marker --- device/PowerSensor/PowerSensor.ino | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/device/PowerSensor/PowerSensor.ino b/device/PowerSensor/PowerSensor.ino index 4072a762..f297be83 100644 --- a/device/PowerSensor/PowerSensor.ino +++ b/device/PowerSensor/PowerSensor.ino @@ -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(); From c8827587ce35041fd27f0b5551888625d4de70eb Mon Sep 17 00:00:00 2001 From: Leon Oostrum Date: Mon, 18 Nov 2024 11:51:09 +0100 Subject: [PATCH 6/8] Remove debug print --- host/src/PowerSensor.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/host/src/PowerSensor.cc b/host/src/PowerSensor.cc index bdb7e755..81492458 100644 --- a/host/src/PowerSensor.cc +++ b/host/src/PowerSensor.cc @@ -378,16 +378,14 @@ void PowerSensor::mark(const State &startState, const State &stopState, std::str * @param timeout maximum waiting time in milliseconds */ void PowerSensor::waitForMarkers(int timeout) { - std::chrono::duration elapsed; auto tstart = std::chrono::high_resolution_clock::now(); while (markers.size() != 0) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); - elapsed = std::chrono::high_resolution_clock::now() - tstart; + auto elapsed = std::chrono::high_resolution_clock::now() - tstart; if (elapsed.count() > timeout) { break; } } - std::cout << "Marker waiting time: " << elapsed.count() << std::endl; } /** From 292292921525f314a2b3cff85873c3241595b2f7 Mon Sep 17 00:00:00 2001 From: Leon Oostrum Date: Mon, 18 Nov 2024 11:55:50 +0100 Subject: [PATCH 7/8] Style fix --- device/PowerSensor/PowerSensor.ino | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/device/PowerSensor/PowerSensor.ino b/device/PowerSensor/PowerSensor.ino index f297be83..21860a69 100644 --- a/device/PowerSensor/PowerSensor.ino +++ b/device/PowerSensor/PowerSensor.ino @@ -253,8 +253,8 @@ void serialEvent() { // 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); + while (sendMarkers > 0) delay(1); + while (!sendData) delay(1); } streamValues = false; #if !defined NODISPLAY && !defined DEMO @@ -266,8 +266,8 @@ void serialEvent() { // 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); + while (sendMarkers > 0) delay(1); + while (!sendData) delay(1); } #ifndef NODISPLAY displayPaused = false; From be4be35098085e0f2c81b88d69ba78b24a2aa30d Mon Sep 17 00:00:00 2001 From: Leon Oostrum Date: Mon, 18 Nov 2024 12:43:03 +0100 Subject: [PATCH 8/8] Remove custom marker function that does not sync with device --- host/include/PowerSensor.hpp | 1 - host/src/PowerSensor.cc | 17 ----------------- 2 files changed, 18 deletions(-) diff --git a/host/include/PowerSensor.hpp b/host/include/PowerSensor.hpp index 028bbd0b..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(); diff --git a/host/src/PowerSensor.cc b/host/src/PowerSensor.cc index 81492458..58108cdb 100644 --- a/host/src/PowerSensor.cc +++ b/host/src/PowerSensor.cc @@ -355,23 +355,6 @@ void PowerSensor::writeMarker() { } } -/** - * @brief Write custom marker to 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) - */ -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; - } -} - /** * @brief Wait for all markers to be written to the dump file *