diff --git a/README.md b/README.md index ca9a1eb..6fba69d 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ More information about the Covid-19 Exposure Notification at [Apple](https://www [Demo Video](https://twitter.com/Lurkars/status/1282223547579019264) This implementation covers for now the BLE part including the cryptography specifications needed (see Bluetooth Specifications and Cryptography Specifications documents in the links above): -* send tokens -* store TEKs on flash (last 14 tokens) -* receive tokens -* received tokens are stored after 5 minutes threshold (storage is limited, ~100k tokens can be stored) +* send beacons +* store TEKs on flash (last 14) +* receive beacons +* received beacons are stored after 5 minutes threshold (storage is limited, ~100k beacons can be stored) Features missing for now are: -* compare received tokens with infected list +* compare received beacons with infected list * calculating risks scores Extensions planned: @@ -22,10 +22,10 @@ Extensions planned: * add display (will test SSD1306) * interface to * set time - * delete tokens + * delete beacons * show status * report infection? -* receive infected token list (will test [Corona Warn App](https://github.com/corona-warn-app)) +* receive infected beacons list (will test [Corona Warn App](https://github.com/corona-warn-app)) * send infected status (will test [Corona Warn App](https://github.com/corona-warn-app)) * battery support * 3d print case @@ -44,7 +44,7 @@ The following acronyms will be used in code and comments: * *AEM* Associated Encrypted Metadata - send and received metadata Open questions -* now save ENIN for stored detection (documentation says timestamp), but for infection status ENIN should be enough!? +* now save ENIN for stored beacons (documentation says timestamp), but for infection status ENIN should be enough!? * service UUID is send reversed, must RPI and AEM also beeing send in reverse? Don't know BLE specification enough * fixed change of advertise payload every 10 minutes, random value between ~15 minutes better? @@ -67,6 +67,10 @@ required recommended * BLE Scan Duplicate (By Device Address and Advertising Data) + +debug options +* Log output set to Debug +* Exposure Notification API enable Dump storage ### Build and Flash @@ -87,29 +91,6 @@ idf.py -p PORT flash monitor (To exit the serial monitor, type ``Ctrl-]``.) -## Example Output - -For now some debug outputs are set. Besides, after each scan a CSV output is printed with stored TEKs, temporary detections (RPI) and full detections (RPI) - -``` -I (1201484) ESP-ENA-advertise: payload for ENIN 2657432 -D (1201494) ESP-ENA-advertise: 0x3ffbb6c4 02 01 1a 03 03 6f fd 17 16 6f fd 9a ee 95 9a 24 |.....o...o.....$| -D (1201494) ESP-ENA-advertise: 0x3ffbb6d4 f0 f9 8e 56 0f 6d 68 5f ac 12 e5 7f 94 a1 47 |...V.mh_......G| -I (1201524) ESP-ENA-scan: start scanning... -D (1202224) ESP-ENA-detection: New temporary detection at 0 with timestamp 1594459201 -D (1202224) ESP-ENA-detection: 19 05 e3 3a 73 16 4e 74 2d 48 fc 0c 41 f6 26 3b -D (1202234) ESP-ENA-detection: 5e 7d a9 48 -D (1202234) ESP-ENA-detection: RSSI -79 -#,enin,tek -0,2657430,d5 13 92 b2 44 e4 7e b6 ca a7 20 c4 f 37 c0 1c -#,timestamp,rpi,aem,rssi -0,1594459201,19 5 e3 3a 73 16 4e 74 2d 48 fc c 41 f6 26 3b,5e 7d a9 48,-79 -#,enin,rpi,aem,rssi -0,2657430,c7 2e b6 66 af 84 42 db b d1 a 0 f1 fd 86 2,4d 1 b2 d1,-76 -1,2657431,19 5 e3 3a 73 16 4e 74 2d 48 fc c 41 f6 26 3b,5e 7d a9 48,-76 -I (1231754) ESP-ENA-scan: finished scanning... -``` - ## Troubleshooting Sometimes I get errors from BT-stack of ESP-IDF printed. Didn't affect functionality for now, but I also could not find out what it caused and what it means. @@ -121,10 +102,10 @@ E (909164) BT_HCI: btu_hcif_hdl_command_complete opcode 0x2005 status 0xc ## Structure The project is divided in different files +* *ena-beacon* handles scanned data by storing temporary beacons, check for threshold and store beacons permanently * *ena-crypto* covers cryptography part (key creation, encryption etc.) -* *ena-storage* storage part to store own TEKs and detections -* *ena-detection* handles scanned data by storing temporary detections, check for threshold and store full detections -* *ena-bluetooth-scan* BLE scans for detecting other tokens -* *ena-bluetooth-advertise* BLE advertising to send own tokens +* *ena-storage* storage part to store own TEKs and beacons +* *ena-bluetooth-scan* BLE scans for detecting other beacons +* *ena-bluetooth-advertise* BLE advertising to send own beacons * *ena* run all together and timing for scanning and advertising * *main* start and run main program diff --git a/components/ena-interface/CMakeLists.txt b/components/ena-interface/CMakeLists.txt new file mode 100644 index 0000000..c5cd82b --- /dev/null +++ b/components/ena-interface/CMakeLists.txt @@ -0,0 +1,9 @@ +idf_component_register( + SRCS + "interface.c" + "interface-datetime.c" + "interface-menu.c" + INCLUDE_DIRS "include" + PRIV_REQUIRES + ena +) \ No newline at end of file diff --git a/main/ena-interface-datetime.h b/components/ena-interface/include/ena-interface-datetime.h similarity index 99% rename from main/ena-interface-datetime.h rename to components/ena-interface/include/ena-interface-datetime.h index fbfc8b7..8849a37 100644 --- a/main/ena-interface-datetime.h +++ b/components/ena-interface/include/ena-interface-datetime.h @@ -11,7 +11,6 @@ // 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.h b/components/ena-interface/include/ena-interface-menu.h similarity index 99% rename from main/ena-interface-menu.h rename to components/ena-interface/include/ena-interface-menu.h index 17d985e..696d362 100644 --- a/main/ena-interface-menu.h +++ b/components/ena-interface/include/ena-interface-menu.h @@ -11,7 +11,6 @@ // 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.h b/components/ena-interface/include/ena-interface.h similarity index 99% rename from main/ena-interface.h rename to components/ena-interface/include/ena-interface.h index d2d6907..4adea8b 100644 --- a/main/ena-interface.h +++ b/components/ena-interface/include/ena-interface.h @@ -11,14 +11,12 @@ // 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_ #define ENA_INTERFACE_LOG "ESP-ENA-interface" // TAG for Logging #define TOUCHPAD_FILTER_TOUCH_PERIOD (10) - #define TOUCH_PAD_COUNT (4) #define TOUCH_PAD_ESC (TOUCH_PAD_NUM0) #define TOUCH_PAD_OK (TOUCH_PAD_NUM6) diff --git a/main/ena-interface-datetime.c b/components/ena-interface/interface-datetime.c similarity index 100% rename from main/ena-interface-datetime.c rename to components/ena-interface/interface-datetime.c diff --git a/main/ena-interface-menu.c b/components/ena-interface/interface-menu.c similarity index 100% rename from main/ena-interface-menu.c rename to components/ena-interface/interface-menu.c diff --git a/main/ena-interface.c b/components/ena-interface/interface.c similarity index 100% rename from main/ena-interface.c rename to components/ena-interface/interface.c diff --git a/components/ena/CMakeLists.txt b/components/ena/CMakeLists.txt new file mode 100644 index 0000000..05fcd90 --- /dev/null +++ b/components/ena/CMakeLists.txt @@ -0,0 +1,14 @@ +idf_component_register( + SRCS + "beacons.c" + "bluetooth-advertise.c" + "bluetooth-scan.c" + "crypto.c" + "ena.c" + "storage.c" + INCLUDE_DIRS "include" + PRIV_REQUIRES + spi_flash + mbedtls + bt +) \ No newline at end of file diff --git a/components/ena/Kconfig b/components/ena/Kconfig new file mode 100644 index 0000000..a655919 --- /dev/null +++ b/components/ena/Kconfig @@ -0,0 +1,85 @@ +menu "Exposure Notification API" + + menu "Storage" + + config ENA_STORAGE_DUMP + bool "Dump storage" + default false + help + Dump storage (stored TEKs, temp. beacons and perm. beacons) to serial output after scan. + + config ENA_STORAGE_TEK_MAX + int "Max. TEKs" + default 14 + help + Defines the maximum number of TEKs to be stored. (Default 14 [14 * 144 => 14 days]) + + config ENA_STORAGE_TEMP_BEACONS_MAX + int "Max. temporary beacons" + default 1000 + help + Defines the maximum number of temporary beacons to be stored. (Default 1000) + + config ENA_STORAGE_START_ADDRESS + int "Storage start address" + default 0 + help + Defines the start address on partition. (Default 0) + + config ENA_STORAGE_PARTITION_NAME + string "Partition name" + default "ena" + help + Name of the partition used for storage. (Default "ena", see partitions.csv) + + config ENA_STORAGE_ERASE + bool "Erase storage (!)" + default false + help + Erases the complete(!) partition on startup and reset counters. + + endmenu + + menu "Scanning" + config ENA_BEACON_TRESHOLD + int "Contact threshold" + default 300 + help + Threshold in seconds after a received beacon is stored permanently. (Default 5 minutes) + + config ENA_SCANNING_TIME + int "Scanning time" + default 30 + help + Time in seconds how long a scan should run. (Default 30 seconds) + + config ENA_SCANNING_INTERVAL + int "Scanning interval" + default 300 + help + Interval in seconds for the next scan to happen. (Default 5 minutes) + endmenu + + menu "Advertising" + + config ENA_BT_ROTATION_TIMEOUT_INTERVAL + int "Rotation timeout interval" + default 900 + help + Base rotation timeout interval in seconds for changing BT address and therefore the advertised beacon. (Default 5 minutes) + + config ENA_BT_RANDOMIZE_ROTATION_TIMEOUT_INTERVAL + int "Randomize rotation timeout interval" + default 150 + help + Range in seconds for randomize the rotation timeout interval. (Default +/- ~2.5 minutes) + + config ENA_TEK_ROLLING_PERIOD + int "TEK rolling period" + default 144 + help + Defines the TEK rolling period in 10 minute steps. (Default 144 => 24 hours) + endmenu + + +endmenu \ No newline at end of file diff --git a/components/ena/beacons.c b/components/ena/beacons.c new file mode 100644 index 0000000..569e579 --- /dev/null +++ b/components/ena/beacons.c @@ -0,0 +1,119 @@ +// 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-crypto.h" +#include "ena-storage.h" + +#include "ena-beacons.h" + +static uint32_t temp_beacons_count = 0; +static ena_temp_beacon_t temp_beacons[ENA_STORAGE_TEMP_BEACONS_MAX]; + +ena_beacon_t ena_beacons_convert(ena_temp_beacon_t temp_beacon) +{ + ena_beacon_t beacon; + memcpy(beacon.rpi, temp_beacon.rpi, ENA_KEY_LENGTH); + memcpy(beacon.aem, temp_beacon.aem, ENA_AEM_METADATA_LENGTH); + beacon.timestamp = temp_beacon.timestamp_last; + beacon.rssi = temp_beacon.rssi; + return beacon; +} + +int ena_get_temp_beacon_index(uint8_t *rpi, uint8_t *aem) +{ + for (int i = 0; i < temp_beacons_count; i++) + { + if (memcmp(temp_beacons[i].rpi, rpi, sizeof(ENA_KEY_LENGTH)) == 0 && + memcmp(temp_beacons[i].aem, aem, sizeof(ENA_AEM_METADATA_LENGTH)) == 0) + { + return i; + } + } + return -1; +} + +void ena_beacons_temp_refresh(uint32_t unix_timestamp) +{ + for (int i = temp_beacons_count - 1; i >= 0; i--) + { + // check for treshold and add permanent beacon + if (temp_beacons[i].timestamp_last - temp_beacons[i].timestamp_first >= ENA_BEACON_TRESHOLD) + { + ESP_LOGD(ENA_BEACON_LOG, "create beacon after treshold"); + ESP_LOG_BUFFER_HEXDUMP(ENA_BEACON_LOG, temp_beacons[i].rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); + ena_beacon_t beacon = ena_beacons_convert(temp_beacons[i]); + ena_storage_add_beacon(&beacon); + ena_storage_remove_temp_beacon(i); + } + else + // delete temp beacons older than two times time window (two times to be safe, one times time window enough?!) + if (unix_timestamp - temp_beacons[i].timestamp_last > (ENA_TIME_WINDOW * 2)) + { + ESP_LOGD(ENA_BEACON_LOG, "remove old temporary beacon %u", i); + ena_storage_remove_temp_beacon(i); + } + } + + // update beacons + temp_beacons_count = ena_storage_temp_beacons_count(); + for (int i = 0; i < temp_beacons_count; i++) + { + ena_storage_get_temp_beacon(i, &temp_beacons[i]); + } + +#if (CONFIG_ENA_STORAGE_DUMP) + // DEBUG dump + ena_storage_dump_tek(); + ena_storage_dump_temp_beacons(); + ena_storage_dump_beacons(); +#endif +} + +void ena_beacon(uint32_t unix_timestamp, uint8_t *rpi, uint8_t *aem, int rssi) +{ + uint32_t beacon_index = ena_get_temp_beacon_index(rpi, aem); + + if (beacon_index == -1) + { + temp_beacons[temp_beacons_count].timestamp_first = unix_timestamp; + memcpy(temp_beacons[temp_beacons_count].rpi, rpi, ENA_KEY_LENGTH); + memcpy(temp_beacons[temp_beacons_count].aem, aem, ENA_AEM_METADATA_LENGTH); + temp_beacons[temp_beacons_count].rssi = rssi; + temp_beacons[temp_beacons_count].timestamp_last = unix_timestamp; + beacon_index = ena_storage_add_temp_beacon(&temp_beacons[temp_beacons_count]); + + ESP_LOGD(ENA_BEACON_LOG, "New temporary beacon at %d with timestamp %u", temp_beacons_count, unix_timestamp); + ESP_LOG_BUFFER_HEX_LEVEL(ENA_BEACON_LOG, rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); + ESP_LOG_BUFFER_HEX_LEVEL(ENA_BEACON_LOG, aem, ENA_AEM_METADATA_LENGTH, ESP_LOG_DEBUG); + ESP_LOGD(ENA_BEACON_LOG, "RSSI %d", rssi); + + if (beacon_index != temp_beacons_count) + { + ESP_LOGW(ENA_BEACON_LOG, "last temporary beacon index does not match array index!"); + } + temp_beacons_count++; + } + else + { + temp_beacons[beacon_index].rssi = (temp_beacons[beacon_index].rssi + rssi) / 2; + temp_beacons[beacon_index].timestamp_last = unix_timestamp; + ESP_LOGD(ENA_BEACON_LOG, "New Timestamp for temporary beacon %d: %u", beacon_index, unix_timestamp); + ESP_LOG_BUFFER_HEX_LEVEL(ENA_BEACON_LOG, rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); + ESP_LOG_BUFFER_HEX_LEVEL(ENA_BEACON_LOG, aem, ENA_AEM_METADATA_LENGTH, ESP_LOG_DEBUG); + ena_storage_set_temp_beacon(temp_beacons_count, &temp_beacons[temp_beacons_count]); + } +} \ No newline at end of file diff --git a/main/ena-bluetooth-advertise.c b/components/ena/bluetooth-advertise.c similarity index 98% rename from main/ena-bluetooth-advertise.c rename to components/ena/bluetooth-advertise.c index eb06797..def2e1e 100644 --- a/main/ena-bluetooth-advertise.c +++ b/components/ena/bluetooth-advertise.c @@ -13,6 +13,7 @@ // limitations under the License. #include "esp_log.h" #include "esp_bt.h" +#include "esp_gap_ble_api.h" #include "ena-crypto.h" diff --git a/main/ena-bluetooth-scan.c b/components/ena/bluetooth-scan.c similarity index 89% rename from main/ena-bluetooth-scan.c rename to components/ena/bluetooth-scan.c index 0b0c13b..c5745a1 100644 --- a/main/ena-bluetooth-scan.c +++ b/components/ena/bluetooth-scan.c @@ -15,9 +15,10 @@ #include #include "esp_log.h" +#include "esp_gap_ble_api.h" #include "ena-crypto.h" -#include "ena-detection.h" +#include "ena-beacons.h" #include "ena-bluetooth-scan.h" @@ -36,6 +37,8 @@ static esp_ble_scan_params_t ena_scan_params = { void ena_bluetooth_scan_event_callback(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { + + uint32_t unix_timestamp = (uint32_t)time(NULL); esp_ble_gap_cb_param_t *p = (esp_ble_gap_cb_param_t *)param; switch (event) { @@ -44,7 +47,7 @@ void ena_bluetooth_scan_event_callback(esp_gap_ble_cb_event_t event, esp_ble_gap break; case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: ESP_LOGD(ENA_SCAN_LOG, "stopped scanning..."); - ena_detections_temp_refresh((uint32_t)time(NULL)); + ena_beacons_temp_refresh(unix_timestamp); break; case ESP_GAP_BLE_SCAN_RESULT_EVT: if (p->scan_rst.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) @@ -56,7 +59,8 @@ void ena_bluetooth_scan_event_callback(esp_gap_ble_cb_event_t event, esp_ble_gap { uint8_t service_data_length = 0; uint8_t *service_data = esp_ble_resolve_adv_data(p->scan_rst.ble_adv, 0x16, &service_data_length); - if (service_data_length != (sizeof(ENA_SERVICE_UUID) + ENA_KEY_LENGTH + ENA_AEM_METADATA_LENGTH)) { + if (service_data_length != (sizeof(ENA_SERVICE_UUID) + ENA_KEY_LENGTH + ENA_AEM_METADATA_LENGTH)) + { ESP_LOGW(ENA_SCAN_LOG, "received ENA Service with invalid payload"); break; } @@ -65,7 +69,7 @@ void ena_bluetooth_scan_event_callback(esp_gap_ble_cb_event_t event, esp_ble_gap memcpy(rpi, &service_data[sizeof(ENA_SERVICE_UUID)], ENA_KEY_LENGTH); uint8_t *aem = malloc(ENA_AEM_METADATA_LENGTH); memcpy(aem, &service_data[sizeof(ENA_SERVICE_UUID) + ENA_KEY_LENGTH], ENA_AEM_METADATA_LENGTH); - ena_detection((uint32_t)time(NULL), rpi, aem, p->scan_rst.rssi); + ena_beacon(unix_timestamp, rpi, aem, p->scan_rst.rssi); free(rpi); free(aem); } @@ -73,7 +77,7 @@ void ena_bluetooth_scan_event_callback(esp_gap_ble_cb_event_t event, esp_ble_gap else if (p->scan_rst.search_evt == ESP_GAP_SEARCH_INQ_CMPL_EVT) { scan_status = ENA_SCAN_STATUS_NOT_SCANNING; - ena_detections_temp_refresh((uint32_t)time(NULL)); + ena_beacons_temp_refresh(unix_timestamp); ESP_LOGD(ENA_SCAN_LOG, "finished scanning..."); } break; @@ -87,8 +91,8 @@ void ena_bluetooth_scan_init(void) { ESP_ERROR_CHECK(esp_ble_gap_set_scan_params(&ena_scan_params)); ESP_ERROR_CHECK(esp_ble_gap_register_callback(ena_bluetooth_scan_event_callback)); - // init temporary detections - ena_detections_temp_refresh((uint32_t)time(NULL)); + // init temporary beacons + ena_beacons_temp_refresh((uint32_t)time(NULL)); } void ena_bluetooth_scan_start(uint32_t duration) diff --git a/main/ena-crypto.c b/components/ena/crypto.c similarity index 100% rename from main/ena-crypto.c rename to components/ena/crypto.c diff --git a/main/ena.c b/components/ena/ena.c similarity index 80% rename from main/ena.c rename to components/ena/ena.c index 4b5315a..3efac43 100644 --- a/main/ena.c +++ b/components/ena/ena.c @@ -26,7 +26,6 @@ #include "nvs_flash.h" -#include "ena-datastructures.h" #include "ena-crypto.h" #include "ena-storage.h" #include "ena-bluetooth-scan.h" @@ -39,13 +38,13 @@ 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) + int random_interval = esp_random() % (2 * ENA_BT_RANDOMIZE_ROTATION_TIMEOUT_INTERVAL); + if (random_interval > ENA_BT_RANDOMIZE_ROTATION_TIMEOUT_INTERVAL) { - random_interval = ENA_RPI_ROLLING_RANDOM_INTERVAL - random_interval; + random_interval = ENA_BT_RANDOMIZE_ROTATION_TIMEOUT_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); + next_rpi_timestamp = timestamp + ENA_BT_ROTATION_TIMEOUT_INTERVAL + random_interval; + ESP_LOGD(ENA_LOG, "next rpi at %u (%u from %u)", next_rpi_timestamp, (ENA_BT_ROTATION_TIMEOUT_INTERVAL + random_interval), timestamp); } void ena_run(void *pvParameter) @@ -56,10 +55,12 @@ void ena_run(void *pvParameter) { unix_timestamp = (uint32_t)time(NULL); current_enin = ena_crypto_enin(unix_timestamp); - if (current_enin - last_tek.enin >= ENA_TEK_ROLLING_PERIOD) + if (current_enin - last_tek.enin >= last_tek.rolling_period) { ena_crypto_tek(last_tek.key_data); last_tek.enin = current_enin; + // validity only to next day 00:00 + last_tek.rolling_period = ENA_TEK_ROLLING_PERIOD - (last_tek.enin % ENA_TEK_ROLLING_PERIOD); ena_storage_write_tek(&last_tek); } @@ -93,6 +94,9 @@ void ena_run(void *pvParameter) void ena_start(void) { +#if (CONFIG_ENA_STORAGE_ERASE) + ena_storage_erase(); +#endif // init NVS for BLE esp_err_t ret; ret = nvs_flash_init(); @@ -141,17 +145,20 @@ void ena_start(void) // init ENA ena_crypto_init(); - uint32_t current_enin = ena_crypto_enin((uint32_t)time(NULL)); - + uint32_t unix_timestamp = (uint32_t)time(NULL); + + uint32_t current_enin = ena_crypto_enin(unix_timestamp); uint32_t tek_count = ena_storage_read_last_tek(&last_tek); - ena_next_rpi_timestamp((uint32_t)time(NULL)); + ena_next_rpi_timestamp(unix_timestamp); // read last TEK or create new - if (tek_count == 0 || (current_enin - last_tek.enin) >= ENA_TEK_ROLLING_PERIOD) + if (tek_count == 0 || (current_enin - last_tek.enin) >= last_tek.rolling_period) { ena_crypto_tek(last_tek.key_data); - last_tek.enin = ena_crypto_enin((uint32_t)time(NULL)); + last_tek.enin = ena_crypto_enin(unix_timestamp); + // validity only to next day 00:00 + last_tek.rolling_period = ENA_TEK_ROLLING_PERIOD - (last_tek.enin % ENA_TEK_ROLLING_PERIOD); ena_storage_write_tek(&last_tek); } diff --git a/main/ena-detection.h b/components/ena/include/ena-beacons.h similarity index 63% rename from main/ena-detection.h rename to components/ena/include/ena-beacons.h index f2826d2..872ed40 100644 --- a/main/ena-detection.h +++ b/components/ena/include/ena-beacons.h @@ -11,37 +11,35 @@ // 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_BEACON_H_ +#define _ena_BEACON_H_ -#ifndef _ena_DETECTION_H_ -#define _ena_DETECTION_H_ - -#define ENA_DETECTION_LOG "ESP-ENA-detection" // TAG for Logging - -#define ENA_DETECTION_TRESHOLD (300) // meet for longer than 5 minutes +#define ENA_BEACON_LOG "ESP-ENA-beacon" // TAG for Logging +#define ENA_BEACON_TRESHOLD (CONFIG_ENA_BEACON_TRESHOLD) // meet for longer than 5 minutes /** - * @brief check temporary detection for full detection or expiring + * @brief check temporary beacon for threshold or expiring * - * This function checks all current temporary detections if the contact threshold is + * This function checks all current temporary beacons 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); +void ena_beacons_temp_refresh(uint32_t unix_timestamp); /** - * @brief handle new detection received from a BLE scan + * @brief handle new beacon 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] unix_timestamp UNIX timestamp when beacon 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); +void ena_beacon(uint32_t unix_timestamp, uint8_t *rpi, uint8_t *aem, int rssi); #endif \ No newline at end of file diff --git a/main/ena-bluetooth-advertise.h b/components/ena/include/ena-bluetooth-advertise.h similarity index 97% rename from main/ena-bluetooth-advertise.h rename to components/ena/include/ena-bluetooth-advertise.h index 1bb29f0..3478194 100644 --- a/main/ena-bluetooth-advertise.h +++ b/components/ena/include/ena-bluetooth-advertise.h @@ -11,14 +11,9 @@ // 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_ -#include "esp_gap_ble_api.h" - #define ENA_ADVERTISE_LOG "ESP-ENA-advertise" // TAG for Logging #define ENA_BLUETOOTH_TAG_DATA (0x1A) // Data for BLE payload TAG diff --git a/main/ena-bluetooth-scan.h b/components/ena/include/ena-bluetooth-scan.h similarity index 86% rename from main/ena-bluetooth-scan.h rename to components/ena/include/ena-bluetooth-scan.h index 06a3953..8309c64 100644 --- a/main/ena-bluetooth-scan.h +++ b/components/ena/include/ena-bluetooth-scan.h @@ -11,16 +11,12 @@ // 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_ -#define ENA_SCAN_LOG "ESP-ENA-scan" // TAG for Logging - -#define ENA_SCANNING_TIME (30) // scan for 30 seconds -#define ENA_SCANNING_INTERVAL (300) // scan every 5 minutes - -#include "esp_gap_ble_api.h" +#define ENA_SCAN_LOG "ESP-ENA-scan" // TAG for Logging +#define ENA_SCANNING_TIME (CONFIG_ENA_SCANNING_TIME) // time how long a scan should run +#define ENA_SCANNING_INTERVAL (CONFIG_ENA_SCANNING_INTERVAL) // interval for next scan to happen /** * @brief status of BLE scan diff --git a/main/ena-crypto.h b/components/ena/include/ena-crypto.h similarity index 92% rename from main/ena-crypto.h rename to components/ena/include/ena-crypto.h index 0a9dab2..0aab2df 100644 --- a/main/ena-crypto.h +++ b/components/ena/include/ena-crypto.h @@ -11,14 +11,13 @@ // 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_ -#define ENA_TIME_WINDOW (600) // time window every 10 minutes -#define ENA_KEY_LENGTH (16) // key length -#define ENA_AEM_METADATA_LENGTH (4) // size of metadata -#define ENA_TEK_ROLLING_PERIOD (144) // TEKRollingPeriod +#define ENA_TIME_WINDOW (600) // time window every 10 minutes +#define ENA_KEY_LENGTH (16) // key length +#define ENA_AEM_METADATA_LENGTH (4) // size of metadata +#define ENA_TEK_ROLLING_PERIOD (CONFIG_ENA_TEK_ROLLING_PERIOD) // TEKRollingPeriod #include diff --git a/components/ena/include/ena-storage.h b/components/ena/include/ena-storage.h new file mode 100644 index 0000000..847450a --- /dev/null +++ b/components/ena/include/ena-storage.h @@ -0,0 +1,221 @@ +// 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" + +#define ENA_STORAGE_LOG "ESP-ENA-storage" // TAG for Logging +#define ENA_STORAGE_PARTITION_NAME (CONFIG_ENA_STORAGE_PARTITION_NAME) // name of partition to use for storing +#define ENA_STORAGE_START_ADDRESS (CONFIG_ENA_STORAGE_START_ADDRESS) // start address of storage +#define ENA_STORAGE_TEK_MAX (CONFIG_ENA_STORAGE_TEK_MAX) // Period of storing TEKs // length of a stored beacon -> RPI keysize + AEM size + 4 Bytes for ENIN + 4 Bytes for RSSI +#define ENA_STORAGE_TEMP_BEACONS_MAX (CONFIG_ENA_STORAGE_TEMP_BEACONS_MAX) // Maximum number of temporary stored beacons + +/** + * @brief structure for TEK + */ +typedef struct __attribute__((__packed__)) +{ + 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 +} ena_tek_t; + +/** + * @brief sturcture for storing a temporary beacon + */ +typedef struct __attribute__((__packed__)) +{ + uint8_t rpi[ENA_KEY_LENGTH]; // received RPI of beacon + uint8_t aem[ENA_AEM_METADATA_LENGTH]; // received AEM of beacon + uint32_t timestamp_first; // timestamp of first recognition + uint32_t timestamp_last; // timestamp of last recognition + int rssi; // average measured RSSI +} ena_temp_beacon_t; + +/** + * @brief sturcture for permanently storing a beacon after threshold reached + */ +typedef struct __attribute__((__packed__)) +{ + uint8_t rpi[ENA_KEY_LENGTH]; // received RPI of beacon + uint8_t aem[ENA_AEM_METADATA_LENGTH]; // received AEM of beacon + uint32_t timestamp; // timestamp of last recognition + int rssi; // average measured RSSI +} ena_beacon_t; + +/** + * @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); + +/** + * @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); + +/** + * @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); + +/** + * @brief get last stored TEK + * + * @param[out] tek pointer to write last TEK to + * + * @return + * total number of TEKs stored + */ +uint32_t ena_storage_read_last_tek(ena_tek_t *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); + +/** + * @brief get number of stored temporary beacons + * + * @return + * total number of temporary beacons stored + */ +uint32_t ena_storage_temp_beacons_count(void); + +/** + * @brief get temporary beacon at given index + * + * @param[in] index the index of the temporary beacon to read + * @param[out] beacon pointer to temporary to write to + */ +void ena_storage_get_temp_beacon(uint32_t index, ena_temp_beacon_t *beacon); + +/** + * @brief store temporary beacon + * + * @param[in] beacon new temporary beacon to store + * + * @return + * index of new stored beacon + */ +uint32_t ena_storage_add_temp_beacon(ena_temp_beacon_t *beacon); + +/** + * @brief store temporary beacon at given index + * + * @param[in] index the index of the temporary beacon to overwrite + * @param[in] beacon temporary beacon to store + */ +void ena_storage_set_temp_beacon(uint32_t index, ena_temp_beacon_t *beacon); + +/** + * @brief remove temporary beacon at given index + * + * @param[in] index the index of the temporary beacon to remove + */ +void ena_storage_remove_temp_beacon(uint32_t index); + +/** + * @brief get number of permanently stored beacons + * + * @return + * total number of beacons stored + */ +uint32_t ena_storage_beacons_count(void); + +/** + * @brief get permanently stored beacon at given index + * + * @param[in] index the index of the beacon to read + * @param[out] beacon pointer to to write to + */ +void ena_storage_get_beacon(uint32_t index, ena_beacon_t *beacon); + +/** + * @brief permanently store beacon + * + * @param[in] beacon new beacon to permanently store + */ +void ena_storage_add_beacon(ena_beacon_t *beacon); + +/** + * @brief erase the storage + * + * This function completely deletes all stored data and resets the counters + * of TEKs, temporary beacon and beacon to zero. + */ +void ena_storage_erase(void); + +/** + * @brief erase all stored TEKs + * + * This function deletes all stored TEKs and resets counter to zero. + */ +void ena_storage_erase_tek(void); + +/** + * @brief erase all stored temporary beacons + * + * This function deletes all stored temporary beacons and resets counter to zero. + */ +void ena_storage_erase_temporary_beacon(void); + +/** + * @brief erase all permanently stored beacons + * + * This function deletes all stored beacons and resets counter to zero. + */ +void ena_storage_erase_beacon(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 beacons to serial output + * + * This function prints all stored temporary beacons to serial output in + * the following CSV format: #,timestamp_first,timestamp_last,rpi,aem,rssi + */ +void ena_storage_dump_temp_beacons(void); + +/** + * @brief dump all stored beacons to serial output + * + * This function prints all stored beacons to serial output in + * the following CSV format: #,timestamp,rpi,aem,rssi + */ +void ena_storage_dump_beacons(void); + +#endif \ No newline at end of file diff --git a/main/ena.h b/components/ena/include/ena.h similarity index 66% rename from main/ena.h rename to components/ena/include/ena.h index f69f45d..f3d54b4 100644 --- a/main/ena.h +++ b/components/ena/include/ena.h @@ -11,14 +11,12 @@ // 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 +#define ENA_LOG "ESP-ENA" // TAG for Logging +#define ENA_BT_ROTATION_TIMEOUT_INTERVAL (CONFIG_ENA_BT_ROTATION_TIMEOUT_INTERVAL) // change advertising payload and therefore the BT address +#define ENA_BT_RANDOMIZE_ROTATION_TIMEOUT_INTERVAL (CONFIG_ENA_BT_RANDOMIZE_ROTATION_TIMEOUT_INTERVAL) // random intervall change for BT address change /** * @brief Start Exposure Notification API diff --git a/main/ena-storage.c b/components/ena/storage.c similarity index 53% rename from main/ena-storage.c rename to components/ena/storage.c index 1a6ae01..77ce6c8 100644 --- a/main/ena-storage.c +++ b/components/ena/storage.c @@ -14,27 +14,26 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_partition.h" -#include "esp_spi_flash.h" #include "esp_log.h" +#include "esp_partition.h" #include "ena-storage.h" #include "ena-crypto.h" #define BLOCK_SIZE (4096) -const int ENA_STORAGE_TEK_COUNT_ADDRESS = (0); // starting address for TEK COUNT +const int ENA_STORAGE_TEK_COUNT_ADDRESS = (ENA_STORAGE_START_ADDRESS); // starting address for TEK COUNT 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)); +const int ENA_STORAGE_TEMP_BEACONS_COUNT_ADDRESS = (ENA_STORAGE_TEK_START_ADDRESS + sizeof(ena_tek_t) * ENA_STORAGE_TEK_MAX); +const int ENA_STORAGE_TEMP_BEACONS_START_ADDRESS = (ENA_STORAGE_TEMP_BEACONS_COUNT_ADDRESS + sizeof(uint32_t)); +const int ENA_STORAGE_BEACONS_COUNT_ADDRESS = (ENA_STORAGE_TEMP_BEACONS_START_ADDRESS + sizeof(ena_temp_beacon_t) * ENA_STORAGE_TEMP_BEACONS_MAX); +const int ENA_STORAGE_BEACONS_START_ADDRESS = (ENA_STORAGE_BEACONS_COUNT_ADDRESS + sizeof(uint32_t)); void ena_storage_read(size_t address, void *data, size_t size) { ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_read"); const esp_partition_t *partition = esp_partition_find_first( - ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, PARTITION_NAME); + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, ENA_STORAGE_PARTITION_NAME); assert(partition); ESP_ERROR_CHECK(esp_partition_read(partition, address, data, size)); vTaskDelay(1); @@ -51,7 +50,7 @@ void ena_storage_write(size_t address, void *data, size_t size) if (address + size <= (block_num + 1) * BLOCK_SIZE) { const esp_partition_t *partition = esp_partition_find_first( - ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, PARTITION_NAME); + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, ENA_STORAGE_PARTITION_NAME); assert(partition); const int block_start = block_num * BLOCK_SIZE; const int block_address = address - block_start; @@ -103,7 +102,7 @@ void ena_storage_shift_delete(size_t address, size_t end_address, size_t 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); + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, ENA_STORAGE_PARTITION_NAME); assert(partition); int block_num_end = end_address / BLOCK_SIZE; @@ -159,7 +158,7 @@ uint32_t ena_storage_read_last_tek(ena_tek_t *tek) { return 0; } - uint8_t index = (tek_count % ENA_STORAGE_TEK_STORE_PERIOD) - 1; + uint8_t index = (tek_count % ENA_STORAGE_TEK_MAX) - 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); @@ -174,7 +173,7 @@ void ena_storage_write_tek(ena_tek_t *tek) 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); + uint8_t index = (tek_count % ENA_STORAGE_TEK_MAX); ena_storage_write(ENA_STORAGE_TEK_START_ADDRESS + index * sizeof(ena_tek_t), tek, sizeof(ena_tek_t)); tek_count++; @@ -185,116 +184,116 @@ void ena_storage_write_tek(ena_tek_t *tek) ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_write_tek"); } -uint32_t ena_storage_temp_detections_count(void) +uint32_t ena_storage_temp_beacons_count(void) { - ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_temp_detections_count"); + ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_temp_beacons_count"); uint32_t count = 0; - ena_storage_read(ENA_STORAGE_TEMP_DETECTIONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); + ena_storage_read(ENA_STORAGE_TEMP_BEACONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); ESP_LOGD(ENA_STORAGE_LOG, "read temp contancts count: %u", count); - ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_temp_detections_count"); + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_temp_beacons_count"); return count; } -void ena_storage_get_temp_detection(uint32_t index, ena_temp_detection_t *detection) +void ena_storage_get_temp_beacon(uint32_t index, ena_temp_beacon_t *beacon) { - 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"); + ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_read_temp_beacon"); + ena_storage_read(ENA_STORAGE_TEMP_BEACONS_START_ADDRESS + index * sizeof(ena_temp_beacon_t), beacon, sizeof(ena_temp_beacon_t)); + ESP_LOGD(ENA_STORAGE_LOG, "read temp beacon: first %u, last %u and rssi %d", beacon->timestamp_first, beacon->timestamp_last, beacon->rssi); + ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, beacon->rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); + ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, beacon->aem, ENA_AEM_METADATA_LENGTH, ESP_LOG_DEBUG); + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_read_temp_beacon"); } -uint32_t ena_storage_add_temp_detection(ena_temp_detection_t *detection) +uint32_t ena_storage_add_temp_beacon(ena_temp_beacon_t *beacon) { - ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_add_temp_detection"); - uint32_t count = ena_storage_temp_detections_count(); - // 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); + ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_add_temp_beacon"); + uint32_t count = ena_storage_temp_beacons_count(); + // overwrite older temporary beacons?! + uint8_t index = count % ENA_STORAGE_TEMP_BEACONS_MAX; + ena_storage_set_temp_beacon(index, beacon); + ESP_LOGD(ENA_STORAGE_LOG, "add temp beacon at %u: first %u, last %u and rssi %d", index, beacon->timestamp_first, beacon->timestamp_last, beacon->rssi); + ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, beacon->rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); + ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, beacon->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, "END ena_storage_add_temp_detection"); + ena_storage_write(ENA_STORAGE_TEMP_BEACONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_add_temp_beacon"); return count - 1; } -void ena_storage_set_temp_detection(uint32_t index, ena_temp_detection_t *detection) +void ena_storage_set_temp_beacon(uint32_t index, ena_temp_beacon_t *beacon) { - 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, "START ena_storage_set_temp_beacon"); + ena_storage_write(ENA_STORAGE_TEMP_BEACONS_START_ADDRESS + index * sizeof(ena_temp_beacon_t), beacon, sizeof(ena_temp_beacon_t)); + ESP_LOGD(ENA_STORAGE_LOG, "set temp beacon at %u: first %u, last %u and rssi %d", index, beacon->timestamp_first, beacon->timestamp_last, beacon->rssi); + ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, beacon->rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); + ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, beacon->aem, ENA_AEM_METADATA_LENGTH, ESP_LOG_DEBUG); - ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_set_temp_detection"); + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_set_temp_beacon"); } -void ena_storage_remove_temp_detection(uint32_t index) +void ena_storage_remove_temp_beacon(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_temp_detection_t); - size_t address_to = ENA_STORAGE_TEMP_DETECTIONS_START_ADDRESS + count * sizeof(ena_temp_detection_t); + ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_remove_temp_beacon"); + uint32_t count = ena_storage_temp_beacons_count(); + size_t address_from = ENA_STORAGE_TEMP_BEACONS_START_ADDRESS + index * sizeof(ena_temp_beacon_t); + size_t address_to = ENA_STORAGE_TEMP_BEACONS_START_ADDRESS + count * sizeof(ena_temp_beacon_t); - ena_storage_shift_delete(address_from, address_to, sizeof(ena_temp_detection_t)); + ena_storage_shift_delete(address_from, address_to, sizeof(ena_temp_beacon_t)); count--; - ena_storage_write(ENA_STORAGE_TEMP_DETECTIONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); - ESP_LOGD(ENA_STORAGE_LOG, "remove temp detection: %u", index); - ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_remove_temp_detection"); + ena_storage_write(ENA_STORAGE_TEMP_BEACONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); + ESP_LOGD(ENA_STORAGE_LOG, "remove temp beacon: %u", index); + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_remove_temp_beacon"); } -uint32_t ena_storage_detections_count(void) +uint32_t ena_storage_beacons_count(void) { - ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_detections_count"); + ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_beacons_count"); uint32_t count = 0; - ena_storage_read(ENA_STORAGE_DETECTIONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); + ena_storage_read(ENA_STORAGE_BEACONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); ESP_LOGD(ENA_STORAGE_LOG, "read contancts count: %u", count); - ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_detections_count"); + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_beacons_count"); return count; } -void ena_storage_get_detection(uint32_t index, ena_detection_t *detection) +void ena_storage_get_beacon(uint32_t index, ena_beacon_t *beacon) { - 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)); - ESP_LOGD(ENA_STORAGE_LOG, "read detection: timestamp %u and rssi %d", detection->timestamp, 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_detection"); + ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_read_beacon"); + ena_storage_read(ENA_STORAGE_BEACONS_START_ADDRESS + index * sizeof(ena_beacon_t), beacon, sizeof(ena_beacon_t)); + ESP_LOGD(ENA_STORAGE_LOG, "read beacon: timestamp %u and rssi %d", beacon->timestamp, beacon->rssi); + ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, beacon->rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); + ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, beacon->aem, ENA_AEM_METADATA_LENGTH, ESP_LOG_DEBUG); + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_read_beacon"); } -void ena_storage_add_detection(ena_detection_t *detection) +void ena_storage_add_beacon(ena_beacon_t *beacon) { - 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); - uint32_t count = ena_storage_detections_count(); - ena_storage_write(ENA_STORAGE_DETECTIONS_START_ADDRESS + count * sizeof(ena_detection_t), detection, sizeof(ena_detection_t)); + ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_write_beacon"); + ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, beacon->rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); + uint32_t count = ena_storage_beacons_count(); + ena_storage_write(ENA_STORAGE_BEACONS_START_ADDRESS + count * sizeof(ena_beacon_t), beacon, sizeof(ena_beacon_t)); count++; - ena_storage_write(ENA_STORAGE_DETECTIONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); - ESP_LOGD(ENA_STORAGE_LOG, "write detection: timestamp %u and rssi %d", detection->timestamp, 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_detection"); + ena_storage_write(ENA_STORAGE_BEACONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); + ESP_LOGD(ENA_STORAGE_LOG, "write beacon: timestamp %u and rssi %d", beacon->timestamp, beacon->rssi); + ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, beacon->rpi, ENA_KEY_LENGTH, ESP_LOG_DEBUG); + ESP_LOG_BUFFER_HEXDUMP(ENA_STORAGE_LOG, beacon->aem, ENA_AEM_METADATA_LENGTH, ESP_LOG_DEBUG); + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_write_beacon"); } void ena_storage_erase(void) { ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_erase"); const esp_partition_t *partition = esp_partition_find_first( - ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, PARTITION_NAME); + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, ENA_STORAGE_PARTITION_NAME); assert(partition); ESP_ERROR_CHECK(esp_partition_erase_range(partition, 0, partition->size)); - ESP_LOGI(ENA_STORAGE_LOG, "erased partition %s!", PARTITION_NAME); + ESP_LOGI(ENA_STORAGE_LOG, "erased partition %s!", ENA_STORAGE_PARTITION_NAME); uint32_t count = 0; 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)); + ena_storage_write(ENA_STORAGE_TEMP_BEACONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); + ena_storage_write(ENA_STORAGE_BEACONS_COUNT_ADDRESS, &count, sizeof(uint32_t)); ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_erase"); } @@ -305,9 +304,9 @@ 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; + uint8_t stored = ENA_STORAGE_TEK_MAX; - if (tek_count < ENA_STORAGE_TEK_STORE_PERIOD) + if (tek_count < ENA_STORAGE_TEK_MAX) { stored = tek_count; } @@ -320,40 +319,40 @@ void ena_storage_erase_tek(void) ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_erase_teks"); } -void ena_storage_erase_temporary_detection(void) +void ena_storage_erase_temporary_beacon(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; + ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_erase_temporary_beacons"); + uint32_t beacon_count = 0; + ena_storage_read(ENA_STORAGE_TEMP_BEACONS_COUNT_ADDRESS, &beacon_count, sizeof(uint32_t)); + uint32_t stored = ENA_STORAGE_TEMP_BEACONS_MAX; - if (detection_count < ENA_STORAGE_TEMP_DETECTIONS_MAX) + if (beacon_count < ENA_STORAGE_TEMP_BEACONS_MAX) { - stored = detection_count; + stored = beacon_count; } - size_t size = sizeof(uint32_t) + stored * sizeof(ena_temp_detection_t); + size_t size = sizeof(uint32_t) + stored * sizeof(ena_temp_beacon_t); uint8_t *zeros = calloc(size, sizeof(uint8_t)); - ena_storage_write(ENA_STORAGE_TEMP_DETECTIONS_COUNT_ADDRESS, zeros, size); + ena_storage_write(ENA_STORAGE_TEMP_BEACONS_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"); + ESP_LOGI(ENA_STORAGE_LOG, "erased %d temporary beacons (size %u at %u)", stored, size, ENA_STORAGE_TEMP_BEACONS_COUNT_ADDRESS); + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_erase_temporary_beacons"); } -void ena_storage_erase_detection(void) +void ena_storage_erase_beacon(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)); + ESP_LOGD(ENA_STORAGE_LOG, "START ena_storage_erase_beacon"); + uint32_t beacon_count = 0; + ena_storage_read(ENA_STORAGE_BEACONS_COUNT_ADDRESS, &beacon_count, sizeof(uint32_t)); - size_t size = sizeof(uint32_t) + detection_count * sizeof(ena_detection_t); + size_t size = sizeof(uint32_t) + beacon_count * sizeof(ena_beacon_t); uint8_t *zeros = calloc(size, sizeof(uint8_t)); - ena_storage_write(ENA_STORAGE_DETECTIONS_COUNT_ADDRESS, zeros, size); + ena_storage_write(ENA_STORAGE_BEACONS_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"); + ESP_LOGI(ENA_STORAGE_LOG, "erased %d beacons (size %u at %u)", beacon_count, size, ENA_STORAGE_BEACONS_COUNT_ADDRESS); + ESP_LOGD(ENA_STORAGE_LOG, "END ena_storage_erase_beacon"); } void ena_storage_dump_hash_array(uint8_t *data, size_t size) @@ -376,15 +375,15 @@ void ena_storage_dump_tek(void) ena_tek_t tek; 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; + uint8_t stored = ENA_STORAGE_TEK_MAX; - if (tek_count < ENA_STORAGE_TEK_STORE_PERIOD) + if (tek_count < ENA_STORAGE_TEK_MAX) { stored = tek_count; } ESP_LOGD(ENA_STORAGE_LOG, "%u TEKs (%u stored)\n", tek_count, stored); - printf("#,enin,tek\n"); + printf("#,enin,tek,rolling_period\n"); for (int i = 0; i < stored; i++) { @@ -392,49 +391,49 @@ void ena_storage_dump_tek(void) ena_storage_read(address, &tek, sizeof(ena_tek_t)); printf("%d,%u,", i, tek.enin); ena_storage_dump_hash_array(tek.key_data, ENA_KEY_LENGTH); - printf("\n"); + printf(",%u\n", tek.rolling_period); } } -void ena_storage_dump_temp_detections(void) +void ena_storage_dump_temp_beacons(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)); - uint32_t stored = ENA_STORAGE_TEMP_DETECTIONS_MAX; + ena_temp_beacon_t beacon; + uint32_t beacon_count = 0; + ena_storage_read(ENA_STORAGE_TEMP_BEACONS_COUNT_ADDRESS, &beacon_count, sizeof(uint32_t)); + uint32_t stored = ENA_STORAGE_TEMP_BEACONS_MAX; - if (detection_count < ENA_STORAGE_TEMP_DETECTIONS_MAX) + if (beacon_count < ENA_STORAGE_TEMP_BEACONS_MAX) { - stored = detection_count; + stored = beacon_count; } - ESP_LOGD(ENA_STORAGE_LOG, "%u temporary detections (%u stored)\n", detection_count, stored); + ESP_LOGD(ENA_STORAGE_LOG, "%u temporary beacons (%u stored)\n", beacon_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); + ena_storage_get_temp_beacon(i, &beacon); + printf("%d,%u,%u,", i, beacon.timestamp_first, beacon.timestamp_last); + ena_storage_dump_hash_array(beacon.rpi, ENA_KEY_LENGTH); printf(","); - ena_storage_dump_hash_array(detection.aem, ENA_AEM_METADATA_LENGTH); - printf(",%d\n", detection.rssi); + ena_storage_dump_hash_array(beacon.aem, ENA_AEM_METADATA_LENGTH); + printf(",%d\n", beacon.rssi); } } -void ena_storage_dump_detections(void) +void ena_storage_dump_beacons(void) { - ena_detection_t detection; - uint32_t detection_count = 0; - ena_storage_read(ENA_STORAGE_DETECTIONS_COUNT_ADDRESS, &detection_count, sizeof(uint32_t)); - ESP_LOGD(ENA_STORAGE_LOG, "%u detections\n", detection_count); + ena_beacon_t beacon; + uint32_t beacon_count = 0; + ena_storage_read(ENA_STORAGE_BEACONS_COUNT_ADDRESS, &beacon_count, sizeof(uint32_t)); + ESP_LOGD(ENA_STORAGE_LOG, "%u beacons\n", beacon_count); printf("#,timestamp,rpi,aem,rssi\n"); - for (int i = 0; i < detection_count; i++) + for (int i = 0; i < beacon_count; i++) { - ena_storage_get_detection(i, &detection); - printf("%d,%u,", i, detection.timestamp); - ena_storage_dump_hash_array(detection.rpi, ENA_KEY_LENGTH); + ena_storage_get_beacon(i, &beacon); + printf("%d,%u,", i, beacon.timestamp); + ena_storage_dump_hash_array(beacon.rpi, ENA_KEY_LENGTH); printf(","); - ena_storage_dump_hash_array(detection.aem, ENA_AEM_METADATA_LENGTH); - printf(",%d\n", detection.rssi); + ena_storage_dump_hash_array(beacon.aem, ENA_AEM_METADATA_LENGTH); + printf(",%d\n", beacon.rssi); } } \ No newline at end of file diff --git a/components/i2c-main/CMakeLists.txt b/components/i2c-main/CMakeLists.txt new file mode 100644 index 0000000..bee6255 --- /dev/null +++ b/components/i2c-main/CMakeLists.txt @@ -0,0 +1,7 @@ +idf_component_register( + SRCS + "i2c-main.c" + INCLUDE_DIRS "." + PRIV_REQUIRES + driver +) \ No newline at end of file diff --git a/components/i2c-main/i2c-main.c b/components/i2c-main/i2c-main.c new file mode 100644 index 0000000..54fb6e5 --- /dev/null +++ b/components/i2c-main/i2c-main.c @@ -0,0 +1,39 @@ +// 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 "driver/i2c.h" + +#include "i2c-main.h" + +static bool i2c_initialized = false; + +void i2c_main_init() +{ + i2c_config_t i2c_config = { + .mode = I2C_MODE_MASTER, + .sda_io_num = I2C_SDA_PIN, + .scl_io_num = I2C_SCL_PIN, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = I2C_CLK_SPEED}; + ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &i2c_config)); + ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0)); +} + +bool i2c_is_initialized() +{ + return i2c_initialized; +} \ No newline at end of file diff --git a/components/i2c-main/i2c-main.h b/components/i2c-main/i2c-main.h new file mode 100644 index 0000000..d117ca8 --- /dev/null +++ b/components/i2c-main/i2c-main.h @@ -0,0 +1,35 @@ +// 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 _i2c_main_H_ +#define _i2c_main_H_ + +#define I2C_SDA_PIN (21) +#define I2C_SCL_PIN (22) +#define I2C_CLK_SPEED (1000000) + +/** + * @brief initialize main I2C interface + */ +void i2c_main_init(); + +/** + * @brief check if I2C interface already initialized + * + * @return + * - false I2C not initialized + * - true I2C initialized + */ +bool i2c_is_initialized(); + +#endif \ No newline at end of file diff --git a/components/ssd1306/CMakeLists.txt b/components/ssd1306/CMakeLists.txt new file mode 100644 index 0000000..fed4b96 --- /dev/null +++ b/components/ssd1306/CMakeLists.txt @@ -0,0 +1,7 @@ +idf_component_register( + SRCS + "ssd1306.c" + INCLUDE_DIRS "include" + PRIV_REQUIRES + i2c-main +) \ No newline at end of file diff --git a/components/ssd1306/include/ssd1306-ascii.h b/components/ssd1306/include/ssd1306-ascii.h new file mode 100644 index 0000000..9f465d8 --- /dev/null +++ b/components/ssd1306/include/ssd1306-ascii.h @@ -0,0 +1,538 @@ +// 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 _ssd1306_FONT_H_ +#define _ssd1306_FONT_H_ + +/** + * @brief constant containing a 5x8 ascii font + */ +const uint8_t ascii_font_5x8[256][5] = { + {0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00 + {0x1E, 0x35, 0x31, 0x35, 0x1E}, // 0x01 + {0x1E, 0x35, 0x37, 0x35, 0x1E}, // 0x02 + {0x0E, 0x1F, 0x3E, 0x1F, 0x0E}, // 0x03 + {0x08, 0x1C, 0x7F, 0x1C, 0x08}, // 0x04 + {0x18, 0x4A, 0x7F, 0x4A, 0x18}, // 0x05 + {0x1C, 0x4E, 0x7F, 0x4E, 0x1C}, // 0x06 + {0x00, 0x00, 0x00, 0x00, 0x00}, // 0x07 + {0x00, 0x00, 0x00, 0x00, 0x00}, // 0x08 + {0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09 + {0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0A + {0x38, 0x44, 0x44, 0x47, 0x3B}, // 0x0B + {0x0E, 0x51, 0xF1, 0x51, 0x0E}, // 0x0C + {0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D + {0x60, 0x7E, 0x02, 0x33, 0x3F}, // 0x0E + {0x2A, 0x1C, 0x36, 0x1C, 0x2A}, // 0x0F + {0x3E, 0x1C, 0x1C, 0x08, 0x08}, // 0x10 + {0x08, 0x08, 0x1C, 0x1C, 0x3E}, // 0x11 + {0x00, 0x22, 0x7F, 0x22, 0x00}, // 0x12 + {0x00, 0x2E, 0x00, 0x2E, 0x00}, // 0x13 + {0x06, 0x7F, 0x01, 0x7F, 0x00}, // 0x14 + {0x00, 0x4A, 0x55, 0x29, 0x00}, // 0x15 + {0x00, 0x18, 0x18, 0x18, 0x18}, // 0x16 + {0x00, 0x4A, 0x5F, 0x4A, 0x00}, // 0x17 + {0x00, 0x02, 0x7F, 0x02, 0x00}, // 0x18 + {0x00, 0x20, 0x7F, 0x20, 0x00}, // 0x19 + {0x00, 0x08, 0x08, 0x1C, 0x08}, // 0x1A + {0x00, 0x08, 0x1C, 0x08, 0x08}, // 0x1B + {0x00, 0x3C, 0x20, 0x20, 0x20}, // 0x1C + {0x08, 0x1C, 0x08, 0x1C, 0x08}, // 0x1D + {0x20, 0x38, 0x3E, 0x38, 0x20}, // 0x1E + {0x02, 0x0E, 0x3E, 0x0E, 0x02}, // 0x1F + {0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 (Space) + {0x00, 0x00, 0x9E, 0x00, 0x00}, // 0x21 ! + {0x00, 0x0E, 0x00, 0x0E, 0x00}, // 0x22 " + {0x28, 0xFE, 0x28, 0xFE, 0x28}, // 0x23 # + {0x48, 0x54, 0xFE, 0x54, 0x24}, // 0x24 $ + {0x46, 0x26, 0x10, 0xC8, 0xC4}, // 0x25 % + {0x6C, 0x92, 0xAA, 0x44, 0xA0}, // 0x26 & + {0x00, 0x0A, 0x06, 0x00, 0x00}, // 0x27 ' + {0x00, 0x38, 0x44, 0x82, 0x00}, // 0x28 ( + {0x00, 0x82, 0x44, 0x38, 0x00}, // 0x29 ) + {0x10, 0x54, 0x38, 0x54, 0x10}, // 0x2A * + {0x10, 0x10, 0x7C, 0x10, 0x10}, // 0x2B + + {0x00, 0xA0, 0x60, 0x00, 0x00}, // 0x2C , + {0x10, 0x10, 0x10, 0x10, 0x10}, // 0x2D - + {0x00, 0x60, 0x60, 0x00, 0x00}, // 0x2E . + {0x40, 0x20, 0x10, 0x08, 0x04}, // 0x2F / + {0x7C, 0xA2, 0x92, 0x8A, 0x7C}, // 0x30 0 + {0x00, 0x84, 0xFE, 0x80, 0x00}, // 0x31 1 + {0x84, 0xC2, 0xA2, 0x92, 0x8C}, // 0x32 2 + {0x42, 0x82, 0x8A, 0x96, 0x62}, // 0x33 3 + {0x30, 0x28, 0x24, 0xFE, 0x20}, // 0x34 4 + {0x4E, 0x8A, 0x8A, 0x8A, 0x72}, // 0x35 5 + {0x78, 0x94, 0x92, 0x92, 0x60}, // 0x36 6 + {0x02, 0xE2, 0x12, 0x0A, 0x06}, // 0x37 7 + {0x6C, 0x92, 0x92, 0x92, 0x6C}, // 0x38 8 + {0x0C, 0x92, 0x92, 0x52, 0x3C}, // 0x39 9 + {0x00, 0x6C, 0x6C, 0x00, 0x00}, // 0x3A : + {0x00, 0xAC, 0x6C, 0x00, 0x00}, // 0x3B ; + {0x00, 0x10, 0x28, 0x44, 0x82}, // 0x3C < + {0x28, 0x28, 0x28, 0x28, 0x28}, // 0x3D = + {0x82, 0x44, 0x28, 0x10, 0x00}, // 0x3E > + {0x04, 0x02, 0xA2, 0x12, 0x0C}, // 0x3F ? + {0x64, 0x92, 0xF2, 0x82, 0x7C}, // 0x40 @ + {0xFC, 0x22, 0x22, 0x22, 0xFC}, // 0x41 A + {0xFE, 0x92, 0x92, 0x92, 0x6C}, // 0x42 B + {0x7C, 0x82, 0x82, 0x82, 0x44}, // 0x43 C + {0xFE, 0x82, 0x82, 0x44, 0x38}, // 0x44 D + {0xFE, 0x92, 0x92, 0x92, 0x82}, // 0x45 E + {0xFE, 0x12, 0x12, 0x02, 0x02}, // 0x46 F + {0x7C, 0x82, 0x82, 0xA2, 0x64}, // 0x47 G + {0xFE, 0x10, 0x10, 0x10, 0xFE}, // 0x48 H + {0x00, 0x82, 0xFE, 0x82, 0x00}, // 0x49 I + {0x40, 0x80, 0x82, 0x7E, 0x02}, // 0x4A J + {0xFE, 0x10, 0x28, 0x44, 0x82}, // 0x4B K + {0xFE, 0x80, 0x80, 0x80, 0x80}, // 0x4C L + {0xFE, 0x04, 0x08, 0x04, 0xFE}, // 0x4D M + {0xFE, 0x08, 0x10, 0x20, 0xFE}, // 0x4E N + {0x7C, 0x82, 0x82, 0x82, 0x7C}, // 0x4F O + {0xFE, 0x12, 0x12, 0x12, 0x0C}, // 0x50 P + {0x7C, 0x82, 0xA2, 0x42, 0xBC}, // 0x51 Q + {0xFE, 0x12, 0x32, 0x52, 0x8C}, // 0x52 R + {0x8C, 0x92, 0x92, 0x92, 0x62}, // 0x53 S + {0x02, 0x02, 0xFE, 0x02, 0x02}, // 0x54 T + {0x7E, 0x80, 0x80, 0x80, 0x7E}, // 0x55 U + {0x3E, 0x40, 0x80, 0x40, 0x3E}, // 0x56 V + {0xFE, 0x40, 0x30, 0x40, 0xFE}, // 0x57 W + {0xC6, 0x28, 0x10, 0x28, 0xC6}, // 0x58 X + {0x06, 0x08, 0xF0, 0x08, 0x06}, // 0x59 Y + {0xC2, 0xA2, 0x92, 0x8A, 0x86}, // 0x5A Z + {0x00, 0x00, 0xFE, 0x82, 0x82}, // 0x5B [ + {0x04, 0x08, 0x10, 0x20, 0x40}, // 0x5C "\" + {0x82, 0x82, 0xFE, 0x00, 0x00}, // 0x5D ] + {0x08, 0x04, 0x02, 0x04, 0x08}, // 0x5E ^ + {0x80, 0x80, 0x80, 0x80, 0x80}, // 0x5F _ + {0x00, 0x02, 0x04, 0x08, 0x00}, // 0x60 ` + {0x40, 0xA8, 0xA8, 0xA8, 0xF0}, // 0x61 a + {0xFE, 0x90, 0x88, 0x88, 0x70}, // 0x62 b + {0x70, 0x88, 0x88, 0x88, 0x40}, // 0x63 c + {0x70, 0x88, 0x88, 0x90, 0xFE}, // 0x64 d + {0x70, 0xA8, 0xA8, 0xA8, 0x30}, // 0x65 e + {0x10, 0xFC, 0x12, 0x02, 0x04}, // 0x66 f + {0x10, 0x28, 0xA8, 0xA8, 0x78}, // 0x67 g + {0xFE, 0x10, 0x08, 0x08, 0xF0}, // 0x68 h + {0x00, 0x88, 0xFA, 0x80, 0x00}, // 0x69 i + {0x40, 0x80, 0x88, 0x7A, 0x00}, // 0x6A j + {0x00, 0xFE, 0x20, 0x50, 0x88}, // 0x6B k + {0x00, 0x82, 0xFE, 0x80, 0x00}, // 0x6C l + {0xF8, 0x08, 0x30, 0x08, 0xF0}, // 0x6D m + {0xF8, 0x10, 0x08, 0x08, 0xF0}, // 0x6E n + {0x70, 0x88, 0x88, 0x88, 0x70}, // 0x6F o + {0xF8, 0x28, 0x28, 0x28, 0x10}, // 0x70 p + {0x10, 0x28, 0x28, 0x30, 0xF8}, // 0x71 q + {0xF8, 0x10, 0x08, 0x08, 0x10}, // 0x72 r + {0x90, 0xA8, 0xA8, 0xA8, 0x40}, // 0x73 s + {0x08, 0x7E, 0x88, 0x80, 0x40}, // 0x74 t + {0x78, 0x80, 0x80, 0x40, 0xF8}, // 0x75 u + {0x38, 0x40, 0x80, 0x40, 0x38}, // 0x76 v + {0x78, 0x80, 0x60, 0x80, 0x78}, // 0x77 w + {0x88, 0x50, 0x20, 0x50, 0x88}, // 0x78 x + {0x18, 0xA0, 0xA0, 0xA0, 0x78}, // 0x79 y + {0x88, 0xC8, 0xA8, 0x98, 0x88}, // 0x7A z + {0x00, 0x10, 0x6C, 0x82, 0x00}, // 0x7B { + {0x00, 0x00, 0xFE, 0x00, 0x00}, // 0x7C | + {0x00, 0x82, 0x6C, 0x10, 0x00}, // 0x7D } + {0x20, 0x10, 0x10, 0x20, 0x10}, // 0x7E + {0xF0, 0x88, 0x84, 0x88, 0xF0}, // 0x7F  + {0x28, 0x7C, 0xAA, 0x82, 0x44}, // 0x80 € + {0xF0, 0x29, 0x27, 0x21, 0xFF}, // 0x81  + {0x00, 0xA0, 0x60, 0x00, 0x00}, // 0x82 ‚ + {0x40, 0x90, 0x7C, 0x12, 0x04}, // 0x83 ƒ + {0xC0, 0xA0, 0x00, 0xC0, 0xA0}, // 0x84 „ + {0x80, 0x00, 0x80, 0x00, 0x80}, // 0x85 … + {0x00, 0x04, 0xFE, 0x04, 0x00}, // 0x86 † + {0x00, 0x44, 0xFE, 0x44, 0x00}, // 0x87 ‡ + {0x00, 0x04, 0x02, 0x04, 0x00}, // 0x88 ˆ + {0xC3, 0xD3, 0x08, 0xC4, 0xC2}, // 0x89 ‰ + {0x4C, 0x93, 0x92, 0x93, 0x64}, // 0x8A Š + {0x00, 0x10, 0x28, 0x00, 0x00}, // 0x8B ‹ + {0x7C, 0x82, 0x82, 0x7C, 0x92}, // 0x8C Œ + {0x02, 0xFE, 0x90, 0x90, 0x60}, // 0x8D  + {0xC2, 0xA3, 0x92, 0x8B, 0x86}, // 0x8E Ž + {0x44, 0x92, 0x8A, 0x92, 0x7C}, // 0x8F  + {0x70, 0x88, 0x90, 0x60, 0x98}, // 0x90  + {0x00, 0x02, 0x04, 0x08, 0x00}, // 0x91 ‘ + {0x00, 0x08, 0x04, 0x02, 0x00}, // 0x92 ’ + {0x02, 0x04, 0x0A, 0x04, 0x08}, // 0x93 “ + {0x08, 0x04, 0x0A, 0x04, 0x02}, // 0x94 ” + {0x00, 0x38, 0x38, 0x38, 0x00}, // 0x95 • + {0x00, 0x10, 0x10, 0x10, 0x10}, // 0x96 – + {0x10, 0x10, 0x10, 0x10, 0x10}, // 0x97 — + {0x02, 0x01, 0x02, 0x04, 0x02}, // 0x98 ˜ + {0xF1, 0x5B, 0x55, 0x51, 0x51}, // 0x99 ™ + {0x90, 0xA9, 0xAA, 0xA9, 0x40}, // 0x9A š + {0x00, 0x88, 0x50, 0x20, 0x00}, // 0x9B › + {0x70, 0x88, 0x70, 0xA8, 0xB0}, // 0x9C œ° + {0x38, 0x7C, 0xF8, 0x7C, 0x38}, // 0x9D  + {0x88, 0xC9, 0xAA, 0x99, 0x88}, // 0x9E ž + {0x1C, 0x21, 0xC0, 0x21, 0x1C}, // 0x9F Ÿ + {0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA0 + {0x00, 0x00, 0xF2, 0x00, 0x00}, // 0xA1 ¡ + {0x38, 0x44, 0xFE, 0x44, 0x20}, // 0xA2 ¢ + {0x90, 0x7C, 0x92, 0x82, 0x40}, // 0xA3 £ + {0x44, 0x38, 0x28, 0x38, 0x44}, // 0xA4 ¤ + {0x2A, 0x2C, 0xF8, 0x2C, 0x2A}, // 0xA5 ¥ + {0x00, 0x00, 0xEE, 0x00, 0x00}, // 0xA6 ¦ + {0x40, 0x94, 0xAA, 0x52, 0x04}, // 0xA7 § + {0x00, 0x02, 0x00, 0x02, 0x00}, // 0xA8 ¨ + {0xFE, 0x82, 0xBA, 0x92, 0xFE}, // 0xA9 © + {0x90, 0xAA, 0xAA, 0xAA, 0xBC}, // 0xAA ª + {0x20, 0x50, 0xA8, 0x50, 0x88}, // 0xAB « + {0x20, 0x20, 0x20, 0x20, 0xE0}, // 0xAC ¬ + {0x20, 0x20, 0x20, 0x20, 0x20}, // 0xAD ­ + {0xFE, 0x82, 0xCA, 0xA2, 0xFE}, // 0xAE ® + {0x02, 0x02, 0x02, 0x02, 0x02}, // 0xAF ¯ + {0x0E, 0x11, 0x11, 0x0E, 0x00}, // 0xB0 ° + {0x88, 0x88, 0xBE, 0x88, 0x88}, // 0xB1 ± + {0x12, 0x19, 0x15, 0x12, 0x00}, // 0xB2 ² + {0x11, 0x15, 0x15, 0x0A, 0x00}, // 0xB3 ³ + {0x00, 0x08, 0x04, 0x02, 0x00}, // 0xB4 ´ + {0xFE, 0x20, 0x20, 0x10, 0x3E}, // 0xB5 µ + {0x0C, 0x12, 0x12, 0xFE, 0xFE}, // 0xB6 ¶ + {0x00, 0x30, 0x30, 0x00, 0x00}, // 0xB7 · + {0x00, 0x80, 0xB0, 0x40, 0x00}, // 0xB8 ¸ + {0x00, 0x02, 0x0F, 0x00, 0x00}, // 0xB9 ¹ + {0x00, 0x02, 0x05, 0x02, 0x00}, // 0xBA º + {0x44, 0x28, 0x54, 0x28, 0x10}, // 0xBB » + {0x22, 0x1F, 0x68, 0x54, 0xFA}, // 0xBC ¼ + {0x02, 0x1F, 0x90, 0xC8, 0xB0}, // 0xBD ½ + {0x15, 0x1F, 0x60, 0x50, 0xF8}, // 0xBE ¾ + {0x60, 0x90, 0x8A, 0x80, 0x40}, // 0xBF ¿ + {0xF0, 0x29, 0x26, 0x28, 0xF0}, // 0xC0 À + {0xF0, 0x28, 0x26, 0x29, 0xF0}, // 0xC1 Á + {0xF0, 0x2A, 0x29, 0x2A, 0xF0}, // 0xC2  + {0xF2, 0x29, 0x29, 0x2A, 0xF1}, // 0xC3 à + {0xF0, 0x29, 0x24, 0x29, 0xF0}, // 0xC4 Ä + {0xF0, 0x2A, 0x2D, 0x2A, 0xF0}, // 0xC5 Å + {0xF8, 0x24, 0xFE, 0x92, 0x92}, // 0xC6 Æ + {0x1E, 0x21, 0xA1, 0xE1, 0x12}, // 0xC7 Ç + {0xF8, 0xA9, 0xAA, 0xA8, 0x88}, // 0xC8 È + {0xF8, 0xA8, 0xAA, 0xA9, 0x88}, // 0xC9 É + {0xF8, 0xAA, 0xA9, 0xAA, 0x88}, // 0xCA Ê + {0xF8, 0xAA, 0xA8, 0xAA, 0x88}, // 0xCB Ë + {0x00, 0x89, 0xFA, 0x88, 0x00}, // 0xCC Ì + {0x00, 0x88, 0xFA, 0x89, 0x00}, // 0xCD Í + {0x00, 0x8A, 0xF9, 0x8A, 0x00}, // 0xCE Î + {0x00, 0x8A, 0xF8, 0x8A, 0x00}, // 0xCF Ï + {0x10, 0xFE, 0x92, 0x82, 0x7C}, // 0xD0 Ð + {0xFA, 0x11, 0x21, 0x42, 0xF9}, // 0xD1 Ñ + {0x78, 0x85, 0x86, 0x84, 0x78}, // 0xD2 Ò + {0x78, 0x84, 0x86, 0x85, 0x78}, // 0xD3 Ó + {0x70, 0x8A, 0x89, 0x8A, 0x70}, // 0xD4 Ô + {0x72, 0x89, 0x89, 0x8A, 0x71}, // 0xD5 Õ + {0x78, 0x85, 0x84, 0x85, 0x78}, // 0xD6 Ö + {0x44, 0x28, 0x10, 0x28, 0x44}, // 0xD7 × + {0x10, 0xAA, 0xFE, 0xAA, 0x10}, // 0xD8 Ø + {0x7C, 0x81, 0x82, 0x80, 0x7C}, // 0xD9 Ù + {0x7C, 0x80, 0x82, 0x81, 0x7C}, // 0xDA Ú + {0x78, 0x82, 0x81, 0x82, 0x78}, // 0xDB Û + {0x7C, 0x81, 0x80, 0x81, 0x7C}, // 0xDC Ü + {0x04, 0x08, 0xF2, 0x09, 0x04}, // 0xDD Ý + {0x81, 0xFF, 0x24, 0x24, 0x18}, // 0xDE Þ + {0x80, 0x7C, 0x92, 0x92, 0x6C}, // 0xDF ß + {0x40, 0xA9, 0xAA, 0xA8, 0xF0}, // 0xE0 à + {0x40, 0xA8, 0xAA, 0xA9, 0xF0}, // 0xE1 á + {0x40, 0xAA, 0xA9, 0xAA, 0xF0}, // 0xE2 â + {0x42, 0xA9, 0xA9, 0xAA, 0xF1}, // 0xE3 ã + {0x40, 0xAA, 0xA8, 0xAA, 0xF0}, // 0xE4 ä + {0x40, 0xAA, 0xAD, 0xAA, 0xF0}, // 0xE5 å + {0x64, 0x94, 0x78, 0x94, 0x58}, // 0xE6 æ + {0x18, 0x24, 0xA4, 0xE4, 0x10}, // 0xE7 ç + {0x70, 0xA9, 0xAA, 0xA8, 0x30}, // 0xE8 è + {0x70, 0xA8, 0xAA, 0xA9, 0x30}, // 0xE9 é + {0x70, 0xAA, 0xA9, 0xAA, 0x30}, // 0xEA ê + {0x70, 0xAA, 0xA8, 0xAA, 0x30}, // 0xEB ë + {0x00, 0x91, 0xFA, 0x80, 0x00}, // 0xEC ì + {0x00, 0x90, 0xFA, 0x81, 0x00}, // 0xED í + {0x00, 0x92, 0xF9, 0x82, 0x00}, // 0xEE î + {0x00, 0x92, 0xF8, 0x82, 0x00}, // 0xEF ï + {0x4A, 0xA4, 0xAA, 0xB0, 0x60}, // 0xF0 ð + {0xFA, 0x11, 0x09, 0x0A, 0xF1}, // 0xF1 ñ + {0x70, 0x89, 0x8A, 0x88, 0x70}, // 0xF2 ò + {0x70, 0x88, 0x8A, 0x89, 0x70}, // 0xF3 ó + {0x60, 0x94, 0x92, 0x94, 0x60}, // 0xF4 ô + {0x64, 0x92, 0x92, 0x94, 0x62}, // 0xF5 õ + {0x70, 0x8A, 0x88, 0x8A, 0x70}, // 0xF6 ö + {0x10, 0x10, 0x54, 0x10, 0x10}, // 0xF7 ÷ + {0x10, 0xA8, 0x7C, 0x2A, 0x10}, // 0xF8 ø + {0x78, 0x81, 0x82, 0x40, 0xF8}, // 0xF9 ù + {0x78, 0x80, 0x82, 0x41, 0xF8}, // 0xFA ú + {0x78, 0x82, 0x81, 0x42, 0xF8}, // 0xFB û + {0x78, 0x82, 0x80, 0x42, 0xF8}, // 0xFC ü + {0x18, 0xA0, 0xA4, 0xA2, 0x78}, // 0xFD v + {0x00, 0x82, 0xFE, 0xA8, 0x10}, // 0xFE þ + {0x18, 0xA2, 0xA0, 0xA2, 0x78} // 0xFF ÿ +}; + +const uint8_t ascii_font_8x8[256][8] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00 + {0x7E, 0x81, 0x95, 0xB1, 0xB1, 0x95, 0x81, 0x7E}, // 0x01 + {0x7E, 0xFF, 0xEB, 0xCF, 0xCF, 0xEB, 0xFF, 0x7E}, // 0x02 + {0x0E, 0x1F, 0x3F, 0x7E, 0x3F, 0x1F, 0x0E, 0x00}, // 0x03 + {0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x08, 0x00}, // 0x04 + {0x38, 0x3A, 0x9F, 0xFF, 0x9F, 0x3A, 0x38, 0x00}, // 0x05 + {0x10, 0x38, 0xBC, 0xFF, 0xBC, 0x38, 0x10, 0x00}, // 0x06 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x07 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x08 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0A + {0x70, 0xF8, 0x88, 0x88, 0xFD, 0x7F, 0x07, 0x0F}, // 0x0B + {0x00, 0x4E, 0x5F, 0xF1, 0xF1, 0x5F, 0x4E, 0x00}, // 0x0C + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D + {0xC0, 0xFF, 0x7F, 0x05, 0x05, 0x65, 0x7F, 0x3F}, // 0x0E + {0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99}, // 0x0F + {0x7F, 0x3E, 0x3E, 0x1C, 0x1C, 0x08, 0x08, 0x00}, // 0x10 + {0x08, 0x08, 0x1C, 0x1C, 0x3E, 0x3E, 0x7F, 0x00}, // 0x11 + {0x00, 0x24, 0x66, 0xFF, 0xFF, 0x66, 0x24, 0x00}, // 0x12 + {0x00, 0x5F, 0x5F, 0x00, 0x00, 0x5F, 0x5F, 0x00}, // 0x13 + {0x06, 0x0F, 0x09, 0x7F, 0x7F, 0x01, 0x7F, 0x7F}, // 0x14 + {0xDA, 0xBF, 0xA5, 0xA5, 0xFD, 0x59, 0x03, 0x02}, // 0x15 + {0x00, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x00}, // 0x16 + {0x80, 0x94, 0xB6, 0xFF, 0xFF, 0xB6, 0x94, 0x80}, // 0x17 + {0x00, 0x04, 0x06, 0x7F, 0x7F, 0x06, 0x04, 0x00}, // 0x18 + {0x00, 0x10, 0x30, 0x7F, 0x7F, 0x30, 0x10, 0x00}, // 0x19 + {0x08, 0x08, 0x08, 0x2A, 0x3E, 0x1C, 0x08, 0x00}, // 0x1A + {0x08, 0x1C, 0x3E, 0x2A, 0x08, 0x08, 0x08, 0x00}, // 0x1B + {0x3C, 0x3C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00}, // 0x1C + {0x08, 0x1C, 0x3E, 0x08, 0x08, 0x3E, 0x1C, 0x08}, // 0x1D + {0x30, 0x38, 0x3C, 0x3E, 0x3E, 0x3C, 0x38, 0x30}, // 0x1E + {0x06, 0x0E, 0x1E, 0x3E, 0x3E, 0x1E, 0x0E, 0x06}, // 0x1F + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 + {0x00, 0x06, 0x5F, 0x5F, 0x06, 0x00, 0x00, 0x00}, // 0x21 + {0x00, 0x07, 0x07, 0x00, 0x07, 0x07, 0x00, 0x00}, // 0x22 + {0x14, 0x7F, 0x7F, 0x14, 0x7F, 0x7F, 0x14, 0x00}, // 0x23 + {0x24, 0x2E, 0x6B, 0x6B, 0x3A, 0x12, 0x00, 0x00}, // 0x24 + {0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, 0x00}, // 0x25 + {0x30, 0x7A, 0x4F, 0x5D, 0x37, 0x7A, 0x48, 0x00}, // 0x26 + {0x04, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x27 + {0x00, 0x1C, 0x3E, 0x63, 0x41, 0x00, 0x00, 0x00}, // 0x28 + {0x00, 0x41, 0x63, 0x3E, 0x1C, 0x00, 0x00, 0x00}, // 0x29 + {0x08, 0x2A, 0x3E, 0x1C, 0x1C, 0x3E, 0x2A, 0x08}, // 0x2A + {0x08, 0x08, 0x3E, 0x3E, 0x08, 0x08, 0x00, 0x00}, // 0x2B + {0x00, 0xA0, 0xE0, 0x60, 0x00, 0x00, 0x00, 0x00}, // 0x2C + {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00}, // 0x2D + {0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00}, // 0x2E + {0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // 0x2F + {0x3E, 0x7F, 0x59, 0x4D, 0x7F, 0x3E, 0x00, 0x00}, // 0x30 + {0x42, 0x42, 0x7F, 0x7F, 0x40, 0x40, 0x00, 0x00}, // 0x31 + {0x62, 0x73, 0x59, 0x49, 0x6F, 0x66, 0x00, 0x00}, // 0x32 + {0x22, 0x63, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00}, // 0x33 + {0x18, 0x1C, 0x16, 0x13, 0x7F, 0x7F, 0x10, 0x00}, // 0x34 + {0x27, 0x67, 0x45, 0x45, 0x7D, 0x39, 0x00, 0x00}, // 0x35 + {0x3C, 0x7E, 0x4B, 0x49, 0x79, 0x30, 0x00, 0x00}, // 0x36 + {0x03, 0x63, 0x71, 0x19, 0x0F, 0x07, 0x00, 0x00}, // 0x37 + {0x36, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00}, // 0x38 + {0x06, 0x4F, 0x49, 0x69, 0x3F, 0x1E, 0x00, 0x00}, // 0x39 + {0x00, 0x00, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00}, // 0x3A + {0x00, 0xA0, 0xEC, 0x6C, 0x00, 0x00, 0x00, 0x00}, // 0x3B + {0x08, 0x1C, 0x36, 0x63, 0x41, 0x00, 0x00, 0x00}, // 0x3C + {0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00}, // 0x3D + {0x00, 0x41, 0x63, 0x36, 0x1C, 0x08, 0x00, 0x00}, // 0x3E + {0x02, 0x03, 0x51, 0x59, 0x0F, 0x06, 0x00, 0x00}, // 0x3F + {0x3E, 0x7F, 0x41, 0x5D, 0x5D, 0x1F, 0x1E, 0x00}, // 0x40 + {0x7C, 0x7E, 0x13, 0x13, 0x7E, 0x7C, 0x00, 0x00}, // 0x41 + {0x41, 0x7F, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00}, // 0x42 + {0x1C, 0x3E, 0x63, 0x41, 0x41, 0x63, 0x22, 0x00}, // 0x43 + {0x41, 0x7F, 0x7F, 0x41, 0x63, 0x7F, 0x1C, 0x00}, // 0x44 + {0x41, 0x7F, 0x7F, 0x49, 0x5D, 0x41, 0x63, 0x00}, // 0x45 + {0x41, 0x7F, 0x7F, 0x49, 0x1D, 0x01, 0x03, 0x00}, // 0x46 + {0x1C, 0x3E, 0x63, 0x41, 0x51, 0x73, 0x72, 0x00}, // 0x47 + {0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00}, // 0x48 + {0x00, 0x41, 0x7F, 0x7F, 0x41, 0x00, 0x00, 0x00}, // 0x49 + {0x30, 0x70, 0x40, 0x41, 0x7F, 0x3F, 0x01, 0x00}, // 0x4A + {0x41, 0x7F, 0x7F, 0x08, 0x1C, 0x77, 0x63, 0x00}, // 0x4B + {0x41, 0x7F, 0x7F, 0x41, 0x40, 0x60, 0x70, 0x00}, // 0x4C + {0x7F, 0x7F, 0x06, 0x0C, 0x06, 0x7F, 0x7F, 0x00}, // 0x4D + {0x7F, 0x7F, 0x06, 0x0C, 0x18, 0x7F, 0x7F, 0x00}, // 0x4E + {0x1C, 0x3E, 0x63, 0x41, 0x63, 0x3E, 0x1C, 0x00}, // 0x4F + {0x41, 0x7F, 0x7F, 0x49, 0x09, 0x0F, 0x06, 0x00}, // 0x50 + {0x1E, 0x3F, 0x21, 0x71, 0x7F, 0x5E, 0x00, 0x00}, // 0x51 + {0x41, 0x7F, 0x7F, 0x19, 0x39, 0x6F, 0x46, 0x00}, // 0x52 + {0x26, 0x67, 0x4D, 0x59, 0x7B, 0x32, 0x00, 0x00}, // 0x53 + {0x03, 0x41, 0x7F, 0x7F, 0x41, 0x03, 0x00, 0x00}, // 0x54 + {0x7F, 0x7F, 0x40, 0x40, 0x7F, 0x7F, 0x00, 0x00}, // 0x55 + {0x1F, 0x3F, 0x60, 0x60, 0x3F, 0x1F, 0x00, 0x00}, // 0x56 + {0x7F, 0x7F, 0x30, 0x18, 0x30, 0x7F, 0x7F, 0x00}, // 0x57 + {0x63, 0x77, 0x1C, 0x08, 0x1C, 0x77, 0x63, 0x00}, // 0x58 + {0x07, 0x4F, 0x78, 0x78, 0x4F, 0x07, 0x00, 0x00}, // 0x59 + {0x67, 0x73, 0x59, 0x4D, 0x47, 0x63, 0x71, 0x00}, // 0x5A + {0x00, 0x7F, 0x7F, 0x41, 0x41, 0x00, 0x00, 0x00}, // 0x5B + {0x01, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00}, // 0x5C + {0x00, 0x41, 0x41, 0x7F, 0x7F, 0x00, 0x00, 0x00}, // 0x5D + {0x08, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x08, 0x00}, // 0x5E + {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}, // 0x5F + {0x00, 0x00, 0x03, 0x07, 0x04, 0x00, 0x00, 0x00}, // 0x60 + {0x20, 0x74, 0x54, 0x54, 0x3C, 0x78, 0x40, 0x00}, // 0x61 + {0x41, 0x3F, 0x7F, 0x44, 0x44, 0x7C, 0x38, 0x00}, // 0x62 + {0x38, 0x7C, 0x44, 0x44, 0x6C, 0x28, 0x00, 0x00}, // 0x63 + {0x30, 0x78, 0x48, 0x49, 0x3F, 0x7F, 0x40, 0x00}, // 0x64 + {0x38, 0x7C, 0x54, 0x54, 0x5C, 0x18, 0x00, 0x00}, // 0x65 + {0x48, 0x7E, 0x7F, 0x49, 0x03, 0x02, 0x00, 0x00}, // 0x66 + {0x98, 0xBC, 0xA4, 0xA4, 0xF8, 0x7C, 0x04, 0x00}, // 0x67 + {0x41, 0x7F, 0x7F, 0x08, 0x04, 0x7C, 0x78, 0x00}, // 0x68 + {0x00, 0x44, 0x7D, 0x7D, 0x40, 0x00, 0x00, 0x00}, // 0x69 + {0x40, 0xC4, 0x84, 0xFD, 0x7D, 0x00, 0x00, 0x00}, // 0x6A + {0x41, 0x7F, 0x7F, 0x10, 0x38, 0x6C, 0x44, 0x00}, // 0x6B + {0x00, 0x41, 0x7F, 0x7F, 0x40, 0x00, 0x00, 0x00}, // 0x6C + {0x7C, 0x7C, 0x0C, 0x18, 0x0C, 0x7C, 0x78, 0x00}, // 0x6D + {0x7C, 0x7C, 0x04, 0x04, 0x7C, 0x78, 0x00, 0x00}, // 0x6E + {0x38, 0x7C, 0x44, 0x44, 0x7C, 0x38, 0x00, 0x00}, // 0x6F + {0x84, 0xFC, 0xF8, 0xA4, 0x24, 0x3C, 0x18, 0x00}, // 0x70 + {0x18, 0x3C, 0x24, 0xA4, 0xF8, 0xFC, 0x84, 0x00}, // 0x71 + {0x44, 0x7C, 0x78, 0x44, 0x1C, 0x18, 0x00, 0x00}, // 0x72 + {0x48, 0x5C, 0x54, 0x54, 0x74, 0x24, 0x00, 0x00}, // 0x73 + {0x00, 0x04, 0x3E, 0x7F, 0x44, 0x24, 0x00, 0x00}, // 0x74 + {0x3C, 0x7C, 0x40, 0x40, 0x3C, 0x7C, 0x40, 0x00}, // 0x75 + {0x1C, 0x3C, 0x60, 0x60, 0x3C, 0x1C, 0x00, 0x00}, // 0x76 + {0x3C, 0x7C, 0x60, 0x30, 0x60, 0x7C, 0x3C, 0x00}, // 0x77 + {0x44, 0x6C, 0x38, 0x10, 0x38, 0x6C, 0x44, 0x00}, // 0x78 + {0x9C, 0xBC, 0xA0, 0xA0, 0xFC, 0x7C, 0x00, 0x00}, // 0x79 + {0x4C, 0x64, 0x74, 0x5C, 0x4C, 0x64, 0x00, 0x00}, // 0x7A + {0x08, 0x08, 0x3E, 0x77, 0x41, 0x41, 0x00, 0x00}, // 0x7B + {0x00, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0x00}, // 0x7C + {0x41, 0x41, 0x77, 0x3E, 0x08, 0x08, 0x00, 0x00}, // 0x7D + {0x02, 0x03, 0x01, 0x03, 0x02, 0x03, 0x01, 0x00}, // 0x7E + {0x78, 0x7C, 0x46, 0x43, 0x46, 0x7C, 0x78, 0x00}, // 0x7F + {0x1E, 0xBF, 0xE1, 0x61, 0x33, 0x12, 0x00, 0x00}, // 0x80 + {0x3A, 0x7A, 0x40, 0x40, 0x7A, 0x7A, 0x40, 0x00}, // 0x81 + {0x38, 0x7C, 0x56, 0x57, 0x5D, 0x18, 0x00, 0x00}, // 0x82 + {0x02, 0x23, 0x75, 0x55, 0x55, 0x7D, 0x7B, 0x42}, // 0x83 + {0x21, 0x75, 0x54, 0x54, 0x7D, 0x79, 0x40, 0x00}, // 0x84 + {0x20, 0x75, 0x57, 0x56, 0x7C, 0x78, 0x40, 0x00}, // 0x85 + {0x00, 0x22, 0x77, 0x55, 0x55, 0x7F, 0x7A, 0x40}, // 0x86 + {0x1C, 0xBE, 0xE2, 0x62, 0x36, 0x14, 0x00, 0x00}, // 0x87 + {0x02, 0x3B, 0x7D, 0x55, 0x55, 0x5D, 0x1B, 0x02}, // 0x88 + {0x39, 0x7D, 0x54, 0x54, 0x5D, 0x19, 0x00, 0x00}, // 0x89 + {0x38, 0x7D, 0x57, 0x56, 0x5C, 0x18, 0x00, 0x00}, // 0x8A + {0x01, 0x45, 0x7C, 0x7C, 0x41, 0x01, 0x00, 0x00}, // 0x8B + {0x02, 0x03, 0x45, 0x7D, 0x7D, 0x43, 0x02, 0x00}, // 0x8C + {0x00, 0x45, 0x7F, 0x7E, 0x40, 0x00, 0x00, 0x00}, // 0x8D + {0x79, 0x7D, 0x26, 0x26, 0x7D, 0x79, 0x00, 0x00}, // 0x8E + {0x70, 0x7A, 0x2D, 0x2D, 0x7A, 0x70, 0x00, 0x00}, // 0x8F + {0x44, 0x7C, 0x7E, 0x57, 0x55, 0x44, 0x00, 0x00}, // 0x90 + {0x20, 0x74, 0x54, 0x54, 0x7C, 0x7C, 0x54, 0x54}, // 0x91 + {0x7C, 0x7E, 0x0B, 0x09, 0x7F, 0x7F, 0x49, 0x00}, // 0x92 + {0x32, 0x7B, 0x49, 0x49, 0x7B, 0x32, 0x00, 0x00}, // 0x93 + {0x32, 0x7A, 0x48, 0x48, 0x7A, 0x32, 0x00, 0x00}, // 0x94 + {0x30, 0x79, 0x4B, 0x4A, 0x78, 0x30, 0x00, 0x00}, // 0x95 + {0x3A, 0x7B, 0x41, 0x41, 0x7B, 0x7A, 0x40, 0x00}, // 0x96 + {0x38, 0x79, 0x43, 0x42, 0x78, 0x78, 0x40, 0x00}, // 0x97 + {0xBA, 0xBA, 0xA0, 0xA0, 0xFA, 0x7A, 0x00, 0x00}, // 0x98 + {0x39, 0x7D, 0x44, 0x44, 0x44, 0x7D, 0x39, 0x00}, // 0x99 + {0x3D, 0x7D, 0x40, 0x40, 0x7D, 0x3D, 0x00, 0x00}, // 0x9A + {0x38, 0x7C, 0x64, 0x54, 0x4C, 0x7C, 0x38, 0x00}, // 0x9B + {0x68, 0x7E, 0x7F, 0x49, 0x43, 0x66, 0x20, 0x00}, // 0x9C + {0x5C, 0x3E, 0x73, 0x49, 0x67, 0x3E, 0x1D, 0x00}, // 0x9D + {0x44, 0x6C, 0x38, 0x38, 0x6C, 0x44, 0x00, 0x00}, // 0x9E + {0x40, 0xC8, 0x88, 0xFE, 0x7F, 0x09, 0x0B, 0x02}, // 0x9F + {0x20, 0x74, 0x56, 0x57, 0x7D, 0x78, 0x40, 0x00}, // 0xA0 + {0x00, 0x44, 0x7E, 0x7F, 0x41, 0x00, 0x00, 0x00}, // 0xA1 + {0x30, 0x78, 0x48, 0x4A, 0x7B, 0x31, 0x00, 0x00}, // 0xA2 + {0x38, 0x78, 0x40, 0x42, 0x7B, 0x79, 0x40, 0x00}, // 0xA3 + {0x7A, 0x7B, 0x09, 0x0B, 0x7A, 0x73, 0x01, 0x00}, // 0xA4 + {0x7A, 0x7B, 0x19, 0x33, 0x7A, 0x7B, 0x01, 0x00}, // 0xA5 + {0x00, 0x26, 0x2F, 0x29, 0x2F, 0x2F, 0x28, 0x00}, // 0xA6 + {0x00, 0x26, 0x2F, 0x29, 0x29, 0x2F, 0x26, 0x00}, // 0xA7 + {0x30, 0x78, 0x4D, 0x45, 0x60, 0x20, 0x00, 0x00}, // 0xA8 + {0x1C, 0x22, 0x7D, 0x4B, 0x5B, 0x65, 0x22, 0x1C}, // 0xA9 + {0x08, 0x08, 0x08, 0x08, 0x38, 0x38, 0x00, 0x00}, // 0xAA + {0x61, 0x3F, 0x1F, 0xCC, 0xEE, 0xAB, 0xB9, 0x90}, // 0xAB + {0x61, 0x3F, 0x1F, 0x4C, 0x66, 0x73, 0xD9, 0xF8}, // 0xAC + {0x00, 0x00, 0x60, 0xFA, 0xFA, 0x60, 0x00, 0x00}, // 0xAD + {0x08, 0x1C, 0x36, 0x22, 0x08, 0x1C, 0x36, 0x22}, // 0xAE + {0x22, 0x36, 0x1C, 0x08, 0x22, 0x36, 0x1C, 0x08}, // 0xAF + {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00}, // 0xB0 + {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55}, // 0xB1 + {0x55, 0xFF, 0xAA, 0xFF, 0x55, 0xFF, 0xAA, 0xFF}, // 0xB2 + {0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00}, // 0xB3 + {0x10, 0x10, 0x10, 0xFF, 0xFF, 0x00, 0x00, 0x00}, // 0xB4 + {0x70, 0x78, 0x2C, 0x2E, 0x7B, 0x71, 0x00, 0x00}, // 0xB5 + {0x72, 0x79, 0x2D, 0x2D, 0x79, 0x72, 0x00, 0x00}, // 0xB6 + {0x71, 0x7B, 0x2E, 0x2C, 0x78, 0x70, 0x00, 0x00}, // 0xB7 + {0x1C, 0x22, 0x5D, 0x55, 0x55, 0x41, 0x22, 0x1C}, // 0xB8 + {0x14, 0x14, 0xF7, 0xF7, 0x00, 0xFF, 0xFF, 0x00}, // 0xB9 + {0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00}, // 0xBA + {0x14, 0x14, 0xF4, 0xF4, 0x04, 0xFC, 0xFC, 0x00}, // 0xBB + {0x14, 0x14, 0x17, 0x17, 0x10, 0x1F, 0x1F, 0x00}, // 0xBC + {0x18, 0x3C, 0x24, 0xE7, 0xE7, 0x24, 0x24, 0x00}, // 0xBD + {0x2B, 0x2F, 0xFC, 0xFC, 0x2F, 0x2B, 0x00, 0x00}, // 0xBE + {0x10, 0x10, 0x10, 0xF0, 0xF0, 0x00, 0x00, 0x00}, // 0xBF + {0x00, 0x00, 0x00, 0x1F, 0x1F, 0x10, 0x10, 0x10}, // 0xC0 + {0x10, 0x10, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x10}, // 0xC1 + {0x10, 0x10, 0x10, 0xF0, 0xF0, 0x10, 0x10, 0x10}, // 0xC2 + {0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0x10, 0x10}, // 0xC3 + {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, // 0xC4 + {0x10, 0x10, 0x10, 0xFF, 0xFF, 0x10, 0x10, 0x10}, // 0xC5 + {0x22, 0x77, 0x55, 0x57, 0x7E, 0x7B, 0x41, 0x00}, // 0xC6 + {0x72, 0x7B, 0x2D, 0x2F, 0x7A, 0x73, 0x01, 0x00}, // 0xC7 + {0x00, 0x00, 0x1F, 0x1F, 0x10, 0x17, 0x17, 0x14}, // 0xC8 + {0x00, 0x00, 0xFC, 0xFC, 0x04, 0xF4, 0xF4, 0x14}, // 0xC9 + {0x14, 0x14, 0x17, 0x17, 0x10, 0x17, 0x17, 0x14}, // 0xCA + {0x14, 0x14, 0xF4, 0xF4, 0x04, 0xF4, 0xF4, 0x14}, // 0xCB + {0x00, 0x00, 0xFF, 0xFF, 0x00, 0xF7, 0xF7, 0x14}, // 0xCC + {0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14}, // 0xCD + {0x14, 0x14, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0x14}, // 0xCE + {0x66, 0x3C, 0x3C, 0x24, 0x3C, 0x3C, 0x66, 0x00}, // 0xCF + {0x05, 0x27, 0x72, 0x57, 0x7D, 0x38, 0x00, 0x00}, // 0xD0 + {0x49, 0x7F, 0x7F, 0x49, 0x63, 0x7F, 0x1C, 0x00}, // 0xD1 + {0x46, 0x7D, 0x7D, 0x55, 0x55, 0x46, 0x00, 0x00}, // 0xD2 + {0x45, 0x7D, 0x7C, 0x54, 0x55, 0x45, 0x00, 0x00}, // 0xD3 + {0x44, 0x7D, 0x7F, 0x56, 0x54, 0x44, 0x00, 0x00}, // 0xD4 + {0x0A, 0x0E, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0xD5 + {0x00, 0x44, 0x7E, 0x7F, 0x45, 0x00, 0x00, 0x00}, // 0xD6 + {0x02, 0x45, 0x7D, 0x7D, 0x45, 0x02, 0x00, 0x00}, // 0xD7 + {0x01, 0x45, 0x7C, 0x7C, 0x45, 0x01, 0x00, 0x00}, // 0xD8 + {0x10, 0x10, 0x10, 0x1F, 0x1F, 0x00, 0x00, 0x00}, // 0xD9 + {0x00, 0x00, 0x00, 0xF0, 0xF0, 0x10, 0x10, 0x10}, // 0xDA + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // 0xDB + {0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0}, // 0xDC + {0x00, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0x00}, // 0xDD + {0x00, 0x45, 0x7F, 0x7E, 0x44, 0x00, 0x00, 0x00}, // 0xDE + {0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F}, // 0xDF + {0x38, 0x7C, 0x46, 0x47, 0x45, 0x7C, 0x38, 0x00}, // 0xE0 + {0xFC, 0xFE, 0x2A, 0x2A, 0x3E, 0x14, 0x00, 0x00}, // 0xE1 + {0x3A, 0x7D, 0x45, 0x45, 0x45, 0x7D, 0x3A, 0x00}, // 0xE2 + {0x38, 0x7C, 0x45, 0x47, 0x46, 0x7C, 0x38, 0x00}, // 0xE3 + {0x32, 0x7B, 0x49, 0x4B, 0x7A, 0x33, 0x01, 0x00}, // 0xE4 + {0x3A, 0x7F, 0x45, 0x47, 0x46, 0x7F, 0x39, 0x00}, // 0xE5 + {0x80, 0xFE, 0x7E, 0x20, 0x20, 0x3E, 0x1E, 0x00}, // 0xE6 + {0x42, 0x7E, 0x7E, 0x54, 0x1C, 0x08, 0x00, 0x00}, // 0xE7 + {0x41, 0x7F, 0x7F, 0x55, 0x14, 0x1C, 0x08, 0x00}, // 0xE8 + {0x3C, 0x7C, 0x42, 0x43, 0x7D, 0x3C, 0x00, 0x00}, // 0xE9 + {0x3A, 0x79, 0x41, 0x41, 0x79, 0x3A, 0x00, 0x00}, // 0xEA + {0x3C, 0x7D, 0x43, 0x42, 0x7C, 0x3C, 0x00, 0x00}, // 0xEB + {0xB8, 0xB8, 0xA2, 0xA3, 0xF9, 0x78, 0x00, 0x00}, // 0xEC + {0x0C, 0x5C, 0x72, 0x73, 0x5D, 0x0C, 0x00, 0x00}, // 0xED + {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00}, // 0xEE + {0x00, 0x00, 0x02, 0x03, 0x01, 0x00, 0x00, 0x00}, // 0xEF + {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00}, // 0xF0 + {0x44, 0x44, 0x5F, 0x5F, 0x44, 0x44, 0x00, 0x00}, // 0xF1 + {0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00}, // 0xF2 + {0x71, 0x35, 0x1F, 0x4C, 0x66, 0x73, 0xD9, 0xF8}, // 0xF3 + {0x06, 0x0F, 0x09, 0x7F, 0x7F, 0x01, 0x7F, 0x7F}, // 0xF4 + {0xDA, 0xBF, 0xA5, 0xA5, 0xFD, 0x59, 0x03, 0x02}, // 0xF5 + {0x08, 0x08, 0x6B, 0x6B, 0x08, 0x08, 0x00, 0x00}, // 0xF6 + {0x00, 0x80, 0xC0, 0x40, 0x00, 0x00, 0x00, 0x00}, // 0xF7 + {0x00, 0x06, 0x0F, 0x09, 0x0F, 0x06, 0x00, 0x00}, // 0xF8 + {0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00}, // 0xF9 + {0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00}, // 0xFA + {0x00, 0x12, 0x13, 0x1F, 0x1F, 0x10, 0x10, 0x00}, // 0xFB + {0x00, 0x11, 0x15, 0x15, 0x1F, 0x1F, 0x0A, 0x00}, // 0xFC + {0x00, 0x19, 0x1D, 0x15, 0x17, 0x12, 0x00, 0x00}, // 0xFD + {0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00}, // 0xFE + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // 0xFF +}; + +#endif \ No newline at end of file diff --git a/components/ssd1306/include/ssd1306.h b/components/ssd1306/include/ssd1306.h new file mode 100644 index 0000000..89c48a5 --- /dev/null +++ b/components/ssd1306/include/ssd1306.h @@ -0,0 +1,103 @@ +// 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 _ssd1306_H_ +#define _ssd1306_H_ + +#define SSD1306_ADDRESS (0x3C) +#define SSD1306_COLUMNS (128) +#define SSD1306_PAGES (8) + +// Write mode for I2C https://robotcantalk.blogspot.com/2015/03/interfacing-arduino-with-ssd1306-driven.html +#define SSD1306_CONTROL_CMD_BYTE (0x80) +#define SSD1306_CONTROL_CMD_STREAM (0x00) +#define SSD1306_CONTROL_DATA_BYTE (0xC0) +#define SSD1306_CONTROL_DATA_STREAM (0x40) + +// 1. Fundamental Command Table +#define SSD1306_CMD_CONTRAST (0x81) +#define SSD1306_CMD_RAM (0xA4) +#define SSD1306_CMD_ALL_ON (0xA5) +#define SSD1306_CMD_NORMAL (0xA6) +#define SSD1306_CMD_INVERSE (0xA7) +#define SSD1306_CMD_OFF (0xAE) +#define SSD1306_CMD_ON (0xAF) + +// 2. Scrolling Command Table +#define SSD1306_CMD_SCROLL_HORI_RIGHT (0x26) +#define SSD1306_CMD_SCROLL_HORI_LEFT (0x27) +#define SSD1306_CMD_SCROLL_VERT_RIGHT (0x29) +#define SSD1306_CMD_SCROLL_VERT_LEFT (0x2A) +#define SSD1306_CMD_SCROLL_STOP (0x2E) +#define SSD1306_CMD_SCROLL_START (0x2F) +#define SSD1306_CMD_SCROLL_VERT_AREA (0xA3) + +// 3. Addressing Setting Command Table +#define SSD1306_CMD_COLUMN_LOW (0x00) +#define SSD1306_CMD_COLUMN_HIGH (0x10) +#define SSD1306_CMD_MEMORY_MODE (0x20) +#define SSD1306_CMD_COLUMN_ADDRESS (0x21) +#define SSD1306_CMD_PAGE_ADDRESS (0x22) +#define SSD1306_CMD_PAGE (0xB0) + +// 4. Hardware Configuration (Panel resolution & layout related) Command Table +#define SSD1306_CMD_START_LINE (0x40) +#define SSD1306_CMD_SEGMENT_LOW (0xA0) +#define SSD1306_CMD_SEGMENT_HIGH (0xA1) +#define SSD1306_CMD_MULTIPLEX_RATIO (0xA8) +#define SSD1306_CMD_SCAN_DIRECTION_NORMAL (0xC0) +#define SSD1306_CMD_SCAN_DIRECTION_REMAPPED (0xC8) +#define SSD1306_CMD_OFFSET (0xD3) +#define SSD1306_CMD_COM_PINS (0xDA) + +// 5. Timing & Driving Scheme Setting Command Table +#define SSD1306_CMD_CLOCK (0xD5) +#define SSD1306_CMD_PRE_CHARGE_PERIOD (0xD9) +#define SSD1306_CMD_VCOMH (0xDB) +#define SSD1306_CMD_NOP (0xE3) + +// 1. Charge Pump Command Table +#define SSD1306_CMD_CHARGE_PUMP (0x8D) + +/** + * @brief initalize SSD1306 with I2C at given address + * + * @param[in] i2address I2C address of SSD1306 + */ +void ssd1306_start(uint8_t i2address); + +/** + * @brief clear the display + * + * @param[in] i2address I2C address of SSD1306 + * @param[in] line the line to clear + */ +void ssd1306_clear_line(uint8_t i2address, uint8_t line, bool invert); + +/** + * @brief clear the display + * + * @param[in] i2address I2C address of SSD1306 + */ +void ssd1306_clear(uint8_t i2address); + +/** + * @brief write text to display + * + * @param[in] i2address I2C address of SSD1306 + * @param[in] text text to display + * @param[in] line the line to write to + */ +void ssd1306_text_line(uint8_t i2address, char *text, uint8_t line, bool invert); + +#endif \ No newline at end of file diff --git a/components/ssd1306/ssd1306.c b/components/ssd1306/ssd1306.c new file mode 100644 index 0000000..12a3fcb --- /dev/null +++ b/components/ssd1306/ssd1306.c @@ -0,0 +1,193 @@ +// 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 "driver/i2c.h" +#include "esp_log.h" + +#include "i2c-main.h" +#include "ssd1306-ascii.h" + +#include "ssd1306.h" + +void ssd1306_start(uint8_t i2address) +{ + if (!i2c_is_initialized()) + { + i2c_main_init(); + } + + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + + i2c_master_start(cmd); + // Begin the I2C comm with SSD1306's address (SLA+Write) + i2c_master_write_byte(cmd, (i2address << 1) | I2C_MASTER_WRITE, true); + // Tell the SSD1306 that a command stream is incoming + i2c_master_write_byte(cmd, SSD1306_CONTROL_CMD_STREAM, true); + // Turn the Display OFF + i2c_master_write_byte(cmd, SSD1306_CMD_OFF, true); + // Set mux ration tp select max number of rows - 64 + i2c_master_write_byte(cmd, SSD1306_CMD_MULTIPLEX_RATIO, true); + i2c_master_write_byte(cmd, 0x3F, true); + // Set the display offset to 0 + i2c_master_write_byte(cmd, SSD1306_CMD_OFFSET, true); + i2c_master_write_byte(cmd, 0x00, true); + // Display start line to 0 + i2c_master_write_byte(cmd, SSD1306_CMD_START_LINE, true); + // Mirror the x-axis. In case you set it up such that the pins are north. + i2c_master_write_byte(cmd, SSD1306_CMD_SEGMENT_HIGH, true); + // Mirror the y-axis. In case you set it up such that the pins are north. + i2c_master_write_byte(cmd, SSD1306_CMD_SCAN_DIRECTION_REMAPPED, true); + // Default - alternate COM pin map + i2c_master_write_byte(cmd, SSD1306_CMD_COM_PINS, true); + i2c_master_write_byte(cmd, 0x12, true); + // set contrast + i2c_master_write_byte(cmd, SSD1306_CMD_CONTRAST, true); + i2c_master_write_byte(cmd, 0xFF, true); + // Set display to enable rendering from GDDRAM (Graphic Display Data RAM) + i2c_master_write_byte(cmd, SSD1306_CMD_RAM, true); + // Normal mode! + i2c_master_write_byte(cmd, SSD1306_CMD_NORMAL, true); + // Default oscillator clock + i2c_master_write_byte(cmd, SSD1306_CMD_CLOCK, true); + i2c_master_write_byte(cmd, 0x80, true); + // Enable the charge pump + i2c_master_write_byte(cmd, SSD1306_CMD_CHARGE_PUMP, true); + i2c_master_write_byte(cmd, 0x14, true); + // Set precharge cycles to high cap type + i2c_master_write_byte(cmd, SSD1306_CMD_PRE_CHARGE_PERIOD, true); + i2c_master_write_byte(cmd, 0x22, true); + // Set the V_COMH deselect volatage to max + i2c_master_write_byte(cmd, SSD1306_CMD_VCOMH, true); + i2c_master_write_byte(cmd, 0x30, true); + // Horizonatal addressing mode to page addressing + i2c_master_write_byte(cmd, SSD1306_CMD_MEMORY_MODE, true); + i2c_master_write_byte(cmd, 0x02, true); + //i2c_master_write_byte(cmd, 0x00, true); + // i2c_master_write_byte(cmd, 0x10, true); + // i2c_master_write_byte(cmd, SSD1306_CMD_SCROLL_STOP, true); + // Turn the Display ON + i2c_master_write_byte(cmd, SSD1306_CMD_ON, true); + i2c_master_stop(cmd); + ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS)); + i2c_cmd_link_delete(cmd); +} + +void ssd1306_init_data(uint8_t i2address) +{ + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + // Begin the I2C comm with SSD1306's address (SLA+Write) + i2c_master_write_byte(cmd, (i2address << 1) | I2C_MASTER_WRITE, true); + // Tell the SSD1306 that a command stream is incoming + i2c_master_write_byte(cmd, SSD1306_CONTROL_CMD_STREAM, true); + + // set column start + end + i2c_master_write_byte(cmd, SSD1306_CMD_COLUMN_LOW, true); + i2c_master_write_byte(cmd, SSD1306_CMD_COLUMN_HIGH, true); + + // set page + i2c_master_write_byte(cmd, SSD1306_CMD_PAGE, true); + + i2c_master_stop(cmd); + ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS)); + i2c_cmd_link_delete(cmd); +} + +void ssd1306_clear_line(uint8_t i2address, uint8_t line, bool invert) +{ + i2c_cmd_handle_t cmd; + uint8_t *zeros = calloc(SSD1306_COLUMNS, sizeof(uint8_t)); + // set line + cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (i2address << 1) | I2C_MASTER_WRITE, true); + + i2c_master_write_byte(cmd, SSD1306_CONTROL_CMD_STREAM, true); + i2c_master_write_byte(cmd, SSD1306_CMD_COLUMN_LOW, true); + i2c_master_write_byte(cmd, SSD1306_CMD_COLUMN_HIGH, true); + i2c_master_write_byte(cmd, SSD1306_CMD_PAGE | line, true); + + i2c_master_stop(cmd); + i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + + // fill line with zeros + cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (i2address << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, SSD1306_CONTROL_DATA_STREAM, true); + i2c_master_write(cmd, zeros, SSD1306_COLUMNS, true); + i2c_master_stop(cmd); + i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + + free(zeros); +} + +void ssd1306_clear(uint8_t i2address) +{ + for (uint8_t i = 0; i < SSD1306_PAGES; i++) + { + ssd1306_clear_line(i2address, i, false); + } +} + +void ssd1306_text_line(uint8_t i2address, char *text, uint8_t line, bool invert) +{ + ssd1306_init_data(i2address); + i2c_cmd_handle_t cmd; + + // set line + cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (i2address << 1) | I2C_MASTER_WRITE, true); + + i2c_master_write_byte(cmd, SSD1306_CONTROL_CMD_STREAM, true); + i2c_master_write_byte(cmd, SSD1306_CMD_COLUMN_LOW, true); + i2c_master_write_byte(cmd, SSD1306_CMD_COLUMN_HIGH, true); + i2c_master_write_byte(cmd, SSD1306_CMD_PAGE | line, true); + + i2c_master_stop(cmd); + i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + + uint8_t *linedata = calloc(SSD1306_COLUMNS, sizeof(uint8_t)); + uint8_t font_width = sizeof(ascii_font_5x8[0]); + for (uint8_t i = 0; i < strlen(text); i++) + { + memcpy(&linedata[i * font_width], ascii_font_5x8[(uint8_t)text[i]], font_width); + } + + if (invert) + { + for (uint8_t i = 0; i < SSD1306_COLUMNS; i++) + { + linedata[i] = ~linedata[i]; + } + } + + cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (i2address << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, SSD1306_CONTROL_DATA_STREAM, true); + + i2c_master_write(cmd, linedata, SSD1306_COLUMNS, true); + + i2c_master_stop(cmd); + i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + + free(linedata); +} \ No newline at end of file diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index ee69b20..af3e167 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,4 +1,5 @@ idf_component_register( - SRCS "ena-detection.c" "ena-storage.c" "ena-crypto.c" "main.c" "ena.c" "ena-bluetooth-scan.c" "ena-bluetooth-advertise.c" "ena-detection.c" "ena-interface.c" "ena-interface-menu.c" "ena-interface-datetime.c" + SRCS + "main.c" INCLUDE_DIRS "" ) diff --git a/main/component.mk b/main/component.mk deleted file mode 100644 index cee4d3c..0000000 --- a/main/component.mk +++ /dev/null @@ -1,5 +0,0 @@ - -# -# "main" pseudo-component makefile. -# -# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) \ No newline at end of file diff --git a/main/ena-datastructures.h b/main/ena-datastructures.h deleted file mode 100644 index 2a286a9..0000000 --- a/main/ena-datastructures.h +++ /dev/null @@ -1,91 +0,0 @@ -// 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_ - -#include -#include "ena-crypto.h" - -/** - * @brief different risk levels - * - * not used for now - */ -typedef enum -{ - RISK_LEVEL_INVALID = 0, - RISK_LEVEL_LOWEST, - RISK_LEVEL_LOW, - RISK_LEVEL_LOW_MEDIUM, - RISK_LEVEL_MEDIUM, - RISK_LEVEL_MEDIUM_HIGH, - RISK_LEVEL_HIGH, - RISK_LEVEL_VERY_HIGH, - RISK_LEVEL_HIGHEST, -} ena_risklevel_t; - -/** - * @brief configuration for risk score calculation - * - * not used for now - */ -typedef struct -{ - int minimum_risk_score; - int attenuation_score[8]; - int attenuation_weight; - int days_sinse_last_exposure_score[8]; - int days_sinse_last_exposure_weight; - int duration_scores[8]; - float duration_weight; - int transmission_risk_scores[8]; - float transmission_risk_weight; - uint8_t duration_at_attenuation_thresholds[2]; -} __packed ena_config_t; - -/** - * @brief structure for TEK - */ -typedef struct -{ - 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; - -/** - * @brief sturcture for a temporary detection - */ -typedef struct -{ - 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; - -/** - * @brief sturcture for a detection - */ -typedef struct -{ - 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 deleted file mode 100644 index f1de834..0000000 --- a/main/ena-detection.c +++ /dev/null @@ -1,116 +0,0 @@ -// 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-datastructures.h" -#include "ena-crypto.h" -#include "ena-storage.h" - -#include "ena-detection.h" - -static uint32_t temp_detections_count = 0; -static ena_temp_detection_t temp_detections[ENA_STORAGE_TEMP_DETECTIONS_MAX]; - -ena_detection_t ena_detections_convert(ena_temp_detection_t temp_detection) -{ - ena_detection_t detection; - memcpy(detection.rpi, temp_detection.rpi, ENA_KEY_LENGTH); - memcpy(detection.aem, temp_detection.aem, ENA_AEM_METADATA_LENGTH); - detection.timestamp = temp_detection.timestamp_last; - detection.rssi = temp_detection.rssi; - return detection; -} - -int ena_get_temp_detection_index(uint8_t *rpi, uint8_t *aem) -{ - for (int i = 0; i < temp_detections_count; i++) - { - if (memcmp(temp_detections[i].rpi, rpi, sizeof(ENA_KEY_LENGTH)) == 0 && - memcmp(temp_detections[i].aem, aem, sizeof(ENA_AEM_METADATA_LENGTH)) == 0) - { - return i; - } - } - return -1; -} - -void ena_detections_temp_refresh(uint32_t unix_timestamp) -{ - 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) - { - 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_add_detection(&detection); - ena_storage_remove_temp_detection(i); - } - else - // delete temp detections older than two times time window (two times to be safe, one times time window enough?!) - if (unix_timestamp - temp_detections[i].timestamp_last > (ENA_TIME_WINDOW * 2)) - { - ESP_LOGD(ENA_DETECTION_LOG, "remove old temporary detection %u", i); - ena_storage_remove_temp_detection(i); - } - } - - // update detections - temp_detections_count = ena_storage_temp_detections_count(); - for (int i = 0; i < temp_detections_count; i++) - { - ena_storage_get_temp_detection(i, &temp_detections[i]); - } - - // DEBUG dump - ena_storage_dump_tek(); - ena_storage_dump_temp_detections(); - ena_storage_dump_detections(); -} - -void ena_detection(uint32_t unix_timestamp, uint8_t *rpi, uint8_t *aem, int rssi) -{ - uint32_t detection_index = ena_get_temp_detection_index(rpi, aem); - - if (detection_index == -1) - { - temp_detections[temp_detections_count].timestamp_first = unix_timestamp; - memcpy(temp_detections[temp_detections_count].rpi, rpi, ENA_KEY_LENGTH); - 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_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); - ESP_LOG_BUFFER_HEX_LEVEL(ENA_DETECTION_LOG, aem, ENA_AEM_METADATA_LENGTH, ESP_LOG_DEBUG); - ESP_LOGD(ENA_DETECTION_LOG, "RSSI %d", rssi); - - if (detection_index != temp_detections_count) - { - ESP_LOGW(ENA_DETECTION_LOG, "last temporary detection index does not match array index!"); - } - temp_detections_count++; - } - else - { - 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-storage.h b/main/ena-storage.h deleted file mode 100644 index f8703a7..0000000 --- a/main/ena-storage.h +++ /dev/null @@ -1,189 +0,0 @@ -// 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" // 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 - -/** - * @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); - -/** - * @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); - -/** - * @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); - -/** - * @brief get last stored TEK - * - * @param[out] tek pointer to write last TEK to - * - * @return - * total number of TEKs stored - */ -uint32_t ena_storage_read_last_tek(ena_tek_t *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); - -/** - * @brief get number of stored temporary detections - * - * @return - * total number of temporary detections stored - */ -uint32_t ena_storage_temp_detections_count(void); - -/** - * @brief get temporary detection at given index - * - * @param[in] index the index of the temporary detection to read - * @param[out] detection pointer to temporary to write to - */ -void ena_storage_get_temp_detection(uint32_t index, ena_temp_detection_t *detection); - -/** - * @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); - -/** - * @brief get number of stored detections - * - * @return - * total number of detections stored - */ -uint32_t ena_storage_detections_count(void); - -/** - * @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_get_detection(uint32_t index, ena_detection_t *detection); - -/** - * @brief store detection - * - * @param[in] detection new detection to store - */ -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/main.c b/main/main.c index 3a29f8e..4bc27ce 100644 --- a/main/main.c +++ b/main/main.c @@ -21,21 +21,33 @@ #include "esp_log.h" #include "ena.h" -#include "ena-detection.h" #include "ena-storage.h" #include "ena-interface.h" #include "ena-interface-menu.h" +#include "ssd1306.h" #include "sdkconfig.h" void app_main(void) { // DEBUG set time - struct timeval tv = {1594459800, 0}; // current hardcoded timestamp (2020-07-11 09:30:00) ¯\_(ツ)_/¯ + struct timeval tv = {1594843200, 0}; // current hardcoded timestamp ¯\_(ツ)_/¯ settimeofday(&tv, NULL); esp_log_level_set(ENA_STORAGE_LOG, ESP_LOG_INFO); - // ena_storage_erase(); // only needed on first start! TODO automatically check (how?) + + ssd1306_start(SSD1306_ADDRESS); + ssd1306_clear(SSD1306_ADDRESS); + + // TODO + ssd1306_text_line(SSD1306_ADDRESS, " TODO TODO", 0, false); + ssd1306_text_line(SSD1306_ADDRESS, " TODO", 1, true); + ssd1306_text_line(SSD1306_ADDRESS, " TODO TODO", 2, false); + ssd1306_text_line(SSD1306_ADDRESS, " TODO", 3, true); + ssd1306_text_line(SSD1306_ADDRESS, " TODO TODO", 4, false); + ssd1306_text_line(SSD1306_ADDRESS, " TODO", 5, true); + ssd1306_text_line(SSD1306_ADDRESS, " TODO TODO", 6, false); + ssd1306_text_line(SSD1306_ADDRESS, " TODO", 7, true); ena_interface_start(); ena_interface_menu_start();