Refactor and Clean Project for essential functionality

This commit is contained in:
Patrick Rathje 2022-05-27 21:52:29 +02:00
parent 6f9de16bd1
commit 612b638433
39 changed files with 579 additions and 2959 deletions

3
.gitignore vendored
View File

@ -46,4 +46,5 @@ massif-*
.pio
.vscode
.DS_Store
.DS_Store
/.idea

View File

@ -1,25 +0,0 @@
#ifndef BLOOM_H
#define BLOOM_H
#include "ens/storage.h"
#include "exposure-notification.h"
typedef struct {
uint8_t* data;
size_t size;
} bloom_filter_t;
/**
* Initialize the bloom filter on basis of the already registerred records.
*/
bloom_filter_t* bloom_init(size_t size);
void bloom_destroy(bloom_filter_t* bloom);
// TODO lome: maybe only use RPI (should be sufficient)
void bloom_add_record(bloom_filter_t* bloom, ENIntervalIdentifier* rpi);
// TODO lome: maybe only use RPI (should be sufficient)
bool bloom_probably_has_record(bloom_filter_t* bloom, ENIntervalIdentifier* rpi);
#endif

View File

@ -1,66 +0,0 @@
/*
* Copyright (c) 2020 Olaf Landsiedel
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef CONTACTS_H
#define CONTACTS_H
#include <zephyr.h>
#include <zephyr/types.h>
#include "covid.h"
#include "covid_types.h"
#include "ens/storage.h"
#include "exposure-notification.h"
typedef struct {
ENIntervalIdentifier interval_identifier;
int met;
time_t search_start;
time_t search_end;
} __packed infected_for_interval_ident_ctx_t;
typedef struct {
ENPeriodKey periodKey;
time_t start;
int met;
} __packed period_key_information_t;
typedef int (*test_func_t)(infected_for_interval_ident_ctx_t* infectedIntervals, int count);
void print_key(_ENBaseKey* key);
void print_rpi(rolling_proximity_identifier_t* rpi);
void print_aem(associated_encrypted_metadata_t* aem);
/**
* Register a new record in the system. This includes adding it to the storage and adding it to the bloom filter.
*
* @param record record to add
* @returns 0 in case of success, -ERRNO in case of an error
*/
int register_record(record_t* record);
/**
* Initialize the contacts module.
*/
int init_contacts();
/**
* Check for a list of specified interval identifiers, whether they were probably met or not.
* @param ctx list of interval identifiers to check
* @param count amount of identifiers to check
* @return the amount of met intervals, -ERRNO on error
*/
int check_possible_contacts_for_intervals(infected_for_interval_ident_ctx_t* ctx, int count);
/**
* Check for a list of specified period keys, whether they were probably met or not.
* @param ctx list of period keys and their meta information to check
* @param count amount of period keys to check
* @return -ERRNO on error, 0 otherwise
*/
int check_possible_contacts_for_periods(period_key_information_t periodKeyInformation[], int count);
#endif

View File

@ -1,31 +0,0 @@
/*
* Copyright (c) 2020 Olaf Landsiedel
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef COVID_H
#define COVID_H
#include <zephyr.h>
#include "exposure-notification.h"
typedef struct period{
ENPeriodKey periodKey;
ENIntervalNumber periodInterval;
} __packed period_t;
int init_covid();
int do_covid();
bool get_infection();
void set_infection(bool _infected);
unsigned int get_period_cnt_if_infected();
period_t* get_period_if_infected(unsigned int id, size_t* size);
int get_index_by_interval(ENIntervalNumber periodInterval);
void print_periods();
#endif

View File

@ -1,33 +0,0 @@
/*
* Copyright (c) 2020 Olaf Landsiedel
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef COVID_TYPES_H
#define COVID_TYPES_H
#include <exposure-notification.h>
#include <zephyr.h>
#include <zephyr/types.h>
#define COVID_ROLLING_PROXIMITY_IDENTIFIER_LEN 16
typedef ENIntervalIdentifier rolling_proximity_identifier_t;
typedef struct bt_metadata {
uint8_t version;
uint8_t tx_power;
uint8_t rsv1;
uint8_t rsv2;
} __packed bt_metadata_t;
// typedef struct bt_metadata bt_metadata_t;
typedef struct associated_encrypted_metadata {
uint8_t data[sizeof(bt_metadata_t)];
} __packed associated_encrypted_metadata_t;
typedef uint8_t rssi_t;
#endif

View File

@ -1,73 +0,0 @@
#ifndef DISPLAY_H
#define DISPLAY_H
/**
* @brief Initializes all display elements and adds them to the canvas.
*
* @return int
*/
int init_display();
/**
* @brief Updates all information on the display using the get functions, defined by `display.c`. Alternatively the
* values of the displayed elements can be set explicitly via set `display_set_<property>`-functions.
*
* @return int
*/
int update_display();
/**
* @brief This is the entry point for the display thread. It peridocially updates the display and handles input events.
*
*/
void display_thread(void*, void*, void*);
/**
* @brief Displays a message at the bottom of the display. The message will persist until it is removed expicitly, by calling `display_set_message("")`.
*
* @param msg A pointer to the string that should be displayed
* @return int
*/
int display_set_message(char* msg);
/**
* @brief Sets the on display clock. The time should have the format `h * 100 + m`. So `display_set_time(1145)` sets the clock to 11:45.
*
* @param time A number representation of the time
* @return int
*/
int display_set_time(int time);
/**
* @brief Set the battery level percentage.
*
* @param bat The battery level in percent
* @return int
*/
int display_set_bat(int bat);
/**
* @brief Set the non-volatile memory state.
*
* @param mem The occupied memory in percent
* @return int
*/
int display_set_mem(int mem);
/**
* @brief Set the number of total registered contacts in the last 14 days.
*
* @param contacts The number of contacts
* @return int
*/
int display_set_contacts(int contacts);
/**
* @brief Set the number of contacts that were tested positively on Covid and registered in the last 14 days.
*
* @param risk_contacts The number of risk contacts
* @return int
*/
int display_set_risk_contacts(int risk_contacts);
#endif

View File

@ -1,10 +0,0 @@
#ifndef ENS_ERROR_H
#define ENS_ERROR_H
#define ENS_INTERR 1 // internal error
#define ENS_NOENT 2 // entry not found or invalid
#define ENS_DELENT 3 // entry got deleted
#define ENS_ADDRINU 4 // address alread in use or corrupt
#define ENS_INVARG 5 // invalid argument
#endif

View File

@ -1,61 +0,0 @@
/*
* Copyright (c) 2021 Louis Meyer and Patrick Rathje
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ENS_RECORDS_H
#define ENS_RECORDS_H
#include "sequencenumber.h"
#include "storage.h"
typedef struct record_iterator {
/**
* @internal
*/
record_t current;
/**
* @internal
*/
record_sequence_number_t sn_next;
/**
* @internal
*/
record_sequence_number_t sn_end; // the last sn to include
/**
* @internal
*/
uint8_t finished;
} record_iterator_t;
// Also uses start and end from storage if NULL pointers given
// iterate over a sequence number range of records (Null will select the latest and newest for start / end)
// automatically
int ens_records_iterator_init_range(record_iterator_t* iterator,
record_sequence_number_t* opt_start,
record_sequence_number_t* opt_end);
// TODO: Do we guarantee that higher sequence numbers have at least our timestamp and lower sequence numbers up to our
// timestamp?
int ens_records_iterator_init_timerange(record_iterator_t* iterator, time_t* ts_start, time_t* ts_end);
record_t* ens_records_iterator_next(record_iterator_t* iter);
int ens_record_iterator_clear(record_iterator_t* iter);
// TODO: Is a callback the easiest thing to do? -> now it is the iterator :)
// TODO: should we really indicated the last record by sending a NULL pointer?
typedef uint8_t (*ens_record_iterator_cb_t)(const record_t* record, void* userdata);
enum {
ENS_RECORD_ITER_STOP, // STOP the iteration, this would not result in a NULL callback after the end is reached
ENS_RECORD_ITER_CONTINUE, // CONTINUE the iteration, this results in a NULL callback after the end is reached
};
// TODO: this function could be made asynchronous to handle delays in contact_storage reads?!
// TODO: How can we handle iteration while records are being added or deleted? (should be safe as long as the
// load_record function is thread safe?!)
uint8_t ens_records_iterate_with_callback(record_iterator_t* iter, ens_record_iterator_cb_t cb, void* userdata);
#endif

View File

@ -1,80 +0,0 @@
#ifndef CONTACT_STORAGE_H
#define CONTACT_STORAGE_H
#include <zephyr/types.h>
#include "covid_types.h"
#include "sequencenumber.h"
typedef uint64_t storage_id_t;
typedef struct record {
record_sequence_number_t sn; // TODO: Convert Sequence Number
uint32_t timestamp; // TODO: Seconds from january first 2000 (UTC+0)
rssi_t rssi; // TODO: Check correct
rolling_proximity_identifier_t rolling_proximity_identifier;
associated_encrypted_metadata_t associated_encrypted_metadata;
} __packed record_t;
typedef struct stored_records_information {
record_sequence_number_t oldest_contact;
uint32_t count;
} stored_records_information_t;
/**
* Initializes the contact storage component
* @param clean flag for indicating, if storage shall be init with clean state
*
* @return 0 for success
*/
int init_record_storage(bool clean);
/**
* Reset state of record storage.
*/
void reset_record_storage();
/**
* Loads the record with number sn into the destination struct
* @param dest
* @param sn
* @return 0 in case of success
*/
int load_record(record_t* dest, record_sequence_number_t sn);
/**
* Stores the record from src with number sn, increases latest sequence number
* @param sn
* @param src
* @return 0 in case of success
*/
int add_record(record_t* src);
/**
* Deletes the record from storage with number sn
* @param sn the sequence number to delete
* @return 0 in case of success
*/
int delete_record(record_sequence_number_t sn);
/**
* TODO: How to handle if none is available?
* @return The latest available sequence number (Caution: can actually be lower than the oldes in case of a
* wrap-around!)
*/
record_sequence_number_t get_latest_sequence_number();
/**
* TODO: How to handle if none is available?
* @return The oldest available sequence number
*/
record_sequence_number_t get_oldest_sequence_number();
/**
* @return The amount of contacts, usually get_latest_sequence_number() - get_oldest_sequence_number()
*/
uint32_t get_num_records();
int get_sequence_number_interval(record_sequence_number_t* oldest, record_sequence_number_t* latest);
#endif

View File

@ -1,355 +0,0 @@
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: export.proto */
#ifndef PROTOBUF_C_export_2eproto__INCLUDED
#define PROTOBUF_C_export_2eproto__INCLUDED
#include <protobuf-c.h>
PROTOBUF_C__BEGIN_DECLS
#if PROTOBUF_C_VERSION_NUMBER < 1000000
# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
#elif 1004000 < PROTOBUF_C_MIN_COMPILER_VERSION
# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
#endif
typedef struct TemporaryExposureKeyExport TemporaryExposureKeyExport;
typedef struct SignatureInfo SignatureInfo;
typedef struct TemporaryExposureKey TemporaryExposureKey;
typedef struct TEKSignatureList TEKSignatureList;
typedef struct TEKSignature TEKSignature;
/* --- enums --- */
/*
* Data type representing why this key was published.
*/
typedef enum _TemporaryExposureKey__ReportType {
/*
* Never returned by the client API.
*/
TEMPORARY_EXPOSURE_KEY__REPORT_TYPE__UNKNOWN = 0,
TEMPORARY_EXPOSURE_KEY__REPORT_TYPE__CONFIRMED_TEST = 1,
TEMPORARY_EXPOSURE_KEY__REPORT_TYPE__CONFIRMED_CLINICAL_DIAGNOSIS = 2,
TEMPORARY_EXPOSURE_KEY__REPORT_TYPE__SELF_REPORT = 3,
TEMPORARY_EXPOSURE_KEY__REPORT_TYPE__RECURSIVE = 4,
/*
* Used to revoke a key, never returned by client API.
*/
TEMPORARY_EXPOSURE_KEY__REPORT_TYPE__REVOKED = 5
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(TEMPORARY_EXPOSURE_KEY__REPORT_TYPE)
} TemporaryExposureKey__ReportType;
/* --- messages --- */
/*
* Protobuf definition for exports of confirmed temporary exposure keys.
* The full file format is documented under "Exposure Key Export File Format
* and Verification" at https://www.google.com/covid19/exposurenotifications/
* These files have a 16-byte, space-padded header before the protobuf data
* starts. They will be contained in a zip archive, alongside a signature
* file verifying the contents.
*/
struct TemporaryExposureKeyExport
{
ProtobufCMessage base;
/*
* Time window of keys in this file based on arrival to server, in UTC
* seconds. start_timestamp, end_timestamp, and batch_num must be unique
* at any given snapshot of the index for a server. If multiple
* files are used for a specific time period, and batch_num/batch_size
* are both 1 (See below), then offsetting the end_timestamp is the
* suggested method for forcing uniqueness.
*/
protobuf_c_boolean has_start_timestamp;
uint64_t start_timestamp;
protobuf_c_boolean has_end_timestamp;
uint64_t end_timestamp;
/*
* Region for which these keys came from (e.g., country)
*/
char *region;
/*
* E.g., Batch 2 of 10. Ordinal, 1-based numbering.
* Note: Not yet supported on iOS. Use values of 1 for both.
*/
protobuf_c_boolean has_batch_num;
int32_t batch_num;
protobuf_c_boolean has_batch_size;
int32_t batch_size;
/*
* Information about signatures
* If there are multiple entries, they must be ordered in descending
* time order by signing key effective time (most recent one first).
* There is a limit of 10 signature infos per export file (mobile OS may
* not check anything after that).
*/
size_t n_signature_infos;
SignatureInfo **signature_infos;
/*
* The TemporaryExposureKeys for initial release of keys.
* Keys should be included in this list for initial release,
* whereas revised or revoked keys should go in revised_keys.
*/
size_t n_keys;
TemporaryExposureKey **keys;
/*
* TemporaryExposureKeys that have changed status.
* Keys should be included in this list if they have changed status
* or have been revoked.
*/
size_t n_revised_keys;
TemporaryExposureKey **revised_keys;
};
#define TEMPORARY_EXPOSURE_KEY_EXPORT__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&temporary_exposure_key_export__descriptor) \
, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0,NULL, 0,NULL, 0,NULL }
struct SignatureInfo
{
ProtobufCMessage base;
/*
* Key version for rollovers
* Must be in character class [a-zA-Z0-9_]. E.g., 'v1'
*/
char *verification_key_version;
/*
* Alias with which to identify public key to be used for verification
* Must be in character class [a-zA-Z0-9_]
* For cross-compatibility with Apple, use MCC
* (https://en.wikipedia.org/wiki/Mobile_country_code).
*/
char *verification_key_id;
/*
* ASN.1 OID for Algorithm Identifier. Supported algorithms are
* either 1.2.840.10045.4.3.2 or 1.2.840.10045.4.3.4
*/
char *signature_algorithm;
};
#define SIGNATURE_INFO__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&signature_info__descriptor) \
, NULL, NULL, NULL }
struct TemporaryExposureKey
{
ProtobufCMessage base;
/*
* Key of infected user
*/
protobuf_c_boolean has_key_data;
ProtobufCBinaryData key_data;
/*
* Varying risks associated with exposure depending on type of verification
* Ignored by the v1.5 client API when report_type is set.
*/
protobuf_c_boolean has_transmission_risk_level PROTOBUF_C__DEPRECATED;
int32_t transmission_risk_level PROTOBUF_C__DEPRECATED;
/*
* The interval number since epoch for which a key starts
*/
protobuf_c_boolean has_rolling_start_interval_number;
int32_t rolling_start_interval_number;
/*
* Increments of 10 minutes describing how long a key is valid
*/
/*
* defaults to 24 hours
*/
protobuf_c_boolean has_rolling_period;
int32_t rolling_period;
/*
* Type of diagnosis associated with a key.
*/
protobuf_c_boolean has_report_type;
TemporaryExposureKey__ReportType report_type;
/*
* Number of days elapsed between symptom onset and the TEK being used.
* E.g. 2 means TEK is 2 days after onset of symptoms.
*/
protobuf_c_boolean has_days_since_onset_of_symptoms;
int32_t days_since_onset_of_symptoms;
};
#define TEMPORARY_EXPOSURE_KEY__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&temporary_exposure_key__descriptor) \
, 0, {0,NULL}, 0, 0, 0, 0, 0, 144, 0, TEMPORARY_EXPOSURE_KEY__REPORT_TYPE__UNKNOWN, 0, 0 }
struct TEKSignatureList
{
ProtobufCMessage base;
/*
* When there are multiple signatures, they must be sorted in time order
* by first effective date for the signing key in descending order.
* The most recent effective signing key must appear first.
* There is a limit of 10 signature infos per export file (mobile OS may
* not check anything after that).
*/
size_t n_signatures;
TEKSignature **signatures;
};
#define TEKSIGNATURE_LIST__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&teksignature_list__descriptor) \
, 0,NULL }
struct TEKSignature
{
ProtobufCMessage base;
/*
* Info about the signing key, version, algorithm, etc.
*/
SignatureInfo *signature_info;
/*
* E.g., Batch 2 of 10
* Must match fields from TemporaryExposureKeyExport, see
* documentation on that message.
*/
protobuf_c_boolean has_batch_num;
int32_t batch_num;
protobuf_c_boolean has_batch_size;
int32_t batch_size;
/*
* Signature in X9.62 format (ASN.1 SEQUENCE of two INTEGER fields)
*/
protobuf_c_boolean has_signature;
ProtobufCBinaryData signature;
};
#define TEKSIGNATURE__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&teksignature__descriptor) \
, NULL, 0, 0, 0, 0, 0, {0,NULL} }
/* TemporaryExposureKeyExport methods */
void temporary_exposure_key_export__init
(TemporaryExposureKeyExport *message);
size_t temporary_exposure_key_export__get_packed_size
(const TemporaryExposureKeyExport *message);
size_t temporary_exposure_key_export__pack
(const TemporaryExposureKeyExport *message,
uint8_t *out);
size_t temporary_exposure_key_export__pack_to_buffer
(const TemporaryExposureKeyExport *message,
ProtobufCBuffer *buffer);
TemporaryExposureKeyExport *
temporary_exposure_key_export__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void temporary_exposure_key_export__free_unpacked
(TemporaryExposureKeyExport *message,
ProtobufCAllocator *allocator);
/* SignatureInfo methods */
void signature_info__init
(SignatureInfo *message);
size_t signature_info__get_packed_size
(const SignatureInfo *message);
size_t signature_info__pack
(const SignatureInfo *message,
uint8_t *out);
size_t signature_info__pack_to_buffer
(const SignatureInfo *message,
ProtobufCBuffer *buffer);
SignatureInfo *
signature_info__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void signature_info__free_unpacked
(SignatureInfo *message,
ProtobufCAllocator *allocator);
/* TemporaryExposureKey methods */
void temporary_exposure_key__init
(TemporaryExposureKey *message);
size_t temporary_exposure_key__get_packed_size
(const TemporaryExposureKey *message);
size_t temporary_exposure_key__pack
(const TemporaryExposureKey *message,
uint8_t *out);
size_t temporary_exposure_key__pack_to_buffer
(const TemporaryExposureKey *message,
ProtobufCBuffer *buffer);
TemporaryExposureKey *
temporary_exposure_key__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void temporary_exposure_key__free_unpacked
(TemporaryExposureKey *message,
ProtobufCAllocator *allocator);
/* TEKSignatureList methods */
void teksignature_list__init
(TEKSignatureList *message);
size_t teksignature_list__get_packed_size
(const TEKSignatureList *message);
size_t teksignature_list__pack
(const TEKSignatureList *message,
uint8_t *out);
size_t teksignature_list__pack_to_buffer
(const TEKSignatureList *message,
ProtobufCBuffer *buffer);
TEKSignatureList *
teksignature_list__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void teksignature_list__free_unpacked
(TEKSignatureList *message,
ProtobufCAllocator *allocator);
/* TEKSignature methods */
void teksignature__init
(TEKSignature *message);
size_t teksignature__get_packed_size
(const TEKSignature *message);
size_t teksignature__pack
(const TEKSignature *message,
uint8_t *out);
size_t teksignature__pack_to_buffer
(const TEKSignature *message,
ProtobufCBuffer *buffer);
TEKSignature *
teksignature__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void teksignature__free_unpacked
(TEKSignature *message,
ProtobufCAllocator *allocator);
/* --- per-message closures --- */
typedef void (*TemporaryExposureKeyExport_Closure)
(const TemporaryExposureKeyExport *message,
void *closure_data);
typedef void (*SignatureInfo_Closure)
(const SignatureInfo *message,
void *closure_data);
typedef void (*TemporaryExposureKey_Closure)
(const TemporaryExposureKey *message,
void *closure_data);
typedef void (*TEKSignatureList_Closure)
(const TEKSignatureList *message,
void *closure_data);
typedef void (*TEKSignature_Closure)
(const TEKSignature *message,
void *closure_data);
/* --- services --- */
/* --- descriptors --- */
extern const ProtobufCMessageDescriptor temporary_exposure_key_export__descriptor;
extern const ProtobufCMessageDescriptor signature_info__descriptor;
extern const ProtobufCMessageDescriptor temporary_exposure_key__descriptor;
extern const ProtobufCEnumDescriptor temporary_exposure_key__report_type__descriptor;
extern const ProtobufCMessageDescriptor teksignature_list__descriptor;
extern const ProtobufCMessageDescriptor teksignature__descriptor;
PROTOBUF_C__END_DECLS
#endif /* PROTOBUF_C_export_2eproto__INCLUDED */

View File

@ -1,41 +0,0 @@
#ifndef EXTRACT_KEYS_H
#define EXTRACT_KEYS_H
#include "export.pb-c.h"
/**
* @brief Process a key. This function could trigger the comparision between the key and those registered by the ENS.
*
* @param key A pointer to the Exposure key data structure
*/
void process_key(TemporaryExposureKey* key);
/**
* @brief Generates a protocol buffer containing dummy keys.
*
* @param buffer_pointer A pointer to the pointer which will be used to reference the buffer externally. This will be
* set to the memory area allocated to store the protocol buffer.
* @param num_keys The number of keys that will be generated
* @return size_t The size of the protocol buffer
*/
size_t generate_keys(uint8_t** buffer_pointer, int num_keys);
/**
* @brief Unpacks the protocol buffer and iterates the `process_key` function over all keys.
*
* @param buf a pointer to the buffer
* @param buf_size the size of the buffer in bytes
* @return int
*/
int unpack_keys(uint8_t* buf, size_t buf_size);
/**
* @brief Generates an protocol buffer with a specified number of keys and measures the time to execute `unpack_keys`,
* which unpacks the protocol buffer and iterates `process_key` over the keys.
*
* @param num_keys the number of keys that will be created
* @return int
*/
int test_unpacking(int num_keys);
#endif

View File

@ -1,13 +0,0 @@
/*
* Copyright (c) 2020 Olaf Landsiedel
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef GATT_SERVICE_H
#define GATT_SERVICE_H
int init_gatt(void);
int do_gatt(void);
#endif

151
include/record_storage.h Normal file
View File

@ -0,0 +1,151 @@
/*
* Copyright (c) 2020 Olaf Landsiedel
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef RECORD_STORAGE_H
#define RECORD_STORAGE_H
#include <zephyr/types.h>
#include "utility/sequencenumber.h"
#include <exposure-notification.h>
/**
* RECORD STORAGE
*/
typedef uint64_t storage_id_t;
typedef struct bt_metadata {
uint8_t version;
uint8_t tx_power;
uint8_t rsv1;
uint8_t rsv2;
} __packed bt_metadata_t;
typedef struct associated_encrypted_metadata {
uint8_t data[sizeof(bt_metadata_t)];
} __packed associated_encrypted_metadata_t;
typedef struct record {
record_sequence_number_t sn; // TODO: Convert Sequence Number
uint32_t timestamp; // TODO: Seconds from january first 2000 (UTC+0)
uint8_t rssi; // TODO: Check correct
ENIntervalIdentifier rolling_proximity_identifier;
associated_encrypted_metadata_t associated_encrypted_metadata;
} __packed record_t;
typedef struct stored_records_information {
record_sequence_number_t oldest_contact;
uint32_t count;
} stored_records_information_t;
/**
* Initializes the contact storage component
* @param clean flag for indicating, if storage shall be init with clean state
*
* @return 0 for success
*/
int record_storage_init(bool clean);
/**
* Reset state of record storage.
*/
void reset_record_storage();
/**
* Loads the record with number sn into the destination struct
* @param dest
* @param sn
* @return 0 in case of success
*/
int load_record(record_t* dest, record_sequence_number_t sn);
/**
* Stores the record from src with number sn, increases latest sequence number
* @param sn
* @param src
* @return 0 in case of success
*/
int add_record(record_t* src);
/**
* Deletes the record from storage with number sn
* @param sn the sequence number to delete
* @return 0 in case of success
*/
int delete_record(record_sequence_number_t sn);
/**
* TODO: How to handle if none is available?
* @return The latest available sequence number (Caution: can actually be lower than the oldes in case of a
* wrap-around!)
*/
record_sequence_number_t get_latest_sequence_number();
/**
* TODO: How to handle if none is available?
* @return The oldest available sequence number
*/
record_sequence_number_t get_oldest_sequence_number();
/**
* @return The amount of contacts, usually get_latest_sequence_number() - get_oldest_sequence_number()
*/
uint32_t get_num_records();
int get_sequence_number_interval(record_sequence_number_t* oldest, record_sequence_number_t* latest);
/**
* RECORD ITERATOR
*/
typedef struct record_iterator {
/**
* @internal
*/
record_t current;
/**
* @internal
*/
record_sequence_number_t sn_next;
/**
* @internal
*/
record_sequence_number_t sn_end; // the last sn to include
/**
* @internal
*/
uint8_t finished;
} record_iterator_t;
// Also uses start and end from storage if NULL pointers given
// iterate over a sequence number range of records (Null will select the latest and newest for start / end)
// automatically
int ens_records_iterator_init_range(record_iterator_t* iterator,
record_sequence_number_t* opt_start,
record_sequence_number_t* opt_end);
// TODO: Do we guarantee that higher sequence numbers have at least our timestamp and lower sequence numbers up to our
// timestamp?
int ens_records_iterator_init_timerange(record_iterator_t* iterator, time_t* ts_start, time_t* ts_end);
record_t* ens_records_iterator_next(record_iterator_t* iter);
int ens_record_iterator_clear(record_iterator_t* iter);
// TODO: Is a callback the easiest thing to do? -> now it is the iterator :)
// TODO: should we really indicated the last record by sending a NULL pointer?
typedef uint8_t (*ens_record_iterator_cb_t)(const record_t* record, void* userdata);
enum {
ENS_RECORD_ITER_STOP, // STOP the iteration, this would not result in a NULL callback after the end is reached
ENS_RECORD_ITER_CONTINUE, // CONTINUE the iteration, this results in a NULL callback after the end is reached
};
// TODO: this function could be made asynchronous to handle delays in contact_storage reads?!
// TODO: How can we handle iteration while records are being added or deleted? (should be safe as long as the
// load_record function is thread safe?!)
uint8_t ens_records_iterate_with_callback(record_iterator_t* iter, ens_record_iterator_cb_t cb, void* userdata);
#endif

13
include/sync_service.h Normal file
View File

@ -0,0 +1,13 @@
/*
* Copyright (c) 2020 Olaf Landsiedel
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef SYNC_SERVICE_H
#define SYNC_SERVICE_H
int sync_service_init(void);
int sync_service_run(void);
#endif

35
include/tek_storage.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2020 Olaf Landsiedel
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef tek_storage_H
#define tek_storage_H
#include <exposure-notification.h>
#include <zephyr/types.h>
#include "utility/sequencenumber.h"
#include "record_storage.h"
typedef struct tek {
uint32_t timestamp; // Seconds from january first 2000 (UTC+0)
ENPeriodKey tek; // the temporary exposure key
} __packed tek_t;
/**
* Initializes the contact storage component
* @param clean flag for indicating, if storage shall be init with clean state
*
* @return 0 for success
*/
int tek_storage_init(bool clean);
int tek_storage_add(tek_t* src);
int tek_storage_delete(tek_t* src);
/**
* Returns 0 on success, else non zero (if none available)
*/
int tek_storage_get_latest_at_ts(tek_t* dest, uint32_t timestamp);
#endif

View File

@ -1,14 +1,13 @@
/* io.h - Application main entry point */
/*
* Copyright (c) 2020 Olaf Landsiedel
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef IO_H
#define IO_H
#ifndef TRACING_H
#define TRACING_H
int init_io();
int tracing_init(void);
int tracing_run(void);
#endif

View File

@ -1,9 +0,0 @@
#ifndef UTIL_H
#define UTIL_H
// TODO: We should use timeutil_sync
// return the current unix timestamp in seconds
uint32_t time_get_unix_seconds();
#endif // UTIL_H

View File

@ -7,6 +7,12 @@
#include <stdint.h>
#include <storage/flash_map.h>
#define ENS_INTERR 1 // internal error
#define ENS_NOENT 2 // entry not found or invalid
#define ENS_DELENT 3 // entry got deleted
#define ENS_ADDRINU 4 // address alread in use or corrupt
#define ENS_INVARG 5 // invalid argument
typedef struct ens_fs {
/**
* Flash area for this file system.

16
include/utility/util.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef UTIL_H
#define UTIL_H
#include <exposure-notification.h>
#include "../record_storage.h" // TODO: this dependency is not great...
// TODO: We should use timeutil_sync
// return the current unix timestamp in seconds
uint32_t time_get_unix_seconds();
void print_key(_ENBaseKey* key);
void print_rpi(ENIntervalIdentifier* rpi);
void print_aem(associated_encrypted_metadata_t* aem);
#endif // UTIL_H

View File

@ -16,7 +16,7 @@ platform = nordicnrf52@7.0.0
board = nrf52840_dk
framework = zephyr
monitor_speed = 115200
upload_protocol = jlink
;upload_protocol = jlink
test_ignore = test_desktop
build_flags =
-Iinclude/tls_config
@ -28,12 +28,12 @@ lib_deps =
prathje/exposure-notification @ ^0.1
lib_ignore =
mbedtls
src_filter = -<../src/main_test.c>
;src_filter = -<../src/main_test.c>
[env:nrf52840_dk_test]
src_filter = -<../src/main.c>
extends = env:nrf52840_dk
board = nrf52840_mdk
;[env:nrf52840_dk_test]
;src_filter = -<../src/main.c>
;extends = env:nrf52840_dk
;board = nrf52840_mdk
[env:nrf52840_mdk]

View File

@ -1,46 +0,0 @@
#include "bloom.h"
#include "ens/storage.h"
#include "exposure-notification.h"
bloom_filter_t* bloom_init(size_t size) {
bloom_filter_t* bloom = k_calloc(1, sizeof(bloom_filter_t));
if (!bloom) {
return NULL;
}
bloom->size = size;
bloom->data = k_calloc(size, sizeof(uint8_t));
if (!bloom->data) {
bloom->size = 0;
k_free(bloom);
return NULL;
}
return bloom;
}
void bloom_destroy(bloom_filter_t* bloom) {
if (bloom) {
k_free(bloom->data);
k_free(bloom);
}
}
void bloom_add_record(bloom_filter_t* bloom, ENIntervalIdentifier* rpi) {
uint8_t* data = bloom->data;
for (int i = 0; i < sizeof(*rpi); i += 2) {
uint32_t hash = (rpi->b[i] << 8) | rpi->b[i + 1];
hash %= bloom->size * 8;
data[hash / 8] |= 1 << (hash % 8);
}
}
bool bloom_probably_has_record(bloom_filter_t* bloom, ENIntervalIdentifier* rpi) {
uint8_t* data = bloom->data;
for (int i = 0; i < sizeof(*rpi); i += 2) {
uint32_t hash = (rpi->b[i] << 8) | rpi->b[i + 1];
hash %= bloom->size * 8;
if (!(data[hash / 8] & (1 << (hash % 8)))) {
return false;
}
}
return true;
}

View File

@ -1,328 +0,0 @@
/*
* Copyright (c) 2020 Olaf Landsiedel
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <string.h>
#include <sys/printk.h>
#include <sys/util.h>
#include <timing/timing.h>
#include <zephyr.h>
#include <zephyr/types.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <device.h>
#include <devicetree.h>
#include <drivers/gpio.h>
#include "bloom.h"
#include "contacts.h"
#include "covid.h"
#include "covid_types.h"
#include "ens/records.h"
#include "ens/storage.h"
#include "exposure-notification.h"
// #define CONFIG_INTERVAL_SPREAD 100
void print_key(_ENBaseKey* key) {
for (int i = 0; i < sizeof(key->b); i++) {
printk("%02x", key->b[i]);
}
}
void print_rpi(rolling_proximity_identifier_t* rpi) {
for (int i = 0; i < sizeof(rolling_proximity_identifier_t); i++) {
printk("%02x", rpi->b[i]);
}
}
void print_aem(associated_encrypted_metadata_t* aem) {
for (int i = 0; i < sizeof(associated_encrypted_metadata_t); i++) {
printk("%02x", aem->data[i]);
}
}
int register_record(record_t* record) {
return add_record(record);
}
/**
* Simple implementation, where an iterator is created for every element in the passed arrray.
*/
int get_number_of_infected_for_multiple_intervals_simple(infected_for_interval_ident_ctx_t* ctx, int count) {
record_iterator_t iterator;
for (int i = 0; i < count; i++) {
if (!ctx[i].met) {
continue;
}
ctx[i].met = 0;
int rc = ens_records_iterator_init_timerange(&iterator, &ctx[i].search_start, &ctx[i].search_end);
if (rc) {
// on error, skip this rpi
continue;
}
record_t* current;
while ((current = ens_records_iterator_next(&iterator))) {
if (memcmp(&(current->rolling_proximity_identifier), &ctx[i].interval_identifier,
sizeof(rolling_proximity_identifier_t)) == 0) {
ctx[i].met++;
}
}
}
return 0;
}
/**
* Fill the bloom filter with all stored records.
*/
void fill_bloom_with_stored_records(bloom_filter_t* bloom) {
// init iterator for filling bloom filter
record_iterator_t iterator;
int rc = ens_records_iterator_init_timerange(&iterator, NULL, NULL);
if (rc) {
printk("init iterator failed0 (err %d)\n", rc);
return;
}
// fill bloom filter with records
record_t* current;
while ((current = ens_records_iterator_next(&iterator))) {
bloom_add_record(bloom, &(current->rolling_proximity_identifier));
}
}
/**
* Fill the bloom filter with flash records and test passed RPIs against it.
*/
int64_t bloom_filter(infected_for_interval_ident_ctx_t* ctx, int count) {
bloom_filter_t* bloom = bloom_init(get_num_records() * 2);
if (!bloom) {
printk("bloom init failed\n");
return -1;
}
fill_bloom_with_stored_records(bloom);
// test bloom performance
for (int i = 0; i < count; i++) {
if (bloom_probably_has_record(bloom, &ctx[i].interval_identifier)) {
ctx[i].met++;
}
}
bloom_destroy(bloom);
return get_number_of_infected_for_multiple_intervals_simple(ctx, count);
}
////////////////////
// FILL TEST DATA //
////////////////////
static ENPeriodKey infectedPeriodKey = {
.b = {0x75, 0xc7, 0x34, 0xc6, 0xdd, 0x1a, 0x78, 0x2d, 0xe7, 0xa9, 0x65, 0xda, 0x5e, 0xb9, 0x31, 0x25}};
static ENPeriodKey dummyPeriodKey = {
.b = {0x89, 0xa7, 0x34, 0xc6, 0xdd, 0x1a, 0x14, 0xda, 0xe7, 0x00, 0x65, 0xda, 0x6a, 0x9b, 0x13, 0x52}};
static ENPeriodKey testKey = {
.b = {0x89, 0xa7, 0x72, 0xc6, 0xdd, 0x10, 0x14, 0xda, 0xe7, 0x00, 0x65, 0xda, 0x8a, 0x9b, 0x13, 0x52}};
static ENPeriodIdentifierKey infectedPik;
static ENPeriodIdentifierKey dummyPik;
static ENPeriodIdentifierKey testPik;
void fill_test_rki_data(infected_for_interval_ident_ctx_t* infectedIntervals, int count) {
int totalTime = EN_TEK_ROLLING_PERIOD * EN_INTERVAL_LENGTH;
int stepSize = totalTime / count;
for (int i = 0; i < count; i++) {
int intervalNumber = (i * stepSize) / EN_INTERVAL_LENGTH;
en_derive_interval_identifier(&infectedIntervals[i].interval_identifier, &infectedPik, intervalNumber);
infectedIntervals[i].met = 0;
infectedIntervals[i].search_start = i < 3 ? 0 : (i - 2) * stepSize;
infectedIntervals[i].search_end = (i + 2) * stepSize;
}
}
////////////////////
// MEASURING FUNC //
////////////////////
void measure_perf(infected_for_interval_ident_ctx_t testIntervals[], int count) {
const char* label = "bloom filter";
printk("---------------------------\n'%s': starting measurement\n", label);
// fill_test_rki_data(infectedIntervals, count);
// setup our ordered array with met RPIs
printk("Starting measurements with %d RPIs to seach and an infection rate of %d\n", count,
CONFIG_TEST_INFECTED_RATE);
timing_t start_time, end_time;
uint64_t total_cycles;
uint64_t total_ns;
timing_init();
timing_start();
start_time = timing_counter_get();
check_possible_contacts_for_intervals(testIntervals, count);
end_time = timing_counter_get();
total_cycles = timing_cycles_get(&start_time, &end_time);
total_ns = timing_cycles_to_ns(total_cycles);
timing_stop();
printk("\n'%s' took %lld ms\n---------------------------\n", label, total_ns / 1000000);
}
void check_results(infected_for_interval_ident_ctx_t testIntervals[], int count) {
int counter = 0;
for (int i = 0; i < count / 2; i++) {
counter += CONFIG_TEST_RECORDS_PER_INTERVAL * CONFIG_TEST_INFECTED_RATE;
int met = counter / 100;
counter %= 100;
if (testIntervals[i].met != met) {
printk("interval %d should have been met %d times (met %d)\n", i, met, testIntervals[i].met);
return;
}
}
for (int j = count / 2; j < count; j++) {
if (testIntervals[j].met) {
printk("infected interval should not have been met (interval %d)\n", j);
return;
}
}
printk("all results are as expected!\n");
}
int reverse_bloom_filter(infected_for_interval_ident_ctx_t* ctx, int count) {
bloom_filter_t* bloom = bloom_init(count * 2);
if (!bloom) {
printk("bloom init failed\n");
return -1;
}
// init bloom filter with passed records
for (int i = 0; i < count; i++) {
bloom_add_record(bloom, &ctx[i].interval_identifier);
}
int rc = 0;
// init iterator over the entire storage
record_iterator_t iterator;
rc = ens_records_iterator_init_timerange(&iterator, NULL, NULL);
if (rc) {
printk("init iterator failed (err %d)\n", rc);
goto cleanup;
}
record_t* current;
while ((current = ens_records_iterator_next(&iterator))) {
if (bloom_probably_has_record(bloom, &(current->rolling_proximity_identifier))) {
for (int i = 0; i < count; i++) {
if (memcmp(&(current->rolling_proximity_identifier), &ctx[i].interval_identifier,
sizeof(current->rolling_proximity_identifier)) == 0) {
ctx[i].met++;
}
}
}
}
cleanup:
// destroy bloom filter after things are finished
bloom_destroy(bloom);
return rc;
}
////////////////////
// SETUP DATA //
////////////////////
void setup_test_data(infected_for_interval_ident_ctx_t testIntervals[], int count) {
en_derive_period_identifier_key(&infectedPik, &infectedPeriodKey);
en_derive_period_identifier_key(&dummyPik, &dummyPeriodKey);
en_derive_period_identifier_key(&testPik, &testKey);
int counter = 0;
for (int i = 0; i < EN_TEK_ROLLING_PERIOD; i++) {
record_t infectedRecord;
record_t dummyRecord;
en_derive_interval_identifier((ENIntervalIdentifier*)&infectedRecord.rolling_proximity_identifier, &infectedPik,
i);
en_derive_interval_identifier((ENIntervalIdentifier*)&dummyRecord.rolling_proximity_identifier, &dummyPik, i);
for (int j = 0; j < CONFIG_TEST_RECORDS_PER_INTERVAL; j++) {
counter += CONFIG_TEST_INFECTED_RATE;
record_t* curRecord;
if (counter >= 100) {
counter -= 100;
curRecord = &infectedRecord;
} else {
curRecord = &dummyRecord;
}
curRecord->timestamp = i * EN_INTERVAL_LENGTH + j * (EN_INTERVAL_LENGTH / CONFIG_TEST_RECORDS_PER_INTERVAL);
int rc = add_record(curRecord);
if (rc) {
printk("err %d\n", rc);
}
}
}
for (int i = 0; i < count / 2; i++) {
en_derive_interval_identifier(&testIntervals[i].interval_identifier, &infectedPik, i);
testIntervals[i].met = 0;
testIntervals[i].search_start = MAX(0, (i * EN_INTERVAL_LENGTH - 2 * 60 * 60));
testIntervals[i].search_end = i * EN_INTERVAL_LENGTH + 2 * 60 * 60;
int j = i + count / 2;
en_derive_interval_identifier(&testIntervals[j].interval_identifier, &testPik, i);
testIntervals[j].met = 0;
testIntervals[j].search_start = MAX(0, (i * EN_INTERVAL_LENGTH - 2 * 60 * 60));
testIntervals[j].search_end = i * EN_INTERVAL_LENGTH + 2 * 60 * 60;
}
}
int init_contacts() {
#if CONFIG_CONTACTS_PERFORM_RISC_CHECK_TEST
static infected_for_interval_ident_ctx_t testIntervals[EN_TEK_ROLLING_PERIOD * 2];
reset_record_storage();
setup_test_data(testIntervals, EN_TEK_ROLLING_PERIOD * 2);
measure_perf(testIntervals, EN_TEK_ROLLING_PERIOD * 2);
check_results(testIntervals, EN_TEK_ROLLING_PERIOD * 2);
#endif
return 0;
}
int check_possible_contacts_for_intervals(infected_for_interval_ident_ctx_t* ctx, int count) {
#if CONFIG_CONTACTS_BLOOM_REVERSE
return reverse_bloom_filter(ctx, count);
#else
return bloom_filter(ctx, count);
#endif
}
int check_possible_contacts_for_periods(period_key_information_t periodKeyInformation[], int count) {
for (int i = 0; i < count; i++) {
static infected_for_interval_ident_ctx_t intervalIdents[EN_TEK_ROLLING_PERIOD];
int periodStart = en_get_interval_number(periodKeyInformation[i].start);
for (int interval = 0; interval < EN_TEK_ROLLING_PERIOD; interval++) {
en_derive_interval_identifier(&intervalIdents[interval].interval_identifier,
&periodKeyInformation[i].periodKey, periodStart + interval);
}
int rc = check_possible_contacts_for_intervals(intervalIdents, 0);
if (rc < 0) {
return rc;
}
periodKeyInformation[i].met = rc;
}
return 0;
}

View File

@ -1,258 +0,0 @@
#if CONFIG_DISPLAY
#include <device.h>
#include <drivers/display.h>
#include <lvgl.h>
#endif
#include <stdio.h>
#include <string.h>
#include <zephyr.h>
#include "display.h"
K_THREAD_STACK_DEFINE(display_stack_area, 5000);
#if CONFIG_DISPLAY
const struct device* display_dev;
lv_obj_t* display_center_pane;
lv_obj_t* display_top_bar;
lv_obj_t* display_bot_bar;
lv_obj_t* display_contacts_label;
lv_obj_t* display_risk_contacts_label;
lv_obj_t* risk_contacts_button;
lv_obj_t* display_clock_label;
lv_obj_t* display_battery_label;
lv_obj_t* display_memory_label;
lv_obj_t* display_msg_label;
lv_style_t green_button_style;
lv_style_t yellow_button_style;
lv_style_t red_button_style;
#endif
int get_battery_percentage() {
// TODO: Implement
return 0;
}
int get_memory_percentage() {
// TODO: Implement
return 0;
}
int get_time() {
// TODO: Implement
return 0;
}
int get_contacts() {
// TODO: Implement
return 0;
}
int get_risk_contacts() {
// TODO: Implement
return 0;
}
#if CONFIG_DISPLAY
void display_thread(void* arg1, void* arg2, void* arg3) {
static uint32_t sleep_time;
while (1) {
sleep_time = lv_task_handler();
update_display();
k_msleep(sleep_time);
}
}
int init_styles() {
lv_style_init(&green_button_style);
lv_style_init(&yellow_button_style);
lv_style_init(&red_button_style);
// Properties for all styles
lv_style_set_bg_opa(&green_button_style, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_style_set_pad_top(&green_button_style, LV_STATE_DEFAULT, 10);
lv_style_set_pad_bottom(&green_button_style, LV_STATE_DEFAULT, 10);
lv_style_set_pad_left(&green_button_style, LV_STATE_DEFAULT, 10);
lv_style_set_pad_right(&green_button_style, LV_STATE_DEFAULT, 10);
lv_style_set_border_width(&green_button_style, LV_STATE_DEFAULT, 1);
lv_style_set_radius(&green_button_style, LV_STATE_DEFAULT, 10);
lv_style_copy(&yellow_button_style, &green_button_style);
lv_style_copy(&red_button_style, &green_button_style);
// Set different colors
lv_style_set_bg_color(&green_button_style, LV_STATE_DEFAULT, LV_COLOR_GREEN);
lv_style_set_text_color(&green_button_style, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_style_set_bg_color(&yellow_button_style, LV_STATE_DEFAULT, LV_COLOR_YELLOW);
lv_style_set_text_color(&yellow_button_style, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_style_set_bg_color(&red_button_style, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_style_set_text_color(&red_button_style, LV_STATE_DEFAULT, LV_COLOR_WHITE);
return 0;
}
int update_display() {
display_set_contacts(get_contacts());
display_set_risk_contacts(get_risk_contacts());
display_set_time(get_time());
display_set_bat(get_battery_percentage());
display_set_mem(get_memory_percentage());
lv_task_handler();
return 0;
}
int init_display() {
init_styles();
display_dev = device_get_binding(CONFIG_LVGL_DISPLAY_DEV_NAME);
if (display_dev == NULL) {
printk("device not found. Aborting test.");
return -1;
}
display_top_bar = lv_cont_create(lv_scr_act(), NULL);
lv_obj_set_width(display_top_bar, lv_obj_get_width(lv_scr_act()));
lv_cont_set_layout(display_top_bar, LV_LAYOUT_PRETTY_TOP);
display_bot_bar = lv_cont_create(lv_scr_act(), NULL);
lv_obj_set_width(display_bot_bar, lv_obj_get_width(lv_scr_act()));
lv_cont_set_layout(display_bot_bar, LV_LAYOUT_PRETTY_BOTTOM);
display_center_pane = lv_cont_create(lv_scr_act(), NULL);
lv_obj_align(display_center_pane, display_top_bar, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
lv_obj_set_width(display_center_pane, lv_obj_get_width(lv_scr_act()));
lv_obj_set_height(display_center_pane, lv_obj_get_height(lv_scr_act()) - lv_obj_get_height(display_top_bar) - lv_obj_get_height(display_bot_bar));
lv_cont_set_layout(display_center_pane, LV_LAYOUT_COLUMN_MID);
lv_obj_align(display_bot_bar, display_center_pane, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
display_contacts_label = lv_label_create(display_center_pane, NULL);
lv_obj_set_height_margin(display_contacts_label, 20);
lv_label_set_text(display_contacts_label, "");
if (IS_ENABLED(CONFIG_LVGL_POINTER_KSCAN)) {
risk_contacts_button = lv_btn_create(display_center_pane, NULL);
lv_btn_set_fit(risk_contacts_button, LV_FIT_TIGHT);
display_risk_contacts_label = lv_label_create(risk_contacts_button, NULL);
} else {
display_risk_contacts_label = lv_label_create(display_center_pane, NULL);
}
lv_obj_set_height_margin(display_risk_contacts_label, 20);
lv_label_set_text(display_risk_contacts_label, "");
display_memory_label = lv_label_create(display_top_bar, NULL);
lv_obj_set_width_margin(display_memory_label, 10);
lv_label_set_text(display_memory_label, "");
display_clock_label = lv_label_create(display_top_bar, NULL);
lv_obj_set_width_margin(display_clock_label, 10);
lv_label_set_text(display_clock_label, "");
display_battery_label = lv_label_create(display_top_bar, NULL);
lv_obj_set_width_margin(display_battery_label, 10);
lv_label_set_text(display_battery_label, "");
display_msg_label = lv_label_create(display_bot_bar, NULL);
lv_label_set_text(display_msg_label, "");
static struct k_thread display_thread_data;
k_thread_create(&display_thread_data, display_stack_area, K_THREAD_STACK_SIZEOF(display_stack_area), display_thread, NULL, NULL, NULL, 0, 0, K_NO_WAIT);
display_blanking_off(display_dev);
return 0;
}
int display_set_message(char* msg) {
lv_label_set_text(display_msg_label, msg);
return 0;
}
int display_set_time(int time) {
lv_label_set_text_fmt(display_clock_label, "%d:%d", time / 100, time % 100)
return 0;
}
int display_set_bat(int bat) {
lv_label_set_text_fmt(display_battery_label, "Bat: %d%%", bat);
return 0;
}
int display_set_mem(int mem) {
lv_label_set_text_fmt(display_memory_label, "Mem: %d%%", mem);
return 0;
}
int display_set_contacts(int contacts) {
lv_label_set_text_fmt(display_contacts_label, "Number of contacts: %d,\nfrom which", contacts);
return 0;
}
int display_set_risk_contacts(int risk_contacts) {
lv_label_set_text_fmt(display_risk_contacts_label, "%d are risk contacts.", risk_contacts);
if (risk_contacts == 0) {
// Set Button green
lv_obj_reset_style_list(risk_contacts_button, LV_OBJ_PART_MAIN);
lv_obj_add_style(risk_contacts_button, LV_BTN_PART_MAIN, &green_button_style);
} else if (risk_contacts < 5) {
// Set Button yellow
lv_obj_reset_style_list(risk_contacts_button, LV_OBJ_PART_MAIN);
lv_obj_add_style(risk_contacts_button, LV_BTN_PART_MAIN, &yellow_button_style);
} else {
// Set Button red
lv_obj_reset_style_list(risk_contacts_button, LV_OBJ_PART_MAIN);
lv_obj_add_style(risk_contacts_button, LV_BTN_PART_MAIN, &red_button_style);
}
return 0;
}
#else
void display_thread(void* arg1, void* arg2, void* arg3) {
// Do nothing
}
int init_styles() {
return 0;
}
int update_display() {
return 0;
}
int init_display() {
return 0;
}
int display_set_message(char* msg) {
return 0;
}
int display_set_time(int time) {
return 0;
}
int display_set_bat(int bat) {
return 0;
}
int display_set_mem(int mem) {
return 0;
}
int display_set_contacts(int contacts) {
return 0;
}
int display_set_risk_contacts(int risk_contacts) {
return 0;
}
#endif

View File

@ -1,208 +0,0 @@
#include <string.h>
#include <sys/types.h>
#include "covid_types.h"
#include "ens/ens_error.h"
#include "ens/records.h"
#include "ens/sequencenumber.h"
#include "ens/storage.h"
int ens_records_iterator_init_range(record_iterator_t* iterator,
record_sequence_number_t* opt_start,
record_sequence_number_t* opt_end) {
// prevent any changes during initialization
int rc = get_sequence_number_interval(&iterator->sn_next, &iterator->sn_end);
if (rc == 0) {
iterator->finished = false;
// we override start and end with the optional values
if (opt_start) {
iterator->sn_next = *opt_start;
}
if (opt_end) {
iterator->sn_end = *opt_end;
}
} else {
iterator->finished = true;
}
return 0;
}
int64_t get_timestamp_for_sn(record_sequence_number_t sn) {
record_t rec;
if (load_record(&rec, sn) == 0) {
return rec.timestamp;
} else {
return -1;
}
}
enum record_timestamp_search_mode {
RECORD_TIMESTAMP_SEARCH_MODE_MIN,
RECORD_TIMESTAMP_SEARCH_MODE_MAX,
};
/**
* Find an entry via binary search for the timestamp.
*
* @param record pointer to the location, where the found sn shall be stored
* @param target timestamp for which to find the nearest entry for
* @param greater flag for indicating, if the loaded sn shall correspond to a greater (1) or smaller (0) timestamp
*/
int find_sn_via_binary_search(record_sequence_number_t* sn_dest,
uint32_t target,
enum record_timestamp_search_mode search_mode) {
record_sequence_number_t start_sn;
record_sequence_number_t end_sn;
// prevent any changes during binary search initialization
int rc = get_sequence_number_interval(&start_sn, &end_sn);
if (rc) {
return rc;
}
record_sequence_number_t last_sn =
start_sn; // used to check if ran into issues, e.g. could not load the entry or rounding errors
while (!sn_equal(start_sn, end_sn)) {
// calculate the sn in the middle between start and end
record_sequence_number_t cur_sn = sn_get_middle_sn(start_sn, end_sn);
if (sn_equal(cur_sn, last_sn)) {
// if we already checked this entry -> we reduce our boundaries and try again
// this also solves issues with rounding
// TODO: This is not the best way...
if (search_mode == RECORD_TIMESTAMP_SEARCH_MODE_MIN) {
int64_t start_ts = get_timestamp_for_sn(start_sn);
if (start_ts == -1 || start_ts < target) {
// we could not load this entry or this entry is strictly smaller than our target
start_sn = sn_increment(start_sn); // we can safely increment as start_sn < end_sn
} else {
// we actually found the wanted entry!
end_sn = start_sn; // this will break our loop
}
} else {
// we search for the biggest value among them
int64_t end_ts = get_timestamp_for_sn(end_sn);
if (end_ts == -1 || end_ts > target) {
// we could not load this entry or this entry is strictly bigger than our target
end_sn = sn_decrement(end_sn); // we can safely decrement as start_sn < end_sn
} else {
// we actually found the wanted entry!
start_sn = end_sn; // this will break our loop
}
}
} else {
int64_t mid_ts = get_timestamp_for_sn(cur_sn);
if (mid_ts >= 0) {
if (target < mid_ts) {
end_sn = cur_sn;
} else if (target > mid_ts) {
start_sn = cur_sn;
} else {
// target == mid_ts
if (search_mode == RECORD_TIMESTAMP_SEARCH_MODE_MIN) {
// we search for the smallest value among them -> look before this item
end_sn = cur_sn;
} else {
// we search for the biggest value among them -> look after this item
start_sn = cur_sn;
}
}
} else {
// some errors -> we keep the current sn and try to narrow our boundaries
}
}
last_sn = cur_sn;
}
*sn_dest = start_sn; // == end_sn
return 0;
}
// TODO: This iterator does neither check if the sequence numbers wrapped around while iteration. As a result, first
// results could have later timestamps than following entries
int ens_records_iterator_init_timerange(record_iterator_t* iterator, time_t* ts_start, time_t* ts_end) {
record_sequence_number_t oldest_sn = 0;
record_sequence_number_t newest_sn = 0;
// assure that *ts_end > *ts_start
if (ts_start && ts_end && *ts_end < *ts_start) {
return 1;
}
if (ts_start) {
int rc = find_sn_via_binary_search(&oldest_sn, *ts_start, RECORD_TIMESTAMP_SEARCH_MODE_MIN);
if (rc) {
return rc;
}
} else {
oldest_sn = get_oldest_sequence_number();
}
if (ts_end) {
int rc = find_sn_via_binary_search(&newest_sn, *ts_end, RECORD_TIMESTAMP_SEARCH_MODE_MAX);
if (rc) {
return rc;
}
} else {
newest_sn = get_latest_sequence_number();
}
return ens_records_iterator_init_range(iterator, &oldest_sn, &newest_sn);
}
record_t* ens_records_iterator_next(record_iterator_t* iter) {
record_t* next = NULL;
while (next == NULL && !iter->finished) {
record_t contact;
// try to load the next contact
int res = load_record(&contact, iter->sn_next);
if (!res) {
next = &iter->current;
memcpy(next, &contact, sizeof(record_t));
}
if (sn_equal(iter->sn_next, iter->sn_end)) {
iter->finished = true; // this iterator will finish after this execution
} else {
// increase the current sn
iter->sn_next = sn_increment(iter->sn_next);
}
}
return next;
}
int ens_record_iterator_clear(record_iterator_t* iter) {
// clear all relevant fields in the iterator
iter->finished = true;
iter->sn_next = 0;
iter->sn_end = 0;
memset(&iter->current, 0, sizeof(iter->current));
return 0;
}
uint8_t ens_records_iterate_with_callback(record_iterator_t* iter, ens_record_iterator_cb_t cb, void* userdata) {
record_t* cur = ens_records_iterator_next(iter);
bool cont = true;
while (cur != NULL && cont) {
int cb_res = cb(cur, userdata);
if (cb_res == ENS_RECORD_ITER_STOP) {
cont = false;
}
}
if (cont) {
cb(NULL, userdata); // we call the callback one last time but with null data
}
return 0;
}

View File

@ -1,682 +0,0 @@
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: export.proto */
/* Do not generate deprecated warnings for self */
#ifndef PROTOBUF_C__NO_DEPRECATED
#define PROTOBUF_C__NO_DEPRECATED
#endif
#include "export.pb-c.h"
void temporary_exposure_key_export__init
(TemporaryExposureKeyExport *message)
{
static const TemporaryExposureKeyExport init_value = TEMPORARY_EXPOSURE_KEY_EXPORT__INIT;
*message = init_value;
}
size_t temporary_exposure_key_export__get_packed_size
(const TemporaryExposureKeyExport *message)
{
assert(message->base.descriptor == &temporary_exposure_key_export__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t temporary_exposure_key_export__pack
(const TemporaryExposureKeyExport *message,
uint8_t *out)
{
assert(message->base.descriptor == &temporary_exposure_key_export__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t temporary_exposure_key_export__pack_to_buffer
(const TemporaryExposureKeyExport *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &temporary_exposure_key_export__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
TemporaryExposureKeyExport *
temporary_exposure_key_export__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (TemporaryExposureKeyExport *)
protobuf_c_message_unpack (&temporary_exposure_key_export__descriptor,
allocator, len, data);
}
void temporary_exposure_key_export__free_unpacked
(TemporaryExposureKeyExport *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &temporary_exposure_key_export__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void signature_info__init
(SignatureInfo *message)
{
static const SignatureInfo init_value = SIGNATURE_INFO__INIT;
*message = init_value;
}
size_t signature_info__get_packed_size
(const SignatureInfo *message)
{
assert(message->base.descriptor == &signature_info__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t signature_info__pack
(const SignatureInfo *message,
uint8_t *out)
{
assert(message->base.descriptor == &signature_info__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t signature_info__pack_to_buffer
(const SignatureInfo *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &signature_info__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
SignatureInfo *
signature_info__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (SignatureInfo *)
protobuf_c_message_unpack (&signature_info__descriptor,
allocator, len, data);
}
void signature_info__free_unpacked
(SignatureInfo *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &signature_info__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void temporary_exposure_key__init
(TemporaryExposureKey *message)
{
static const TemporaryExposureKey init_value = TEMPORARY_EXPOSURE_KEY__INIT;
*message = init_value;
}
size_t temporary_exposure_key__get_packed_size
(const TemporaryExposureKey *message)
{
assert(message->base.descriptor == &temporary_exposure_key__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t temporary_exposure_key__pack
(const TemporaryExposureKey *message,
uint8_t *out)
{
assert(message->base.descriptor == &temporary_exposure_key__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t temporary_exposure_key__pack_to_buffer
(const TemporaryExposureKey *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &temporary_exposure_key__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
TemporaryExposureKey *
temporary_exposure_key__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (TemporaryExposureKey *)
protobuf_c_message_unpack (&temporary_exposure_key__descriptor,
allocator, len, data);
}
void temporary_exposure_key__free_unpacked
(TemporaryExposureKey *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &temporary_exposure_key__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void teksignature_list__init
(TEKSignatureList *message)
{
static const TEKSignatureList init_value = TEKSIGNATURE_LIST__INIT;
*message = init_value;
}
size_t teksignature_list__get_packed_size
(const TEKSignatureList *message)
{
assert(message->base.descriptor == &teksignature_list__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t teksignature_list__pack
(const TEKSignatureList *message,
uint8_t *out)
{
assert(message->base.descriptor == &teksignature_list__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t teksignature_list__pack_to_buffer
(const TEKSignatureList *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &teksignature_list__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
TEKSignatureList *
teksignature_list__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (TEKSignatureList *)
protobuf_c_message_unpack (&teksignature_list__descriptor,
allocator, len, data);
}
void teksignature_list__free_unpacked
(TEKSignatureList *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &teksignature_list__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void teksignature__init
(TEKSignature *message)
{
static const TEKSignature init_value = TEKSIGNATURE__INIT;
*message = init_value;
}
size_t teksignature__get_packed_size
(const TEKSignature *message)
{
assert(message->base.descriptor == &teksignature__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t teksignature__pack
(const TEKSignature *message,
uint8_t *out)
{
assert(message->base.descriptor == &teksignature__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t teksignature__pack_to_buffer
(const TEKSignature *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &teksignature__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
TEKSignature *
teksignature__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (TEKSignature *)
protobuf_c_message_unpack (&teksignature__descriptor,
allocator, len, data);
}
void teksignature__free_unpacked
(TEKSignature *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &teksignature__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
static const ProtobufCFieldDescriptor temporary_exposure_key_export__field_descriptors[8] =
{
{
"start_timestamp",
1,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_FIXED64,
offsetof(TemporaryExposureKeyExport, has_start_timestamp),
offsetof(TemporaryExposureKeyExport, start_timestamp),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"end_timestamp",
2,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_FIXED64,
offsetof(TemporaryExposureKeyExport, has_end_timestamp),
offsetof(TemporaryExposureKeyExport, end_timestamp),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"region",
3,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(TemporaryExposureKeyExport, region),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"batch_num",
4,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_INT32,
offsetof(TemporaryExposureKeyExport, has_batch_num),
offsetof(TemporaryExposureKeyExport, batch_num),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"batch_size",
5,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_INT32,
offsetof(TemporaryExposureKeyExport, has_batch_size),
offsetof(TemporaryExposureKeyExport, batch_size),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"signature_infos",
6,
PROTOBUF_C_LABEL_REPEATED,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(TemporaryExposureKeyExport, n_signature_infos),
offsetof(TemporaryExposureKeyExport, signature_infos),
&signature_info__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"keys",
7,
PROTOBUF_C_LABEL_REPEATED,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(TemporaryExposureKeyExport, n_keys),
offsetof(TemporaryExposureKeyExport, keys),
&temporary_exposure_key__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"revised_keys",
8,
PROTOBUF_C_LABEL_REPEATED,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(TemporaryExposureKeyExport, n_revised_keys),
offsetof(TemporaryExposureKeyExport, revised_keys),
&temporary_exposure_key__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned temporary_exposure_key_export__field_indices_by_name[] = {
3, /* field[3] = batch_num */
4, /* field[4] = batch_size */
1, /* field[1] = end_timestamp */
6, /* field[6] = keys */
2, /* field[2] = region */
7, /* field[7] = revised_keys */
5, /* field[5] = signature_infos */
0, /* field[0] = start_timestamp */
};
static const ProtobufCIntRange temporary_exposure_key_export__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 8 }
};
const ProtobufCMessageDescriptor temporary_exposure_key_export__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"TemporaryExposureKeyExport",
"TemporaryExposureKeyExport",
"TemporaryExposureKeyExport",
"",
sizeof(TemporaryExposureKeyExport),
8,
temporary_exposure_key_export__field_descriptors,
temporary_exposure_key_export__field_indices_by_name,
1, temporary_exposure_key_export__number_ranges,
(ProtobufCMessageInit) temporary_exposure_key_export__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor signature_info__field_descriptors[3] =
{
{
"verification_key_version",
3,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(SignatureInfo, verification_key_version),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"verification_key_id",
4,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(SignatureInfo, verification_key_id),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"signature_algorithm",
5,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(SignatureInfo, signature_algorithm),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned signature_info__field_indices_by_name[] = {
2, /* field[2] = signature_algorithm */
1, /* field[1] = verification_key_id */
0, /* field[0] = verification_key_version */
};
static const ProtobufCIntRange signature_info__number_ranges[1 + 1] =
{
{ 3, 0 },
{ 0, 3 }
};
const ProtobufCMessageDescriptor signature_info__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"SignatureInfo",
"SignatureInfo",
"SignatureInfo",
"",
sizeof(SignatureInfo),
3,
signature_info__field_descriptors,
signature_info__field_indices_by_name,
1, signature_info__number_ranges,
(ProtobufCMessageInit) signature_info__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCEnumValue temporary_exposure_key__report_type__enum_values_by_number[6] =
{
{ "UNKNOWN", "TEMPORARY_EXPOSURE_KEY__REPORT_TYPE__UNKNOWN", 0 },
{ "CONFIRMED_TEST", "TEMPORARY_EXPOSURE_KEY__REPORT_TYPE__CONFIRMED_TEST", 1 },
{ "CONFIRMED_CLINICAL_DIAGNOSIS", "TEMPORARY_EXPOSURE_KEY__REPORT_TYPE__CONFIRMED_CLINICAL_DIAGNOSIS", 2 },
{ "SELF_REPORT", "TEMPORARY_EXPOSURE_KEY__REPORT_TYPE__SELF_REPORT", 3 },
{ "RECURSIVE", "TEMPORARY_EXPOSURE_KEY__REPORT_TYPE__RECURSIVE", 4 },
{ "REVOKED", "TEMPORARY_EXPOSURE_KEY__REPORT_TYPE__REVOKED", 5 },
};
static const ProtobufCIntRange temporary_exposure_key__report_type__value_ranges[] = {
{0, 0},{0, 6}
};
static const ProtobufCEnumValueIndex temporary_exposure_key__report_type__enum_values_by_name[6] =
{
{ "CONFIRMED_CLINICAL_DIAGNOSIS", 2 },
{ "CONFIRMED_TEST", 1 },
{ "RECURSIVE", 4 },
{ "REVOKED", 5 },
{ "SELF_REPORT", 3 },
{ "UNKNOWN", 0 },
};
const ProtobufCEnumDescriptor temporary_exposure_key__report_type__descriptor =
{
PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
"TemporaryExposureKey.ReportType",
"ReportType",
"TemporaryExposureKey__ReportType",
"",
6,
temporary_exposure_key__report_type__enum_values_by_number,
6,
temporary_exposure_key__report_type__enum_values_by_name,
1,
temporary_exposure_key__report_type__value_ranges,
NULL,NULL,NULL,NULL /* reserved[1234] */
};
static const int32_t temporary_exposure_key__rolling_period__default_value = 144;
static const ProtobufCFieldDescriptor temporary_exposure_key__field_descriptors[6] =
{
{
"key_data",
1,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_BYTES,
offsetof(TemporaryExposureKey, has_key_data),
offsetof(TemporaryExposureKey, key_data),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"transmission_risk_level",
2,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_INT32,
offsetof(TemporaryExposureKey, has_transmission_risk_level),
offsetof(TemporaryExposureKey, transmission_risk_level),
NULL,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_DEPRECATED, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"rolling_start_interval_number",
3,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_INT32,
offsetof(TemporaryExposureKey, has_rolling_start_interval_number),
offsetof(TemporaryExposureKey, rolling_start_interval_number),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"rolling_period",
4,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_INT32,
offsetof(TemporaryExposureKey, has_rolling_period),
offsetof(TemporaryExposureKey, rolling_period),
NULL,
&temporary_exposure_key__rolling_period__default_value,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"report_type",
5,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_ENUM,
offsetof(TemporaryExposureKey, has_report_type),
offsetof(TemporaryExposureKey, report_type),
&temporary_exposure_key__report_type__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"days_since_onset_of_symptoms",
6,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_SINT32,
offsetof(TemporaryExposureKey, has_days_since_onset_of_symptoms),
offsetof(TemporaryExposureKey, days_since_onset_of_symptoms),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned temporary_exposure_key__field_indices_by_name[] = {
5, /* field[5] = days_since_onset_of_symptoms */
0, /* field[0] = key_data */
4, /* field[4] = report_type */
3, /* field[3] = rolling_period */
2, /* field[2] = rolling_start_interval_number */
1, /* field[1] = transmission_risk_level */
};
static const ProtobufCIntRange temporary_exposure_key__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 6 }
};
const ProtobufCMessageDescriptor temporary_exposure_key__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"TemporaryExposureKey",
"TemporaryExposureKey",
"TemporaryExposureKey",
"",
sizeof(TemporaryExposureKey),
6,
temporary_exposure_key__field_descriptors,
temporary_exposure_key__field_indices_by_name,
1, temporary_exposure_key__number_ranges,
(ProtobufCMessageInit) temporary_exposure_key__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor teksignature_list__field_descriptors[1] =
{
{
"signatures",
1,
PROTOBUF_C_LABEL_REPEATED,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(TEKSignatureList, n_signatures),
offsetof(TEKSignatureList, signatures),
&teksignature__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned teksignature_list__field_indices_by_name[] = {
0, /* field[0] = signatures */
};
static const ProtobufCIntRange teksignature_list__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 1 }
};
const ProtobufCMessageDescriptor teksignature_list__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"TEKSignatureList",
"TEKSignatureList",
"TEKSignatureList",
"",
sizeof(TEKSignatureList),
1,
teksignature_list__field_descriptors,
teksignature_list__field_indices_by_name,
1, teksignature_list__number_ranges,
(ProtobufCMessageInit) teksignature_list__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor teksignature__field_descriptors[4] =
{
{
"signature_info",
1,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_MESSAGE,
0, /* quantifier_offset */
offsetof(TEKSignature, signature_info),
&signature_info__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"batch_num",
2,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_INT32,
offsetof(TEKSignature, has_batch_num),
offsetof(TEKSignature, batch_num),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"batch_size",
3,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_INT32,
offsetof(TEKSignature, has_batch_size),
offsetof(TEKSignature, batch_size),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"signature",
4,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_BYTES,
offsetof(TEKSignature, has_signature),
offsetof(TEKSignature, signature),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned teksignature__field_indices_by_name[] = {
1, /* field[1] = batch_num */
2, /* field[2] = batch_size */
3, /* field[3] = signature */
0, /* field[0] = signature_info */
};
static const ProtobufCIntRange teksignature__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 4 }
};
const ProtobufCMessageDescriptor teksignature__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"TEKSignature",
"TEKSignature",
"TEKSignature",
"",
sizeof(TEKSignature),
4,
teksignature__field_descriptors,
teksignature__field_indices_by_name,
1, teksignature__number_ranges,
(ProtobufCMessageInit) teksignature__init,
NULL,NULL,NULL /* reserved[123] */
};

View File

@ -1,115 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <sys/printk.h>
#include <timing/timing.h>
#include <zephyr.h>
#include <protobuf-c.h>
#include "export.pb-c.h"
#include "extract_keys.h"
#define KEY_SIZE 16
void process_key(TemporaryExposureKey* key) {
// TODO: Implement
}
size_t generate_keys(uint8_t** buffer_pointer, int num_keys) {
// Initialize the key export data structure
TemporaryExposureKeyExport export = TEMPORARY_EXPOSURE_KEY_EXPORT__INIT;
TemporaryExposureKey** key_ptrs = (TemporaryExposureKey**)k_malloc(sizeof(TemporaryExposureKey*) * num_keys);
if (key_ptrs == NULL) {
printk("Could not allocate memory for pointers\n");
return 0;
}
export.batch_num = 1;
export.batch_size = 1;
// Initialize the keys and their data
uint8_t key_data[KEY_SIZE];
for (int i = 0; i < KEY_SIZE; i++) {
key_data[i] = 0xFF;
}
TemporaryExposureKey key = TEMPORARY_EXPOSURE_KEY__INIT;
key.key_data.data = key_data;
key.key_data.len = KEY_SIZE;
key.has_key_data = true;
// All pointers will point to the same key. The protocol buffer will still have n keys encoded
for (int i = 0; i < num_keys; i++) {
key_ptrs[i] = &key;
}
export.n_keys = num_keys;
export.keys = key_ptrs;
// Check size allocate memory and pack the buffer
size_t required_buffer = temporary_exposure_key_export__get_packed_size(&export);
uint8_t* buffer = (uint8_t*) k_malloc(required_buffer);
if (buffer == NULL) {
printk("Could not allocate memory for buffer\n");
return 0;
}
*buffer_pointer = buffer;
if (buffer != NULL) {
size_t buf_size = temporary_exposure_key_export__pack(&export, buffer);
k_free(key_ptrs);
return buf_size;
} else {
printk("Buffer too small to serialize %d keys. %d bytes necessary\n", num_keys, required_buffer);
return 0;
}
}
int unpack_keys(uint8_t* buf, size_t buf_size) {
// Unpack protocol buffer
printk("Buf size: %d\n", buf_size);
TemporaryExposureKeyExport* export = temporary_exposure_key_export__unpack(NULL, buf_size, buf);
if (export == NULL) {
printk("error unpacking incoming message\n");
return -2;
}
// Iterate over new keys
for (int i = 0; i < export->n_keys; i++) {
TemporaryExposureKey* key = export->keys[i];
process_key(key);
}
// Iterate over revised keys
for (int i = 0; i < export->n_revised_keys; i++) {
TemporaryExposureKey* key = export->revised_keys[i];
process_key(key);
}
return 0;
}
int test_unpacking(int num_keys) {
// Prepare time measurement
timing_t start_time, end_time;
uint64_t total_cycles;
uint64_t total_ns;
// Generate Buffer
uint8_t* buffer;
size_t buffer_size = generate_keys(&buffer, num_keys);
// Test unpacking
timing_init();
timing_start();
if (buffer_size) {
start_time = timing_counter_get();
unpack_keys(buffer, buffer_size);
end_time = timing_counter_get();
}
// Calculate measurements
total_cycles = timing_cycles_get(&start_time, &end_time);
total_ns = timing_cycles_to_ns(total_cycles);
printk("\nUnpacking %d keys took %lld us\n\n", num_keys, total_ns / 1000);
timing_stop();
k_free(buffer);
return 0;
}

View File

@ -1,106 +0,0 @@
/*
* Copyright (c) 2020 Olaf Landsiedel
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <sys/printk.h>
#include <sys/byteorder.h>
#include <zephyr.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include <bluetooth/uuid.h>
#include <bluetooth/gatt.h>
#include "covid.h"
#include "contacts.h"
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
/* My Service UUID (same as above) */
BT_DATA_BYTES(BT_DATA_UUID128_ALL,
0x06, 0x51, 0xC7, 0x9E, 0xAD, 0xA7, 0x42, 0xEA,
0x98, 0x6A, 0x9F, 0x69, 0x79, 0x0D, 0x11, 0xF2),
};
static void connected(struct bt_conn *conn, uint8_t err)
{
if (err) {
printk("Connection failed (err 0x%02x)\n", err);
} else {
printk("Connected\n");
}
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
printk("Disconnected (reason 0x%02x)\n", reason);
}
static struct bt_conn_cb conn_callbacks = {
.connected = connected,
.disconnected = disconnected,
};
static void auth_cancel(struct bt_conn *conn)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Pairing cancelled: %s\n", addr);
}
static struct bt_conn_auth_cb auth_cb_display = {
.cancel = auth_cancel,
};
int init_gatt(void)
{
bt_conn_cb_register(&conn_callbacks);
bt_conn_auth_cb_register(&auth_cb_display);
return 0;
}
#if CONFIG_BT
int do_gatt(void){
//printk("gatt start\n");
int err;
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
if (err) {
printk("Advertising failed to start (err %d)\n", err);
return err;
}
k_sleep(K_SECONDS(1));
err = bt_le_adv_stop();
if (err) {
printk("Advertising failed to stop (err %d)\n", err);
return err;
}
//printk("gatt end\n");
return 0;
}
#else
int do_gatt(void) {
return 0;
}
#endif

189
src/io.c
View File

@ -1,189 +0,0 @@
/* io.c - Application main entry point */
/*
* Copyright (c) 2020 Olaf Landsiedel
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <device.h>
#include <drivers/gpio.h>
#include "covid.h"
#include "io.h"
/*
* Devicetree helper macro which gets the 'flags' cell from a 'gpios'
* property, or returns 0 if the property has no 'flags' cell.
*/
#define FLAGS_OR_ZERO(node) \
COND_CODE_1(DT_PHA_HAS_CELL(node, gpios, flags), \
(DT_GPIO_FLAGS(node, gpios)), \
(0))
/*
* Get button configuration from the devicetree sw0 alias.
*
* At least a GPIO device and pin number must be provided. The 'flags'
* cell is optional.
*/
#ifndef NATIVE_POSIX
//on my NRF board this is button 1
#define SW0_NODE DT_ALIAS(sw0)
#if DT_NODE_HAS_STATUS(SW0_NODE, okay)
#define SW0_GPIO_LABEL DT_GPIO_LABEL(SW0_NODE, gpios)
#define SW0_GPIO_PIN DT_GPIO_PIN(SW0_NODE, gpios)
#define SW0_GPIO_FLAGS (GPIO_INPUT | FLAGS_OR_ZERO(SW0_NODE))
#else
#error "Unsupported board: sw0 devicetree alias is not defined"
#define SW0_GPIO_LABEL ""
#define SW0_GPIO_PIN 0
#define SW0_GPIO_FLAGS 0
#endif
//on my NRF board this is button 2
#define SW1_NODE DT_ALIAS(sw1)
#if DT_NODE_HAS_STATUS(SW1_NODE, okay)
#define SW1_GPIO_LABEL DT_GPIO_LABEL(SW1_NODE, gpios)
#define SW1_GPIO_PIN DT_GPIO_PIN(SW1_NODE, gpios)
#define SW1_GPIO_FLAGS (GPIO_INPUT | FLAGS_OR_ZERO(SW1_NODE))
#else
#error "Unsupported board: sw1 devicetree alias is not defined"
#define SW1_GPIO_LABEL ""
#define SW1_GPIO_PIN 0
#define SW1_GPIO_FLAGS 0
#endif
/* The devicetree node identifier for the "led0" alias. */
#define LED0_NODE DT_ALIAS(led0)
#if DT_NODE_HAS_STATUS(LED0_NODE, okay)
#define LED0 DT_GPIO_LABEL(LED0_NODE, gpios)
#define PIN DT_GPIO_PIN(LED0_NODE, gpios)
#if DT_PHA_HAS_CELL(LED0_NODE, gpios, flags)
#define FLAGS DT_GPIO_FLAGS(LED0_NODE, gpios)
#endif
#else
/* A build error here means your board isn't set up to blink an LED. */
#error "Unsupported board: led0 devicetree alias is not defined"
#define LED0 ""
#define PIN 0
#endif
#endif
#ifndef FLAGS
#define FLAGS 0
#endif
static struct gpio_callback button_0_cb_data;
static struct gpio_callback button_1_cb_data;
#ifndef NATIVE_POSIX
void button_0_pressed(struct device *dev, struct gpio_callback *cb, uint32_t pins){
set_infection(true);
gpio_pin_set(dev, PIN, (int)1);
printk("Button 0 (=infected) pressed at %" PRIu32 "\n", k_cycle_get_32());
}
void button_1_pressed(struct device *dev, struct gpio_callback *cb, uint32_t pins){
set_infection(false);
gpio_pin_set(dev, PIN, (int)0);
printk("Button 1 (=healthy) pressed at %" PRIu32 "\n", k_cycle_get_32());
}
int init_io(){
struct device *button0, *button1;
int err = 0;
//struct device *led;
button0 = device_get_binding(SW0_GPIO_LABEL);
if (button0 == NULL) {
printk("Error: didn't find %s device\n", SW0_GPIO_LABEL);
return -1;
}
button1 = device_get_binding(SW1_GPIO_LABEL);
if (button1 == NULL) {
printk("Error: didn't find %s device\n", SW1_GPIO_LABEL);
return -1;
}
err = gpio_pin_configure(button0, SW0_GPIO_PIN, SW0_GPIO_FLAGS);
if (err != 0) {
printk("Error %d: failed to configure %s pin %d\n",
err, SW0_GPIO_LABEL, SW0_GPIO_PIN);
return err;
}
err = gpio_pin_configure(button1, SW1_GPIO_PIN, SW1_GPIO_FLAGS);
if (err != 0) {
printk("Error %d: failed to configure %s pin %d\n",
err, SW1_GPIO_LABEL, SW1_GPIO_PIN);
return err;
}
err = gpio_pin_interrupt_configure(button0,
SW0_GPIO_PIN,
GPIO_INT_EDGE_TO_ACTIVE);
if (err != 0) {
printk("Error %d: failed to configure interrupt on %s pin %d\n",
err, SW0_GPIO_LABEL, SW0_GPIO_PIN);
return err;
}
err = gpio_pin_interrupt_configure(button1,
SW1_GPIO_PIN,
GPIO_INT_EDGE_TO_ACTIVE);
if (err != 0) {
printk("Error %d: failed to configure interrupt on %s pin %d\n",
err, SW1_GPIO_LABEL, SW1_GPIO_PIN);
return err;
}
gpio_init_callback(&button_0_cb_data, button_0_pressed, BIT(SW0_GPIO_PIN));
gpio_add_callback(button0, &button_0_cb_data);
printk("Set up button at %s pin %d\n", SW0_GPIO_LABEL, SW0_GPIO_PIN);
gpio_init_callback(&button_1_cb_data, button_1_pressed, BIT(SW1_GPIO_PIN));
gpio_add_callback(button1, &button_1_cb_data);
printk("Set up button at %s pin %d\n", SW1_GPIO_LABEL, SW1_GPIO_PIN);
struct device *dev;
dev = device_get_binding(LED0);
if (dev == NULL) {
return -1;
}
err = gpio_pin_configure(dev, PIN, GPIO_OUTPUT_ACTIVE | FLAGS);
if (err < 0) {
printk("Error %d: failed to configure leds\n", err);
return err;
}
//Turn LED 0 off
gpio_pin_set(dev, PIN, (int)0);
return 0;
}
#else
void button_0_pressed(struct device *dev, struct gpio_callback *cb, uint32_t pins) {
// Do nothing
}
void button_1_pressed(struct device *dev, struct gpio_callback *cb, uint32_t pins) {
// Do nothing
}
int init_io(){
return 0;
}
#endif

View File

@ -6,62 +6,41 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <bluetooth/hci.h>
#include <random/rand32.h>
#include <sys/printk.h>
#include "bloom.h"
#include "contacts.h"
#include "covid.h"
#include "covid_types.h"
#include "display.h"
#include "ens/storage.h"
#include "exposure-notification.h"
#include "extract_keys.h"
#include "gatt_service.h"
#include "io.h"
#include "record_storage.h"
#include "tek_storage.h"
#include "sync_service.h"
#include "tracing.h"
void main(void) {
#if CONFIG_TEST_UNPACK_KEYS
for (int i = 0; i < CONFIG_TEST_UNPACK_KEYS_N; i++) {
test_unpacking(1 << i);
}
#endif
int err = 0;
printk("Starting Covid Contact Tracer\n");
printk("Starting Contact-Tracing Wristband...\n");
// first init everything
#ifndef NATIVE_POSIX
// Use custom randomization as the mbdet_tls context initialization messes with the Zeyhr BLE stack.
err = en_init(sys_csrand_get);
if (err) {
printk("Cyrpto init failed (err %d)\n", err);
printk("Crypto init failed (err %d)\n", err);
return;
}
#endif
#if CONFIG_FLASH
err = init_record_storage(false);
err = record_storage_init(false);
if (err) {
printk("init storage failed (err %d)\n", err);
printk("init record storage failed (err %d)\n", err);
return;
}
err = init_contacts();
err = tek_storage_init(false);
if (err) {
printk("init contacts failed (err %d)\n", err);
return;
}
#endif
err = init_io();
if (err) {
printk("Button init failed (err %d)\n", err);
printk("init key storage failed (err %d)\n", err);
return;
}
#if CONFIG_BT
/* Initialize the Bluetooth Subsystem */
err = bt_enable(NULL);
if (err) {
@ -69,29 +48,24 @@ void main(void) {
return;
}
printk("Bluetooth initialized\n");
err = init_gatt();
/* Initialize the Tracing Subsystem */
err = tracing_init();
if (err) {
printk("init gatt failed(err %d)\n", err);
return;
}
#endif
err = init_covid();
if (err) {
printk("init covid failed (err %d)\n", err);
printk("Tracing init failed (err %d)\n", err);
return;
}
printk("init display\n");
err = init_display();
/* Initialize the Gatt Subsystem */
err = sync_service_init();
if (err) {
printk("init display failed (err %d)\n", err);
printk("Sync Service init failed (err %d)\n", err);
return;
}
printk("Components initialized! Starting Tracing and Gatt...\n");
do {
do_covid();
do_gatt();
tracing_run();
sync_service_run();
} while (1);
}
}

View File

@ -9,10 +9,10 @@
#include <zephyr.h>
#include <sys/printk.h>
void main(void) {
void main_test(void) {
while(1) {
printk("Hello World!\n");
k_msleep(1000);
}
}

View File

@ -6,11 +6,10 @@
#include <storage/flash_map.h>
#include <string.h>
#include <zephyr.h>
#include <sys/types.h>
#include "ens/ens_error.h"
#include "ens/ens_fs.h"
#include "ens/sequencenumber.h"
#include "ens/storage.h"
#include "utility/ens_fs.h"
#include "record_storage.h"
#define STORED_CONTACTS_INFO_ID 0
@ -59,7 +58,7 @@ int save_storage_information() {
return rc;
}
int init_record_storage(bool clean) {
int record_storage_init(bool clean) {
int rc = 0;
struct flash_pages_info info;
// define the nvs file system
@ -231,3 +230,207 @@ int get_sequence_number_interval(record_sequence_number_t* oldest, record_sequen
uint32_t get_num_records() {
return record_information.count;
}
int ens_records_iterator_init_range(record_iterator_t* iterator,
record_sequence_number_t* opt_start,
record_sequence_number_t* opt_end) {
// prevent any changes during initialization
int rc = get_sequence_number_interval(&iterator->sn_next, &iterator->sn_end);
if (rc == 0) {
iterator->finished = false;
// we override start and end with the optional values
if (opt_start) {
iterator->sn_next = *opt_start;
}
if (opt_end) {
iterator->sn_end = *opt_end;
}
} else {
iterator->finished = true;
}
return 0;
}
int64_t get_timestamp_for_sn(record_sequence_number_t sn) {
record_t rec;
if (load_record(&rec, sn) == 0) {
return rec.timestamp;
} else {
return -1;
}
}
enum record_timestamp_search_mode {
RECORD_TIMESTAMP_SEARCH_MODE_MIN,
RECORD_TIMESTAMP_SEARCH_MODE_MAX,
};
/**
* Find an entry via binary search for the timestamp.
*
* @param record pointer to the location, where the found sn shall be stored
* @param target timestamp for which to find the nearest entry for
* @param greater flag for indicating, if the loaded sn shall correspond to a greater (1) or smaller (0) timestamp
*/
int find_sn_via_binary_search(record_sequence_number_t* sn_dest,
uint32_t target,
enum record_timestamp_search_mode search_mode) {
record_sequence_number_t start_sn;
record_sequence_number_t end_sn;
// prevent any changes during binary search initialization
int rc = get_sequence_number_interval(&start_sn, &end_sn);
if (rc) {
return rc;
}
record_sequence_number_t last_sn =
start_sn; // used to check if ran into issues, e.g. could not load the entry or rounding errors
while (!sn_equal(start_sn, end_sn)) {
// calculate the sn in the middle between start and end
record_sequence_number_t cur_sn = sn_get_middle_sn(start_sn, end_sn);
if (sn_equal(cur_sn, last_sn)) {
// if we already checked this entry -> we reduce our boundaries and try again
// this also solves issues with rounding
// TODO: This is not the best way...
if (search_mode == RECORD_TIMESTAMP_SEARCH_MODE_MIN) {
int64_t start_ts = get_timestamp_for_sn(start_sn);
if (start_ts == -1 || start_ts < target) {
// we could not load this entry or this entry is strictly smaller than our target
start_sn = sn_increment(start_sn); // we can safely increment as start_sn < end_sn
} else {
// we actually found the wanted entry!
end_sn = start_sn; // this will break our loop
}
} else {
// we search for the biggest value among them
int64_t end_ts = get_timestamp_for_sn(end_sn);
if (end_ts == -1 || end_ts > target) {
// we could not load this entry or this entry is strictly bigger than our target
end_sn = sn_decrement(end_sn); // we can safely decrement as start_sn < end_sn
} else {
// we actually found the wanted entry!
start_sn = end_sn; // this will break our loop
}
}
} else {
int64_t mid_ts = get_timestamp_for_sn(cur_sn);
if (mid_ts >= 0) {
if (target < mid_ts) {
end_sn = cur_sn;
} else if (target > mid_ts) {
start_sn = cur_sn;
} else {
// target == mid_ts
if (search_mode == RECORD_TIMESTAMP_SEARCH_MODE_MIN) {
// we search for the smallest value among them -> look before this item
end_sn = cur_sn;
} else {
// we search for the biggest value among them -> look after this item
start_sn = cur_sn;
}
}
} else {
// some errors -> we keep the current sn and try to narrow our boundaries
}
}
last_sn = cur_sn;
}
*sn_dest = start_sn; // == end_sn
return 0;
}
// TODO: This iterator does neither check if the sequence numbers wrapped around while iteration. As a result, first
// results could have later timestamps than following entries
int ens_records_iterator_init_timerange(record_iterator_t* iterator, time_t* ts_start, time_t* ts_end) {
record_sequence_number_t oldest_sn = 0;
record_sequence_number_t newest_sn = 0;
// assure that *ts_end > *ts_start
if (ts_start && ts_end && *ts_end < *ts_start) {
return 1;
}
if (ts_start) {
int rc = find_sn_via_binary_search(&oldest_sn, *ts_start, RECORD_TIMESTAMP_SEARCH_MODE_MIN);
if (rc) {
return rc;
}
} else {
oldest_sn = get_oldest_sequence_number();
}
if (ts_end) {
int rc = find_sn_via_binary_search(&newest_sn, *ts_end, RECORD_TIMESTAMP_SEARCH_MODE_MAX);
if (rc) {
return rc;
}
} else {
newest_sn = get_latest_sequence_number();
}
return ens_records_iterator_init_range(iterator, &oldest_sn, &newest_sn);
}
record_t* ens_records_iterator_next(record_iterator_t* iter) {
record_t* next = NULL;
while (next == NULL && !iter->finished) {
record_t contact;
// try to load the next contact
int res = load_record(&contact, iter->sn_next);
if (!res) {
next = &iter->current;
memcpy(next, &contact, sizeof(record_t));
}
if (sn_equal(iter->sn_next, iter->sn_end)) {
iter->finished = true; // this iterator will finish after this execution
} else {
// increase the current sn
iter->sn_next = sn_increment(iter->sn_next);
}
}
return next;
}
int ens_record_iterator_clear(record_iterator_t* iter) {
// clear all relevant fields in the iterator
iter->finished = true;
iter->sn_next = 0;
iter->sn_end = 0;
memset(&iter->current, 0, sizeof(iter->current));
return 0;
}
uint8_t ens_records_iterate_with_callback(record_iterator_t* iter, ens_record_iterator_cb_t cb, void* userdata) {
record_t* cur = ens_records_iterator_next(iter);
bool cont = true;
while (cur != NULL && cont) {
int cb_res = cb(cur, userdata);
if (cb_res == ENS_RECORD_ITER_STOP) {
cont = false;
}
}
if (cont) {
cb(NULL, userdata); // we call the callback one last time but with null data
}
return 0;
}

27
src/sync_service.c Normal file
View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2020 Olaf Landsiedel
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <sys/printk.h>
#include <sys/byteorder.h>
#include <zephyr.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include <bluetooth/uuid.h>
#include <bluetooth/gatt.h>
int sync_service_init(void) {
return 0; // TODO!
}
int sync_service_run(void) {
return 0;
}

26
src/tek_storage.c Normal file
View File

@ -0,0 +1,26 @@
#include <string.h>
#include "tek_storage.h"
int tek_storage_init(bool clean) {
return 0;
}
int tek_storage_add(tek_t* src) {
// TODO
return -1;
}
int tek_storage_delete(tek_t* src) {
// TODO
return -1;
}
/**
* Returns 0 on success, else non zero (if none available)
* TODO: This is not really implemented...
*/
int tek_storage_get_latest_at_ts(tek_t* dest, uint32_t timestamp) {
dest->timestamp = timestamp;
memset(&dest->tek, 0, sizeof(dest->tek));
return 0;
}

View File

@ -15,21 +15,29 @@
#include <kernel.h>
#include "exposure-notification.h"
#include "covid_types.h"
#include "contacts.h"
#include "covid.h"
#include "ens/storage.h"
#include "tracing.h"
#include "record_storage.h"
#include "util.h"
#include "utility/util.h"
#define COVID_ENS (0xFD6F)
typedef ENIntervalIdentifier ENIntervalIdentifier;
typedef struct period{
ENPeriodKey periodKey;
ENIntervalNumber periodInterval;
} __packed period_t;
#ifndef COVID_MEASURE_PERFORMANCE
#define COVID_MEASURE_PERFORMANCE 0
#endif
typedef struct covid_adv_svd
{
uint16_t ens;
rolling_proximity_identifier_t rolling_proximity_identifier;
ENIntervalIdentifier rolling_proximity_identifier;
associated_encrypted_metadata_t associated_encrypted_metadata;
} __packed covid_adv_svd_t;
@ -40,8 +48,6 @@ const static bt_metadata_t bt_metadata = {
.rsv2 = 0,
};
#define COVID_ENS (0xFD6F)
static covid_adv_svd_t covid_adv_svd = {
.ens = COVID_ENS,
//do not initialiuze the rest of the packet, will write this later
@ -80,15 +86,15 @@ static void scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type, str
covid_adv_svd_t *rx_adv = (covid_adv_svd_t *)buf->data;
if (rx_adv->ens == COVID_ENS)
{
printk("Attempting to store contact...\n");
record_t contact;
printk("Attempting to store record...\n");
record_t record;
uint32_t timestamp = time_get_unix_seconds();
memcpy(&contact.rssi, &rssi, sizeof(contact.rssi));
memcpy(&contact.associated_encrypted_metadata, &rx_adv->associated_encrypted_metadata, sizeof(contact.associated_encrypted_metadata));
memcpy(&contact.rolling_proximity_identifier, &rx_adv->rolling_proximity_identifier, sizeof(contact.rolling_proximity_identifier));
memcpy(&contact.timestamp, &timestamp, sizeof(contact.timestamp));
int rc = register_record(&contact);
printk("Contact stored (err %d)\n", rc);
memcpy(&record.rssi, &rssi, sizeof(record.rssi));
memcpy(&record.associated_encrypted_metadata, &rx_adv->associated_encrypted_metadata, sizeof(record.associated_encrypted_metadata));
memcpy(&record.rolling_proximity_identifier, &rx_adv->rolling_proximity_identifier, sizeof(record.rolling_proximity_identifier));
memcpy(&record.timestamp, &timestamp, sizeof(record.timestamp));
int rc = add_record(&record);
printk("Record stored (err %d)\n", rc);
}
}
net_buf_simple_pull(buf, len - 1); //consume the rest, note we already consumed one byte via net_buf_simple_pull_u8(buf)
@ -167,120 +173,6 @@ static void new_period_key(time_t currentTime)
#endif
}
#if COVID_MEASURE_PERFORMANCE
static void measure_performance()
{
u32_t runs = 100;
u32_t start_time;
u32_t cycles_spent;
u32_t nanoseconds_spent;
ENPeriodKey pk;
ENPeriodIdentifierKey pik;
ENIntervalIdentifier intervalIdentifier;
ENIntervalNumber intervalNumber = 2642976;
ENIntervalIdentifier id;
ENPeriodMetadataEncryptionKey pmek;
unsigned char metadata[4] = {0x40, 0x08, 0x00, 0x00};
unsigned char encryptedMetadata[sizeof(metadata)] = {0};
printk("\n----------------------------------------\n");
printk("MEASURING PERFORMANCE\n");
// Measure en_generate_period_key
{
start_time = k_cycle_get_32();
for (int i = 0; i < runs; i++)
{
en_generate_period_key(&pk);
}
nanoseconds_spent = SYS_CLOCK_HW_CYCLES_TO_NS(k_cycle_get_32() - start_time);
printk("en_generate_period_key %d ns\n", nanoseconds_spent/runs);
}
// Measure en_derive_period_identifier_key
{
start_time = k_cycle_get_32();
for (int i = 0; i < runs; i++)
{
en_derive_period_identifier_key(&pik, &pk);
}
nanoseconds_spent = SYS_CLOCK_HW_CYCLES_TO_NS(k_cycle_get_32() - start_time);
printk("en_derive_period_identifier_key %d ns\n", nanoseconds_spent/runs);
}
// Measure en_derive_interval_identifier
{
start_time = k_cycle_get_32();
for (int i = 0; i < runs; i++)
{
en_derive_interval_identifier(&intervalIdentifier, &pik, intervalNumber);
}
nanoseconds_spent = SYS_CLOCK_HW_CYCLES_TO_NS(k_cycle_get_32() - start_time);
printk("en_derive_interval_identifier %d ns\n", nanoseconds_spent/runs);
}
// Measure en_derive_period_metadata_encryption_key
{
start_time = k_cycle_get_32();
for (int i = 0; i < runs; i++)
{
en_derive_period_metadata_encryption_key(&pmek, &pk);
}
nanoseconds_spent = SYS_CLOCK_HW_CYCLES_TO_NS(k_cycle_get_32() - start_time);
printk("en_derive_period_metadata_encryption_key %d ns\n", nanoseconds_spent/runs);
}
// Measure en_encrypt_interval_metadata
{
start_time = k_cycle_get_32();
for (int i = 0; i < runs; i++)
{
en_encrypt_interval_metadata(&pmek, &intervalIdentifier, metadata, encryptedMetadata, sizeof(metadata));
}
nanoseconds_spent = SYS_CLOCK_HW_CYCLES_TO_NS(k_cycle_get_32() - start_time);
printk("en_encrypt_interval_metadata %d ns\n", nanoseconds_spent/runs);
}
// Measure Full key generation
{
start_time = k_cycle_get_32();
for (int i = 0; i < runs; i++)
{
ENPeriodKey pk;
en_generate_period_key(&pk);
ENPeriodIdentifierKey ik;
en_derive_period_identifier_key(&ik, &pk);
for(int iv = 0; iv < EN_TEK_ROLLING_PERIOD; iv++) {
ENIntervalNumber intervalNumber = en_get_interval_number(iv);
ENIntervalIdentifier id;
en_derive_interval_identifier(&id, &ik, intervalNumber);
}
}
nanoseconds_spent = SYS_CLOCK_HW_CYCLES_TO_NS(k_cycle_get_32() - start_time);
printk("Full key generation %d ns\n", nanoseconds_spent/runs);
}
printk("\FINISHED\n");
printk("----------------------------------------\n\n");
}
#endif
//To be called when new keys are needed
static void check_keys(struct k_work *work)
{
@ -314,10 +206,10 @@ static void check_keys(struct k_work *work)
printk("Time: %u, ", currentTime);
printk("Interval: %u, ", currentInterval);
printk("TEK: ");
print_rpi((rolling_proximity_identifier_t *)&periods[current_period_index].periodKey);
print_rpi((ENIntervalIdentifier *)&periods[current_period_index].periodKey);
printk(", ");
printk("RPI: ");
print_rpi((rolling_proximity_identifier_t *)&intervalIdentifier);
print_rpi((ENIntervalIdentifier *)&intervalIdentifier);
printk(", ");
printk("AEM: ");
print_aem(&encryptedMetadata);
@ -325,7 +217,7 @@ static void check_keys(struct k_work *work)
// lock, so we can be sure to only advertise correct packages
k_mutex_lock(&key_change_lock, K_FOREVER);
memcpy(&covid_adv_svd.rolling_proximity_identifier, &intervalIdentifier, sizeof(rolling_proximity_identifier_t));
memcpy(&covid_adv_svd.rolling_proximity_identifier, &intervalIdentifier, sizeof(ENIntervalIdentifier));
memcpy(&covid_adv_svd.associated_encrypted_metadata, &encryptedMetadata, sizeof(associated_encrypted_metadata_t));
k_mutex_unlock(&key_change_lock);
@ -351,7 +243,7 @@ static const struct bt_le_scan_param scan_param = {
#define KEY_CHECK_INTERVAL (K_MSEC(EN_INTERVAL_LENGTH * 1000 / 10))
int init_covid()
int tracing_init()
{
#if COVID_MEASURE_PERFORMANCE
@ -383,7 +275,7 @@ int init_covid()
return 0;
}
int do_covid()
int tracing_run()
{
//printk("covid start\n");
@ -445,17 +337,3 @@ period_t *get_period_if_infected(unsigned int id, size_t *size)
*size = sizeof(period_t);
return &periods[id];
}
int get_index_by_interval(ENIntervalNumber periodInterval)
{
int index = 0;
while (index < NUM_PERIOD_KEYS || index < period_cnt)
{
if (periods[index].periodInterval == periodInterval)
{
return index;
}
index++;
}
return -1;
}

View File

@ -1,6 +0,0 @@
#include "time.h"
#include <zephyr.h>
// TODO: this is very basic atm
uint32_t time_get_unix_seconds() {
return k_uptime_get() / 1000;
}

View File

@ -6,8 +6,7 @@
#include <string.h>
#include <sys/crc.h>
#include "ens/ens_error.h"
#include "ens/ens_fs.h"
#include "utility/ens_fs.h"
#define SEED 42

View File

@ -1,4 +1,4 @@
#include "ens/sequencenumber.h"
#include "utility/sequencenumber.h"
#define SN_MASK 0xffffff

27
src/utility/util.c Normal file
View File

@ -0,0 +1,27 @@
#include "time.h"
#include <zephyr.h>
#include "utility/util.h"
// TODO: this is very basic atm
uint32_t time_get_unix_seconds() {
return k_uptime_get() / 1000;
}
void print_key(_ENBaseKey* key) {
for (int i = 0; i < sizeof(key->b); i++) {
printk("%02x", key->b[i]);
}
}
void print_rpi(ENIntervalIdentifier* rpi) {
for (int i = 0; i < sizeof(ENIntervalIdentifier); i++) {
printk("%02x", rpi->b[i]);
}
}
void print_aem(associated_encrypted_metadata_t* aem) {
for (int i = 0; i < sizeof(associated_encrypted_metadata_t); i++) {
printk("%02x", aem->data[i]);
}
}