Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions components/vigilant_engine/include/i2c.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <stddef.h>

#include "esp_err.h"
#include "vigilant_i2c_device.h"

Expand All @@ -13,6 +15,7 @@ esp_err_t i2c_remove_device(VigilantI2CDevice *device);
esp_err_t i2c_set_reg8(VigilantI2CDevice *device, uint8_t reg, uint8_t value);
esp_err_t i2c_read_reg8(VigilantI2CDevice *device, uint8_t reg, uint8_t *value);
esp_err_t i2c_whoami_check(VigilantI2CDevice *device);
esp_err_t i2c_get_detected_devices(uint8_t *addresses, size_t max_addresses, size_t *count);
void i2c_deinit(void);

#ifdef __cplusplus
Expand Down
12 changes: 12 additions & 0 deletions components/vigilant_engine/include/vigilant.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,20 @@ typedef struct {
char ip_ap[16]; // current AP IPv4 (or "0.0.0.0")
} VigilantInfo;

typedef struct {
bool enabled;
uint8_t sda_io;
uint8_t scl_io;
uint32_t frequency_hz;
uint8_t added_device_count;
VigilantI2CDevice added_devices[8]; // fixed-size array for simplicity; adjust as needed
uint8_t detected_device_count;
uint8_t detected_devices[16]; // 7-bit addresses detected on the bus
} VigilantI2cInfo;

esp_err_t vigilant_init(VigilantConfig VgConfig);
esp_err_t vigilant_get_info(VigilantInfo *info);
esp_err_t vigilant_get_i2cinfo(VigilantI2cInfo *info);
esp_err_t vigilant_i2c_add_device(VigilantI2CDevice *device);
esp_err_t vigilant_i2c_remove_device(VigilantI2CDevice *device);
esp_err_t vigilant_i2c_set_reg8(VigilantI2CDevice *device, uint8_t reg, uint8_t value);
Expand Down
114 changes: 114 additions & 0 deletions components/vigilant_engine/src/http_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,119 @@ static const httpd_uri_t info_uri = {
.user_ctx = NULL,
};

static esp_err_t i2cinfo_get_handler(httpd_req_t *req)
{
VigilantI2cInfo info = {0};
esp_err_t err = vigilant_get_i2cinfo(&info);
if (err != ESP_OK) {
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to fetch i2c info");
return err;
}

httpd_resp_set_type(req, "application/json");
size_t payload_capacity = 256 // Calculates a size for the json object, for malloc later
+ ((size_t)info.added_device_count * 160) // Added devices contain more information in the json than detected devices.
+ ((size_t)info.detected_device_count * 96);
char *payload = malloc(payload_capacity);
if (!payload) {
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "No memory for i2c info");
return ESP_ERR_NO_MEM;
}

size_t offset = 0;
int written = snprintf(
payload + offset,
payload_capacity - offset,
"{\"enabled\":%s,\"sda_io\":%u,\"scl_io\":%u,\"frequency_hz\":%" PRIu32 ",\"added_device_count\":%u,\"detected_device_count\":%u,\"added_devices\":[",
info.enabled ? "true" : "false",
(unsigned int)info.sda_io,
(unsigned int)info.scl_io,
info.frequency_hz,
(unsigned int)info.added_device_count,
(unsigned int)info.detected_device_count
);

if (written < 0 || written >= (int)(payload_capacity - offset)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need the cast

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

payload_capacity is size_t so im not sure if it makes problems when we compare against an int

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So both ways aren't "safe" afaik haha

This is probably a discussion we should have in general anyway: how safe code has to be

free(payload);
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Info too large");
return ESP_FAIL;
}
offset += (size_t)written;

for (uint8_t i = 0; i < info.added_device_count; ++i) {
const VigilantI2CDevice *device = &info.added_devices[i];
written = snprintf(
payload + offset,
payload_capacity - offset,
"%s{\"name\":\"I2C Device 0x%02X\",\"address\":%u,\"address_hex\":\"0x%02X\",\"whoami_reg\":%u,\"whoami_reg_hex\":\"0x%02X\",\"expected_whoami\":%u,\"expected_whoami_hex\":\"0x%02X\"}",
i == 0 ? "" : ",",
(unsigned int)device->address,
(unsigned int)device->address,
(unsigned int)device->address,
(unsigned int)device->whoami_reg,
(unsigned int)device->whoami_reg,
(unsigned int)device->expected_whoami,
(unsigned int)device->expected_whoami
);

if (written < 0 || written >= (int)(payload_capacity - offset)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if cast is removed above, also remove here

free(payload);
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Info too large");
return ESP_FAIL;
}
offset += (size_t)written;
}

written = snprintf(payload + offset, payload_capacity - offset, "],\"detected_devices\":[");
if (written < 0 || written >= (int)(payload_capacity - offset)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again

free(payload);
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Info too large");
return ESP_FAIL;
}
offset += (size_t)written;

for (uint8_t i = 0; i < info.detected_device_count; ++i) {
uint8_t address = info.detected_devices[i];
written = snprintf(
payload + offset,
payload_capacity - offset,
"%s{\"name\":\"Detected I2C Device 0x%02X\",\"address\":%u,\"address_hex\":\"0x%02X\"}",
i == 0 ? "" : ",",
(unsigned int)address,
(unsigned int)address,
(unsigned int)address
);

if (written < 0 || written >= (int)(payload_capacity - offset)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again

free(payload);
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Info too large");
return ESP_FAIL;
}
offset += (size_t)written;
}

written = snprintf(payload + offset, payload_capacity - offset, "]}");
if (written < 0 || written >= (int)(payload_capacity - offset)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again

free(payload);
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Info too large");
return ESP_FAIL;
}
offset += (size_t)written;

httpd_resp_send(req, payload, (ssize_t)offset);
free(payload);
return ESP_OK;
}

static const httpd_uri_t i2cinfo_uri = {
.uri = "/i2cinfo",
.method = HTTP_GET,
.handler = i2cinfo_get_handler,
.user_ctx = NULL,
};



esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err)
{
if (strcmp("/hello", req->uri) == 0) {
Expand Down Expand Up @@ -294,6 +407,7 @@ static httpd_handle_t start_webserver_internal(void)
httpd_register_uri_handler(server, &ctrl);
httpd_register_uri_handler(server, &any);
httpd_register_uri_handler(server, &info_uri);
httpd_register_uri_handler(server, &i2cinfo_uri);
websocket_register_handlers(server);

// OTA-Handler registrieren
Expand Down
154 changes: 115 additions & 39 deletions components/vigilant_engine/src/i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,96 @@
#define I2C_TIMEOUT_MS 50

static const char *TAG = "ve_i2c";
static i2c_master_bus_handle_t s_i2c_bus = NULL;
static uint8_t s_detected_i2c_addresses[16] = {0};
static size_t s_detected_i2c_count = 0;

static esp_err_t i2c_scan_devices(uint8_t *addresses, size_t max_addresses, size_t *count, bool log_results)
{
if (!s_i2c_bus) {
return ESP_ERR_INVALID_STATE;
}
if (!count) {
return ESP_ERR_INVALID_ARG;
}

static i2c_master_bus_handle_t s_i2c_bus = NULL;
char line[128];
size_t found = 0;
size_t stored = 0;

if (log_results) {
ESP_LOGI(TAG, "I2C bus scan on SDA=%d SCL=%d", I2C_SDA_IO, I2C_SCL_IO);

strcpy(line, " ");
for (int i = 0; i < 16; i++) {
char tmp[4];
snprintf(tmp, sizeof(tmp), "%02X ", i);
strncat(line, tmp, sizeof(line) - strlen(line) - 1);
}
ESP_LOGI(TAG, "%s", line);
}

for (int high = 0; high < 8; high++) {
if (log_results) {
snprintf(line, sizeof(line), "%02X: ", high << 4);
}

for (int low = 0; low < 16; low++) {
uint8_t addr = (high << 4) | low;
char cell[4] = " ";

if (addr >= 0x03 && addr <= 0x77) {
esp_err_t err = i2c_master_probe(s_i2c_bus, addr, I2C_TIMEOUT_MS);
if (err == ESP_OK) {
if (addresses && stored < max_addresses) {
addresses[stored++] = addr;
}
found++;
if (log_results) {
snprintf(cell, sizeof(cell), "%02X ", addr);
}
} else if (log_results) {
snprintf(cell, sizeof(cell), "-- ");
}
}

if (log_results) {
strncat(line, cell, sizeof(line) - strlen(line) - 1);
}
}

if (log_results) {
ESP_LOGI(TAG, "%s", line);
}
}

if (log_results) {
ESP_LOGI(TAG, "Scan complete, found %u device(s)", (unsigned int)found);
if (stored < found) {
ESP_LOGW(TAG, "Detected device list truncated to %u entrie(s)", (unsigned int)stored);
}
}

*count = stored;
return ESP_OK;
}

static esp_err_t i2c_refresh_detected_devices(bool log_results)
{
size_t detected_count = 0;
esp_err_t err = i2c_scan_devices(
s_detected_i2c_addresses,
sizeof(s_detected_i2c_addresses) / sizeof(s_detected_i2c_addresses[0]),
&detected_count,
log_results
);
if (err != ESP_OK) {
return err;
}

s_detected_i2c_count = detected_count;
return ESP_OK;
}

esp_err_t i2c_init(void)
{
Expand Down Expand Up @@ -46,46 +133,11 @@ esp_err_t i2c_init(void)
}

ESP_LOGI(TAG, "Bus initialized successfully");
ESP_LOGI(TAG, "I2C bus scan on SDA=%d SCL=%d", I2C_SDA_IO, I2C_SCL_IO);

char line[128];
int found = 0;

strcpy(line, " ");
for (int i = 0; i < 16; i++) {
char tmp[4];
snprintf(tmp, sizeof(tmp), "%02X ", i);
strncat(line, tmp, sizeof(line) - strlen(line) - 1);
}
ESP_LOGI(TAG, "%s", line);

for (int high = 0; high < 8; high++) {
snprintf(line, sizeof(line), "%02X: ", high << 4);

for (int low = 0; low < 16; low++) {
uint8_t addr = (high << 4) | low;
char cell[4];

if (addr < 0x03 || addr > 0x77) {
snprintf(cell, sizeof(cell), " ");
} else {
err = i2c_master_probe(s_i2c_bus, addr, I2C_TIMEOUT_MS);
if (err == ESP_OK) {
snprintf(cell, sizeof(cell), "%02X ", addr);
found++;
} else {
snprintf(cell, sizeof(cell), "-- ");
}
}

strncat(line, cell, sizeof(line) - strlen(line) - 1);
}

ESP_LOGI(TAG, "%s", line);
err = i2c_refresh_detected_devices(true);
if (err != ESP_OK) {
ESP_LOGW(TAG, "Initial I2C scan failed: %s", esp_err_to_name(err));
}

ESP_LOGI(TAG, "Scan complete, found %d device(s)", found);

return ESP_OK;
}

Expand Down Expand Up @@ -193,6 +245,28 @@ esp_err_t i2c_whoami_check(VigilantI2CDevice *device)
return ESP_OK;
}

esp_err_t i2c_get_detected_devices(uint8_t *addresses, size_t max_addresses, size_t *count)
{
if (!count) {
return ESP_ERR_INVALID_ARG;
}
if (!s_i2c_bus) {
return ESP_ERR_INVALID_STATE;
}

size_t copied_count = s_detected_i2c_count;
if (copied_count > max_addresses) {
copied_count = max_addresses;
}

if (addresses && copied_count > 0) {
memcpy(addresses, s_detected_i2c_addresses, copied_count * sizeof(s_detected_i2c_addresses[0]));
}

*count = copied_count;
return ESP_OK;
}

void i2c_deinit(void)
{
if (s_i2c_bus) {
Expand All @@ -203,5 +277,7 @@ void i2c_deinit(void)
}

s_i2c_bus = NULL;
memset(s_detected_i2c_addresses, 0, sizeof(s_detected_i2c_addresses));
s_detected_i2c_count = 0;
}
}
Loading
Loading