diff --git a/README.md b/README.md index 597abff..31e6f38 100644 --- a/README.md +++ b/README.md @@ -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]. + + +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. \ No newline at end of file diff --git a/exec/download_csv.py b/exec/download_csv.py new file mode 100644 index 0000000..2d3da10 --- /dev/null +++ b/exec/download_csv.py @@ -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() \ No newline at end of file diff --git a/exec/time.py b/exec/time.py index 36b6d1e..ebc05cd 100755 --- a/exec/time.py +++ b/exec/time.py @@ -1,12 +1,23 @@ import serial import time -# Remplace par ton port Arduino -ser = serial.Serial('/dev/ttyACM0', 9600) -time.sleep(2) # attendre que l’Arduino 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}") \ No newline at end of file diff --git a/images/storage_structure.drawio b/images/storage_structure.drawio index 1eae6cf..e396293 100644 --- a/images/storage_structure.drawio +++ b/images/storage_structure.drawio @@ -1,6 +1,6 @@ - + @@ -22,7 +22,7 @@ - + @@ -217,9 +217,60 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/storage_structure.drawio.png b/images/storage_structure.drawio.png index e2f9be2..dc1783e 100644 Binary files a/images/storage_structure.drawio.png and b/images/storage_structure.drawio.png differ diff --git a/lib/debug_config.h b/lib/debug_config.h index f22d21e..e57e2e0 100644 --- a/lib/debug_config.h +++ b/lib/debug_config.h @@ -26,4 +26,4 @@ #define ASSERT(condition, msg) #endif -#endif // DEBUG_CONFIG_H \ No newline at end of file +#endif \ No newline at end of file diff --git a/lib/storage/storage_interface.cpp b/lib/storage/storage_interface.cpp index 56065ad..7c56257 100644 --- a/lib/storage/storage_interface.cpp +++ b/lib/storage/storage_interface.cpp @@ -3,7 +3,7 @@ #include #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, ×tamp_schedule); } else if (timestamp_schedule != 0) { flags = flags | 0b00100000; - EEPROM.write(offset + OFFSET_MEASURES_SCH, timestamp_schedule); + set_measure_sch(offset, ×tamp_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, ×tamp_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, ×tamp, &is_final, &photo_sensor, &temp_sensor, &schedule, &nb_photo_sensor, &nb_temp_sensor, &photo_size, &temp_size, &next_package, &nb_measures); + write_csv_header(×tamp, &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, ×tamp_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(); } \ No newline at end of file diff --git a/lib/storage/storage_interface.h b/lib/storage/storage_interface.h index eab068a..a4f6f3c 100644 --- a/lib/storage/storage_interface.h +++ b/lib/storage/storage_interface.h @@ -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); diff --git a/platformio.ini b/platformio.ini index 59c142a..f1969f5 100755 --- a/platformio.ini +++ b/platformio.ini @@ -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 diff --git a/src/main.cpp b/src/main.cpp index e264ad1..26c630b 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -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 diff --git a/test/EEPROM_test_struct.cpp b/test/EEPROM_test_struct.cpp index 3743f14..95c775b 100644 --- a/test/EEPROM_test_struct.cpp +++ b/test/EEPROM_test_struct.cpp @@ -3,7 +3,7 @@ #include "storage_interface.h" #include -// 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();