first commit

This commit is contained in:
valeh
2020-12-22 14:30:09 +02:00
commit 26b0ba5954
1832 changed files with 17777948 additions and 0 deletions

View File

@@ -0,0 +1,509 @@
#ifndef MAIN_INCLUDE_CONTROLLER_H_
#define MAIN_INCLUDE_CONTROLLER_H_
/**
* @file controller.h
* @brief definition of controllers.
* */
#include <string>
#include <algorithm>
#include <vector>
#include "string.h"
#include "esp_log.h"
#include "mbedtls/base64.h"
#include "mbedtls/asn1.h"
#include "mbedtls/asn1write.h"
#include "mbedtls/sha256.h"
#include "expat.h"
#include "module.h"
#include "model.h"
#include "view.h"
/**
* \class Controller
*
* \brief abstract class Controller. C in MVC,
*
* Controllers are bridge between views and models. They take data from model, modify it if required and pass it to the view to present to client.
* It has one main method - index(), which is called when controller is reached.
* However, depending on their complexity , controller may have other methods.
*
* */
class Controller {
protected:
View * vw; /**< associated view object*/
public:
virtual void index() = 0; /**< abstract method index */
virtual ~Controller(){}; /**< Destructor */
};
/**
* \class IndexController
* \brief sample inherited controller
* */
class IndexController : public Controller {
public:
IndexController(); /**< constructor */
void index(); /**< a method that prints welcome message */
void end(); /**< a method that prints final screen */
};
/**
* \class AuthorizationController
* \brief responsible for logic behind mobilID authorization
*
*
* */
class AuthorizationController : public Controller{
private:
UserModel * model; /**< user model*/
const char * TAG = "authController";
const char* sni; /**< SNI for authorization */
public:
AuthorizationController(BaseModel *model, const char* sni); /**< constructor */
/**
* @brief JSON body generator to retrieve Authentication Certificate
* Example:
*
* {
* "id": 0.0,
* "method": "RPC.Authenticate",
* "params": [
* {
* "OS": "Operating System,2,0",
* "PhoneNo": "+37200000766",
* "IdCode": "60001019906"
* }
* ]
* }
*
* */
char* generateAuthenticateRequestJSON();
/**
* @brief JSON body generator to retrieve Authentication Status
*
* Example:
*
* {
* "id": 0.0,
* "method": "RPC.AuthenticateStatus",
* "params": [
* {
* "OS": "Operating System,2,0",
* "SessionCode": "2127729011",
* "SessionID": "057229fdfa2df7d3c7f4ced81b02760b"
* }
* ]
* }
*
* */
char* generateAuthenticateStatusRequestJSON();
/**
* @brief index method
*
* This method does nothing specific.
* */
void index();
/**
* @brief authorization request method.
*
* This method invokes authorization request to voting server.
* Server doesn't directly send authorization token. Instead, sends a challenge to user to verify (verification code)
* Session ID is also returned which will be used in all upcoming requests.
* */
void auth();
/**
* @brief authorization status method
*
* After auth() called, server returns challenge code, session id and session code. Challenge code is displayed to user verify itself.
* To check whether user has been verified and get authorization token that is also going to be used in all upcoming requests, authorization status
* request has to be sent to server. This function sends that request until user verifies itself every 10 seconds.
*
* Upon successful verification, authorization token is obtained and stored in model.
* */
void authStatus();
};
/**
* \class ChoiceController
* \brief An authenticated user can request for list of candidates from voting server.
*
* Voting server returns list of candidates in special scheme in JSON format. ChoiceController parses that response and
* make candidate names be displayed on screen.
* */
class ChoiceController : public Controller{
private:
ChoiceModel *model; /**< choices model */
const char * TAG = "choicesCtrl";
const char* sni; /**< SNI for choices service */
public:
/**
* @brief JSON body generator to retrieve the List of Choices
*
* @param at Authentication token
* @param ssid SessionID
*
* Example:
*
* {
* "id": 0.0,
* "method": "RPC.VoterChoices",
* "params": [
* {
* "AuthMethod": "ticket",
* "AuthToken": "G1RTZqBSBKrzqReuKYrmFUFXWFPvaxhJjdiZi6zqAnaK3OvrT...",
* "OS": "Operating System,2,0",
* "SessionID": "057229fdfa2df7d3c7f4ced81b02760b"
* }
* ]
* }
*
* */
char* generateChoicesRequestJSON(ChoiceModel *cm);
ChoiceController(BaseModel *model, const char* sni); /**< constructor*/
/**
* @brief fetches data from server and waits user select a candidate
* */
void index();
/**
* Recursive function to parse JSON which holds the list of choices into choiceList,choiceListKeys and partyNameOf
* @param item pointer to cJSON structure
* @param par party (also, parent) name of current element, otherwise ""
*
* Example JSON body:
*
* {
* "Kuused":{
* "0000.101":"ARA SMIRNOVVVK",
* "0000.102":"MARGUS OTT KOVTP"
* },
* "Männid":{
* "0000.103":"ADINE SÄDEVVK"
* },
* "Üksikkandidaadid":{
* "0000.104":"LEILI KOVTP",
* "0000.107":"JUTA KOVVALAH",
* "0000.105":"KAJA KOVVALAG",
* "0000.106":"MAREK KOVVALAG"
* }
* }
*
* */
void parse_object(cJSON *item, char* par);
};
/**
* \class EncryptionController
* \brief A controller where selected candidate is turned into ballot and encrypted
*
* */
class EncryptionController : public Controller{
private:
EncryptionModel *model; /**< encryption model*/
const char * TAG = "encCtrl";
public:
/**
* @brief main controller method.
*
* Encrypt voters casted ballot using public election key
*
* */
void index();
EncryptionController(BaseModel *model); /**< constructor */
};
/**
* \class SignatureController
* \brief digitally sign encrypted ballot
* */
class SignatureController : Controller{
private:
SignatureModel *model; /**< signature model*/
const char* sni; /**< sni for signature service*/
const char* TAG = "signCtrl";
/**
* XML container for element SignedProperties
* */
const char * SignedProperties = ""
"<xades:SignedProperties xmlns:asic=\"http://uri.etsi.org/02918/v1.2.1#\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:xades=\"http://uri.etsi.org/01903/v1.3.2#\" Id=\"S0-SignedProperties\">"
"<xades:SignedSignatureProperties>"
"<xades:SigningTime>%s</xades:SigningTime>"
"<xades:SigningCertificate>"
"<xades:Cert>"
"<xades:CertDigest>"
"<ds:DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\"></ds:DigestMethod>"
"<ds:DigestValue>%s</ds:DigestValue>"
"</xades:CertDigest>"
"<xades:IssuerSerial>"
"<ds:X509IssuerName>%s</ds:X509IssuerName>"
"<ds:X509SerialNumber>%s</ds:X509SerialNumber>"
"</xades:IssuerSerial>"
"</xades:Cert>"
"</xades:SigningCertificate>"
"</xades:SignedSignatureProperties>"
"<xades:SignedDataObjectProperties>"
"<xades:DataObjectFormat ObjectReference=\"#S0-RefId0\">"
"<xades:MimeType>application/octet-stream</xades:MimeType>"
"</xades:DataObjectFormat>"
"</xades:SignedDataObjectProperties>"
"</xades:SignedProperties>";
/**
* XML container for element SignedInfo
* */
const char * SignedInfo = ""
"<ds:SignedInfo xmlns:asic=\"http://uri.etsi.org/02918/v1.2.1#\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:xades=\"http://uri.etsi.org/01903/v1.3.2#\">"
"<ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/2006/12/xml-c14n11\"></ds:CanonicalizationMethod>"
"<ds:SignatureMethod Algorithm=\"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256\"></ds:SignatureMethod>"
"<ds:Reference Id=\"S0-RefId0\" URI=\"%s\">"
"<ds:DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\"></ds:DigestMethod>"
"<ds:DigestValue>%s</ds:DigestValue>"
"</ds:Reference>"
"<ds:Reference Id=\"S0-RefId1\" Type=\"http://uri.etsi.org/01903#SignedProperties\" URI=\"#S0-SignedProperties\">"
"<ds:Transforms>"
"<ds:Transform Algorithm=\"http://www.w3.org/2006/12/xml-c14n11\"></ds:Transform>"
"</ds:Transforms>"
"<ds:DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\"></ds:DigestMethod>"
"<ds:DigestValue>%s</ds:DigestValue>"
"</ds:Reference>"
"</ds:SignedInfo>";
/**
* XML container for element SignatureValue
* */
const char * SignatureValue = "<ds:SignatureValue xmlns:asic=\"http://uri.etsi.org/02918/v1.2.1#\" "
"xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:xades=\"http://uri.etsi.org/01903/v1.3.2#\" Id=\"S0-SIG\">%s</ds:SignatureValue>";
/**
* XML container for element XadESSignature
* */
const char * Signature = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
"<asic:XAdESSignatures xmlns:asic=\"http://uri.etsi.org/02918/v1.2.1#\">"
"<ds:Signature xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" Id=\"S0\">"
"%s"
"%s"
"<ds:KeyInfo>"
"<ds:X509Data>"
"<ds:X509Certificate>%s</ds:X509Certificate>"
"</ds:X509Data>"
"</ds:KeyInfo>"
"<ds:Object>"
"<xades:QualifyingProperties xmlns:xades=\"http://uri.etsi.org/01903/v1.3.2#\" Target=\"#S0\">"
"%s"
"</xades:QualifyingProperties>"
"</ds:Object>"
"</ds:Signature>"
"</asic:XAdESSignatures>";
public:
SignatureController(BaseModel *model, const char* sni);
/**
* @brief retrieve user's public siging Certificate
* */
void index();
/**
* @brief JSON body generator to get signing Certificate
*
* Example:
*
* {
* "id": 0.0,
* "method": "RPC.GetCertificate",
* "params": [
* {
* "AuthMethod": "ticket",
* "AuthToken": "G1RTZqBSBKrzqReuKYrmFUFXWFPvaxhJjdiZi6zqAnaK3OvrT...",
* "OS": "Operating System,2,0",
* "SessionID": "057229fdfa2df7d3c7f4ced81b02760b"
* "PhoneNo": "+37200000766",
* "IdCode": "60001019906"
* }
* ]
* }
*
* */
char* generateGetCertificateRequestJSON();
/*
* JSON body generator to initiate vote signing
* Example:
* {
* "id": 0.0,
* "method": "RPC.Sign",
* "params": [
* {
* "AuthMethod": "ticket",
* "AuthToken": "G1RTZqBSBKrzqReuKYrmFUFXWFPvaxhJjdiZi6zqAnaK3OvrT...",
* "Hash": "9IBrA05ylt2StdjxKkSTYMW/rQXY3Vub4upzShdfEzo=",
* "OS": "Operating System,2,0",
* "SessionID": "057229fdfa2df7d3c7f4ced81b02760b"
* "PhoneNo": "+37200000766",
* "IdCode": "60001019906"
* }
* ]
* }
*
* */
char* generateSignRequestJSON();
/**
* @brief send sign request for encrypted ballot hash
*
*
* */
void sign();
/*
* @brief JSON body generator to retrieve Signing Status
*
* Example:
*
* {
* "id": 0.0,
* "method": "RPC.SignStatus",
* "params": [
* {
* "OS": "Operating System,2,0",
* "SessionCode": "2127729011",
* "SessionID": "057229fdfa2df7d3c7f4ced81b02760b"
* }
* ]
* }
*
* */
char* generateSignStatusRequestJSON();
/**
* @brief check status of sign request
* */
void status();
/**
* @brief a helper method to put all xml elements into one single large elements.
* */
void combine();
};
/**
* \class ZipController
* \brief BDOC container creator for singature file
* */
class ZipController : public Controller{
private:
ZipModel *model;
const char* TAG = "zipCtrl";
/**
* XML container for manifest.xml
*/
const char * manifest = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n"
"<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n"
" <manifest:file-entry manifest:full-path=\"/\" manifest:media-type=\"application/vnd.etsi.asic-e+zip\"/>\n"
" <manifest:file-entry manifest:full-path=\"%s\" manifest:media-type=\"application/octet-stream\"/>\n"
"</manifest:manifest>";
public:
ZipController(BaseModel *model); /**< constructor */
/**
* @brief create signature container according to BDOC 2.0 standards
*
* Using slightly modified miniz library, create .zip archieve with following file structure
*
* \META-INF
* singature0.xml
* manifest.xml
* EP2065.1.ballot
* mimetype
*
*/
void index();
};
/**
* \class VoteController
* \brief cast signed ballot file to voting service
*
* */
class VoteController : public Controller{
private:
VoteModel *model;
const char * TAG = "voteCtrl";
const char * sni;
public:
VoteController(BaseModel *model, const char* sni); /**< constructor */
/**
* @brief send bdoc container to voting service to cast your vote.
*
* A vote id is returned after bdoc container and vote data is validated in server side
* */
void index();
/**
* @brief JSON body generator to send signed vote
*
* Example
*
* {
* "id": 0.0,
* "method": "RPC.Vote",
* "params": [
* {
* "AuthMethod": "ticket",
* "AuthToken": "G1RTZqBSBKrzqReuKYrmFUFXWFPvaxhJjdiZi6zqAnaK3OvrT...",
* "Choices": "0140.1",
* "SessionID": "ec3a0cab353d552952289f2c7ad52e27",
* "OS": "Operating System,2,0",
* "Type": "bdoc",
* "Vote": "UEsDBAoABgAAAAIAAAAbWltZXR5cGVhcHBsaWNhdGlv\nbi92bmQuZX..."
* }
* ]
* }
* */
char* generateVoteRequestJSON();
};
/**
* \class QRController
* \brief show vote data to verification app as QR code
*
* */
class QRController : public Controller{
private:
QRModel *model; /**< qr model */
const char* TAG = "btCtrl";
public:
QRController(BaseModel* model); /**< controller */
/**
* @brief create QRcode from session id, randomness and vote id, then show it on screen
* */
void index();
};
#endif /* MAIN_INCLUDE_CONTROLLER_H_ */

View File

@@ -0,0 +1,141 @@
#ifndef MAIN_INCLUDE_CONVERTER_H_
#define MAIN_INCLUDE_CONVERTER_H_
/**
* @file converter.h
* @brief converter namespace - collection of frequently used conversion/encoding/decoding functions
*
* */
#include <stdint.h>
#include <string.h>
#include "expat.h"
/** Buffer size for xml parsing */
#define output_size 10240
/**
* \namespace converter
* */
namespace converter{
/** @brief a helper function to convert pem files to der.
*
* source: https://github.com/ARMmbed/mbedtls/blob/master/programs/util/pem2der.c
*
* @param input pem file buffer
* @param ilen input buffer length
* @param output buffer to store converted der content
* @param olen length of data written in output buffer
*
* @returns 0 if OK, else -1
* */
int convert_pem_to_der( const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen );
/**
* @brief a helper function to convert long hex numbers to base b = 2^32
*
* In base 2^32, every digit is 32 bit length unsigned integers (uint32_t).
* Therefore, each consequent 4 bytes in hex converted into one digit in base b.
* Note: numbers may contain '0x00' in hex representation which is treated as end of string
* in string functions. Another parameter is required to indicate length of hex representation
*
* @param hex input number buffer
* @param len input buffer length
*
* @returns long base-b number
*/
uint32_t* hex2u32(unsigned char* hex, size_t len);
/**
* @brief a helper function to convert long base-b number to hex values for DER encoding
*
* Inverse of hex2u32 function
*
* @param x long base-b number
* @param length length of input number
* @param len output buffer length
*
* @returns buffer containing number in hex representation
* */
unsigned char * nb(uint32_t *x, int length, size_t *olen);
/**
* @brief a helper function convert to first hash, then base64 encode
*
* This function wraps to mbed_tls functions. Given input string buffer,
* it first finds SHA256 hash, then converts the resulting hash into base64.
*
* @param input string buffer
* @param len input buffer length
*
* @returns output buffer
* */
unsigned char * base64hash(unsigned char* input, size_t len);
/** @brief struct used in xml parsing functions
* */
typedef struct {
int depth; /**< depth of recursion*/
char* output; /**< output buffer (for parsed xml) */
int output_off; /**< output buffer offset (last written index, i.e length of written data)*/
const char *last_name; /**< last opened xml tag */
} xml_data_t;
/**
* @brief a helper function to insert space for indentation
*
* This function prints extra whitespaces to output buffer for indentation purposes.
*
* @param user_data parsed xml data
* */
static void insert_space(xml_data_t *user_data);
/**
* @brief a callback function called at start of new xml node
*
* XMLParser traverses through xml nodes and each time it reaches a new node, this callback function is called.
* Copy tag name and attributes to output buffer
*
* @param user_data parsed xml data
* @param name just opened current xml node tag name
* @param atts other attributes of current xml node
* */
static void XMLCALL start_element(void *userData, const XML_Char *name, const XML_Char **atts);
/**
* @brief a callback function called at the end of new xml node
*
* XMLParser traverses through xml nodes and each time it reaches a closing tags of current node, this callback function is called.
* If current node is leaf node, add closing tags immediately. Otherwise, add whitespace before closing tags.
*
* @param user_data parsed xml data
* @param name to be closed current xml node tag name
* */
static void XMLCALL end_element(void *userData, const XML_Char *name);
/**
* @brief a function to define how to parse xml elements
*
* In between starting and closing tags, this functions is called by XMLParser.
* Here, it just copies data buffer to output buffer without adding extra whitespace.
*
* @param user_data parsed xml data
* @param s data in current xml node
* @param len length of data
* */
static void data_handler(void *userData, const XML_Char *s, int len);
/**
* @brief a helper funciton to canonicalize xml data (XMLC14N11).
*
* Specifications can be found here: \see https://www.w3.org/TR/xml-c14n11/#Example-SETags
*
* @param str xml input buffer
* @param len input buffer length
* */
void xmlc14n11(char* str, size_t len);
}
#endif

View File

@@ -0,0 +1,141 @@
#ifndef MAIN_INCLUDE_MODEL_H_
#define MAIN_INCLUDE_MODEL_H_
/**
* @file model.h
* @brief header for model definitions
* */
#include "stdint.h"
#include <vector>
/**
* \class BaseModel
* \brief base model class
* */
class BaseModel{
public:
char* ssid; /**< session ID*/
char* authToken; /**< authentication token */
};
/**
* \class UserModel
* \brief data model to use in AuthorizationController
* */
class UserModel : public BaseModel{
public:
char ID[12]; /**< ID code of user */
char phone[13]; /**< Phone number of user */
char* sscode; /**< session code for PIN confirmation */
UserModel(char* id, char* phone); /**< constructor */
};
/**
* @brief struct to store candidate details
* */
typedef struct{
char * party; /**< candidate party name */
char * code; /**< District code */
char * candidate; /**< candidate full name */
}choice_t;
/**
* \class ChoiceModel
* \brief data model to use in ChoiceController
* */
class ChoiceModel : public BaseModel{
public:
std::vector<choice_t> *choice_list; /**< list of candidates*/
char* choices; /**< The voters district identifier */
char* ballot; /**< ballot generated from selected candidate */
ChoiceModel(char *ssid, char* authToken); /**< constructor */
};
/**
* \class EncryptionModel
* \brief data model to use in EncryptionController
* */
class EncryptionModel : public BaseModel{
public:
char* ballot; /**< ballot generated from selected candidate */
unsigned char* ballotASN; /**< encoded encrypted ballot ballot data in ASN1 DER */
size_t ballotLength; /**< ballotASN file length */
unsigned char* rndBase64; /**< Base64 encoded randomness used in ecryption */
unsigned char* ballotHash; /**< ballotASN hash */
char* ballotFileName; /**< filename for encrypted ballot */
char* election_id; /**< election id from public election key*/
const unsigned char* keypem; /**< public election file in PEM */
int keypem_length; /**< public key buffer length */
EncryptionModel(char* ballot,char* ssid, char * authToken, const uint8_t keypem[], int keypem_length); /**< constructor */
};
/**
* \class SignatureModel
* \brief data model to use in SignatureController
* */
class SignatureModel : public BaseModel{
public:
char ID[12]; /**< ID code of user */
char phone[13]; /**< Phone number of user */
char* sscode; /**< session code for PIN confirmation */
unsigned char* ballotHash; /**< ballotASN hash */
size_t ballotLength; /**< ballotASN file length */
char* ballotFileName; /**< filename for encrypted ballot */
unsigned char* SignedInfoHash; /**< hash of SignedInfo element */
char* signature; /**< digital signature returned from mobilID*/
char* certificate; /**< signature certificate */
char* SI_XML; /**< SignedInfo XML element*/
char* SP_XML; /**< SignedProperties XML element*/
char* SV_XML; /**< SignatureValue XML element*/
char* Signature; /**< Signature XML element*/
SignatureModel(char* ssid, char * authToken, char* phone, char* id, unsigned char* ballotHash, size_t ballotLength, char* ballotFileName);
};
/**
* \class ZipModel
* \brief data model to use in ZipController
* */
class ZipModel : public BaseModel {
public:
unsigned char* ballot; /**< encrypted digital ballot */
char* ballotFileName; /**< ballot file name */
size_t ballotLength; /**< ballot length */
char* Signature; /**< Signature XML*/
unsigned char* voteBase64; /**< Base64 encoded bdoc container*/
ZipModel(unsigned char* ballot, char* ballotFileName, size_t ballotLength, char* Signature); /** constructor */
};
/**
* \class VoteModel
* \brief data model to use in VoteController
* */
class VoteModel : public BaseModel{
public:
unsigned char* voteBase64; /**< Base64 encoded bdoc container*/
char* voteID; /**< voteID */
char* choices; /**< voters district identifier */
VoteModel(char* ssid, char* authToken, unsigned char* voteBase64, char* choices); /**< constructor */
};
/**
* \class QRModel
* \brief data model to use in QRController
* */
class QRModel : public BaseModel{
public:
char* ssid; /**< session ID */
char* voteID; /**< voteID */
unsigned char* rndBase64; /**< Base64 encoded randomness used in encryption */
QRModel(char* ssid, char* voteID, unsigned char* rndBase64); /**< constructor */
};
#endif /* MAIN_INCLUDE_MODEL_H_ */

View File

@@ -0,0 +1,142 @@
#ifndef MAIN_INCLUDE_MODULE_H_
#define MAIN_INCLUDE_MODULE_H_
/**
* @file module.h
* @brief Header for module definitions
* */
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_tls.h"
#include "cJSON.h"
/**
* \class Module
* \brief base abstract module class
* */
class Module{
public:
/**
* @brief module initialization abstract method
* */
virtual esp_err_t init()=0;
/**
* @brief module deinitialization abstract method
* */
virtual esp_err_t deinit()=0;
/**
* @brief default module destructor
* */
virtual ~Module(){};
};
/**
* \class RPC
* \brief remote procedure call module
*
* This module follows singleton pattern to prevent concurrent tls communications which may abort program
* */
class RPC{
private:
const char* TLS_TAG = "rpc";
RPC();
public:
esp_tls_cfg_t *cfg; /**< tls connection config file */
char* server; /**< host server address (full domain or ipaddress) */
int port; /**< host server process port, default 443 */
/**
* @brief RPC Communication method.
*
*
* @param const char* sni SNI of the service to make a request
* @param const char* req stringified JSON request body
*
* @returns pointer to cJSON structure variable that holds parsed JSON response
* */
cJSON * send_json_rpc(const char* sni, char* req);
static RPC& Instance(); /**< singleton RPC instance*/
};
/**
* \class ScreenModule
* \brief screen device module
*
* This module follows singleton pattern to prevent unexpected behaviors when two process concurrently want to write data
* */
class ScreenModule : public Module{
private:
const char* TAG = "ssd_1306";
uint8_t screen_id = 0; /**< connected screen id */
uint8_t lineOff = 0; /**< last written line */
ScreenModule();
public:
gpio_num_t SCL_PIN; /**< SCL connection pin number */
gpio_num_t SDA_PIN; /**< SDA connection pin number */
gpio_num_t RESET_PIN = GPIO_NUM_NC; /**< OLED RESET connection pin number */
void setSCL(gpio_num_t scl_pin); /**< set SCL pin */
void setSDA(gpio_num_t sda_pin); /**< set SCL pin */
void setRST(gpio_num_t rst_pin); /**< set RESET pin */
esp_err_t init();
esp_err_t deinit();
static ScreenModule& Instance(); /**< singleton ScreenModule instance*/
};
/**
* \class WiFiModule
* \brief WiFi connections module
* */
class WiFiModule : public Module{
private:
const char * TAG = "wi-fi";
char* WIFI_SSID; /**< WiFi SSID name */
char* WIFI_PASS; /**< WiFi password */
public:
WiFiModule(char *ssid, char* pass);
esp_err_t init();
esp_err_t deinit();
};
/**
* \class TouchModule
* \brief TouchScreen module
* */
class TouchModule : public Module {
private:
const char* TAG = "Touch";
gpio_num_t YP; /**< Y+ pin. Should connect to only Analog pin */
gpio_num_t YM; /**< Y- pin. Should connect to any digital pin */
gpio_num_t XP; /**< X+ pin. Should connect to any digital pin */
gpio_num_t XM; /**< X- pin. Should connect to only Analog pin */
public:
TouchModule(gpio_num_t a, gpio_num_t b, gpio_num_t c, gpio_num_t d);
esp_err_t init();
esp_err_t deinit();
};
/**
* \class SNTPModule
* \brief Time synchronization module
* */
class SNTPModule : public Module{
private:
const char* TAG = "sntp";
public:
static void initialize_sntp(void); /**< synchronize time over network*/
esp_err_t init();
esp_err_t deinit();
};
#endif /* MAIN_INCLUDE_MODULE_H_ */

View File

@@ -0,0 +1,86 @@
#ifndef MAIN_INCLUDE_VIEW_H_
#define MAIN_INCLUDE_VIEW_H_
/**
* @file view.h
* @brief View class
* */
#include <vector>
#include "lvgl/lvgl.h"
#include "module.h"
#include "model.h"
static lv_style_t style_scr_bg;
static lv_style_t big_text_style;
static lv_style_t headline_style;
static lv_style_t style;
/**
* \class View
* \brief V in MVC pattern. Each controller is associated with a view.
* There is only one screen device attached to board. This view helps to display data and accept user input
* */
class View{
public:
ScreenModule screen = ScreenModule::Instance(); /**< singleton screen instance */
virtual void render(void* data) = 0; /**< abstract method to render data*/
virtual ~View(){}; // destructor
virtual void setLabel(char* data) = 0;
virtual void showLoader(bool en) = 0;
};
/**
* \class IndexView
* @brief default inherited class
* */
class IndexView : public View{
public:
IndexView();
/**
* @brief display data on screen
*
* @param data (void *) casted string buffer to display
* */
void render(void * data);
void setLabel(char* data);
void showLoader(bool en);
};
/**
* \class ChoiceView
* @brief more functional view class that ChoiceController uses.
* */
class ChoiceView : public View{
public:
ChoiceView();
/**
* @brief render ChoiceController data
*
* Here, users allowed to interact with device using RotaryEncoder. Every time encoder state is changed,
* screen is updated. A small circle in front of candidate names represent selected option index. This method
* will listen rotary encoder until click event is fired, and then create ballot based on selected candidate data.
*
* @param data (void *) casted ChoiceModel * model.
* */
void render(void * data);
void setLabel(char* data);
void showLoader(bool en);
};
class QRView : public View{
public:
QRView();
/**
* @brief display data on screen
*
* @param data (void *) casted string buffer to display
* */
void render(void * data);
void setLabel(char* data);
void showLoader(bool en);
};
#endif /* MAIN_INCLUDE_VIEW_H_ */