Restructure and improve
This commit is contained in:
414
main/atecc608a.h
414
main/atecc608a.h
@@ -2,417 +2,23 @@
|
||||
#define ATECC608B_H
|
||||
|
||||
#include "cryptoauthlib.h"
|
||||
#include "sdkconfig.h"
|
||||
#include <cJSON.h>
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
static const char *TAG_ATECC = "ATECC608B";
|
||||
|
||||
// ATECC608B Configuration
|
||||
ATCAIfaceCfg atecc_cfg;
|
||||
|
||||
bool atecc608B_init() {
|
||||
ESP_LOGI(TAG_ATECC, "\n=== ATECC608B Initialization ===");
|
||||
|
||||
// Configure cryptoauthlib for ATECC608B - it will handle I2C initialization
|
||||
atecc_cfg.iface_type = ATCA_I2C_IFACE;
|
||||
atecc_cfg.devtype = ATECC608B;
|
||||
atecc_cfg.atcai2c.address = CONFIG_ATCA_I2C_ADDRESS;
|
||||
atecc_cfg.atcai2c.bus = 0; // I2C bus number
|
||||
atecc_cfg.atcai2c.baud = CONFIG_ATCA_I2C_BAUD_RATE;
|
||||
atecc_cfg.wake_delay = 1500;
|
||||
atecc_cfg.rx_retries = 20;
|
||||
|
||||
ESP_LOGI(TAG_ATECC,
|
||||
"Configuring ATECC608B: SDA=GPIO%d, SCL=GPIO%d, Address=0x%02X "
|
||||
"(7-bit: 0x%02X)",
|
||||
CONFIG_ATCA_I2C_SDA_PIN, CONFIG_ATCA_I2C_SCL_PIN,
|
||||
CONFIG_ATCA_I2C_ADDRESS, CONFIG_ATCA_I2C_ADDRESS >> 1);
|
||||
|
||||
// Initialize cryptoauthlib (it will initialize I2C internally)
|
||||
ATCA_STATUS status = atcab_init(&atecc_cfg);
|
||||
if (status != ATCA_SUCCESS) {
|
||||
ESP_LOGE(TAG_ATECC, "ERROR: atcab_init failed with status 0x%02X", status);
|
||||
return false;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_ATECC, "ATECC608B initialized successfully");
|
||||
|
||||
// Give the device a moment to stabilize
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
// Wake the device and test communication
|
||||
status = atcab_wakeup();
|
||||
if (status != ATCA_SUCCESS) {
|
||||
ESP_LOGW(TAG_ATECC, "WARNING: Wake command returned status 0x%02X", status);
|
||||
}
|
||||
|
||||
// Put device to idle
|
||||
atcab_idle();
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Global storage for config zone data
|
||||
uint8_t g_atecc_config_data[128] = {0};
|
||||
bool g_atecc_config_valid = false;
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* Read ATECC608B configuration zone into global buffer
|
||||
* Initialise the ATECC608B over I2C.
|
||||
* Returns true on success.
|
||||
*/
|
||||
bool atecc608B_read_config() {
|
||||
ESP_LOGI(TAG_ATECC, "Reading ATECC608B configuration zone...");
|
||||
|
||||
ATCA_STATUS status = atcab_read_config_zone(g_atecc_config_data);
|
||||
|
||||
if (status != ATCA_SUCCESS) {
|
||||
ESP_LOGE(TAG_ATECC, "ERROR: Failed to read config zone, status 0x%02X",
|
||||
status);
|
||||
|
||||
// Try reading it in blocks as a workaround
|
||||
ESP_LOGI(TAG_ATECC, "Attempting to read config in 4-byte blocks...");
|
||||
bool read_success = true;
|
||||
for (uint8_t block = 0; block < 32; block++) {
|
||||
status = atcab_read_zone(ATCA_ZONE_CONFIG, 0, block, 0,
|
||||
&g_atecc_config_data[block * 4], 4);
|
||||
if (status != ATCA_SUCCESS) {
|
||||
ESP_LOGE(TAG_ATECC, "ERROR: Failed to read block %d, status 0x%02X",
|
||||
block, status);
|
||||
read_success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!read_success) {
|
||||
ESP_LOGE(TAG_ATECC, "ERROR: Could not read configuration zone");
|
||||
g_atecc_config_valid = false;
|
||||
return false;
|
||||
}
|
||||
ESP_LOGI(TAG_ATECC, "Successfully read config in blocks");
|
||||
}
|
||||
|
||||
g_atecc_config_valid = true;
|
||||
return true;
|
||||
}
|
||||
bool atecc608B_init(void);
|
||||
|
||||
/**
|
||||
* Print ATECC608B configuration zone to console with detailed subzone breakdown
|
||||
* According to ATECC608B Table 2-4
|
||||
* Read the full configuration zone and print it to the console.
|
||||
* Useful for first-time setup diagnostics.
|
||||
*/
|
||||
void atecc608B_print_config() {
|
||||
ESP_LOGI(TAG_ATECC, "\n=== ATECC608B Configuration Zone ===");
|
||||
|
||||
// First, try to read the serial number as a simple communication test
|
||||
uint8_t serial_number[9];
|
||||
ATCA_STATUS status = atcab_read_serial_number(serial_number);
|
||||
|
||||
if (status != ATCA_SUCCESS) {
|
||||
ESP_LOGE(TAG_ATECC, "ERROR: Failed to read serial number, status 0x%02X",
|
||||
status);
|
||||
ESP_LOGE(TAG_ATECC, "This might indicate a communication or wiring issue.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Read configuration zone into global buffer
|
||||
if (!atecc608B_read_config()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *config_data = g_atecc_config_data;
|
||||
|
||||
// Print complete hex dump first
|
||||
ESP_LOGI(TAG_ATECC, "\n--- Complete Configuration Zone (128 bytes) ---");
|
||||
for (int i = 0; i < 128; i++) {
|
||||
if (i % 16 == 0) {
|
||||
printf("\n0x%02X: ", i);
|
||||
}
|
||||
printf("%02X ", config_data[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// Print detailed subzone breakdown according to Table 2-4
|
||||
ESP_LOGI(TAG_ATECC, "\n--- Subzone Breakdown (Table 2-4) ---");
|
||||
|
||||
// Bytes 0-3: Serial Number[0:3]
|
||||
printf("\n[Bytes 0-3] Serial Number[0:3]: ");
|
||||
for (int i = 0; i < 4; i++)
|
||||
printf("%02X ", config_data[i]);
|
||||
printf("\n");
|
||||
|
||||
// Bytes 4-7: Revision Number
|
||||
printf("[Bytes 4-7] Revision Number: ");
|
||||
for (int i = 4; i < 8; i++)
|
||||
printf("%02X ", config_data[i]);
|
||||
printf("\n");
|
||||
|
||||
// Bytes 8-12: Serial Number[4:8]
|
||||
printf("[Bytes 8-12] Serial Number[4:8]: ");
|
||||
for (int i = 8; i < 13; i++)
|
||||
printf("%02X ", config_data[i]);
|
||||
printf("\n");
|
||||
|
||||
// Full Serial Number
|
||||
printf(" --> Complete Serial Number: ");
|
||||
for (int i = 0; i < 4; i++)
|
||||
printf("%02X", config_data[i]);
|
||||
for (int i = 8; i < 13; i++)
|
||||
printf("%02X", config_data[i]);
|
||||
printf("\n");
|
||||
|
||||
// Byte 13: Reserved
|
||||
printf("[Byte 13] Reserved: %02X\n", config_data[13]);
|
||||
|
||||
// Byte 14: I2C_Enable
|
||||
printf("[Byte 14] I2C_Enable: %02X\n", config_data[14]);
|
||||
|
||||
// Byte 15: Reserved
|
||||
printf("[Byte 15] Reserved: %02X\n", config_data[15]);
|
||||
|
||||
// Byte 16: I2C_Address
|
||||
printf("[Byte 16] I2C_Address: 0x%02X (7-bit: 0x%02X)\n", config_data[16],
|
||||
config_data[16] >> 1);
|
||||
|
||||
// Byte 17: Reserved
|
||||
printf("[Byte 17] Reserved: %02X\n", config_data[17]);
|
||||
|
||||
// Byte 18: OTPmode
|
||||
printf("[Byte 18] OTPmode: 0x%02X\n", config_data[18]);
|
||||
|
||||
// Byte 19: ChipMode
|
||||
printf("[Byte 19] ChipMode: 0x%02X ", config_data[19]);
|
||||
if (config_data[19] & 0x01)
|
||||
printf("[I2C_UserExtraAdd] ");
|
||||
if (config_data[19] & 0x02)
|
||||
printf("[TTL_Enable] ");
|
||||
if (config_data[19] & 0x04)
|
||||
printf("[Watchdog_1.3s] ");
|
||||
printf("\n");
|
||||
|
||||
// Bytes 20-51: SlotConfig[0:15] (16 slots × 2 bytes)
|
||||
printf("\n[Bytes 20-51] SlotConfig[0:15]:\n");
|
||||
for (int slot = 0; slot < 16; slot++) {
|
||||
int offset = 20 + (slot * 2);
|
||||
uint8_t slot_config_low = config_data[offset];
|
||||
uint8_t slot_config_high = config_data[offset + 1];
|
||||
uint16_t slot_config = (slot_config_high << 8) | slot_config_low;
|
||||
printf(" Slot %2d [Bytes %2d-%2d]: 0x%02X 0x%02X (", slot, offset,
|
||||
offset + 1, slot_config_low, slot_config_high);
|
||||
|
||||
// Print 16-bit binary representation
|
||||
for (int b = 15; b >= 0; b--)
|
||||
printf("%d", (slot_config >> b) & 1);
|
||||
printf(")");
|
||||
|
||||
bool is_secret = (slot_config & 0x8000) != 0;
|
||||
bool encrypt_read = (slot_config & 0x4000) != 0;
|
||||
if (is_secret)
|
||||
printf(" [Secret]");
|
||||
if (encrypt_read)
|
||||
printf(" [EncryptRead]");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Bytes 52-59: Counter[0]
|
||||
printf("\n[Bytes 52-59] Counter[0]: ");
|
||||
for (int i = 52; i < 60; i++)
|
||||
printf("%02X ", config_data[i]);
|
||||
printf("\n");
|
||||
|
||||
// Bytes 60-67: Counter[1]
|
||||
printf("[Bytes 60-67] Counter[1]: ");
|
||||
for (int i = 60; i < 68; i++)
|
||||
printf("%02X ", config_data[i]);
|
||||
printf("\n");
|
||||
|
||||
// Bytes 68-83: LastKeyUse[0:15]
|
||||
printf("\n[Bytes 68-83] LastKeyUse[0:15]: ");
|
||||
for (int i = 68; i < 84; i++)
|
||||
printf("%02X ", config_data[i]);
|
||||
printf("\n");
|
||||
|
||||
// Byte 84: UserExtra
|
||||
printf("\n[Byte 84] UserExtra: 0x%02X\n", config_data[84]);
|
||||
|
||||
// Byte 85: Selector
|
||||
printf("[Byte 85] Selector: 0x%02X\n", config_data[85]);
|
||||
|
||||
// Byte 86: LockValue (Data/OTP Zone Lock)
|
||||
printf("[Byte 86] LockValue (Data/OTP): 0x%02X %s\n", config_data[86],
|
||||
config_data[86] == 0x00 ? "[LOCKED]" : "[UNLOCKED]");
|
||||
|
||||
// Byte 87: LockConfig (Config Zone Lock)
|
||||
printf("[Byte 87] LockConfig: 0x%02X %s\n", config_data[87],
|
||||
config_data[87] == 0x00 ? "[LOCKED]" : "[UNLOCKED]");
|
||||
|
||||
// Bytes 88-89: SlotLocked
|
||||
printf("\n[Bytes 88-89] SlotLocked: %02X %02X\n", config_data[88],
|
||||
config_data[89]);
|
||||
|
||||
// Bytes 90-91: ChipOptions
|
||||
printf("[Bytes 90-91] ChipOptions: ");
|
||||
uint16_t chip_options = (config_data[91] << 8) | config_data[90];
|
||||
printf("0x%04X\n", chip_options);
|
||||
|
||||
// Bytes 92-95: X509format
|
||||
printf("[Bytes 92-95] X509format: ");
|
||||
for (int i = 92; i < 96; i++)
|
||||
printf("%02X ", config_data[i]);
|
||||
printf("\n");
|
||||
|
||||
// Bytes 96-127: KeyConfig[0:15] (16 slots × 2 bytes)
|
||||
printf("\n[Bytes 96-127] KeyConfig[0:15]:\n");
|
||||
for (int slot = 0; slot < 16; slot++) {
|
||||
int offset = 96 + (slot * 2);
|
||||
uint8_t key_config_low = config_data[offset];
|
||||
uint8_t key_config_high = config_data[offset + 1];
|
||||
uint16_t key_config = (key_config_high << 8) | key_config_low;
|
||||
printf(" Slot %2d [Bytes %2d-%2d]: 0x%02X 0x%02X (", slot, offset,
|
||||
offset + 1, key_config_low, key_config_high);
|
||||
|
||||
// Print 16-bit binary representation
|
||||
for (int b = 15; b >= 0; b--)
|
||||
printf("%d", (key_config >> b) & 1);
|
||||
printf(")");
|
||||
|
||||
bool is_private = (key_config & 0x0001) != 0;
|
||||
if (is_private)
|
||||
printf(" [Private]");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG_ATECC, "\n=== End of ATECC608B Configuration ===\n");
|
||||
}
|
||||
void atecc608B_print_config(void);
|
||||
|
||||
/**
|
||||
* Get ATECC608B configuration as JSON string (caller must free the returned
|
||||
* string)
|
||||
* Release cryptoauthlib resources.
|
||||
*/
|
||||
char *atecc608B_get_config_json() {
|
||||
if (!g_atecc_config_valid) {
|
||||
ESP_LOGE(TAG_ATECC,
|
||||
"Config data not valid. Call atecc608B_print_config() first.");
|
||||
return NULL;
|
||||
}
|
||||
void atecc608B_release(void);
|
||||
|
||||
uint8_t *config = g_atecc_config_data;
|
||||
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
|
||||
// Add raw hex data
|
||||
char hex_str[385]; // 128 bytes * 3 chars per byte + null
|
||||
char *ptr = hex_str;
|
||||
for (int i = 0; i < 128; i++) {
|
||||
ptr += sprintf(ptr, "%02X ", config[i]);
|
||||
}
|
||||
cJSON_AddStringToObject(root, "raw_hex", hex_str);
|
||||
|
||||
// Serial Number
|
||||
char serial_str[19];
|
||||
sprintf(serial_str, "%02X%02X%02X%02X%02X%02X%02X%02X%02X", config[0],
|
||||
config[1], config[2], config[3], config[8], config[9], config[10],
|
||||
config[11], config[12]);
|
||||
cJSON_AddStringToObject(root, "serial_number", serial_str);
|
||||
|
||||
// Revision
|
||||
char revision_str[12];
|
||||
sprintf(revision_str, "%02X%02X%02X%02X", config[4], config[5], config[6],
|
||||
config[7]);
|
||||
cJSON_AddStringToObject(root, "revision", revision_str);
|
||||
|
||||
// I2C settings
|
||||
cJSON_AddNumberToObject(root, "i2c_enable", config[14]);
|
||||
cJSON_AddNumberToObject(root, "i2c_address", config[16]);
|
||||
|
||||
// Mode settings
|
||||
cJSON_AddNumberToObject(root, "otp_mode", config[18]);
|
||||
cJSON_AddNumberToObject(root, "chip_mode", config[19]);
|
||||
|
||||
// Lock status
|
||||
cJSON *locks = cJSON_CreateObject();
|
||||
cJSON_AddBoolToObject(locks, "config_locked", config[87] == 0x00);
|
||||
cJSON_AddBoolToObject(locks, "data_otp_locked", config[86] == 0x00);
|
||||
cJSON_AddItemToObject(root, "locks", locks);
|
||||
|
||||
// Slot configurations
|
||||
cJSON *slots = cJSON_CreateArray();
|
||||
for (int slot = 0; slot < 16; slot++) {
|
||||
cJSON *slot_obj = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(slot_obj, "slot", slot);
|
||||
|
||||
int slot_config_offset = 20 + (slot * 2);
|
||||
uint8_t slot_config_low = config[slot_config_offset];
|
||||
uint8_t slot_config_high = config[slot_config_offset + 1];
|
||||
uint16_t slot_config = (slot_config_high << 8) | slot_config_low;
|
||||
|
||||
cJSON *slot_config_arr = cJSON_CreateArray();
|
||||
char slot_config_low_str[5];
|
||||
char slot_config_high_str[5];
|
||||
sprintf(slot_config_low_str, "0x%02X", slot_config_low);
|
||||
sprintf(slot_config_high_str, "0x%02X", slot_config_high);
|
||||
cJSON_AddItemToArray(slot_config_arr,
|
||||
cJSON_CreateString(slot_config_low_str));
|
||||
cJSON_AddItemToArray(slot_config_arr,
|
||||
cJSON_CreateString(slot_config_high_str));
|
||||
cJSON_AddItemToObject(slot_obj, "slot_config", slot_config_arr);
|
||||
|
||||
// Add 16-bit binary representation
|
||||
char slot_config_bin[18];
|
||||
for (int b = 0; b < 16; b++) {
|
||||
slot_config_bin[15 - b] = ((slot_config >> b) & 1) ? '1' : '0';
|
||||
}
|
||||
slot_config_bin[16] = '\0';
|
||||
cJSON_AddStringToObject(slot_obj, "slot_config_binary", slot_config_bin);
|
||||
|
||||
int key_config_offset = 96 + (slot * 2);
|
||||
uint8_t key_config_low = config[key_config_offset];
|
||||
uint8_t key_config_high = config[key_config_offset + 1];
|
||||
uint16_t key_config = (key_config_high << 8) | key_config_low;
|
||||
|
||||
cJSON *key_config_arr = cJSON_CreateArray();
|
||||
char key_config_low_str[5];
|
||||
char key_config_high_str[5];
|
||||
sprintf(key_config_low_str, "0x%02X", key_config_low);
|
||||
sprintf(key_config_high_str, "0x%02X", key_config_high);
|
||||
cJSON_AddItemToArray(key_config_arr,
|
||||
cJSON_CreateString(key_config_low_str));
|
||||
cJSON_AddItemToArray(key_config_arr,
|
||||
cJSON_CreateString(key_config_high_str));
|
||||
cJSON_AddItemToObject(slot_obj, "key_config", key_config_arr);
|
||||
|
||||
// Add 16-bit binary representation
|
||||
char key_config_bin[18];
|
||||
for (int b = 0; b < 16; b++) {
|
||||
key_config_bin[15 - b] = ((key_config >> b) & 1) ? '1' : '0';
|
||||
}
|
||||
key_config_bin[16] = '\0';
|
||||
cJSON_AddStringToObject(slot_obj, "key_config_binary", key_config_bin);
|
||||
|
||||
cJSON_AddBoolToObject(slot_obj, "is_secret", (slot_config & 0x8000) != 0);
|
||||
cJSON_AddBoolToObject(slot_obj, "encrypt_read",
|
||||
(slot_config & 0x4000) != 0);
|
||||
cJSON_AddBoolToObject(slot_obj, "is_private", (key_config & 0x0001) != 0);
|
||||
|
||||
cJSON_AddItemToArray(slots, slot_obj);
|
||||
}
|
||||
cJSON_AddItemToObject(root, "slots", slots);
|
||||
|
||||
// Additional fields
|
||||
cJSON_AddNumberToObject(root, "user_extra", config[84]);
|
||||
cJSON_AddNumberToObject(root, "selector", config[85]);
|
||||
|
||||
char *json_str = cJSON_Print(root);
|
||||
cJSON_Delete(root);
|
||||
|
||||
return json_str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release ATECC608B resources
|
||||
*/
|
||||
void atecc608B_release() { atcab_release(); }
|
||||
|
||||
#endif // ATECC608B_H
|
||||
#endif /* ATECC608B_H */
|
||||
|
||||
Reference in New Issue
Block a user