add tests, add upload arduino functions, add download python file and change many things.

This commit is contained in:
Aurélien Gauthier 2025-12-08 16:29:36 +01:00
parent 00f14bea4a
commit 573019aa8b
11 changed files with 558 additions and 86 deletions

View file

@ -17,9 +17,34 @@ To facilitate the understanding of the storage in the EEPROM see the following i
All executables files are in `exec/` folder.
### Time update
Once the arduino is connected to your desktop.
`python3 time.py `
### Collect data measures
TODO describe once done
## Tutorial
In first, you need to mount the arduino (image shown higher in the Readme).
(Optional) You can download and create the support with a 3D printer from [Link Text](https://example.com) made by [id].
<!-- ![Support]() -->
Now, you can simply download the project from this webpage.
Open VSCode with the PlatformIO extension on the project directory.
Verify that platformio has successfully opened the project.
Plug the arduino to your PC and check.
Run project tests graphically or with `pio test`.
Upload the project on the arduino.
Check [RTC update](#rtc-update).
Connect your arduino near of a windows and let him take action.
After some time you can bring back the measure from the arduino to your PC.
Collect data with [Gather](#gather-measures).
### RTC update
Before build the project, uncoment the `-D DEBUG` line in platform.ini.
Once build-upload done, check the output on the serial port.
If the date is wrong, execute the [update time](exec/time.py) file with `python3 time.py `.
The code permit a schedule change (winter or summer padding).
You can change the value in the [main file](main.cpp) or simply disable it.
### Gather measures
After a measure time.
Connect the arduino to your PC, execute the [download](exec/download_csv.py) file with `python3 download_csv.py` to create a csv from collected data.
The download action remove whole arduino memory.

84
exec/download_csv.py Normal file
View file

@ -0,0 +1,84 @@
import serial
import time
import os
ARDUINO_PORT = '/dev/ttyACM0'
BAUD_RATE = 9600
FILE_PREFIX = 'arduino_data_package'
LISTENING_TIME = 1000
START_PACKAGE_FLAG = "START_PACKAGE:"
END_PACKAGE_FLAG = "END_PACKAGE"
CLOSE_TRANSFERT_FLAG = "END_TRANSFERT"
def download_data():
try:
ser = serial.Serial(ARDUINO_PORT, BAUD_RATE)
time.sleep(2)
except serial.SerialException as e:
print(f"Error : failure to open {ARDUINO_PORT}: {e}")
return
print(f"Connected to {ARDUINO_PORT}.")
dowload_cmd = 'D\n'
ser.write(dowload_cmd.encode())
print(f"-> Cmd sent: {dowload_cmd.strip()}")
print("-> Waiting for data...")
current_file_handle = None
start_download = time.time()
while True:
if LISTENING_TIME > 0 and time.time() - start_download > LISTENING_TIME:
print("\nElapsed time, session closed.")
break
if ser.in_waiting > 0:
raw_line = ser.readline()
str_line = raw_line.decode('utf-8').strip()
if str_line.startswith(START_PACKAGE_FLAG):
if current_file_handle:
print(f"Unsignaled end file, closure of : {current_file_handle.name}")
current_file_handle.close()
try:
unique_part = str_line.split(':', 1)[1]
file_name = f"{FILE_PREFIX}_{unique_part}.csv"
except IndexError:
file_name = f"{FILE_PREFIX}_auto_{time.strftime('%Y%m%d_%H%M%S')}.csv"
print(f"\n*** New package detected, opening the new package : {file_name} ***")
current_file_handle = open(file_name, 'w')
continue
elif str_line == END_PACKAGE_FLAG:
if current_file_handle:
print(f"-> Flag '{END_PACKAGE_FLAG}' detected. File closure : {current_file_handle.name}")
current_file_handle.close()
current_file_handle = None
else:
print(f"-> Flag '{END_PACKAGE_FLAG}' Ignored.")
continue
elif str_line == CLOSE_TRANSFERT_FLAG:
print(f"\n*** Flag '{CLOSE_TRANSFERT_FLAG}' detected. End of the download. ***")
break
if current_file_handle:
current_file_handle.write(str_line + '\n')
# else:
# print(f"Ignored data : {str_line}")
if current_file_handle:
print(f"\nClosure of the opened file : {current_file_handle.name}")
current_file_handle.close()
ser.close()
print("\nConnection closed. Download done.")
if __name__ == "__main__":
download_data()

View file

@ -1,12 +1,23 @@
import serial
import time
# Remplace par ton port Arduino
ser = serial.Serial('/dev/ttyACM0', 9600)
time.sleep(2) # attendre que lArduino démarre
ARDUINO_PORT = '/dev/ttyACM0'
BAUD_RATE = 9600
epoch = int(time.time()) # secondes depuis 1970
ser.write(f"{epoch}\n".encode()) # envoie sous forme texte, terminé par \n
try:
ser = serial.Serial(ARDUINO_PORT, BAUD_RATE)
time.sleep(2)
except serial.SerialException as e:
print(f"Error : fail to open serial port {ARDUINO_PORT}: {e}")
exit()
epoch = int(time.time())
commande_rtc = f"T{epoch}\n"
ser.write(commande_rtc.encode())
ser.close()
print(f"Envoyé epoch: {epoch}")
print(f"Cmd send : {commande_rtc.strip()}")
print(f"Epoch send: {epoch}")

View file

@ -1,6 +1,6 @@
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/28.2.8 Chrome/140.0.7339.240 Electron/38.4.0 Safari/537.36" version="28.2.8">
<diagram name="Page-1" id="XH51GEJ8jh-4uo7cCshW">
<mxGraphModel dx="679" dy="459" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<mxGraphModel dx="1426" dy="964" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
@ -22,7 +22,7 @@
<mxCell id="YM7KdBzIgsha6Ef9Inx_-6" value="&lt;font style=&quot;color: rgb(51, 51, 255);&quot;&gt;0&lt;/font&gt;" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="120" y="120" width="40" height="30" as="geometry" />
</mxCell>
<mxCell id="YM7KdBzIgsha6Ef9Inx_-7" value="0" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxCell id="YM7KdBzIgsha6Ef9Inx_-7" value="1" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="160" y="80" width="80" height="20" as="geometry" />
</mxCell>
<mxCell id="YM7KdBzIgsha6Ef9Inx_-8" value="2" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
@ -217,9 +217,60 @@
<mxCell id="YM7KdBzIgsha6Ef9Inx_-125" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" parent="1" vertex="1">
<mxGeometry x="210" y="120" width="10" height="30" as="geometry" />
</mxCell>
<mxCell id="okEfVRTz3dfG7SeP_zBs-1" value="&lt;font size=&quot;1&quot;&gt;Starting data measures&lt;/font&gt;" style="rounded=0;whiteSpace=wrap;html=1;fillStyle=auto;" vertex="1" parent="1">
<mxCell id="okEfVRTz3dfG7SeP_zBs-1" value="&lt;font size=&quot;1&quot;&gt;Starting data measures&lt;/font&gt;" style="rounded=0;whiteSpace=wrap;html=1;fillStyle=auto;" parent="1" vertex="1">
<mxGeometry x="320" y="180" width="160" height="30" as="geometry" />
</mxCell>
<mxCell id="QSkjXpjbQmgyMwp4ZzM3-1" value="Header structure" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" parent="1" vertex="1">
<mxGeometry x="80" y="40" width="110" height="30" as="geometry" />
</mxCell>
<mxCell id="QSkjXpjbQmgyMwp4ZzM3-2" value="Stored measures structure" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" parent="1" vertex="1">
<mxGeometry x="80" y="340" width="150" height="30" as="geometry" />
</mxCell>
<mxCell id="QSkjXpjbQmgyMwp4ZzM3-3" value="Timestamp" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="120" y="380" width="80" height="40" as="geometry" />
</mxCell>
<mxCell id="QSkjXpjbQmgyMwp4ZzM3-4" value="0..1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" parent="1" vertex="1">
<mxGeometry x="120" y="370" width="30" height="10" as="geometry" />
</mxCell>
<mxCell id="QSkjXpjbQmgyMwp4ZzM3-5" value="" style="endArrow=classic;startArrow=classic;html=1;rounded=0;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="120" y="430" as="sourcePoint" />
<mxPoint x="200" y="430" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="QSkjXpjbQmgyMwp4ZzM3-7" value="uint_32" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" parent="1" vertex="1">
<mxGeometry x="127.5" y="440" width="60" height="10" as="geometry" />
</mxCell>
<mxCell id="QSkjXpjbQmgyMwp4ZzM3-9" value="Photo values" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="200" y="380" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="QSkjXpjbQmgyMwp4ZzM3-10" value="0..254" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" parent="1" vertex="1">
<mxGeometry x="200" y="370" width="30" height="10" as="geometry" />
</mxCell>
<mxCell id="QSkjXpjbQmgyMwp4ZzM3-11" value="" style="endArrow=classic;startArrow=classic;html=1;rounded=0;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="200" y="430" as="sourcePoint" />
<mxPoint x="320" y="430" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="QSkjXpjbQmgyMwp4ZzM3-12" value="nb_photo_sensor * photo_measure_size" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" parent="1" vertex="1">
<mxGeometry x="207.5" y="440" width="102.5" height="10" as="geometry" />
</mxCell>
<mxCell id="QSkjXpjbQmgyMwp4ZzM3-13" value="Temp values" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="320" y="380" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="QSkjXpjbQmgyMwp4ZzM3-14" value="0..254" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" parent="1" vertex="1">
<mxGeometry x="320" y="370" width="30" height="10" as="geometry" />
</mxCell>
<mxCell id="QSkjXpjbQmgyMwp4ZzM3-15" value="" style="endArrow=classic;startArrow=classic;html=1;rounded=0;" parent="1" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="320" y="430" as="sourcePoint" />
<mxPoint x="440" y="430" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="QSkjXpjbQmgyMwp4ZzM3-16" value="nb_temp_sensor * temp_measure_size" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" parent="1" vertex="1">
<mxGeometry x="327.5" y="440" width="102.5" height="10" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 224 KiB

View file

@ -26,4 +26,4 @@
#define ASSERT(condition, msg)
#endif
#endif // DEBUG_CONFIG_H
#endif

View file

@ -3,7 +3,7 @@
#include <EEPROM.h>
#include "debug_config.h"
/**** Inline macros ****/
// Manual implements of EEPROM.put() for few uint type
uint16_t inline read_eeprom_uint16(uint8_t idx){
@ -49,6 +49,73 @@ void inline write_eeprom_uint32(uint8_t idx, uint32_t value) {
EEPROM.write(idx + 3, (uint8_t)(value & 0xFF));
}
/**** header get set macros ****/
void inline Storage_interface::get_measure_sch(uint16_t header_idx, uint8_t *schedule){
EEPROM.get(header_idx + OFFSET_MEASURES_SCH, *schedule);
}
void inline Storage_interface::set_measure_sch(uint16_t header_idx, uint8_t *schedule){
EEPROM.put(header_idx + OFFSET_MEASURES_SCH, *schedule);
}
void inline Storage_interface::get_nb_photo_sensor(uint16_t header_idx, uint8_t *nb_photo_sensor){
EEPROM.get(header_idx + OFFSET_NB_PHOTO_SENSOR, *nb_photo_sensor);
}
void inline Storage_interface::set_nb_photo_sensor(uint16_t header_idx, uint8_t *nb_photo_sensor){
EEPROM.put(header_idx + OFFSET_NB_PHOTO_SENSOR, *nb_photo_sensor);
}
void inline Storage_interface::get_nb_temp_sensor(uint16_t header_idx, uint8_t *nb_temp_sensor){
EEPROM.get(header_idx + OFFSET_NB_TEMP_SENSOR, *nb_temp_sensor);
}
void inline Storage_interface::set_nb_temp_sensor(uint16_t header_idx, uint8_t *nb_temp_sensor){
EEPROM.put(header_idx + OFFSET_NB_TEMP_SENSOR, *nb_temp_sensor);
}
void inline Storage_interface::get_photo_meas_size(uint16_t header_idx, uint8_t *photo_meas_size){
EEPROM.get(header_idx + OFFSET_PHOTO_MEASURES_SIZE, *photo_meas_size);
}
void inline Storage_interface::set_photo_meas_size(uint16_t header_idx, uint8_t *photo_meas_size){
EEPROM.put(header_idx + OFFSET_PHOTO_MEASURES_SIZE, *photo_meas_size);
}
void inline Storage_interface::get_temp_meas_size(uint16_t header_idx, uint8_t *temp_meas_size){
EEPROM.get(header_idx + OFFSET_TEMP_MEASURES_SIZE, *temp_meas_size);
}
void inline Storage_interface::set_temp_meas_size(uint16_t header_idx, uint8_t *temp_meas_size){
EEPROM.put(header_idx + OFFSET_TEMP_MEASURES_SIZE, *temp_meas_size);
}
void inline Storage_interface::get_nb_measures(uint16_t header_idx, uint16_t *nb_measures){
EEPROM.get(header_idx + OFFSET_NB_MEASURES, *nb_measures);
}
void inline Storage_interface::set_nb_measures(uint16_t header_idx, uint16_t *nb_measures){
EEPROM.put(header_idx + OFFSET_NB_MEASURES, *nb_measures);
}
void inline Storage_interface::get_next_package(uint16_t header_idx, uint16_t *next_package){
EEPROM.get(header_idx + OFFSET_NEXT_PACKAGE, *next_package);
}
void inline Storage_interface::set_next_package(uint16_t header_idx, uint16_t *next_package){
EEPROM.put(header_idx + OFFSET_NEXT_PACKAGE, *next_package);
}
// void inline Storage_interface::get_start_data_measure(uint16_t header_idx, uint16_t *start_data_measure){
// EEPROM.get(header_idx + OFFSET_START_DATA_MEASURES, *start_data_measure);
// }
// void inline Storage_interface::set_start_data_measure(uint16_t header_idx, uint16_t *start_data_measure){
// EEPROM.put(header_idx + OFFSET_START_DATA_MEASURES, *start_data_measure);
// }
Storage_interface::Storage_interface(){}
Storage_interface::~Storage_interface(){}
@ -81,19 +148,41 @@ uint16_t Storage_interface::get_last_header_nbpackage(uint16_t* last_header_idx)
while ((flags & 0b1) != 0){
nb_package++;
*last_header_idx = start_package;
start_package = read_eeprom_uint16(start_package + OFFSET_NEXT_PACKAGE);
get_next_package(start_package, &start_package);
flags = EEPROM.read(start_package);
nb_package++;
}
return nb_package;
}
// factorise reused code implementation and keep level acces
// factorise reused code implementation and keep level access
uint16_t Storage_interface::get_nb_package(){
uint16_t pointer;
return get_last_header_nbpackage(&pointer);
}
/**
* @brief get_idx_package
* * Get the EEPROM index of the targeted package
*
* * @param package_number @c uint16_t
* @return @c uint16_t idx_package_header
*/
uint16_t Storage_interface::get_idx_package(uint16_t package_number){
uint8_t flags;
uint16_t start_package = 0, nb_package = 0;
uint16_t last_header_idx = 0;
flags = EEPROM.read(start_package);
while (((flags & 0b1) != 0) && nb_package < package_number){
last_header_idx = start_package;
get_next_package(start_package, &start_package);
flags = EEPROM.read(start_package);
nb_package++;
}
return last_header_idx;
}
void Storage_interface::get_struct(uint16_t offset, bool* timestamp, bool* is_final_set, bool* photo_sensor, bool* temp_sensor, uint8_t* timestamp_schedule, uint8_t* nb_photo_sensor, uint8_t* nb_temp_sensor, uint8_t* photo_size, uint8_t* temp_size, uint16_t* p_next_package, uint16_t* nb_measures){
uint8_t flags;
@ -114,37 +203,38 @@ void Storage_interface::get_struct(uint16_t offset, bool* timestamp, bool* is_fi
*timestamp = false;
if ((flags & 0b00100000) != 0 ){
*timestamp = true;
*timestamp_schedule = EEPROM.read(offset + OFFSET_MEASURES_SCH);
get_measure_sch(offset, timestamp_schedule);
}
*timestamp_schedule = 0;
if (flags & 0b01000000){
*timestamp = true;
WARN_IF(EEPROM.read(offset + OFFSET_MEASURES_SCH) != 0, "Incoherent timestamp parameter in the header.")
get_measure_sch(offset, timestamp_schedule);
WARN_IF(*timestamp_schedule != 0, "Incoherent timestamp parameter in the header.")
}
// photo res reads
*photo_sensor = false;
if (flags & 0b00010000){
*photo_sensor = true;
*nb_photo_sensor = EEPROM.read(offset + OFFSET_NB_PHOTO_SENSOR);
get_nb_photo_sensor(offset, nb_photo_sensor);
}
// temp res reads
*temp_sensor = false;
if (flags & 0b00001000){
*temp_sensor = true;
*nb_temp_sensor = EEPROM.read(offset + OFFSET_NB_TEMP_SENSOR);
get_nb_temp_sensor(offset, nb_temp_sensor);
}
// gather the index of the next package in the EEPROM
*p_next_package = read_eeprom_uint16(offset + OFFSET_NEXT_PACKAGE);
get_next_package(offset, p_next_package);
// gather the number of measures
*nb_measures = read_eeprom_uint16(offset + OFFSET_NB_MEASURES);
get_nb_measures(offset, nb_measures);
// read type size of photo temperature measures
*photo_size = EEPROM.read(offset + OFFSET_PHOTO_MEASURES_SIZE);
*temp_size = EEPROM.read(offset + OFFSET_TEMP_MEASURES_SIZE);
get_photo_meas_size(offset, photo_size);
get_temp_meas_size(offset, temp_size);
}
void Storage_interface::set_struct(uint16_t offset, bool timestamp, bool is_final_set, bool photo_sensor, bool temp_sensor, uint8_t timestamp_schedule, uint8_t nb_photo_sensor, uint8_t nb_temp_sensor, uint8_t photo_size, uint8_t temp_size){
@ -161,31 +251,35 @@ void Storage_interface::set_struct(uint16_t offset, bool timestamp, bool is_fina
if (timestamp && (timestamp_schedule == 0)) {
flags = flags | 0b01000000;
EEPROM.write(offset + OFFSET_MEASURES_SCH, 0); // Écrire 0 si pas de schedule
timestamp_schedule = 0;
set_measure_sch(offset, &timestamp_schedule);
} else if (timestamp_schedule != 0) {
flags = flags | 0b00100000;
EEPROM.write(offset + OFFSET_MEASURES_SCH, timestamp_schedule);
set_measure_sch(offset, &timestamp_schedule);
WARN_IF(!timestamp, "Redundant/conflicting timestamp parameter (expected true for schedule).")
} else {
EEPROM.write(offset + OFFSET_MEASURES_SCH, 0);
timestamp_schedule = 0;
set_measure_sch(offset, &timestamp_schedule);
}
// Sensor part
if (photo_sensor){
flags = flags | 0b00010000;
EEPROM.write(offset + OFFSET_NB_PHOTO_SENSOR, nb_photo_sensor);
set_nb_photo_sensor(offset, &nb_photo_sensor);
}else{
EEPROM.write(offset + OFFSET_NB_PHOTO_SENSOR, 0);
nb_photo_sensor = 0;
set_nb_photo_sensor(offset, &nb_photo_sensor);
WARN_IF(nb_photo_sensor != 0, "Bad photo sensor parameter for header writer.")
}
if (temp_sensor){
flags = flags | 0b00001000;
EEPROM.write(offset + OFFSET_NB_TEMP_SENSOR, nb_temp_sensor);
set_nb_temp_sensor(offset, &nb_temp_sensor);
}else{
EEPROM.write(offset + OFFSET_NB_TEMP_SENSOR, 0);
nb_temp_sensor = 0;
set_nb_temp_sensor(offset, &nb_temp_sensor);
WARN_IF(nb_temp_sensor != 0, "Bad temperature sensor parameter for header writer.")
}
@ -194,18 +288,21 @@ void Storage_interface::set_struct(uint16_t offset, bool timestamp, bool is_fina
flags = flags | 0b00000100;
}
// uint16_t next package pointer set at 0
write_eeprom_uint16(offset + OFFSET_NEXT_PACKAGE, offset + OFFSET_START_DATA_MEASURES);
// uint16_t next package pointer to free space
uint16_t p_next_package = offset + OFFSET_START_DATA_MEASURES;
set_next_package(offset, &p_next_package);
// set number of measures to 0
write_eeprom_uint16(offset + OFFSET_NB_MEASURES, 0);
uint16_t nb_measures = 0;
set_nb_measures(offset, &nb_measures);
// write flags header
EEPROM.write(offset , flags);
// write types measures size
EEPROM.write(offset + OFFSET_PHOTO_MEASURES_SIZE, photo_size);
EEPROM.write(offset + OFFSET_TEMP_MEASURES_SIZE, temp_size);
// write types measures size
set_photo_meas_size(offset, &photo_size);
set_temp_meas_size(offset, &temp_size);
}
void Storage_interface::add_last_package(bool timestamp, bool is_final_set, bool photo_sensor, bool temp_sensor, uint8_t timestamp_schedule, uint8_t nb_photo_sensor, uint8_t nb_temp_sensor, uint8_t photo_size, uint8_t temp_size, uint16_t nb_measures){
@ -219,27 +316,31 @@ void Storage_interface::add_last_package(bool timestamp, bool is_final_set, bool
flags = flags & 0b11111011;
EEPROM.write(p_last_header , flags);
free_space = EEPROM.read(p_last_header + OFFSET_NEXT_PACKAGE);
get_next_package(p_last_header, &free_space);
set_struct(free_space, timestamp, is_final_set, photo_sensor, temp_sensor, timestamp_schedule, nb_photo_sensor, nb_temp_sensor, photo_size, temp_size);
}
// Dont check if the stored measure structure match with the header
// the function ont check if the stored measure structure match with the header
void Storage_interface::add_measure(uint8_t* array_photo_val, uint8_t* array_temp_val, uint32_t timestamp, uint8_t nb_photo, uint8_t nb_temp){
uint16_t p_last_header, free_space, idx;
uint16_t p_last_header, free_space, idx, next_free_space, nb_measure;
get_last_header_nbpackage(&p_last_header);
free_space = EEPROM.read(p_last_header + OFFSET_NEXT_PACKAGE);
EEPROM.write(p_last_header + OFFSET_NB_MEASURES, EEPROM.read(p_last_header + OFFSET_NB_MEASURES) + 1);
get_next_package(p_last_header, &free_space);
get_nb_measures(p_last_header, &nb_measure);
nb_measure++;
set_nb_measures(p_last_header, &nb_measure);
EEPROM.put(free_space, timestamp);
idx = p_last_header + sizeof(uint32_t);
idx = free_space + sizeof(uint32_t);
for(int i = 0; i < nb_photo; i++, idx += sizeof(uint8_t)){
EEPROM.put(idx, array_photo_val[i]);
}
for(int i = 0; i < nb_temp; i++, idx += sizeof(uint8_t)){
EEPROM.put(idx, array_temp_val[i]);
}
next_free_space = free_space + sizeof(uint32_t) + sizeof(uint8_t) * (nb_photo + nb_temp);
set_next_package(p_last_header, &next_free_space);
}
void Storage_interface::get_measure(uint8_t* array_photo_val, uint8_t* array_temp_val, uint32_t* timestamp, uint8_t* nb_photo, uint8_t* nb_temp, uint16_t idx_measure){
@ -249,8 +350,8 @@ void Storage_interface::get_measure(uint8_t* array_photo_val, uint8_t* array_tem
get_last_header_nbpackage(&p_last_header);
idx = p_last_header + OFFSET_START_DATA_MEASURES;
*nb_photo = EEPROM.read(p_last_header + OFFSET_NB_PHOTO_SENSOR);
*nb_temp = EEPROM.read(p_last_header + OFFSET_NB_TEMP_SENSOR);
get_nb_photo_sensor(p_last_header, nb_photo);
get_nb_temp_sensor(p_last_header, nb_temp);
flags = EEPROM.read(p_last_header);
if((flags & 0b01000000) != 0){
@ -258,7 +359,7 @@ void Storage_interface::get_measure(uint8_t* array_photo_val, uint8_t* array_tem
idx += sizeof(uint32_t) * idx_measure;
}else if ((flags & 0b00100000) != 0){
uint8_t schedule;
schedule = EEPROM.read(p_last_header + OFFSET_MEASURES_SCH);
get_measure_sch(p_last_header, &schedule);
WARN_IF(schedule == 0, "Struct error for timestamp scheduling.")
if(idx_measure % schedule != 0)
@ -274,4 +375,116 @@ void Storage_interface::get_measure(uint8_t* array_photo_val, uint8_t* array_tem
for(int i = 0; i < *nb_temp; i++, idx += sizeof(uint8_t)){
array_temp_val[i] = EEPROM.read(idx);
}
}
void Storage_interface::get_measure_at(uint8_t* array_photo_val, uint8_t* array_temp_val, uint32_t* timestamp, uint8_t* nb_photo, uint8_t* nb_temp, uint16_t package_number, uint16_t measure_number){
uint16_t p_header, idx;
uint8_t flags;
p_header = get_idx_package(package_number);
idx = p_header + OFFSET_START_DATA_MEASURES;
get_nb_photo_sensor(p_header, nb_photo);
get_nb_temp_sensor(p_header, nb_temp);
flags = EEPROM.read(p_header);
if((flags & 0b01000000) != 0){
EEPROM.get(p_header + OFFSET_START_DATA_MEASURES, timestamp);
idx += sizeof(uint32_t) * measure_number;
}else if ((flags & 0b00100000) != 0){
uint8_t schedule;
get_measure_sch(p_header, &schedule);
WARN_IF(schedule == 0, "Struct error for timestamp scheduling.")
if(measure_number % schedule != 0)
idx += sizeof(uint32_t);
idx += sizeof(uint32_t) * (measure_number / schedule);
}
idx += ((*nb_photo) + (*nb_temp)) * measure_number * sizeof(uint8_t);
for(int i = 0; i < *nb_photo; i++, idx += sizeof(uint8_t)){
array_photo_val[i] = EEPROM.read(idx);
}
for(int i = 0; i < *nb_temp; i++, idx += sizeof(uint8_t)){
array_temp_val[i] = EEPROM.read(idx);
}
}
void Storage_interface::write_csv_header(bool* timestamp, bool* photo_sensor, bool* temp_sensor, uint8_t* nb_photo_sensor, uint8_t* nb_temp_sensor){
String header_csv = "";
if(*timestamp){
header_csv += String("Epoch,");
}
if(*photo_sensor){
for(int8_t i; i < *nb_photo_sensor; i++){
header_csv += String("Photo_sensor") + String(i) + String(",");
}
}
if(*temp_sensor){
for(int8_t i; i < *nb_photo_sensor; i++){
header_csv += String("Temp_sensor") + String(i) + String(",");
}
}
if (header_csv.length() > 0) {
header_csv.remove(header_csv.length() - 1);
}
Serial.println(header_csv);
}
/**
* @brief upload_csv
* *
* Upload all stored package, one file per package
* @attention After the transfert, the entire EEPROM mem will be cleared.
*/
void Storage_interface::upload_csv(){
const String close_transfert = "END_TRANSFERT", end_package = "END_PACKAGE", start_package = "START_PACKAGE";
uint16_t nb_package = get_nb_package(), package_number = 0;
WARN_IF(nb_package == 0, "Warning : upload csv function call but no data stored in memory.")
while(package_number < nb_package){
Serial.println(start_package);
uint16_t next_package, nb_measures;
uint8_t schedule, nb_photo_sensor, nb_temp_sensor, photo_size, temp_size;
bool timestamp, is_final, photo_sensor, temp_sensor;
get_struct(package_number, &timestamp, &is_final, &photo_sensor, &temp_sensor, &schedule, &nb_photo_sensor, &nb_temp_sensor, &photo_size, &temp_size, &next_package, &nb_measures);
write_csv_header(&timestamp, &photo_sensor, &temp_sensor, &nb_photo_sensor, &nb_temp_sensor);
uint8_t photo_array[nb_photo_sensor], temp_array[nb_temp_sensor];
uint32_t timestamp_val;
String line;
for(uint16_t measure_number = 0; measure_number < nb_measures; measure_number++){
get_measure_at(photo_array, temp_array, &timestamp_val, &nb_photo_sensor, &nb_temp_sensor, package_number, measure_number);
line = String("");
if(timestamp){
line += String(timestamp_val);
}
if(photo_sensor){
for(int8_t i; i < nb_photo_sensor; i++){
line += String(photo_array[i]) + String(",");
}
}
if(temp_sensor){
for(int8_t i; i < nb_temp_sensor; i++){
line += String(temp_array[i]) + String(",");
}
}
if (line.length() > 0) {
line.remove(line.length() - 1);
}
Serial.println(line);
delay(100);
}
Serial.println(end_package);
package_number++;
}
Serial.println(close_transfert);
// TODO uncomment after upload csv done and must conform to the tests
// clear_eeprom();
}

View file

@ -14,7 +14,32 @@ private:
void clear_eeprom_at(uint16_t idx);
// Getter setter EEPROM header functions
void inline get_measure_sch(uint16_t header_idx, uint8_t *schedule);
void inline set_measure_sch(uint16_t header_idx, uint8_t *schedule);
void inline get_nb_photo_sensor(uint16_t header_idx, uint8_t *nb_photo_sensor);
void inline set_nb_photo_sensor(uint16_t header_idx, uint8_t *nb_photo_sensor);
void inline get_nb_temp_sensor(uint16_t header_idx, uint8_t *nb_temp_sensor);
void inline set_nb_temp_sensor(uint16_t header_idx, uint8_t *nb_temp_sensor);
void inline get_photo_meas_size(uint16_t header_idx, uint8_t *photo_meas_size);
void inline set_photo_meas_size(uint16_t header_idx, uint8_t *photo_meas_size);
void inline get_temp_meas_size(uint16_t header_idx, uint8_t *temp_meas_siz);
void inline set_temp_meas_size(uint16_t header_idx, uint8_t *temp_meas_size);
void inline get_nb_measures(uint16_t header_idx, uint16_t *nb_measures);
void inline set_nb_measures(uint16_t header_idx, uint16_t *nb_measures);
void inline get_next_package(uint16_t header_idx, uint16_t *next_package);
void inline set_next_package(uint16_t header_idx, uint16_t *next_package);
// Following commented function are uncessary for now
// void inline get_start_data_measure(uint16_t header_idx, uint16_t *start_data_measure);
// void inline set_start_data_measure(uint16_t header_idx, uint16_t *start_data_measure);
uint16_t get_last_header_nbpackage(uint16_t* last_header_idx);
uint16_t get_idx_package(uint16_t package_number);
void write_csv_header(bool* timestamp, bool* photo_sensor, bool* temp_sensor, uint8_t* nb_photo_sensor, uint8_t* nb_temp_sensor);
void get_measure(uint8_t* array_photo_val, uint8_t* array_temp_val, uint32_t* timestamp, uint8_t* nb_photo, uint8_t* nb_temp, uint16_t idx_measure);
public:
@ -25,15 +50,16 @@ public:
void clear_eeprom();
void add_last_package(bool timestamp, bool is_final_set, bool photo_sensor, bool temp_sensor, uint8_t timestamp_schedule, uint8_t nb_photo_sensor, uint8_t nb_temp_sensor, uint8_t photo_size, uint8_t temp_size, uint16_t nb_measures);
void add_measure(uint8_t* photo_values, uint8_t* temp_values, uint32_t timestamp, uint8_t nb_photo, uint8_t nb_temp);
void get_measure(uint8_t* photo_values, uint8_t* temp_values, uint32_t* timestamp, uint8_t* nb_photo, uint8_t* nb_temp, uint16_t idx_measure);
void get_measure_at(uint8_t* array_photo_val, uint8_t* array_temp_val, uint32_t* timestamp, uint8_t* nb_photo, uint8_t* nb_temp, uint16_t idx_package, uint16_t idx_measure);
void get_struct(uint16_t offset, bool* timestamp, bool* is_final_set, bool* photo_sensor, bool* temp_sensor, uint8_t* timestamp_schedule, uint8_t* nb_photo_sensor, uint8_t* nb_temp_sensor, uint8_t* photo_size, uint8_t* temp_size, uint16_t* p_next_package, uint16_t* nb_measures);
void set_struct(uint16_t offset, bool timestamp, bool is_final_set, bool photo_sensor, bool temp_sensor, uint8_t timestamp_schedule, uint8_t nb_photo_sensor, uint8_t nb_temp_sensor, uint8_t photo_size, uint8_t temp_size);
void upload_csv();
// Dont check if the stored measure structure match with the header
// The function dont check if the stored measure structure match with the header
template< typename T, typename TT>
void add_measure(T* photo_values, TT* temp_values, uint32_t timestamp, uint8_t nb_photo, uint8_t nb_temp){
void put_measure(T* photo_values, TT* temp_values, uint32_t timestamp, uint8_t nb_photo, uint8_t nb_temp){
uint16_t p_last_header, free_space, idx;
get_last_header_nbpackage(&p_last_header);

View file

@ -17,6 +17,7 @@ test_framework = unity
build_flags =
-std=gnu++17
-I lib/
;-D DEBUG
lib_deps =
northernwidget/DS3231@^1.1.2
arduino-libraries/Ethernet

View file

@ -8,6 +8,8 @@
#include "traitement.h"
#include "storage_interface.h"
const long BAUD_RATE = 9600;
int ledPin = 2, decTemp = 4; // nb decimal temperature printing
const int nbPhotoSensor = 6;
uint8_t analogPin [nbPhotoSensor] = {A0, A1, A2 ,A3 ,A5 ,A6};
@ -18,13 +20,14 @@ bool winter = 1;
SensorOhm test[nbPhotoSensor];
SensorManager s_manager;
Traitement tr;
Storage_interface sto_intrf;
RTClib myRTC;
DS3231 Clock;
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.begin(BAUD_RATE);
s_manager.setup(nbPhotoSensor, analogPin);
}
@ -32,45 +35,53 @@ void loop() {
DateTime now;
if (Serial.available()) {
unsigned long epoch = Serial.parseInt(); // read epoch
if (epoch > 1000000000UL) { // sanity check
// summer or winter time
if (winter == 1) {
epoch += 3600;
}
Clock.setEpoch(epoch);
char commande = Serial.read();
if (commande == 'T') {
unsigned long epoch = Serial.parseInt(); // read epoch
if (epoch > 1000000000UL) { // sanity check
// summer or winter time
if (winter == 1) {
epoch += 3600;
}
Clock.setEpoch(epoch);
#ifdef DEBUG
Serial.print("RTC mis à jour avec epoch: ");
Serial.println(epoch);
Serial.print("RTC mis à jour avec epoch: ");
Serial.println(epoch);
#endif
}
while (Serial.available()) Serial.read(); // clean buffer
}
while (Serial.available()) Serial.read(); // clean buffer
#ifdef DEBUG
// Just for verification of DS3231 Data
// check now the data from ESP8266 and DS3231
// get year
bool century = false;
bool h12Flag;
bool pmFlag;
now = myRTC.now();
Serial.print("\n\n");
Serial.print(" DateTime of DS3231: ");
Serial.print(Clock.getYear(), DEC);
Serial.print("-");
Serial.print(Clock.getMonth(century), DEC);
Serial.print("-");
Serial.print(Clock.getDate(), DEC);
Serial.print(" ");
Serial.print(Clock.getHour(h12Flag, pmFlag), DEC);
Serial.print(":");
Serial.print(Clock.getMinute(), DEC);
Serial.print(":");
Serial.print(Clock.getSecond(), DEC);
Serial.print(" - weekday ");
Serial.print(Clock.getDoW(), DEC);
Serial.println();
// Just for verification of DS3231 Data
// check now the data from ESP8266 and DS3231
// get year
bool century = false;
bool h12Flag;
bool pmFlag;
now = myRTC.now();
Serial.print("\n\n");
Serial.print(" DateTime of DS3231: ");
Serial.print(Clock.getYear(), DEC);
Serial.print("-");
Serial.print(Clock.getMonth(century), DEC);
Serial.print("-");
Serial.print(Clock.getDate(), DEC);
Serial.print(" ");
Serial.print(Clock.getHour(h12Flag, pmFlag), DEC);
Serial.print(":");
Serial.print(Clock.getMinute(), DEC);
Serial.print(":");
Serial.print(Clock.getSecond(), DEC);
Serial.print(" - weekday ");
Serial.print(Clock.getDoW(), DEC);
Serial.println();
#endif
}else if (commande == 'D'){
sto_intrf.upload_csv();
}
while (Serial.available()) Serial.read(); // clean buffer
delay(10);
}
#ifdef DEBUG

View file

@ -3,7 +3,7 @@
#include "storage_interface.h"
#include <EEPROM.h>
// uint32_t epoch = 1764249314;
uint32_t epoch = 1764249314;
// WARNING : copy from storage interface (if somes changes are apply on storageinterface's OFFSET_ apply it here too)
static constexpr uint8_t OFFSET_MEASURES_SCH = 1, OFFSET_NB_PHOTO_SENSOR = 2, OFFSET_NB_TEMP_SENSOR = 3, OFFSET_PHOTO_MEASURES_SIZE = 4, OFFSET_TEMP_MEASURES_SIZE = 5, OFFSET_NB_MEASURES = 6, OFFSET_NEXT_PACKAGE = 8, OFFSET_START_DATA_MEASURES = 10; // unit in byte
@ -144,6 +144,55 @@ void test_get_struct(){
TEST_ASSERT(r_sizeof_photo == sizeofuint8);
}
void test_add_measure(){
// test if every values is normaly store
Storage_interface test;
uint16_t offset = 0, reading_head;
uint8_t schedule = 0, nb_photo_sensor = 2, nb_temp_sensor = 1, sizeofuint8 = sizeof(uint8_t);
// Useless folowing EEPROM.GET, here only for avoid wrong flags of unused variable of reading_head
EEPROM.get(offset, reading_head);
bool timestamp = true, is_final = true, photo_sensor = true, temp_sensor = true;
test.set_struct(offset, timestamp, is_final, photo_sensor, temp_sensor, schedule, nb_photo_sensor, nb_temp_sensor, sizeofuint8, sizeofuint8);
uint8_t photo_val_array[nb_photo_sensor], temp_val_array[nb_temp_sensor];
for (int i = 0; i < nb_photo_sensor; i++){
photo_val_array[i] = i;
}
for (int i = 0; i < nb_temp_sensor; i++){
temp_val_array[i] = i;
}
test.add_measure(photo_val_array, temp_val_array, epoch, nb_photo_sensor, nb_temp_sensor);
uint32_t horo;
EEPROM.get(offset + OFFSET_START_DATA_MEASURES, horo);
TEST_ASSERT(horo == epoch);
for (int i = 0, reading_head = offset + OFFSET_START_DATA_MEASURES + sizeof(uint32_t); i < nb_photo_sensor; i++, reading_head += sizeofuint8){
TEST_ASSERT(EEPROM.read(reading_head) == photo_val_array[i]);
}
for (int i = 0, reading_head = offset + OFFSET_START_DATA_MEASURES + sizeof(uint32_t) + sizeofuint8 * nb_photo_sensor; i < nb_temp_sensor; i++, reading_head += sizeofuint8){
TEST_ASSERT(EEPROM.read(reading_head) == temp_val_array[i]);
}
}
void test_put_measure(){
// test if the template type work right
// test if values
}
void test_get_measure(){
//
}
void test_gather_package(){
}
void setup(void)
{
Serial.begin(9600);
@ -152,6 +201,7 @@ void setup(void)
//WARNING: Tests are not exhaustive and do not cover all possibilities.
int main( int argc, char **argv) {
UNITY_BEGIN();
RUN_TEST(test_add_measure);
RUN_TEST(test_get_struct);
RUN_TEST(test_set_struct);
UNITY_END();