247 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			247 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
#include <stdio.h>
 | 
						|
#include "esp_system.h"
 | 
						|
#include "esp_log.h"
 | 
						|
#include "esp_app_desc.h"
 | 
						|
 | 
						|
#include "dev_name.h"
 | 
						|
#include "storage.h"
 | 
						|
#include "system.h"
 | 
						|
#include "crypto.h"
 | 
						|
#include "unsecure_api.h"
 | 
						|
#include "secure_api.h"
 | 
						|
#include "ethernet.h"
 | 
						|
#include "constants.h"
 | 
						|
#include "relays.h"
 | 
						|
#include "ota.h"
 | 
						|
 | 
						|
static const char *TAG = "main";
 | 
						|
 | 
						|
void app_main(void)
 | 
						|
{
 | 
						|
    esp_log_level_set("*", ESP_LOG_INFO);
 | 
						|
 | 
						|
    system_show_free_memory();
 | 
						|
 | 
						|
    ESP_LOGI(TAG, "SolarEnergy WT32-ETH01 device version %s", esp_app_get_description()->version);
 | 
						|
 | 
						|
    // Turn off all relays
 | 
						|
    relays_turn_off_all();
 | 
						|
    relays_setup();
 | 
						|
 | 
						|
    // Initialize storage
 | 
						|
    if (storage_init() == false)
 | 
						|
    {
 | 
						|
        ESP_LOGE(TAG, "Failed to init storage!");
 | 
						|
        reboot();
 | 
						|
    }
 | 
						|
 | 
						|
    // Give a name to the device
 | 
						|
    if (dev_generate_name())
 | 
						|
    {
 | 
						|
        ESP_LOGI(TAG, "Generated a new device name");
 | 
						|
    }
 | 
						|
 | 
						|
    char *name = dev_name();
 | 
						|
    ESP_LOGI(TAG, "Dev name: %s", name);
 | 
						|
    free(name);
 | 
						|
 | 
						|
    // Generate private key, if needed
 | 
						|
    if (crypto_gen_priv_key())
 | 
						|
    {
 | 
						|
        ESP_LOGI(TAG, "Generated device private key!");
 | 
						|
    }
 | 
						|
    ESP_LOGI(TAG, "Device private key:");
 | 
						|
    crypto_print_priv_key();
 | 
						|
 | 
						|
    // Show current private key
 | 
						|
    char *csr = crypto_get_csr();
 | 
						|
    ESP_LOGI(TAG, "Current CSR:\n%s", csr);
 | 
						|
    free(csr);
 | 
						|
 | 
						|
    // Initialize network stack
 | 
						|
    ESP_LOGI(TAG, "Initialize network");
 | 
						|
    ethernet_init();
 | 
						|
    ethernet_wait_for_network();
 | 
						|
 | 
						|
    // Get if secure origin endpoint is known
 | 
						|
    ESP_LOGI(TAG, "Check secure origin");
 | 
						|
    if (storage_get_secure_origin(NULL) == 0)
 | 
						|
    {
 | 
						|
        char *sec_ori = unsecure_api_get_secure_origin();
 | 
						|
        if (!sec_ori)
 | 
						|
        {
 | 
						|
            ESP_LOGE(TAG, "Failed to fetch secure origin!");
 | 
						|
            reboot();
 | 
						|
        }
 | 
						|
        storage_set_secure_origin(sec_ori);
 | 
						|
        free(sec_ori);
 | 
						|
    }
 | 
						|
 | 
						|
    // Print secure origin endpoint for debugging purposes
 | 
						|
    ESP_LOGI(TAG, "Get secure origin");
 | 
						|
    char *sec_ori = calloc(SEC_ORIG_LEN, 1);
 | 
						|
    assert(storage_get_secure_origin(sec_ori) > 0);
 | 
						|
    ESP_LOGI(TAG, "Current secure origin: %s", sec_ori);
 | 
						|
    free(sec_ori);
 | 
						|
 | 
						|
    // Check if root CA is available locally
 | 
						|
    ESP_LOGI(TAG, "Check root CA");
 | 
						|
    if (storage_get_root_ca(NULL) == 0)
 | 
						|
    {
 | 
						|
        char *root_ca = unsecure_api_get_root_ca();
 | 
						|
        if (!root_ca)
 | 
						|
        {
 | 
						|
            ESP_LOGE(TAG, "Failed to fetch root CA!");
 | 
						|
            reboot();
 | 
						|
        }
 | 
						|
        storage_set_root_ca(root_ca);
 | 
						|
        free(root_ca);
 | 
						|
    }
 | 
						|
 | 
						|
    // Print root CA for debugging purposes
 | 
						|
    ESP_LOGI(TAG, "Get root CA");
 | 
						|
    char *root_ca = calloc(ROOT_CA_MAX_BYTES, 1);
 | 
						|
    assert(storage_get_root_ca(root_ca) > 0);
 | 
						|
    ESP_LOGI(TAG, "Current root CA:\n%s", root_ca);
 | 
						|
    free(root_ca);
 | 
						|
 | 
						|
    bool validated = false;
 | 
						|
    while (!validated)
 | 
						|
    {
 | 
						|
        // Check current device enrollment status
 | 
						|
        ESP_LOGI(TAG, "Check enrollment status");
 | 
						|
        enum DevEnrollmentStatus status = secure_api_get_device_enrollment_status();
 | 
						|
        ESP_LOGI(TAG, "Current enrollment status: %d", status);
 | 
						|
 | 
						|
        switch (status)
 | 
						|
        {
 | 
						|
        case DevEnrollError:
 | 
						|
            ESP_LOGE(TAG, "Failed to retrieve device enrollment status!");
 | 
						|
            break;
 | 
						|
 | 
						|
        case DevEnrollPending:
 | 
						|
            ESP_LOGI(TAG, "Device enrolled, but not validated yet. Please accept device on central system web UI");
 | 
						|
            break;
 | 
						|
 | 
						|
        case DevEnrollValidated:
 | 
						|
            ESP_LOGI(TAG, "Device enrolled and validated. Ready to operate!");
 | 
						|
            validated = true;
 | 
						|
            break;
 | 
						|
 | 
						|
        case DevEnrollUnknown:
 | 
						|
            ESP_LOGI(TAG, "Device unknown, need to enroll!");
 | 
						|
 | 
						|
            // Remove certificate if present
 | 
						|
            storage_set_dev_cert("");
 | 
						|
 | 
						|
            // Enroll device
 | 
						|
            ESP_LOGI(TAG, "Enroll device");
 | 
						|
            if (secure_api_enroll_device() != 0)
 | 
						|
            {
 | 
						|
                ESP_LOGE(TAG, "Failed to enroll device!");
 | 
						|
                reboot();
 | 
						|
            }
 | 
						|
            ESP_LOGI(TAG, "Requested device enrollment.");
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        // Wait before next try
 | 
						|
        if (!validated)
 | 
						|
            system_sleep(60);
 | 
						|
    };
 | 
						|
 | 
						|
    // Retrieve device certificate if missing
 | 
						|
    ESP_LOGI(TAG, "Check device certificate");
 | 
						|
    if (storage_get_dev_cert(NULL) < 2)
 | 
						|
    {
 | 
						|
        char *dev_cert = secure_api_get_dev_certificate();
 | 
						|
        if (!dev_cert)
 | 
						|
        {
 | 
						|
            ESP_LOGE(TAG, "Failed to fetch device certificate!");
 | 
						|
            reboot();
 | 
						|
        }
 | 
						|
        storage_set_dev_cert(dev_cert);
 | 
						|
        free(dev_cert);
 | 
						|
    }
 | 
						|
 | 
						|
    // Print device certificate for debugging purposes
 | 
						|
    ESP_LOGI(TAG, "Get device certificate");
 | 
						|
    char *dev_certificate = calloc(DEV_CERT_MAX_BYTES, 1);
 | 
						|
    assert(storage_get_dev_cert(dev_certificate) > 0);
 | 
						|
    ESP_LOGI(TAG, "Current device certificate:\n%s", dev_certificate);
 | 
						|
    free(dev_certificate);
 | 
						|
 | 
						|
    // Main loop
 | 
						|
    ESP_LOGI(TAG, "Starting main loop");
 | 
						|
    secure_api_report_log_message(Info, "Starting program main loop");
 | 
						|
 | 
						|
    size_t fails = 0;
 | 
						|
    while (true)
 | 
						|
    {
 | 
						|
        sync_response *res = secure_api_sync_device();
 | 
						|
        if (!res)
 | 
						|
        {
 | 
						|
            fails += 1;
 | 
						|
            ESP_LOGE(TAG, "Failed to synchronise device! (number=%d)", fails);
 | 
						|
 | 
						|
            // Safely turn off all relays after a given number of failures
 | 
						|
            if (fails > 5)
 | 
						|
            {
 | 
						|
                ESP_LOGE(TAG, "Many failures, will stop all relays...");
 | 
						|
                relays_turn_off_all();
 | 
						|
            }
 | 
						|
 | 
						|
            // Restart the card after too much failures
 | 
						|
            if (fails > 10)
 | 
						|
            {
 | 
						|
                ESP_LOGE(TAG, "Too many failures, will try to reboot in 3 secs...");
 | 
						|
                system_sleep(3);
 | 
						|
                reboot();
 | 
						|
            }
 | 
						|
 | 
						|
            system_sleep(SYNC_TIME_INTERVAL);
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
 | 
						|
        fails = 0;
 | 
						|
 | 
						|
        sync_response_print(res);
 | 
						|
 | 
						|
        // Check for firmware update
 | 
						|
        if (res->available_update)
 | 
						|
        {
 | 
						|
            ESP_LOGI(TAG, "Will perform system upgrade to version %s!", res->available_update);
 | 
						|
            relays_turn_off_all();
 | 
						|
 | 
						|
            secure_api_report_log_message(Info, "Device is starting the OTA procedure...");
 | 
						|
 | 
						|
            if (ota_perform_update(res->available_update))
 | 
						|
            {
 | 
						|
                ESP_LOGI(TAG, "OTA update succesfully executed, will reboot...");
 | 
						|
                secure_api_report_log_message(Info, "Device successfully updated!");
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                ESP_LOGE(TAG, "OTA update failed! Will reboot...");
 | 
						|
                secure_api_report_log_message(Error, "Device update failed!");
 | 
						|
            }
 | 
						|
 | 
						|
            secure_api_report_log_message(Info, "Device will restart after OTA procedure...");
 | 
						|
 | 
						|
            system_sleep(SYNC_TIME_INTERVAL);
 | 
						|
            reboot();
 | 
						|
        }
 | 
						|
 | 
						|
        // Update relays configuration
 | 
						|
        for (size_t i = 0; i < relays_count(); i++)
 | 
						|
        {
 | 
						|
            relays_set(i, sync_response_is_relay_on(res, i));
 | 
						|
        }
 | 
						|
 | 
						|
        sync_response_free(res);
 | 
						|
        system_sleep(SYNC_TIME_INTERVAL);
 | 
						|
    }
 | 
						|
 | 
						|
    reboot();
 | 
						|
}
 |