diff --git a/.gitignore b/.gitignore index 791c6c9..cd45f94 100644 --- a/.gitignore +++ b/.gitignore @@ -2,11 +2,6 @@ *.o *.pyc -# gtags -GTAGS -GRTAGS -GPATH - # emacs .dir-locals.el @@ -21,47 +16,8 @@ GPATH # MacOS directory files .DS_Store -# Example project files -examples/**/sdkconfig -examples/**/sdkconfig.old -examples/**/build - # Doc build artifacts -docs/_build/ -docs/doxygen_sqlite3.db - -# Downloaded font files -docs/_static/DejaVuSans.ttf -docs/_static/NotoSansSC-Regular.otf - -# Unit test app files -tools/unit-test-app/sdkconfig -tools/unit-test-app/sdkconfig.old -tools/unit-test-app/build -tools/unit-test-app/builds -tools/unit-test-app/output -tools/unit-test-app/test_configs - -# Unit Test CMake compile log folder -log_ut_cmake - -# test application build files -tools/test_apps/**/build -tools/test_apps/**/sdkconfig -tools/test_apps/**/sdkconfig.old - -# IDF monitor test -tools/test_idf_monitor/outputs - -TEST_LOGS - -# gcov coverage reports -*.gcda -*.gcno -coverage.info -coverage_report/ - -test_multi_heap_host +docs # VS Code Settings .vscode/ @@ -84,6 +40,5 @@ build # lock files for examples and components dependencies.lock -build/ sdkconfig sdkconfig.old \ No newline at end of file diff --git a/main/ena-bluetooth-advertise.c b/main/ena-bluetooth-advertise.c index d7a0f17..eb06797 100644 --- a/main/ena-bluetooth-advertise.c +++ b/main/ena-bluetooth-advertise.c @@ -1,3 +1,16 @@ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #include "esp_log.h" #include "esp_bt.h" diff --git a/main/ena-bluetooth-advertise.h b/main/ena-bluetooth-advertise.h index 4fd978c..1bb29f0 100644 --- a/main/ena-bluetooth-advertise.h +++ b/main/ena-bluetooth-advertise.h @@ -1,15 +1,18 @@ -/** - * provide bluetooth part of Exposure Notification API v1.2 as defined by Apple/Google - * - * Source documents: - * - * https://blog.google/documents/70/Exposure_Notification_-_Bluetooth_Specification_v1.2.2.pdf - * - * https://covid19-static.cdn-apple.com/applications/covid19/current/static/detection-tracing/pdf/ExposureNotification-BluetoothSpecificationv1.2.pdf - * - * - * - */ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + #ifndef _ena_BLUETOOTH_ADVERTISE_H_ #define _ena_BLUETOOTH_ADVERTISE_H_ @@ -17,12 +20,32 @@ #include "esp_gap_ble_api.h" #define ENA_ADVERTISE_LOG "ESP-ENA-advertise" // TAG for Logging -#define ENA_BLUETOOTH_TAG_DATA (0x1A) +#define ENA_BLUETOOTH_TAG_DATA (0x1A) // Data for BLE payload TAG +/** + * @brief Start BLE advertising + */ void ena_bluetooth_advertise_start(void); +/** + * @brief Set payload for BLE advertising + * + * This will set the payload for based on given ENIN and TEK. + * + * Source documents (Section: Advertising Payload) + * + * https://blog.google/documents/70/Exposure_Notification_-_Bluetooth_Specification_v1.2.2.pdf + * + * https://covid19-static.cdn-apple.com/applications/covid19/current/static/detection-tracing/pdf/ExposureNotification-BluetoothSpecificationv1.2.pdf + * + * @param[in] enin ENIN defining the start of the tek vadility. This should be the ENIN for the current timestamp + * @param[in] tek pointer to the TEK used to encrypt the payload. + */ void ena_bluetooth_advertise_set_payload(uint32_t enin, uint8_t *tek); +/** + * @brief Stop BLE advertising + */ void ena_bluetooth_advertise_stop(void); #endif \ No newline at end of file diff --git a/main/ena-bluetooth-scan.c b/main/ena-bluetooth-scan.c index 761ac02..0b0c13b 100644 --- a/main/ena-bluetooth-scan.c +++ b/main/ena-bluetooth-scan.c @@ -1,8 +1,22 @@ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #include #include #include "esp_log.h" +#include "ena-crypto.h" #include "ena-detection.h" #include "ena-bluetooth-scan.h" diff --git a/main/ena-bluetooth-scan.h b/main/ena-bluetooth-scan.h index 56901aa..06a3953 100644 --- a/main/ena-bluetooth-scan.h +++ b/main/ena-bluetooth-scan.h @@ -1,15 +1,16 @@ -/** - * provide bluetooth scanning part of Exposure Notification API v1.2 as defined by Apple/Google - * - * Source documents: - * - * https://blog.google/documents/70/Exposure_Notification_-_Bluetooth_Specification_v1.2.2.pdf - * - * https://covid19-static.cdn-apple.com/applications/covid19/current/static/detection-tracing/pdf/ExposureNotification-BluetoothSpecificationv1.2.pdf - * - * - * - */ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #ifndef _ena_BLUETOOTH_SCAN_H_ #define _ena_BLUETOOTH_SCAN_H_ @@ -21,19 +22,46 @@ #include "esp_gap_ble_api.h" +/** + * @brief status of BLE scan + */ typedef enum { - ENA_SCAN_STATUS_SCANNING = 0, - ENA_SCAN_STATUS_NOT_SCANNING, - ENA_SCAN_STATUS_WAITING, + ENA_SCAN_STATUS_SCANNING = 0, // scan is running + ENA_SCAN_STATUS_NOT_SCANNING, // scan is not running + ENA_SCAN_STATUS_WAITING, // scan is not running but stopped manually } ena_bluetooth_scan_status; +/** + * @brief initialize the BLE scanning + * + */ void ena_bluetooth_scan_init(void); +/** + * @brief start BLE scanning for a given duration + * + * Source documents (Section: Scanning Behavior) + * + * https://blog.google/documents/70/Exposure_Notification_-_Bluetooth_Specification_v1.2.2.pdf + * + * https://covid19-static.cdn-apple.com/applications/covid19/current/static/detection-tracing/pdf/ExposureNotification-BluetoothSpecificationv1.2.pdf + * + * @param[in] duration duration of the scan in seconds + */ void ena_bluetooth_scan_start(uint32_t duration); +/** + * @brief stop a running BLE scanning + */ void ena_bluetooth_scan_stop(void); +/** + * @brief return the current scanning status + * + * @return + * current scan status + */ int ena_bluetooth_scan_get_status(void); #endif \ No newline at end of file diff --git a/main/ena-crypto.c b/main/ena-crypto.c index f7db6f2..0b02ee0 100644 --- a/main/ena-crypto.c +++ b/main/ena-crypto.c @@ -1,4 +1,16 @@ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #include "mbedtls/md.h" #include "mbedtls/aes.h" #include "mbedtls/hkdf.h" diff --git a/main/ena-crypto.h b/main/ena-crypto.h index 067ffcb..0a9dab2 100644 --- a/main/ena-crypto.h +++ b/main/ena-crypto.h @@ -1,16 +1,16 @@ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at -/** - * provide cryptographic part of Exposure Notification API v1.2 as defined by Apple/Google - * - * Source documents: - * - * https://blog.google/documents/69/Exposure_Notification_-_Cryptography_Specification_v1.2.1.pdf - * - * https://covid19-static.cdn-apple.com/applications/covid19/current/static/detection-tracing/pdf/ExposureNotification-CryptographySpecificationv1.2.pdf - * - * - * - */ +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #ifndef _ena_CRYPTO_H_ #define _ena_CRYPTO_H_ @@ -23,37 +23,98 @@ #include /** - * initialize crypto (setup entropy for key generation) + * @brief initialize cryptography + * + * This initialize the cryptography by setting up entropy. */ void ena_crypto_init(void); /** - * Calculate ENIntervalNumber (ENIN) for given UNIX timestamp + * @brief calculate ENIntervalNumber (ENIN) for given UNIX timestamp + * + * Source documents (Section: ENIntervalNumber) + * + * https://blog.google/documents/69/Exposure_Notification_-_Cryptography_Specification_v1.2.1.pdf + * + * https://covid19-static.cdn-apple.com/applications/covid19/current/static/detection-tracing/pdf/ExposureNotification-CryptographySpecificationv1.2.pdf + * + * + * @param[in] unix_timestamp UNIX Timestamp to calculate ENIN for + * + * @return + * ENIN for given timestamp */ -uint32_t ena_crypto_enin(uint32_t seconds); +uint32_t ena_crypto_enin(uint32_t unix_timestamp); /** - * calculate a new random Temporary Exposure Key (TEK) + * @brief calculate a new random Temporary Exposure Key (TEK) + * + * Source documents (Section: Temporary Exposure Key) + * + * https://blog.google/documents/69/Exposure_Notification_-_Cryptography_Specification_v1.2.1.pdf + * + * https://covid19-static.cdn-apple.com/applications/covid19/current/static/detection-tracing/pdf/ExposureNotification-CryptographySpecificationv1.2.pdf + * + * @param[out] tek pointer to the new TEK */ void ena_crypto_tek(uint8_t *tek); /** - * calculate a new Rolling Proximity Identifier Key (RPIK) with given TEK + * @brief calculate a new Rolling Proximity Identifier Key (RPIK) with given TEK + * + * Source documents (Section: Rolling Proximity Identifier Key) + * + * https://blog.google/documents/69/Exposure_Notification_-_Cryptography_Specification_v1.2.1.pdf + * + * https://covid19-static.cdn-apple.com/applications/covid19/current/static/detection-tracing/pdf/ExposureNotification-CryptographySpecificationv1.2.pdf + * + * @param[out] rpik pointer to the new RPIK + * @param[in] tek TEK for calculating RPIK */ void ena_crypto_rpik(uint8_t *rpik, uint8_t *tek); /** - * calculate a new Rolling Proximity Identifier with given RPIK and ENIN + * @brief calculate a new Rolling Proximity Identifier with given RPIK and ENIN + * + * Source documents (Section: Rolling Proximity Identifier) + * + * https://blog.google/documents/69/Exposure_Notification_-_Cryptography_Specification_v1.2.1.pdf + * + * https://covid19-static.cdn-apple.com/applications/covid19/current/static/detection-tracing/pdf/ExposureNotification-CryptographySpecificationv1.2.pdf + * + * @param[out] rpi pointer to the new RPI + * @param[in] rpik RPIK for encrypting RPI + * @param[in] enin ENIN to encrypt in RPI */ void ena_crypto_rpi(uint8_t *rpi, uint8_t *rpik, uint32_t enin); /** - * calculate a new Associated Encrypted Metadata Key (AEMK) with given TEK + * @brief calculate a new Associated Encrypted Metadata Key (AEMK) with given TEK + * + * Source documents (Section: Associated Encrypted Metadata Key) + * + * https://blog.google/documents/69/Exposure_Notification_-_Cryptography_Specification_v1.2.1.pdf + * + * https://covid19-static.cdn-apple.com/applications/covid19/current/static/detection-tracing/pdf/ExposureNotification-CryptographySpecificationv1.2.pdf + * + * @param[out] aemk pointer to the new AEMK + * @param[in] tek TEK for calculating AEMK */ void ena_crypto_aemk(uint8_t *aemk, uint8_t *tek); /** - * create Associated Encrypted Metadata (AEM) with given AEMK along the RPI + * @brief create Associated Encrypted Metadata (AEM) with given AEMK along the RPI + * + * Source documents (Section: Associated Encrypted Metadata) + * + * https://blog.google/documents/69/Exposure_Notification_-_Cryptography_Specification_v1.2.1.pdf + * + * https://covid19-static.cdn-apple.com/applications/covid19/current/static/detection-tracing/pdf/ExposureNotification-CryptographySpecificationv1.2.pdf + * + * @param[out] aem pointer to the new AEM + * @param[in] aemk AEMK for encrypting AEM + * @param[in] rpi RPI for encrypting AEM + * @param[in] power_level BLE power level to encrypt in AEM */ void ena_crypto_aem(uint8_t *aem, uint8_t *aemk, uint8_t *rpi, uint8_t power_level); diff --git a/main/ena-datastructures.h b/main/ena-datastructures.h index f312b9d..2a286a9 100644 --- a/main/ena-datastructures.h +++ b/main/ena-datastructures.h @@ -1,8 +1,16 @@ -/** - * provide data structure models of Exposure Notification API - * - * - */ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #ifndef _ena_DATASTRUCTURES_H_ #define _ena_DATASTRUCTURES_H_ @@ -10,7 +18,12 @@ #include #include "ena-crypto.h" -typedef enum +/** + * @brief different risk levels + * + * not used for now + */ +typedef enum { RISK_LEVEL_INVALID = 0, RISK_LEVEL_LOWEST, @@ -23,8 +36,12 @@ typedef enum RISK_LEVEL_HIGHEST, } ena_risklevel_t; -// maybe used later -typedef struct +/** + * @brief configuration for risk score calculation + * + * not used for now + */ +typedef struct { int minimum_risk_score; int attenuation_score[8]; @@ -38,28 +55,37 @@ typedef struct uint8_t duration_at_attenuation_thresholds[2]; } __packed ena_config_t; -typedef struct +/** + * @brief structure for TEK + */ +typedef struct { - uint8_t key_data[ENA_KEY_LENGTH]; - uint32_t enin; - uint8_t rolling_period; + uint8_t key_data[ENA_KEY_LENGTH]; // key data for encryption + uint32_t enin; // ENIN marking start of validity + uint8_t rolling_period; // period after validity start to mark key as expired } __packed ena_tek_t; -typedef struct +/** + * @brief sturcture for a temporary detection + */ +typedef struct { - uint8_t rpi[ENA_KEY_LENGTH]; - uint8_t aem[ENA_AEM_METADATA_LENGTH]; - uint32_t timestamp_first; - uint32_t timestamp_last; - int rssi; + uint8_t rpi[ENA_KEY_LENGTH]; // received RPI of detection + uint8_t aem[ENA_AEM_METADATA_LENGTH]; // received AEM of detection + uint32_t timestamp_first; // timestamp of first recognition + uint32_t timestamp_last; // timestamp of last recognition + int rssi; // last measured RSSI } __packed ena_temp_detection_t; -typedef struct +/** + * @brief sturcture for a detection + */ +typedef struct { - uint8_t rpi[ENA_KEY_LENGTH]; - uint8_t aem[ENA_AEM_METADATA_LENGTH]; - uint32_t timestamp; - int rssi; + uint8_t rpi[ENA_KEY_LENGTH]; // received RPI of detection + uint8_t aem[ENA_AEM_METADATA_LENGTH]; // received AEM of detection + uint32_t timestamp; // timestamp of last recognition + int rssi; // last measured RSSI } __packed ena_detection_t; #endif \ No newline at end of file diff --git a/main/ena-detection.c b/main/ena-detection.c index 01204a3..f1de834 100644 --- a/main/ena-detection.c +++ b/main/ena-detection.c @@ -1,3 +1,16 @@ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #include #include "esp_log.h" @@ -9,7 +22,7 @@ #include "ena-detection.h" static uint32_t temp_detections_count = 0; -static ena_temp_detection_t temp_detections[ENA_STOARGE_TEMP_DETECTIONS_MAX]; +static ena_temp_detection_t temp_detections[ENA_STORAGE_TEMP_DETECTIONS_MAX]; ena_detection_t ena_detections_convert(ena_temp_detection_t temp_detection) { @@ -36,7 +49,7 @@ int ena_get_temp_detection_index(uint8_t *rpi, uint8_t *aem) void ena_detections_temp_refresh(uint32_t unix_timestamp) { - for (int i = 0; i < temp_detections_count; i++) + for (int i = temp_detections_count - 1; i >= 0; i--) { // check for treshold and add permanent detection if (temp_detections[i].timestamp_last - temp_detections[i].timestamp_first >= ENA_DETECTION_TRESHOLD) @@ -44,7 +57,7 @@ void ena_detections_temp_refresh(uint32_t unix_timestamp) ESP_LOGD(ENA_DETECTION_LOG, "create detection after treshold"); ESP_LOG_BUFFER_HEXDUMP(ENA_DETECTION_LOG, temp_detections[i].rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); ena_detection_t detection = ena_detections_convert(temp_detections[i]); - ena_storage_write_detection(&detection); + ena_storage_add_detection(&detection); ena_storage_remove_temp_detection(i); } else @@ -60,7 +73,7 @@ void ena_detections_temp_refresh(uint32_t unix_timestamp) temp_detections_count = ena_storage_temp_detections_count(); for (int i = 0; i < temp_detections_count; i++) { - ena_storage_read_temp_detection(i, &temp_detections[i]); + ena_storage_get_temp_detection(i, &temp_detections[i]); } // DEBUG dump @@ -80,7 +93,7 @@ void ena_detection(uint32_t unix_timestamp, uint8_t *rpi, uint8_t *aem, int rssi memcpy(temp_detections[temp_detections_count].aem, aem, ENA_AEM_METADATA_LENGTH); temp_detections[temp_detections_count].rssi = rssi; temp_detections[temp_detections_count].timestamp_last = unix_timestamp; - detection_index = ena_storage_write_temp_detection(&temp_detections[temp_detections_count]); + detection_index = ena_storage_add_temp_detection(&temp_detections[temp_detections_count]); ESP_LOGD(ENA_DETECTION_LOG, "New temporary detection at %d with timestamp %u", temp_detections_count, unix_timestamp); ESP_LOG_BUFFER_HEX_LEVEL(ENA_DETECTION_LOG, rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); @@ -98,5 +111,6 @@ void ena_detection(uint32_t unix_timestamp, uint8_t *rpi, uint8_t *aem, int rssi temp_detections[detection_index].rssi = rssi; temp_detections[detection_index].timestamp_last = unix_timestamp; ESP_LOGD(ENA_DETECTION_LOG, "New Timestamp for temporary detection %d: %u", detection_index, unix_timestamp); + ena_storage_set_temp_detection(temp_detections_count, &temp_detections[temp_detections_count]); } } \ No newline at end of file diff --git a/main/ena-detection.h b/main/ena-detection.h index 4167bb5..f2826d2 100644 --- a/main/ena-detection.h +++ b/main/ena-detection.h @@ -1,7 +1,16 @@ -/** - * combine bluetooth and crypto parts to build EXPOSURE NOTIFICATION - * - */ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #ifndef _ena_DETECTION_H_ #define _ena_DETECTION_H_ @@ -10,10 +19,29 @@ #define ENA_DETECTION_TRESHOLD (300) // meet for longer than 5 minutes -#include "ena-crypto.h" - +/** + * @brief check temporary detection for full detection or expiring + * + * This function checks all current temporary detections if the contact threshold is + * reached or if the temporary contact can be discarded. + * + * @param[in] unix_timestamp current time as UNIX timestamp to compate + * + */ void ena_detections_temp_refresh(uint32_t unix_timestamp); +/** + * @brief handle new detection received from a BLE scan + * + * This function gets called when a running BLE scan received a new ENA payload. + * On already detected RPI this will update just the timestamp and RSSI. + * + * @param[in] unix_timestamp UNIX timestamp when detection was made + * @param[in] rpi received RPI from scanned payload + * @param[in] aem received AEM from scanned payload + * @param[in] rssi measured RSSI on scan + * + */ void ena_detection(uint32_t unix_timestamp, uint8_t *rpi, uint8_t *aem, int rssi); #endif \ No newline at end of file diff --git a/main/ena-interface-datetime.c b/main/ena-interface-datetime.c index ee7c424..c731cf0 100644 --- a/main/ena-interface-datetime.c +++ b/main/ena-interface-datetime.c @@ -1,7 +1,21 @@ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #include #include "esp_log.h" #include "ena-interface.h" +#include "driver/touch_pad.h" #include "ena-interface-menu.h" #include "ena-interface-datetime.h" diff --git a/main/ena-interface-datetime.h b/main/ena-interface-datetime.h index a7a7a45..fbfc8b7 100644 --- a/main/ena-interface-datetime.h +++ b/main/ena-interface-datetime.h @@ -1,3 +1,17 @@ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef _ena_INTERFACE_DATETIME_H_ #define _ena_INTERFACE_DATETIME_H_ diff --git a/main/ena-interface-menu.c b/main/ena-interface-menu.c index 8efe815..e77c336 100644 --- a/main/ena-interface-menu.c +++ b/main/ena-interface-menu.c @@ -1,6 +1,20 @@ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #include #include "esp_log.h" +#include "driver/touch_pad.h" #include "ena-interface.h" #include "ena-interface-datetime.h" diff --git a/main/ena-interface-menu.h b/main/ena-interface-menu.h index 9b6a2a7..17d985e 100644 --- a/main/ena-interface-menu.h +++ b/main/ena-interface-menu.h @@ -1,3 +1,17 @@ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef _ena_INTERFACE_MENU_H_ #define _ena_INTERFACE_MENU_H_ diff --git a/main/ena-interface.c b/main/ena-interface.c index 233ec19..e0ae368 100644 --- a/main/ena-interface.c +++ b/main/ena-interface.c @@ -1,4 +1,16 @@ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -10,7 +22,8 @@ static int interface_state = ENA_INTERFACE_STATE_IDLE; -static bool touch_status[TOUCH_PAD_MAX] = {0}; +static int touch_mapping[TOUCH_PAD_COUNT] = {0}; +static bool touch_status[TOUCH_PAD_COUNT] = {0}; static ena_interface_touch_callback touch_callbacks[TOUCH_PAD_MAX]; void ena_interface_register_touch_callback(int touch_pad, ena_interface_touch_callback callback) @@ -21,18 +34,24 @@ void ena_interface_register_touch_callback(int touch_pad, ena_interface_touch_ca void ena_interface_run(void *pvParameter) { uint16_t touch_value; + uint16_t touch_thresh; bool touch_status_current[4] = {0}; while (1) { - for (int i = 0; i < TOUCH_PAD_MAX; i++) + for (int i = 0; i < TOUCH_PAD_COUNT; i++) { + int touch_id = touch_mapping[i]; + ESP_ERROR_CHECK_WITHOUT_ABORT(touch_pad_read_filtered(touch_id, &touch_value)); + ESP_ERROR_CHECK_WITHOUT_ABORT(touch_pad_get_thresh(touch_id, &touch_thresh)); + touch_status_current[i] = touch_value < touch_thresh; - touch_pad_read_filtered(i, &touch_value); - touch_status_current[i] = touch_value < TOUCHPAD_TOUCH_THRESHOLD; - - if (!touch_status[i] & touch_status_current[i] && touch_callbacks[i] != NULL) + if (!touch_status[i] & touch_status_current[i]) { - (*touch_callbacks[i])(); + ESP_LOGD(ENA_INTERFACE_LOG, "touch %u at %d (thresh %u)", touch_value, touch_id, touch_thresh); + if (touch_callbacks[touch_id] != NULL) + { + (*touch_callbacks[touch_id])(); + } } touch_status[i] = touch_status_current[i]; } @@ -46,11 +65,29 @@ void ena_interface_start(void) ESP_ERROR_CHECK(touch_pad_init()); ESP_ERROR_CHECK(touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V)); ESP_ERROR_CHECK(touch_pad_set_trigger_mode(TOUCH_TRIGGER_BELOW)); + + touch_mapping[0] = TOUCH_PAD_ESC; + touch_mapping[1] = TOUCH_PAD_OK; + touch_mapping[2] = TOUCH_PAD_UP; + touch_mapping[3] = TOUCH_PAD_DOWN; + + for (int i = 0; i < TOUCH_PAD_COUNT; i++) + { + int touch_id = touch_mapping[i]; + ESP_ERROR_CHECK(touch_pad_config(touch_id, 0)); + } + ESP_ERROR_CHECK(touch_pad_filter_start(TOUCHPAD_FILTER_TOUCH_PERIOD)); - ESP_ERROR_CHECK(touch_pad_config(TOUCH_PAD_ESC, TOUCHPAD_TOUCH_THRESHOLD)); - ESP_ERROR_CHECK(touch_pad_config(TOUCH_PAD_OK, TOUCHPAD_TOUCH_THRESHOLD)); - ESP_ERROR_CHECK(touch_pad_config(TOUCH_PAD_UP, TOUCHPAD_TOUCH_THRESHOLD)); - ESP_ERROR_CHECK(touch_pad_config(TOUCH_PAD_DOWN, TOUCHPAD_TOUCH_THRESHOLD)); + + uint16_t touch_value; + for (int i = 0; i < TOUCH_PAD_COUNT; i++) + { + int touch_id = touch_mapping[i]; + ESP_ERROR_CHECK(touch_pad_read_filtered(touch_id, &touch_value)); + ESP_ERROR_CHECK(touch_pad_set_thresh(touch_id, touch_value * 2 / 3)); + ESP_LOGD(ENA_INTERFACE_LOG, "calibrate %u at %u (thresh %u)", touch_id, touch_value, (touch_value * 2 / 3)); + } + xTaskCreate(&ena_interface_run, "ena_interface_run", configMINIMAL_STACK_SIZE * 4, NULL, 5, NULL); } diff --git a/main/ena-interface.h b/main/ena-interface.h index cddd5db..d2d6907 100644 --- a/main/ena-interface.h +++ b/main/ena-interface.h @@ -1,8 +1,16 @@ -/** - * Interface for different operations - * - */ -#include "driver/touch_pad.h" +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #ifndef _ena_INTERFACE_H_ #define _ena_INTERFACE_H_ @@ -10,34 +18,63 @@ #define ENA_INTERFACE_LOG "ESP-ENA-interface" // TAG for Logging #define TOUCHPAD_FILTER_TOUCH_PERIOD (10) -#define TOUCHPAD_TOUCH_THRESHOLD (600) +#define TOUCH_PAD_COUNT (4) #define TOUCH_PAD_ESC (TOUCH_PAD_NUM0) #define TOUCH_PAD_OK (TOUCH_PAD_NUM6) #define TOUCH_PAD_UP (TOUCH_PAD_NUM4) #define TOUCH_PAD_DOWN (TOUCH_PAD_NUM3) +/** + * @brief different interface states + */ typedef enum { - ENA_INTERFACE_STATE_IDLE = 0, - ENA_INTERFACE_STATE_MENU, - ENA_INTERFACE_STATE_SET_YEAR, - ENA_INTERFACE_STATE_SET_MONTH, - ENA_INTERFACE_STATE_SET_DAY, - ENA_INTERFACE_STATE_SET_HOUR, - ENA_INTERFACE_STATE_SET_MINUTE, - ENA_INTERFACE_STATE_SET_SECONDS, - ENA_INTERFACE_STATE_STATUS, + ENA_INTERFACE_STATE_IDLE = 0, // ilde state, do nothing + ENA_INTERFACE_STATE_MENU, // main menu + ENA_INTERFACE_STATE_SET_YEAR, // set current year + ENA_INTERFACE_STATE_SET_MONTH, // set current month + ENA_INTERFACE_STATE_SET_DAY, // set current day + ENA_INTERFACE_STATE_SET_HOUR, // set current hour + ENA_INTERFACE_STATE_SET_MINUTE, // set current minute + ENA_INTERFACE_STATE_SET_SECONDS, // set current second + ENA_INTERFACE_STATE_STATUS, // view current status } ena_interface_state; +/** + * @brief callback function on touch event + */ typedef void (*ena_interface_touch_callback)(void); +/** + * @brief register a callback function for touch event + * + * @param[in] touch_pad id of the touchpad to listen touch + * @param[in] callback callback function + */ void ena_interface_register_touch_callback(int touch_pad, ena_interface_touch_callback callback); +/** + * @brief get current interface state + * + * @return + * current state the interface is in + */ int ena_interface_get_state(void); +/** + * @brief set current interface state + * + * @param[in] state new state to set + */ void ena_interface_set_state(ena_interface_state state); +/** + * @brief start interface logic + * + * This will initialize the touch controls and start a task to listen to touch + * inputs and calling the callbacks + */ void ena_interface_start(void); #endif \ No newline at end of file diff --git a/main/ena-storage.c b/main/ena-storage.c index 2c8038e..1a6ae01 100644 --- a/main/ena-storage.c +++ b/main/ena-storage.c @@ -1,3 +1,16 @@ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -11,10 +24,10 @@ #define BLOCK_SIZE (4096) const int ENA_STORAGE_TEK_COUNT_ADDRESS = (0); // starting address for TEK COUNT -const int ENA_STORAGE_TEK_START_ADDRESS = (ENA_STORAGE_TEK_COUNT_ADDRESS + sizeof(uint8_t)); -const int ENA_STORAGE_TEMP_DETECTIONS_COUNT_ADDRESS = (ENA_STORAGE_TEK_START_ADDRESS + sizeof(ena_tek_t) * ENA_STOARGE_TEK_STORE_PERIOD); // starting address for temporary detections COUNT (offset from max. stored TEKs) -const int ENA_STORAGE_TEMP_DETECTIONS_START_ADDRESS = (ENA_STORAGE_TEMP_DETECTIONS_COUNT_ADDRESS + sizeof(uint32_t)); // starting address for temporary detections -const int ENA_STORAGE_DETECTIONS_COUNT_ADDRESS = (ENA_STORAGE_TEMP_DETECTIONS_START_ADDRESS + sizeof(ena_temp_detection_t) * ENA_STOARGE_TEMP_DETECTIONS_MAX); // starting address for detections COUNT (offset from max. stored temporary detections) +const int ENA_STORAGE_TEK_START_ADDRESS = (ENA_STORAGE_TEK_COUNT_ADDRESS + sizeof(uint32_t)); +const int ENA_STORAGE_TEMP_DETECTIONS_COUNT_ADDRESS = (ENA_STORAGE_TEK_START_ADDRESS + sizeof(ena_tek_t) * ENA_STORAGE_TEK_STORE_PERIOD); +const int ENA_STORAGE_TEMP_DETECTIONS_START_ADDRESS = (ENA_STORAGE_TEMP_DETECTIONS_COUNT_ADDRESS + sizeof(uint32_t)); +const int ENA_STORAGE_DETECTIONS_COUNT_ADDRESS = (ENA_STORAGE_TEMP_DETECTIONS_START_ADDRESS + sizeof(ena_temp_detection_t) * ENA_STORAGE_TEMP_DETECTIONS_MAX); const int ENA_STORAGE_DETECTIONS_START_ADDRESS = (ENA_STORAGE_DETECTIONS_COUNT_ADDRESS + sizeof(uint32_t)); void ena_storage_read(size_t address, void *data, size_t size) @@ -63,15 +76,14 @@ void ena_storage_write(size_t address, void *data, size_t size) else { ESP_LOGD(ENA_STORAGE_LOG, "overflow block at address %u with size %d (block %d)", address, size, block_num); - const size_t block1_address = address; const size_t block2_address = (block_num + 1) * BLOCK_SIZE; const size_t data2_size = address + size - block2_address; const size_t data1_size = size - data2_size; - ESP_LOGD(ENA_STORAGE_LOG, "block1_address %d, block1_size %d (block %d)", block1_address, data1_size, block_num); + ESP_LOGD(ENA_STORAGE_LOG, "block1_address %d, block1_size %d (block %d)", address, data1_size, block_num); ESP_LOGD(ENA_STORAGE_LOG, "block2_address %d, block2_size %d (block %d)", block2_address, data2_size, block_num + 1); void *data1 = malloc(data1_size); memcpy(data1, data, data1_size); - ena_storage_write(block1_address, data1, data1_size); + ena_storage_write(address, data1, data1_size); free(data1); void *data2 = malloc(data2_size); @@ -88,7 +100,7 @@ void ena_storage_shift_delete(size_t address, size_t end_address, size_t size) int block_num_start = address / BLOCK_SIZE; // check for overflow - if (address + size < (block_num_start + 1) * BLOCK_SIZE) + if (address + size <= (block_num_start + 1) * BLOCK_SIZE) { const esp_partition_t *partition = esp_partition_find_first( ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, PARTITION_NAME); @@ -116,12 +128,6 @@ void ena_storage_shift_delete(size_t address, size_t end_address, size_t size) memcpy((buffer + BLOCK_SIZE - size), buffer_next_block, size); free(buffer_next_block); } - else - { - // fill end with zeros - ESP_LOGD(ENA_STORAGE_LOG, "fill with zeros %u", size); - memset((buffer + BLOCK_SIZE - size), 0, size); - } ESP_ERROR_CHECK(esp_partition_erase_range(partition, block_num_start * BLOCK_SIZE, BLOCK_SIZE)); ESP_ERROR_CHECK(esp_partition_write(partition, block_num_start * BLOCK_SIZE, buffer, BLOCK_SIZE)); @@ -138,24 +144,23 @@ void ena_storage_shift_delete(size_t address, size_t end_address, size_t size) const size_t block2_address = (block_num_start + 1) * BLOCK_SIZE; const size_t data2_size = address + size - block2_address; const size_t data1_size = size - data2_size; - ena_storage_shift_delete(block1_address, end_address, data1_size); + ena_storage_shift_delete(block1_address, block2_address, data1_size); ena_storage_shift_delete(block2_address, end_address - data1_size, data2_size); } ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_shift_delete"); } -uint8_t ena_storage_read_last_tek(ena_tek_t *tek) +uint32_t ena_storage_read_last_tek(ena_tek_t *tek) { ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_read_tek"); - uint8_t tek_count = 0; - ena_storage_read(ENA_STORAGE_TEK_COUNT_ADDRESS, &tek_count, sizeof(uint8_t)); + uint32_t tek_count = 0; + ena_storage_read(ENA_STORAGE_TEK_COUNT_ADDRESS, &tek_count, sizeof(uint32_t)); if (tek_count < 1) { return 0; } - size_t address = ENA_STORAGE_TEK_START_ADDRESS + (tek_count - 1) * sizeof(ena_tek_t); - - ena_storage_read(address, tek, sizeof(ena_tek_t)); + uint8_t index = (tek_count % ENA_STORAGE_TEK_STORE_PERIOD) - 1; + ena_storage_read(ENA_STORAGE_TEK_START_ADDRESS + index * sizeof(ena_tek_t), tek, sizeof(ena_tek_t)); ESP_LOGD(ENA_STORAGE_LOG, "read last tek %u:", tek->enin); ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, tek->key_data, ENA_KEY_LENGTH, ESP_LOG_DEBUG); @@ -167,16 +172,13 @@ void ena_storage_write_tek(ena_tek_t *tek) { ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_write_tek"); - uint8_t tek_count = 0; - ena_storage_read(ENA_STORAGE_TEK_COUNT_ADDRESS, &tek_count, sizeof(uint8_t)); - ena_storage_write(ENA_STORAGE_TEK_START_ADDRESS + tek_count * sizeof(ena_tek_t), tek, sizeof(ena_tek_t)); + uint32_t tek_count = 0; + ena_storage_read(ENA_STORAGE_TEK_COUNT_ADDRESS, &tek_count, sizeof(uint32_t)); + uint8_t index = (tek_count % ENA_STORAGE_TEK_STORE_PERIOD); + ena_storage_write(ENA_STORAGE_TEK_START_ADDRESS + index * sizeof(ena_tek_t), tek, sizeof(ena_tek_t)); tek_count++; - if (tek_count > ENA_STOARGE_TEK_STORE_PERIOD) - { - tek_count = 1; - } - ena_storage_write(ENA_STORAGE_TEK_COUNT_ADDRESS, &tek_count, sizeof(uint8_t)); + ena_storage_write(ENA_STORAGE_TEK_COUNT_ADDRESS, &tek_count, sizeof(uint32_t)); ESP_LOGD(ENA_STORAGE_LOG, "write tek: ENIN %u", tek->enin); ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, tek->key_data, ENA_KEY_LENGTH, ESP_LOG_DEBUG); @@ -194,46 +196,51 @@ uint32_t ena_storage_temp_detections_count(void) return count; } -void ena_storage_read_temp_detection(uint32_t index, ena_temp_detection_t *detection) +void ena_storage_get_temp_detection(uint32_t index, ena_temp_detection_t *detection) { ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_read_temp_detection"); ena_storage_read(ENA_STORAGE_TEMP_DETECTIONS_START_ADDRESS + index * sizeof(ena_temp_detection_t), detection, sizeof(ena_temp_detection_t)); - ESP_LOGD(ENA_STORAGE_LOG, "read temp detection: first %u, last %u and rssi %d", detection->timestamp_first, detection->timestamp_last, detection->rssi); ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, detection->rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, detection->aem, ENA_AEM_METADATA_LENGTH, ESP_LOG_DEBUG); ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_read_temp_detection"); } -uint32_t ena_storage_write_temp_detection(ena_temp_detection_t *detection) +uint32_t ena_storage_add_temp_detection(ena_temp_detection_t *detection) { - ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_write_temp_detection"); + ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_add_temp_detection"); uint32_t count = ena_storage_temp_detections_count(); - - // start overwriting temporay detections?! - if (count > ENA_STOARGE_TEMP_DETECTIONS_MAX) - { - count = 0; - } - ena_storage_write(ENA_STORAGE_TEMP_DETECTIONS_START_ADDRESS + count * sizeof(ena_temp_detection_t), detection, sizeof(ena_temp_detection_t)); + // overwrite older temporary detections?! + uint8_t index = count % ENA_STORAGE_TEMP_DETECTIONS_MAX; + ena_storage_set_temp_detection(index, detection); + ESP_LOGD(ENA_STORAGE_LOG, "add temp detection at %u: first %u, last %u and rssi %d", index, detection->timestamp_first, detection->timestamp_last, detection->rssi); + ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, detection->rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); + ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, detection->aem, ENA_AEM_METADATA_LENGTH, ESP_LOG_DEBUG); count++; ena_storage_write(ENA_STORAGE_TEMP_DETECTIONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); - ESP_LOGD(ENA_STORAGE_LOG, "write temp detection: first %u, last %u and rssi %d", detection->timestamp_first, detection->timestamp_last, detection->rssi); + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_add_temp_detection"); + return count - 1; +} + +void ena_storage_set_temp_detection(uint32_t index, ena_temp_detection_t *detection) +{ + ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_set_temp_detection"); + ena_storage_write(ENA_STORAGE_TEMP_DETECTIONS_START_ADDRESS + index * sizeof(ena_temp_detection_t), detection, sizeof(ena_temp_detection_t)); + ESP_LOGD(ENA_STORAGE_LOG, "set temp detection at %u: first %u, last %u and rssi %d", index, detection->timestamp_first, detection->timestamp_last, detection->rssi); ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, detection->rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, detection->aem, ENA_AEM_METADATA_LENGTH, ESP_LOG_DEBUG); - ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_write_temp_detection"); - return count - 1; + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_set_temp_detection"); } void ena_storage_remove_temp_detection(uint32_t index) { ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_remove_temp_detection"); uint32_t count = ena_storage_temp_detections_count(); - size_t address_from = ENA_STORAGE_TEMP_DETECTIONS_START_ADDRESS + index * sizeof(ena_detection_t); - size_t address_to = ENA_STORAGE_TEMP_DETECTIONS_START_ADDRESS + count * sizeof(ena_detection_t); + size_t address_from = ENA_STORAGE_TEMP_DETECTIONS_START_ADDRESS + index * sizeof(ena_temp_detection_t); + size_t address_to = ENA_STORAGE_TEMP_DETECTIONS_START_ADDRESS + count * sizeof(ena_temp_detection_t); - ena_storage_shift_delete(address_from, address_to, sizeof(ena_detection_t)); + ena_storage_shift_delete(address_from, address_to, sizeof(ena_temp_detection_t)); count--; ena_storage_write(ENA_STORAGE_TEMP_DETECTIONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); @@ -251,7 +258,7 @@ uint32_t ena_storage_detections_count(void) return count; } -void ena_storage_read_detection(uint32_t index, ena_detection_t *detection) +void ena_storage_get_detection(uint32_t index, ena_detection_t *detection) { ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_read_detection"); ena_storage_read(ENA_STORAGE_DETECTIONS_START_ADDRESS + index * sizeof(ena_detection_t), detection, sizeof(ena_detection_t)); @@ -261,7 +268,7 @@ void ena_storage_read_detection(uint32_t index, ena_detection_t *detection) ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_read_detection"); } -void ena_storage_write_detection(ena_detection_t *detection) +void ena_storage_add_detection(ena_detection_t *detection) { ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_write_detection"); ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, detection->rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); @@ -282,16 +289,73 @@ void ena_storage_erase(void) ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, PARTITION_NAME); assert(partition); ESP_ERROR_CHECK(esp_partition_erase_range(partition, 0, partition->size)); - ESP_LOGI(PARTITION_NAME, "erase partition!"); + ESP_LOGI(ENA_STORAGE_LOG, "erased partition %s!", PARTITION_NAME); uint32_t count = 0; - ena_storage_write(ENA_STORAGE_TEK_COUNT_ADDRESS, &count, sizeof(uint8_t)); + ena_storage_write(ENA_STORAGE_TEK_COUNT_ADDRESS, &count, sizeof(uint32_t)); ena_storage_write(ENA_STORAGE_TEMP_DETECTIONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); ena_storage_write(ENA_STORAGE_DETECTIONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_erase"); } +void ena_storage_erase_tek(void) +{ + + ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_erase_teks"); + uint32_t tek_count = 0; + ena_storage_read(ENA_STORAGE_TEK_COUNT_ADDRESS, &tek_count, sizeof(uint32_t)); + uint8_t stored = ENA_STORAGE_TEK_STORE_PERIOD; + + if (tek_count < ENA_STORAGE_TEK_STORE_PERIOD) + { + stored = tek_count; + } + + size_t size = sizeof(uint32_t) + stored * sizeof(ena_tek_t); + uint8_t *zeros = calloc(size, sizeof(uint8_t)); + ena_storage_write(ENA_STORAGE_TEK_COUNT_ADDRESS, zeros, size); + free(zeros); + ESP_LOGI(ENA_STORAGE_LOG, "erased %d teks (size %u at %u)", stored, size, ENA_STORAGE_TEK_COUNT_ADDRESS); + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_erase_teks"); +} + +void ena_storage_erase_temporary_detection(void) +{ + ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_erase_temporary_detections"); + uint32_t detection_count = 0; + ena_storage_read(ENA_STORAGE_TEMP_DETECTIONS_COUNT_ADDRESS, &detection_count, sizeof(uint32_t)); + uint32_t stored = ENA_STORAGE_TEMP_DETECTIONS_MAX; + + if (detection_count < ENA_STORAGE_TEMP_DETECTIONS_MAX) + { + stored = detection_count; + } + + size_t size = sizeof(uint32_t) + stored * sizeof(ena_temp_detection_t); + uint8_t *zeros = calloc(size, sizeof(uint8_t)); + ena_storage_write(ENA_STORAGE_TEMP_DETECTIONS_COUNT_ADDRESS, zeros, size); + free(zeros); + + ESP_LOGI(ENA_STORAGE_LOG, "erased %d temporary detections (size %u at %u)", stored, size, ENA_STORAGE_TEMP_DETECTIONS_COUNT_ADDRESS); + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_erase_temporary_detections"); +} + +void ena_storage_erase_detection(void) +{ + ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_erase_detection"); + uint32_t detection_count = 0; + ena_storage_read(ENA_STORAGE_DETECTIONS_COUNT_ADDRESS, &detection_count, sizeof(uint32_t)); + + size_t size = sizeof(uint32_t) + detection_count * sizeof(ena_detection_t); + uint8_t *zeros = calloc(size, sizeof(uint8_t)); + ena_storage_write(ENA_STORAGE_DETECTIONS_COUNT_ADDRESS, zeros, size); + free(zeros); + + ESP_LOGI(ENA_STORAGE_LOG, "erased %d detections (size %u at %u)", detection_count, size, ENA_STORAGE_DETECTIONS_COUNT_ADDRESS); + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_erase_detection"); +} + void ena_storage_dump_hash_array(uint8_t *data, size_t size) { for (int i = 0; i < size; i++) @@ -310,11 +374,18 @@ void ena_storage_dump_hash_array(uint8_t *data, size_t size) void ena_storage_dump_tek(void) { ena_tek_t tek; - uint8_t tek_count = 0; - ena_storage_read(ENA_STORAGE_TEK_COUNT_ADDRESS, &tek_count, sizeof(uint8_t)); - ESP_LOGD(ENA_STORAGE_LOG, "%u TEKs\n", tek_count); + uint32_t tek_count = 0; + ena_storage_read(ENA_STORAGE_TEK_COUNT_ADDRESS, &tek_count, sizeof(uint32_t)); + uint8_t stored = ENA_STORAGE_TEK_STORE_PERIOD; + + if (tek_count < ENA_STORAGE_TEK_STORE_PERIOD) + { + stored = tek_count; + } + + ESP_LOGD(ENA_STORAGE_LOG, "%u TEKs (%u stored)\n", tek_count, stored); printf("#,enin,tek\n"); - for (int i = 0; i < tek_count; i++) + for (int i = 0; i < stored; i++) { size_t address = ENA_STORAGE_TEK_START_ADDRESS + i * sizeof(ena_tek_t); @@ -330,11 +401,17 @@ void ena_storage_dump_temp_detections(void) ena_temp_detection_t detection; uint32_t detection_count = 0; ena_storage_read(ENA_STORAGE_TEMP_DETECTIONS_COUNT_ADDRESS, &detection_count, sizeof(uint32_t)); - ESP_LOGD(ENA_STORAGE_LOG, "%u temporary detections\n", detection_count); - printf("#,timestamp_first,timestamp_last,rpi,aem,rssi\n"); - for (int i = 0; i < detection_count; i++) + uint32_t stored = ENA_STORAGE_TEMP_DETECTIONS_MAX; + + if (detection_count < ENA_STORAGE_TEMP_DETECTIONS_MAX) { - ena_storage_read_temp_detection(i, &detection); + stored = detection_count; + } + ESP_LOGD(ENA_STORAGE_LOG, "%u temporary detections (%u stored)\n", detection_count, stored); + printf("#,timestamp_first,timestamp_last,rpi,aem,rssi\n"); + for (int i = 0; i < stored; i++) + { + ena_storage_get_temp_detection(i, &detection); printf("%d,%u,%u,", i, detection.timestamp_first, detection.timestamp_last); ena_storage_dump_hash_array(detection.rpi, ENA_KEY_LENGTH); printf(","); @@ -353,7 +430,7 @@ void ena_storage_dump_detections(void) printf("#,timestamp,rpi,aem,rssi\n"); for (int i = 0; i < detection_count; i++) { - ena_storage_read_detection(i, &detection); + ena_storage_get_detection(i, &detection); printf("%d,%u,", i, detection.timestamp); ena_storage_dump_hash_array(detection.rpi, ENA_KEY_LENGTH); printf(","); diff --git a/main/ena-storage.h b/main/ena-storage.h index 0e6ab10..f8703a7 100644 --- a/main/ena-storage.h +++ b/main/ena-storage.h @@ -1,84 +1,189 @@ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef _ena_STORAGE_H_ #define _ena_STORAGE_H_ #include "ena-crypto.h" #include "ena-datastructures.h" -#define ENA_STORAGE_LOG "ESP-ENA-storage" // TAG for Logging -#define PARTITION_NAME "ena" -#define ENA_STOARGE_TEK_STORE_PERIOD (14) // Period of storing TEKs // length of a stored detection -> RPI keysize + AEM size + 4 Bytes for ENIN + 4 Bytes for RSSI -#define ENA_STOARGE_TEMP_DETECTIONS_MAX (1000) // Maximum number of temporary stored detections +#define ENA_STORAGE_LOG "ESP-ENA-storage" // TAG for Logging +#define PARTITION_NAME "ena" // name of partition to use for storing +#define ENA_STORAGE_TEK_STORE_PERIOD (14) // Period of storing TEKs // length of a stored detection -> RPI keysize + AEM size + 4 Bytes for ENIN + 4 Bytes for RSSI +#define ENA_STORAGE_TEMP_DETECTIONS_MAX (1000) // Maximum number of temporary stored detections /** - * read bytes at given address + * @brief read bytes at given address + * + * @param[in] address the address to read bytes from + * @param[out] data pointer to write the read data + * @param[in] size how many bytes to read */ void ena_storage_read(size_t address, void *data, size_t size); /** - * store bytes at given address + * @brief store bytes at given address + * + * @param[in] address the address to write bytes to + * @param[in] data pointer to the data to write + * @param[in] size how many bytes to write */ void ena_storage_write(size_t address, void *data, size_t size); /** - * deletes bytes at given address and shift other data back + * @brief deletes bytes at given address and shift other data back + * + * @param[in] address the address to delete from + * @param[in] end_address the address to mark end of shift + * @param[in] size how many bytes to delete */ void ena_storage_shift_delete(size_t address, size_t end_address, size_t size); /** - * get last stored TEK + * @brief get last stored TEK * - * return cound + * @param[out] tek pointer to write last TEK to + * + * @return + * total number of TEKs stored */ -uint8_t ena_storage_read_last_tek(ena_tek_t *tek); +uint32_t ena_storage_read_last_tek(ena_tek_t *tek); /** - * store TEK + * @brief store given TEK + * + * This will store the given TEK as new TEK. + * + * @param[in] tek the tek to store */ void ena_storage_write_tek(ena_tek_t *tek); /** - * get number of stored temporary detections + * @brief get number of stored temporary detections + * + * @return + * total number of temporary detections stored */ uint32_t ena_storage_temp_detections_count(void); /** - * get temporary detection (RPI + AEM + RSSI with UNIX timestamp) at given index - */ -void ena_storage_read_temp_detection(uint32_t index, ena_temp_detection_t *detection); - -/** - * store temporary detection (RPI + AEM + RSSI with UNIX timestamp) + * @brief get temporary detection at given index * - * returns index + * @param[in] index the index of the temporary detection to read + * @param[out] detection pointer to temporary to write to */ -uint32_t ena_storage_write_temp_detection(ena_temp_detection_t *detection); +void ena_storage_get_temp_detection(uint32_t index, ena_temp_detection_t *detection); /** - * remove temporary detection at given index + * @brief store temporary detection + * + * @param[in] detection new temporary detection to store + * + * @return + * index of new stored detection + */ +uint32_t ena_storage_add_temp_detection(ena_temp_detection_t *detection); + +/** + * @brief store temporary detection at given index + * + * @param[in] index the index of the temporary detection to overwrite + * @param[in] detection temporary detection to store + */ +void ena_storage_set_temp_detection(uint32_t index, ena_temp_detection_t *detection); + +/** + * @brief remove temporary detection at given index + * + * @param[in] index the index of the temporary detection to remove */ void ena_storage_remove_temp_detection(uint32_t index); /** - * get number of stored detections + * @brief get number of stored detections + * + * @return + * total number of detections stored */ uint32_t ena_storage_detections_count(void); /** - * get detection (RPI + AEM + RSSI with ENIN) at given index + * @brief get detection at given index + * + * @param[in] index the index of the detection to read + * @param[out] detection pointer to to write to */ -void ena_storage_read_detection(uint32_t index, ena_detection_t *detection); +void ena_storage_get_detection(uint32_t index, ena_detection_t *detection); /** - * store detection (RPI + AEM + RSSI with ENIN) + * @brief store detection + * + * @param[in] detection new detection to store */ -void ena_storage_write_detection(ena_detection_t *detection); +void ena_storage_add_detection(ena_detection_t *detection); +/** + * @brief erase the storage + * + * This function completely deletes all stored data and resets the counters + * of TEKs, temporary detection and detection to zero. + */ void ena_storage_erase(void); +/** + * @brief erase stored TEKs + * + * This function deletes all stored TEKs and resets counter to zero. + */ +void ena_storage_erase_tek(void); + +/** + * @brief erase stored temporary detections + * + * This function deletes all stored temporary detections and resets counter to zero. + */ +void ena_storage_erase_temporary_detection(void); + +/** + * @brief erase stored detections + * + * This function deletes all stored detections and resets counter to zero. + */ +void ena_storage_erase_detection(void); + +/** + * @brief dump all stored TEKs to serial output + * + * This function prints all stored TEKs to serial output in + * the following CSV format: #,enin,tek + */ void ena_storage_dump_tek(void); +/** + * @brief dump all stored temporary detections to serial output + * + * This function prints all stored temporary detections to serial output in + * the following CSV format: #,timestamp_first,timestamp_last,rpi,aem,rssi + */ void ena_storage_dump_temp_detections(void); +/** + * @brief dump all stored detections to serial output + * + * This function prints all stored detections to serial output in + * the following CSV format: #,timestamp,rpi,aem,rssi + */ void ena_storage_dump_detections(void); #endif \ No newline at end of file diff --git a/main/ena.c b/main/ena.c index b09d628..4b5315a 100644 --- a/main/ena.c +++ b/main/ena.c @@ -1,4 +1,16 @@ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #include #include @@ -22,7 +34,19 @@ #include "ena.h" -static ena_tek_t last_tek; // last ENIN +static ena_tek_t last_tek; // last ENIN +static uint32_t next_rpi_timestamp; // next rpi + +void ena_next_rpi_timestamp(uint32_t timestamp) +{ + int random_interval = esp_random() % (2 * ENA_RPI_ROLLING_RANDOM_INTERVAL); + if (random_interval > ENA_RPI_ROLLING_RANDOM_INTERVAL) + { + random_interval = ENA_RPI_ROLLING_RANDOM_INTERVAL - random_interval; + } + next_rpi_timestamp = timestamp + ENA_RPI_ROLLING_PERIOD + random_interval; + ESP_LOGD(ENA_LOG, "next rpi at %u (%u from %u)", next_rpi_timestamp, (ENA_RPI_ROLLING_PERIOD + random_interval), timestamp); +} void ena_run(void *pvParameter) { @@ -40,7 +64,7 @@ void ena_run(void *pvParameter) } // change RPI - if (unix_timestamp % ENA_TIME_WINDOW == 0) + if (unix_timestamp >= next_rpi_timestamp) { if (ena_bluetooth_scan_get_status() == ENA_SCAN_STATUS_SCANNING) { @@ -53,6 +77,7 @@ void ena_run(void *pvParameter) { ena_bluetooth_scan_start(ENA_SCANNING_TIME); } + ena_next_rpi_timestamp(unix_timestamp); } // scan @@ -118,7 +143,9 @@ void ena_start(void) uint32_t current_enin = ena_crypto_enin((uint32_t)time(NULL)); - uint8_t tek_count = ena_storage_read_last_tek(&last_tek); + uint32_t tek_count = ena_storage_read_last_tek(&last_tek); + + ena_next_rpi_timestamp((uint32_t)time(NULL)); // read last TEK or create new if (tek_count == 0 || (current_enin - last_tek.enin) >= ENA_TEK_ROLLING_PERIOD) diff --git a/main/ena.h b/main/ena.h index 2d01734..f69f45d 100644 --- a/main/ena.h +++ b/main/ena.h @@ -1,13 +1,32 @@ -/** - * combine bluetooth and crypto parts to build EXPOSURE NOTIFICATION - * - */ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #ifndef _ena_H_ #define _ena_H_ #define ENA_LOG "ESP-ENA" // TAG for Logging +#define ENA_RPI_ROLLING_PERIOD (900) // change RPI every 15 minutes +#define ENA_RPI_ROLLING_RANDOM_INTERVAL (150) // random intervall change of rpi +/- ~2.5 minutes + +/** + * @brief Start Exposure Notification API + * + * This initializes the complete stack of ESP_ENA. It will initialize BLE module and + * starting a task for managing advertising and scanning processes. + * + */ void ena_start(void); #endif \ No newline at end of file diff --git a/main/main.c b/main/main.c index 9e855fc..3a29f8e 100644 --- a/main/main.c +++ b/main/main.c @@ -1,17 +1,18 @@ -/** - * provide bluetooth part of Exposure Notification API v1.2 as defined by Apple/Google - * - * Source documents: - * - * https://blog.google/documents/70/Exposure_Notification_-_Bluetooth_Specification_v1.2.2.pdf - * - * https://covid19-static.cdn-apple.com/applications/covid19/current/static/detection-tracing/pdf/ExposureNotification-BluetoothSpecificationv1.2.pdf - * - * - * - */ +// Copyright 2020 Lukas Haubaum +// +// Licensed under the GNU Affero General Public License, Version 3; +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// https://www.gnu.org/licenses/agpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #include +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include @@ -20,6 +21,7 @@ #include "esp_log.h" #include "ena.h" +#include "ena-detection.h" #include "ena-storage.h" #include "ena-interface.h" #include "ena-interface-menu.h" @@ -33,7 +35,7 @@ void app_main(void) settimeofday(&tv, NULL); esp_log_level_set(ENA_STORAGE_LOG, ESP_LOG_INFO); - // ena_storage_erase(); // only needed on first start! TODO automatically check + // ena_storage_erase(); // only needed on first start! TODO automatically check (how?) ena_interface_start(); ena_interface_menu_start();