Compare commits

...

10 Commits

28 changed files with 1125 additions and 343 deletions

View File

@@ -1,6 +1,6 @@
{
"C_Cpp.intelliSenseEngine": "default",
"idf.espIdfPath": "/home/bruno/esp/master/esp-idf",
"idf.espIdfPath": "/home/bruno/esp/v5.4.1/esp-idf",
"idf.pythonInstallPath": "/usr/bin/python",
"idf.openOcdConfigs": [
"board/esp32s3-builtin.cfg"

View File

@@ -2,7 +2,7 @@ dependencies:
idf:
source:
type: idf
version: 5.5.0
version: 5.4.1
k0i05/esp_bme680:
component_hash: 2df0cb14d4425565a8745d4a96bfaa8ff7e90bbec3e208a073821406dded23c8
dependencies:

View File

@@ -25,6 +25,8 @@ idf_component_register(SRCS
"components/servocontroller.h"
"components/radio.c"
"components/radio.h"
"components/sdcard.c"
"components/sdcard.h"
"main.c"
INCLUDE_DIRS ".")

View File

@@ -2,79 +2,107 @@
#define PACKETS_STRUCTS
#include "stdint.h"
#define UplinkSync "PlechHore"
#define DownlinkSync "PlechDole"
#define UplinkPacketType_SystemControl 0
#define UplinkPacketType_Ping 1
#define UplinkPacketType_ACK 255
#define DownlinkPacketType_Telemetry 0
#define DownlinkPacketType_Ping 1
#define DownlinkPacketType_ACK 255
typedef struct __attribute__((packed))
{
uint32_t packetIndex;
uint8_t packetType;
uint32_t missionTimer;
char syncPhrase[10]; //10
uint32_t packetIndex; //14
uint8_t packetType; //15
uint32_t missionTimer; //19
uint32_t CRCCheck;
} DownBoundPacket;
typedef struct __attribute__((packed))
{
// MPU data
int16_t accelerationX;
int16_t accelerationY;
int16_t accelerationZ;
int16_t gyroX;
int16_t gyroY;
int16_t gyroZ;
int16_t magnetX;
int16_t magnetY;
int16_t magnetZ;
int16_t accelerometer_temperature;
int16_t accelerationX;//21
int16_t accelerationY; //23
int16_t accelerationZ;//25
int16_t gyroX;//27
int16_t gyroY;//29
int16_t gyroZ;//31
int16_t magnetX;//33
int16_t magnetY;//35
int16_t magnetZ;//37
int16_t accelerometer_temperature;//39
// CCS data
uint16_t eCO2;
uint16_t tvoc;
uint8_t currentCCS;
uint16_t rawCCSData;
uint16_t eCO2;//41
uint16_t tvoc;//43
uint8_t currentCCS;//44
uint16_t rawCCSData;//46
// INA data
uint16_t volts;
uint16_t current;
uint16_t power;
uint16_t volts;//48
uint16_t current;//50
uint16_t power;//52
// BME DATA
uint32_t temperature;
uint16_t humidity;
uint32_t pressure;
uint16_t gas;
bool gas_valid;
bool heater_stable;
uint8_t gas_range;
uint8_t gas_index;
uint32_t temperature;//56
uint16_t humidity;//58
uint32_t pressure;//62
uint16_t gas;//64
bool gas_valid;//later
bool heater_stable;//later
uint8_t gas_range;//65
uint8_t gas_index;//66
float air_temperature; /*!< air temperature in degrees celsius */ //70
float relative_humidity; /*!< relative humidity in percent */ //74
float barometric_pressure; /*!< barometric pressure in hecto-pascal */ //78
float gas_resistance; /*!< gas resistance in ohms */ //82
uint16_t iaq_score; /*!< air quality index (0..500) */ //84
float temperature_score; //88
float humidity_score; //92
float gas_score; //96
// GPS DATA
uint32_t time_seconds; // Seconds since start of day
int32_t latitude_centi_degrees; // Latitude * 10,000
int32_t longitude_centi_degrees; // Longitude * 10,000
int16_t altitude_centi_meters; // Altitude * 100
uint8_t fix_quality;
uint8_t num_satellites;
uint16_t date_yyddmm; // YYDDMM (from GPRMC)
uint16_t speed_centi_knots; // Speed * 100 (from GPRMC)
uint32_t time_seconds; // Seconds since start of day //100
int32_t latitude_centi_degrees; // Latitude * 10,000 //104
int32_t longitude_centi_degrees; // Longitude * 10,000 //108
int16_t altitude_centi_meters; // Altitude * 100 //110
uint8_t fix_quality; //111
uint8_t num_satellites; //112
uint16_t date_yyddmm; // YYDDMM (from GPRMC) //114
uint16_t speed_centi_knots; // Speed * 100 (from GPRMC) //116
int32_t predicted_latitude_centi_degrees; // Latitude * 10,000
int32_t predicted_longitude_centi_degrees; // Longitude * 10,000
int16_t predicted_altitude_centi_meters; // Altitude * 100
int32_t predicted_latitude_centi_degrees; // Latitude * 10,000 //120
int32_t predicted_longitude_centi_degrees; // Longitude * 10,000 //124
int16_t predicted_altitude_centi_meters; // Altitude * 100 //126
// ADC DATA
int32_t NH3;
int32_t CO;
int32_t NO2;
int32_t UVC;
int32_t NH3; //130
int32_t CO; //134
int32_t NO2; //138
int32_t UVC; //142
int16_t currentServoA;
int16_t targetServoA;
int16_t currentServoB;
int16_t targetServoB;
int16_t currentServoA; //144
int16_t targetServoA; //146
int16_t currentServoB; //148
int16_t targetServoB; //150
uint8_t presentDevices;
uint8_t telemetryIndex; //151
} TelemetryPacket;
typedef struct __attribute__((packed))
{
char syncPhrase[10];
uint32_t packetIndex;
uint8_t packetType;
uint32_t CRCCheck;
} UplinkPacket;
typedef struct __attribute__((packed))
@@ -85,4 +113,15 @@ typedef struct __attribute__((packed))
uint16_t servoB;
} SystemControlPacket;
typedef struct __attribute__((packed))
{
uint8_t PingData[20];
} PingPacket;
typedef struct __attribute__((packed))
{
uint32_t packetIndex;
uint32_t crc32Checksum;
} ACKPacket;
#endif

View File

@@ -5,100 +5,388 @@
#include "esp_log.h"
#include "string.h"
#include "esp_timer.h"
const char *msg = "Testing 123 test why is this not on air";
#include "esp_rom_crc.h"
#include <hw/buscfg.h>
#include "sensors.h"
#include "sdcard.h"
#define TAG "LoRa"
uint32_t packetIndex = 0;
#define ACK_TIMEOUT_MS 250 // Wait 300ms for ACK
#define MAX_RETRIES 1
uint32_t packetIndexTX = 0;
uint32_t packetIndexRX = 0;
TelemetryPacket telemetryPacket;
uint8_t packetReadiness = 0;
void lora_comms_task(void *pvParameters)
volatile bool ackReceived = false;
uint32_t lastAckIndex = 0;
SemaphoreHandle_t loraRadioMutex;
void setup_lora(void)
{
const int64_t interval_us = 100000; // 100 ms
int64_t start_time, end_time, elapsed;
LoRaInit();
int8_t txPowerInDbm = 20;
uint32_t frequencyInHz = 869525000;
float tcxoVoltage = 2.2;
bool useRegulatorLDO = true;
uint32_t frequencyInHz = 0;
frequencyInHz = 869525000;
ESP_LOGW(TAG, "Enable TCXO");
float tcxoVoltage = 2.2; // use TCXO
bool useRegulatorLDO = true; // use DCDC + LDO
LoRaDebugPrint(false);
// LoRaDebugPrint(true);
if (LoRaBegin(frequencyInHz, txPowerInDbm, tcxoVoltage, useRegulatorLDO) != 0)
{
ESP_LOGE(TAG, "Does not recognize the module");
ESP_LOGE(TAG, "LoRa module not recognized. Halting.");
while (1)
{
vTaskDelay(1);
}
}
uint8_t spreadingFactor = 7;
uint8_t spreadingFactor = 8;
uint8_t bandwidth = SX126X_LORA_BW_250_0;
uint8_t codingRate = SX126X_LORA_CR_4_8;
uint16_t preambleLength = 8;
uint8_t payloadLen = 0;
uint16_t preambleLength = 4;
bool crcOn = true;
bool invertIrq = false;
LoRaConfig(spreadingFactor, bandwidth, codingRate, preambleLength, payloadLen, crcOn, invertIrq);
uint8_t bufIn[256]; // Maximum Payload size of SX1261/62/68 is 255
uint8_t bufOut[256]; // Maximum Payload size of SX1261/62/68 is 255
DownBoundPacket downboundPacket;
UplinkPacket uplinkPacket;
SystemControlPacket systemControlPacket;
LoRaConfig(spreadingFactor, bandwidth, codingRate, preambleLength, 0, crcOn, invertIrq);
}
while (1)
static void prepare_downbound_packet(DownBoundPacket *packet, uint8_t type, uint64_t missionTimer, uint32_t crc)
{
memset(packet, 0, sizeof(DownBoundPacket));
packet->missionTimer = missionTimer;
packet->packetIndex = packetIndexTX++;
ESP_LOGI(TAG_RADIO, "Sending downbound packet with index %ld", packetIndexTX - 1);
packet->packetType = type;
packet->CRCCheck = crc;
strcpy(packet->syncPhrase, "PlechDole");
}
static void send_packet_without_retries(uint8_t *data, uint16_t size)
{
if (xSemaphoreTake(loraRadioMutex, portMAX_DELAY) == pdTRUE)
{
start_time = esp_timer_get_time(); // µs since boot
if (packetReadiness == 1)
writeFile(sensFile, data, size);
if (!LoRaSend(data, size, SX126x_TXMODE_SYNC))
{
uint8_t downPacketSize = 0;
memset(bufOut, 0, sizeof(bufOut));
downboundPacket.missionTimer = start_time;
downboundPacket.packetIndex = packetIndex++;
downboundPacket.packetType = 1;
ESP_LOGW(TAG, "LoRaSend failed");
xSemaphoreGive(loraRadioMutex);
}
else
{
ESP_LOGI(TAG, "%d byte packet sent", size);
xSemaphoreGive(loraRadioMutex);
}
}
}
memcpy(bufOut, &downboundPacket, sizeof(downboundPacket));
downPacketSize += sizeof(downboundPacket);
memcpy(((uint8_t *)bufOut) + downPacketSize, &telemetryPacket, sizeof(telemetryPacket));
downPacketSize += sizeof(telemetryPacket);
ESP_LOGI(pcTaskGetName(NULL), "%d byte packet sent...", downPacketSize);
// Wait for transmission to complete
if (LoRaSend(bufOut, downPacketSize, SX126x_TXMODE_SYNC) == false)
static void send_packet_with_retries(uint8_t *data, uint16_t size)
{
if (xSemaphoreTake(loraRadioMutex, portMAX_DELAY) == pdTRUE)
{
writeFile(sensFile, data, size);
for (int retry = 0; retry <= MAX_RETRIES; retry++)
{
if (!LoRaSend(data, size, SX126x_TXMODE_SYNC))
{
ESP_LOGE(pcTaskGetName(NULL), "LoRaSend fail");
} else {
packetReadiness = 0;
ESP_LOGW(TAG, "LoRaSend failed, retry %d", retry);
xSemaphoreGive(loraRadioMutex);
}
else
{
ESP_LOGI(TAG, "%d byte packet sent (attempt %d)", size, retry + 1);
xSemaphoreGive(loraRadioMutex);
// Wait for ACK
ackReceived = false;
uint64_t start_wait = esp_timer_get_time();
while ((esp_timer_get_time() - start_wait) < (ACK_TIMEOUT_MS * 1000))
{
if (ackReceived)
{
ESP_LOGI(TAG, "ACK received for packet.");
return;
}
vTaskDelay(pdMS_TO_TICKS(10));
}
ESP_LOGW(TAG, "ACK timeout, retrying...");
}
}
}
uint8_t rxLen = LoRaReceive(bufIn, sizeof(bufIn));
if (rxLen > 0)
{
ESP_LOGI(pcTaskGetName(NULL), "%d byte packet received:[%.*s]", rxLen, rxLen, bufIn);
ESP_LOGE(TAG, "Failed to send packet after %d retries", MAX_RETRIES);
}
int8_t rssi, snr;
GetPacketStatus(&rssi, &snr);
ESP_LOGI(pcTaskGetName(NULL), "rssi=%d[dBm] snr=%d[dB]", rssi, snr);
void prepare_and_send_telemetry(uint64_t missionTimer)
{
uint8_t bufOut[256] = {0};
DownBoundPacket downboundPacket;
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)&telemetryPacket, sizeof(telemetryPacket));
prepare_downbound_packet(&downboundPacket, DownlinkPacketType_Telemetry, missionTimer, crc);
uint16_t offset = 0;
memcpy(bufOut + offset, &downboundPacket, sizeof(downboundPacket));
offset += sizeof(downboundPacket);
memcpy(bufOut + offset, &telemetryPacket, sizeof(telemetryPacket));
offset += sizeof(telemetryPacket);
if (csvFile != NULL) {
fprintf(csvFile,
"%llu,%lu,%u,%u," // missionTimer, packetIndex, telemetryIndex, packetType
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d," // MPU
"%u,%u,%d,%u," // CCS
"%u,%u,%u,%lu,%u,%lu,%u," // INA, BME basic
"%s,%s,%u,%u," // bools and gas index/range
"%.2f,%.2f,%.2f,%.2f," // Bosch env data
"%u,%.2f,%.2f,%.2f," // IAQ + scores
"%lu,%ld,%ld,%d,%u,%u,%u,%u," // GPS data
"%ld,%ld,%d," // Predicted GPS
"%ld,%ld,%ld,%ld," // ADC
"%d,%d,%d,%d," // Servo
"%u\n", // presentDevices
missionTimer,
downboundPacket.packetIndex,
telemetryPacket.telemetryIndex,
downboundPacket.packetType,
telemetryPacket.accelerationX, telemetryPacket.accelerationY, telemetryPacket.accelerationZ,
telemetryPacket.gyroX, telemetryPacket.gyroY, telemetryPacket.gyroZ,
telemetryPacket.magnetX, telemetryPacket.magnetY, telemetryPacket.magnetZ,
telemetryPacket.accelerometer_temperature,
telemetryPacket.eCO2, telemetryPacket.tvoc, telemetryPacket.currentCCS, telemetryPacket.rawCCSData,
telemetryPacket.volts, telemetryPacket.current, telemetryPacket.power,
telemetryPacket.temperature, telemetryPacket.humidity, telemetryPacket.pressure, telemetryPacket.gas,
telemetryPacket.gas_valid ? "Yes" : "No",
telemetryPacket.heater_stable ? "Yes" : "No",
telemetryPacket.gas_range, telemetryPacket.gas_index,
telemetryPacket.air_temperature, telemetryPacket.relative_humidity,
telemetryPacket.barometric_pressure, telemetryPacket.gas_resistance,
telemetryPacket.iaq_score,
telemetryPacket.temperature_score, telemetryPacket.humidity_score, telemetryPacket.gas_score,
telemetryPacket.time_seconds,
telemetryPacket.latitude_centi_degrees,
telemetryPacket.longitude_centi_degrees,
telemetryPacket.altitude_centi_meters,
telemetryPacket.fix_quality,
telemetryPacket.num_satellites,
telemetryPacket.date_yyddmm,
telemetryPacket.speed_centi_knots,
telemetryPacket.predicted_latitude_centi_degrees,
telemetryPacket.predicted_longitude_centi_degrees,
telemetryPacket.predicted_altitude_centi_meters,
telemetryPacket.NH3, telemetryPacket.CO, telemetryPacket.NO2, telemetryPacket.UVC,
telemetryPacket.currentServoA, telemetryPacket.targetServoA,
telemetryPacket.currentServoB, telemetryPacket.targetServoB,
telemetryPacket.presentDevices);
fflush(csvFile);
fsync(fileno(csvFile)); // Critical: this ensures actual write to disk
}
int lost = GetPacketLost();
if (lost != 0)
printf("Sending %d byte packet hehe\n", offset);
send_packet_without_retries(bufOut, offset);
packetReadiness = 0;
}
static void build_and_send_ack(uint32_t ackIndex, uint32_t crc32Checksum, uint64_t missionTimer)
{
uint8_t bufOut[256] = {0};
ACKPacket ackPacket = {
.packetIndex = ackIndex,
.crc32Checksum = crc32Checksum,
};
uint32_t crc = esp_rom_crc32_le(0, (uint8_t *)&ackPacket, sizeof(ackPacket));
DownBoundPacket downboundPacket;
prepare_downbound_packet(&downboundPacket, DownlinkPacketType_ACK, missionTimer, crc);
uint16_t offset = 0;
memcpy(bufOut + offset, &downboundPacket, sizeof(downboundPacket));
offset += sizeof(downboundPacket);
memcpy(bufOut + offset, &ackPacket, sizeof(ackPacket));
offset += sizeof(ackPacket);
if (xSemaphoreTake(loraRadioMutex, portMAX_DELAY) == pdTRUE)
{
if (!LoRaSend(bufOut, offset, SX126x_TXMODE_SYNC))
{
ESP_LOGW(pcTaskGetName(NULL), "%d packets lost", lost);
ESP_LOGE(TAG, "Failed to send ACK");
}
else
{
ESP_LOGI(TAG, "%d byte ACK sent", offset);
}
xSemaphoreGive(loraRadioMutex);
}
}
void process_uplink_packet(uint8_t *data, uint8_t len, uint64_t missionTimer)
{
if (len < sizeof(UplinkPacket))
{
ESP_LOGW(TAG, "Uplink packet too small: %d bytes", len);
return;
}
UplinkPacket uplinkPacket;
memcpy(&uplinkPacket, data, sizeof(UplinkPacket));
if (strcmp(UplinkSync, uplinkPacket.syncPhrase) != 0)
{
ESP_LOGW(TAG, "Invalid sync phrase");
return;
}
ESP_LOGI(TAG, "Got uplink packet of type %d, index %ld", uplinkPacket.packetType, uplinkPacket.packetIndex);
uint8_t *payload = data + sizeof(UplinkPacket);
uint8_t payloadRXLen = len - sizeof(UplinkPacket);
uint32_t crc = esp_rom_crc32_le(0, payload, payloadRXLen);
if (crc != uplinkPacket.CRCCheck)
{
ESP_LOGE(TAG, "Received BAD CRC for packet %ld, crc is %ld, should be %ld", uplinkPacket.packetIndex, crc, uplinkPacket.CRCCheck);
return;
}
if (uplinkPacket.packetType == UplinkPacketType_ACK)
{
ESP_LOGI(TAG, "Received ACK for packet %ld", uplinkPacket.packetIndex);
ackReceived = true;
lastAckIndex = uplinkPacket.packetIndex;
return;
}
if (uplinkPacket.packetIndex == packetIndexRX + 1)
{
ESP_LOGI(TAG, "Packet arrived in correct order");
packetIndexRX = uplinkPacket.packetIndex;
uint32_t crc = esp_rom_crc32_le(0, data + sizeof(UplinkPacket), payloadRXLen);
build_and_send_ack(packetIndexRX, crc, missionTimer);
switch (uplinkPacket.packetType)
{
case UplinkPacketType_SystemControl:
if (payloadRXLen == sizeof(SystemControlPacket))
{
SystemControlPacket sysCtrl;
memcpy(&sysCtrl, data + sizeof(UplinkPacket), sizeof(SystemControlPacket));
setPowerMode(sysCtrl.powerMode);
// TODO: Process sysCtrl
}
else
{
ESP_LOGW(TAG, "SystemControlPacket size mismatch");
}
break;
case UplinkPacketType_Ping:
// TODO: handle Ping
break;
default:
ESP_LOGW(TAG, "Unknown uplink packet type %d", uplinkPacket.packetType);
break;
}
}
else if (uplinkPacket.packetIndex > packetIndexRX + 1)
{
ESP_LOGW(TAG, "Skipped %ld packets", uplinkPacket.packetIndex - (packetIndexRX + 1));
packetIndexRX = uplinkPacket.packetIndex;
}
else
{
ESP_LOGW(TAG, "Duplicate packet: %ld", (packetIndexRX + 1) - uplinkPacket.packetIndex);
}
}
void lora_receive_task(void *pvParameters)
{
ESP_LOGI(TAG, "lora_receive_task started");
uint8_t bufIn[256];
while (1)
{
// Wait to take the semaphore before accessing LoRa
if (xSemaphoreTake(loraRadioMutex, 0) == pdTRUE)
{
uint8_t rxLen = LoRaReceive(bufIn, sizeof(bufIn));
if (rxLen > 0)
{
ESP_LOGI(TAG, "%d byte packet received", rxLen);
process_uplink_packet(bufIn, rxLen, esp_timer_get_time());
int8_t rssi, snr;
GetPacketStatus(&rssi, &snr);
ESP_LOGI(TAG, "rssi=%d[dBm], snr=%d[dB]", rssi, snr);
}
// Release the semaphore when done with LoRa RX
xSemaphoreGive(loraRadioMutex);
}
vTaskDelay(pdMS_TO_TICKS(10)); // Delay to prevent busy-waiting
}
}
void lora_comms_task(void *pvParameters)
{
// while (foundDevices[0] != 2) {
// vTaskDelay(10);
// }
// Initialize the semaphore for radio access (binary semaphore, 1 = available)
loraRadioMutex = xSemaphoreCreateMutex();
xSemaphoreGive(loraRadioMutex); // Set semaphore as available
ESP_LOGI(TAG, "lora_comms_task started");
setup_lora();
ESP_LOGI(TAG, "lora_comms_task continuing");
xTaskCreate(
lora_receive_task,
"LoraReceiveTask",
8192,
NULL,
(tskIDLE_PRIORITY + 2),
NULL);
ESP_LOGI(TAG, "loraInit");
while (1)
{
int64_t start_time = esp_timer_get_time();
if (packetReadiness)
{
ESP_LOGI(TAG, "Preparing telemetry");
prepare_and_send_telemetry(start_time);
}
end_time = esp_timer_get_time();
elapsed = end_time - start_time;
const int64_t interval_us = ((powerMode == HIGH_POWER_MODE) ? 10000 : 10000000); // 10 ms or 10 000 ms
int64_t end_time = esp_timer_get_time();
int64_t elapsed = end_time - start_time;
if (elapsed < interval_us)
{

View File

@@ -12,8 +12,10 @@
#include "packets.h"
void lora_comms_task(void *pvParameters);
void lora_receive_task(void *pvParameters);
extern TelemetryPacket telemetryPacket;
extern uint8_t packetReadiness;
extern SemaphoreHandle_t loraRadioMutex;
#endif

128
main/components/sdcard.c Normal file
View File

@@ -0,0 +1,128 @@
#include "sdcard.h"
void writeFile(FILE *f, const void *data, size_t size)
{
if (f != NULL)
{
fwrite(data, size, 1, f);
fflush(f);
fsync(fileno(f)); // Critical: this ensures actual write to disk
}
}
FILE *csvFile = NULL;
FILE *sensFile = NULL;
void initSD(void)
{
esp_err_t ret;
// Options for mounting the filesystem.
// If format_if_mount_failed is set to true, SD card will be partitioned and
// formatted in case when mounting fails.
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = true,
.max_files = 100,
.allocation_unit_size = 16 * 1024};
sdmmc_card_t *card;
const char mount_point[] = MOUNT_POINT;
ESP_LOGI(TAGSD, "Initializing SD card");
// Use settings defined above to initialize SD card and mount FAT filesystem.
// Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions.
// Please check its source code and implement error recovery when developing
// production applications.
ESP_LOGI(TAGSD, "Using SPI peripheral");
// By default, SD card frequency is initialized to SDMMC_FREQ_DEFAULT (20MHz)
// For setting a specific frequency, use host.max_freq_khz (range 400kHz - 20MHz for SDSPI)
// Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000;
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
host.slot = SPI3_HOST;
// This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
slot_config.gpio_cs = HSPI_SD_CS;
slot_config.host_id = host.slot;
ESP_LOGI(TAGSD, "Mounting filesystem");
ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK)
{
if (ret == ESP_FAIL)
{
ESP_LOGE(TAGSD, "Failed to mount filesystem. "
"If you want the card to be formatted, set the CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
}
else
{
ESP_LOGE(TAGSD, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors in place.",
esp_err_to_name(ret));
}
return;
}
ESP_LOGI(TAGSD, "Filesystem mounted");
// Card has been initialized, print its properties
sdmmc_card_print_info(stdout, card);
int index = 0;
FILE *f = fopen(COUNTER_FILE, "r");
if (f)
{
fscanf(f, "%d", &index);
fclose(f);
}
// === 2. Increment and write back ===
f = fopen(COUNTER_FILE, "w");
if (!f)
{
ESP_LOGE(TAGSD, "Failed to open counter file");
return;
}
index++;
if (f != NULL)
{
fprintf(f, "%d", index);
fflush(f);
fsync(fileno(f)); // Critical: this ensures actual write to disk
fclose(f);
ESP_LOGI(TAGSD, "Index is now %d", index);
}
// === 3. Make folder ===
char folder_path[MAX_PATH - 20];
snprintf(folder_path, MAX_PATH, MOUNT_POINT "/%d", index);
mkdir(folder_path, 0777); // safe if exists already
// === 4. Create CSV and BIN ===
char csv_path[MAX_PATH], bin_path[MAX_PATH];
snprintf(csv_path, MAX_PATH, "%s/data.csv", folder_path);
snprintf(bin_path, MAX_PATH, "%s/data.bin", folder_path);
csvFile = fopen(csv_path, "w");
sensFile = fopen(bin_path, "wb");
if (csvFile != NULL)
{
fprintf(csvFile,
"missionTimer,packetIndex,telemetryIndex,packetType,"
"accX,accY,accZ,gyroX,gyroY,gyroZ,magX,magY,magZ,accTemp,"
"eCO2,tVOC,currentCCS,rawCCS,"
"volts,current,power,rawtemperature,rawhumidity,rawpressure,rawgas,"
"gasValid,heaterStable,gasRange,gasIndex,"
"airTemp,relHumidity,baroPressure,gasResistance,"
"iaqScore,tempScore,humidityScore,gasScore,"
"gpsTime,latitude,longitude,altitude,fixQuality,numSatellites,date,speed,"
"predLatitude,predLongitude,predAltitude,"
"NH3,CO,NO2,UVC,"
"currentServoA,targetServoA,currentServoB,targetServoB,"
"presentDevices\n");
fflush(csvFile);
fsync(fileno(csvFile)); // Critical: this ensures actual write to disk
}
}

26
main/components/sdcard.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef SDCARD_COMPONENT
#define SDCARD_COMPONENT
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#include "../hw/buscfg.h"
#define TAGSD "SDSubsys"
#define COUNTER_FILE "cnt.txt"
#define MOUNT_POINT "/sdcard"
void writeFile(FILE *f, const void *data, size_t size);
extern FILE *csvFile;
extern FILE *sensFile;
#define MAX_PATH 80
void initSD(void);
#endif

View File

@@ -4,31 +4,166 @@
#include "../hw/gps.h"
#include "servocontroller.h"
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#define MOUNT_POINT "/sdcard"
#define MAX_LINE_LENGTH 64
#define BLINK_GPIO 2
// uint8_t powerMode = LOW_POWER_MODE;
uint8_t powerMode = HIGH_POWER_MODE;
static uint8_t s_led_state = 0;
uint8_t telemetryIndex = 1;
const uint8_t expectedAdressesCount = 5;
const uint8_t expectedAdresses[] = {MCP23018_ADDRESS, BME680_ADDRESS, CCS811_ADDRESS, MPU9250_ADDRESS, INA260_ADDRESS};
uint8_t foundDevices[5];
uint8_t prevDevices[5];
static void configure_led(void)
{
gpio_reset_pin(BLINK_GPIO);
gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
}
void update_devices()
{
memcpy(prevDevices, foundDevices, sizeof(prevDevices));
for (uint8_t i = 0; i < expectedAdressesCount; i++)
{
fflush(stdout);
esp_err_t ret = i2c_master_probe(i2c0_bus_hdl, expectedAdresses[i], 20);
if (ret == ESP_OK)
{
if (foundDevices[i] == 0)
{
foundDevices[i] = 1;
}
// printf("Found device at 0x%02X\n", i);
}
else
{
foundDevices[i] = 0;
if (i == 1 && powerMode != HIGH_POWER_MODE)
{
continue;
}
printf("Not found device at 0x%02X\n", expectedAdresses[i]);
}
}
}
void setPowerMode(uint8_t powerModeIn)
{
powerMode = powerModeIn;
if (foundDevices[0] == 2)
{
if (powerMode == HIGH_POWER_MODE)
{
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_CCS811_WAKE, 0);
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_CCS811_POWER, 1);
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_MICS_POWER, 1);
}
else
{
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_CCS811_WAKE, 1);
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_CCS811_POWER, 0);
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_MICS_POWER, 0);
}
}
}
void init_connected()
{
for (uint8_t i = 0; i < expectedAdressesCount; i++)
{
if (foundDevices[i] != prevDevices[i])
{
if (foundDevices[i])
{
esp_err_t ret = ESP_FAIL;
bool foundUsed = true;
switch (i)
{
case MCP23018_ADDRESS:
/* code */
ret = mcp23018_init();
setPowerMode(powerMode);
mcp3550_spi_init();
break;
case INA260_ADDRESS:
ret = ina260_init();
/* code */
break;
case CCS811_ADDRESS:
ret = ccs811_init();
/* code */
break;
case MPU9250_ADDRESS:
ret = mpu9250_init();
/* code */
break;
case BME680_ADDRESS:
ret = bme680b_init();
/* code */
break;
default:
foundUsed = false;
break;
}
if (foundUsed)
{
if (ret == ESP_OK)
{
foundDevices[i] = 2;
}
else
{
printf("Device init error at 0x%02X - %s\n", expectedAdresses[i], esp_err_to_name(ret));
}
}
}
}
}
}
void i2c_sensors_task(void *pvParameters)
{
memset(foundDevices, 0, sizeof(foundDevices));
memset(prevDevices, 0, sizeof(prevDevices));
bme680b_init();
mpu9250_init();
ccs811_init();
ina260_init();
// update_devices();
// init_connected();
// initialize the xLastWakeTime variable with the current time.
const int64_t interval_us = 100000; // 100 ms
const int64_t interval_us = 50000; // 50 ms
int64_t start_time, end_time, elapsed;
//
// initialize i2c device configuration
bme680b_init();
mpu9250_init();
ina260_init();
ccs811_init();
mcp3550_spi_init();
configure_led();
int16_t accel[3], gyro[3], temp, magnet[3];
@@ -44,14 +179,22 @@ void i2c_sensors_task(void *pvParameters)
uint16_t power;
bme680_data_t bmeData;
mics_adc_data_t ADCData;
// task loop entry point
for (;;)
{
packetReadiness = 2;
start_time = esp_timer_get_time(); // µs since boot
uint8_t presentDevices = 0xFF;
// update_devices();
// init_connected();
//
// handle sensor
presentDevices |= BME680_PRESENT_BIT;
if (BME680_DEV_HANDLE)
{
esp_err_t result = bme680_get_data(BME680_DEV_HANDLE, &bmeData);
@@ -76,10 +219,12 @@ void i2c_sensors_task(void *pvParameters)
bme680b_init();
}
presentDevices |= CCS811_PRESENT_BIT;
ccs811_get_data(&eCO2, &tvoc, &currentCCS, &rawData);
ESP_LOGI(TAG_CCS, "eCO₂: %d ppm, TVOC: %d ppb", eCO2, tvoc);
ESP_LOGI(TAG_CCS, "Current: %d μA, Raw voltage: %d V", currentCCS, rawData);
presentDevices |= MPU9250_PRESENT_BIT;
if (mpu9250_read_sensor_data(MPU9250_DEV_HANDLE, accel, gyro, &temp, magnet) == ESP_OK)
{
mpu9250_convert_data(accel, gyro, temp, magnet, accel_f, gyro_f, &temp_f, magnet_f);
@@ -94,29 +239,18 @@ void i2c_sensors_task(void *pvParameters)
ESP_LOGE(TAG_MPU, "Failed to read sensor data");
}
presentDevices |= INA260_PRESENT_BIT;
ina260_readParams(&volts, &current, &power);
ina260_printParams(volts, current, power);
float VREFVoltage = volts * 1.25 / 1000; // Mame vobec nieco na VREFE? Na scheme su len medzi sebou prepojene
mics_adc_data_t ADCData = mcp3550_read_all(5.0); // vref = 5.0V
log_mics_adc_values(&ADCData);
presentDevices |= MCP23018_PRESENT_BIT;
float VREFVoltage = 2.5;
ADCData = mcp3550_read_all(VREFVoltage);
log_mics_adc_values(&ADCData);
gpio_set_level(BLINK_GPIO, s_led_state);
/* Toggle the LED state */
s_led_state = !s_led_state;
end_time = esp_timer_get_time();
elapsed = end_time - start_time;
if (elapsed < interval_us)
if (packetReadiness == 0)
{
vTaskDelay(pdMS_TO_TICKS((interval_us - elapsed) / 1000));
}
if (packetReadiness == 0) {
memset(&telemetryPacket, 0, sizeof(telemetryPacket));
telemetryPacket.accelerationX = accel[0];
telemetryPacket.accelerationY = accel[1];
@@ -141,7 +275,6 @@ void i2c_sensors_task(void *pvParameters)
telemetryPacket.current = current;
telemetryPacket.power = power;
telemetryPacket.temperature = bmeData.raw_data.temperature;
telemetryPacket.humidity = bmeData.raw_data.humidity;
telemetryPacket.pressure = bmeData.raw_data.pressure;
@@ -149,13 +282,22 @@ void i2c_sensors_task(void *pvParameters)
telemetryPacket.gas_range = bmeData.raw_data.gas_range;
telemetryPacket.heater_stable = bmeData.raw_data.heater_stable;
telemetryPacket.gas_valid = bmeData.raw_data.gas_valid;
telemetryPacket.air_temperature = bmeData.air_temperature;
telemetryPacket.relative_humidity = bmeData.relative_humidity;
telemetryPacket.barometric_pressure = bmeData.barometric_pressure;
telemetryPacket.gas_resistance = bmeData.gas_resistance;
telemetryPacket.iaq_score = bmeData.iaq_score;
telemetryPacket.temperature_score = bmeData.temperature_score;
telemetryPacket.humidity_score = bmeData.humidity_score;
telemetryPacket.gas_score = bmeData.gas_score;
telemetryPacket.NH3 = ADCData.raw_nh3;
telemetryPacket.CO = ADCData.raw_co;
telemetryPacket.NO2 = ADCData.raw_no2;
telemetryPacket.UVC = ADCData.raw_uvc;
//TODO MOVE THIS TO A BETTER PLACE FOR SYNC
// TODO MOVE THIS TO A BETTER PLACE FOR SYNC
telemetryPacket.time_seconds = gpsDataOut.time_seconds;
telemetryPacket.latitude_centi_degrees = gpsDataOut.latitude_centi_degrees;
telemetryPacket.longitude_centi_degrees = gpsDataOut.longitude_centi_degrees;
@@ -174,9 +316,20 @@ void i2c_sensors_task(void *pvParameters)
telemetryPacket.currentServoA = servoState.currentServoA;
telemetryPacket.currentServoB = servoState.currentServoB;
telemetryPacket.presentDevices = presentDevices;
telemetryPacket.telemetryIndex = telemetryIndex++;
}
packetReadiness = 1;
s_led_state = !s_led_state;
end_time = esp_timer_get_time();
elapsed = end_time - start_time;
if (elapsed < interval_us)
{
vTaskDelay(pdMS_TO_TICKS((interval_us - elapsed) / 1000));
}
}
//
// free resources

View File

@@ -18,8 +18,18 @@
#include "../hw/mpu9250.h"
#include "esp_log.h"
#define LOW_POWER_MODE 0
#define HIGH_POWER_MODE 1
extern uint8_t powerMode;
extern uint8_t foundDevices[5];
extern uint8_t prevDevices[5];
void init_connected();
void update_devices();
void setPowerMode(uint8_t powerModeIn);
void i2c_sensors_task(void *pvParameters);
#endif

View File

@@ -38,14 +38,15 @@ void bme680_print_registers(bme680_handle_t handle)
ESP_LOGI(TAG_BME, "Control Gas 1 (0x%02x): %s", ctrl_gas1_reg.reg, uint8_to_binary(ctrl_gas1_reg.reg));
}
void bme680b_init() {
esp_err_t bme680b_init() {
// init device
bme680_init(i2c0_bus_hdl, &BME680_DEV_CFG, &BME680_DEV_HANDLE);
esp_err_t ret = bme680_init(i2c0_bus_hdl, &BME680_DEV_CFG, &BME680_DEV_HANDLE);
if (BME680_DEV_HANDLE == NULL)
{
ESP_LOGE(TAG_BME, "bme680 handle init failed");
} else {
bme680_print_registers(BME680_DEV_HANDLE);
}
return ret;
}

View File

@@ -8,6 +8,6 @@ extern bme680_config_t BME680_DEV_CFG;
extern bme680_handle_t BME680_DEV_HANDLE;
void bme680_print_registers(bme680_handle_t handle);
void bme680b_init();
esp_err_t bme680b_init();
#endif

View File

@@ -8,6 +8,18 @@
#define ESP_RXD0 GPIO_NUM_44
#define ESP_TXD0 GPIO_NUM_43
#define BME680_ADDRESS 0x76
#define CCS811_ADDRESS 0x5A
#define MPU9250_ADDRESS 0x68
#define INA260_ADDRESS 0x40
#define MCP23018_ADDRESS 0x20
#define BME680_PRESENT_BIT (1 << 0)
#define CCS811_PRESENT_BIT (1 << 1)
#define MPU9250_PRESENT_BIT (1 << 2)
#define INA260_PRESENT_BIT (1 << 3)
#define MCP23018_PRESENT_BIT (1 << 4)
#define ESP_CONNECTOR_P1 MCP3550_MISO_GPIO
#define ESP_CONNECTOR_P2 MCP3550_MOSI_GPIO
#define ESP_CONNECTOR_P3 MCP3550_SCK_GPIO
@@ -42,8 +54,6 @@
#define HSPI_MISO_GPIO GPIO_NUM_13
#define HSPI_MOSI_GPIO GPIO_NUM_11
//#define HSPI_MISO_GPIO GPIO_NUM_11
//#define HSPI_MOSI_GPIO GPIO_NUM_13
#define HSPI_SCK_GPIO GPIO_NUM_12
#define HSPI_LORA_CS GPIO_NUM_48

View File

@@ -1,16 +1,14 @@
#include "ccs811.h"
#define CONFIG_FREERTOS_HZ 100
i2c_device_config_t CCS811_DEV_CFG = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = 0x5A,
.device_address = CCS811_ADDRESS,
.scl_speed_hz = 100000,
};
i2c_master_dev_handle_t CCS811_DEV_HANDLE;
void ccs811_getStatus()
esp_err_t ccs811_getStatus()
{
uint8_t errorID;
uint8_t status;
@@ -18,29 +16,38 @@ void ccs811_getStatus()
uint16_t version;
uint16_t bootVersion;
i2c_read_register_8(CCS811_DEV_HANDLE, CCS811_REG_STATUS, &status);
i2c_read_register_16(CCS811_DEV_HANDLE, CCS811_REG_FW_APP_VERSION, &version);
i2c_read_register_16(CCS811_DEV_HANDLE, CCS811_REG_FW_BOOT_VERSION, &bootVersion);
i2c_read_register_8(CCS811_DEV_HANDLE, CCS811_REG_HW_VERSION, &hardwareVersion);
i2c_read_register_8(CCS811_DEV_HANDLE, CCS811_REG_ERROR_ID, &errorID);
esp_err_t ret = i2c_read_register_8(CCS811_DEV_HANDLE, CCS811_REG_STATUS, &status);
if (ret != ESP_OK) {return ret;}
ret = i2c_read_register_16(CCS811_DEV_HANDLE, CCS811_REG_FW_APP_VERSION, &version);
if (ret != ESP_OK) {return ret;}
ret = i2c_read_register_16(CCS811_DEV_HANDLE, CCS811_REG_FW_BOOT_VERSION, &bootVersion);
if (ret != ESP_OK) {return ret;}
ret = i2c_read_register_8(CCS811_DEV_HANDLE, CCS811_REG_HW_VERSION, &hardwareVersion);
if (ret != ESP_OK) {return ret;}
ret = i2c_read_register_8(CCS811_DEV_HANDLE, CCS811_REG_ERROR_ID, &errorID);
ESP_LOGW(TAG_CCS, "CCS811 status: %d, version: %d, boot version: %d, hardware version: %d, error ID: %d", status, version, bootVersion, hardwareVersion, errorID);
return ret;
}
void ccs811_init()
esp_err_t ccs811_init()
{
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c0_bus_hdl, &CCS811_DEV_CFG, &CCS811_DEV_HANDLE));
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_CCS811_WAKE, 0);
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_CCS811_POWER, 1);
esp_err_t ret =i2c_master_bus_add_device(i2c0_bus_hdl, &CCS811_DEV_CFG, &CCS811_DEV_HANDLE);
if (ret != ESP_OK) {return ret;}
vTaskDelay(10 / portTICK_PERIOD_MS);
uint8_t reset_seq[4] = {0x11, 0xE5, 0x72, 0x8A};
i2c_write_register(CCS811_DEV_HANDLE, CCS811_REG_SW_RESET, reset_seq, sizeof(reset_seq)); // Reset
ret = i2c_write_register(CCS811_DEV_HANDLE, CCS811_REG_SW_RESET, reset_seq, sizeof(reset_seq)); // Reset
if (ret != ESP_OK) {return ret;}
vTaskDelay(10 / portTICK_PERIOD_MS);
ccs811_getStatus();
i2c_write_register(CCS811_DEV_HANDLE, CCS811_REG_APP_START, NULL, 0); // start
ret = ccs811_getStatus();
if (ret != ESP_OK) {return ret;}
ret = i2c_write_register(CCS811_DEV_HANDLE, CCS811_REG_APP_START, NULL, 0); // start
if (ret != ESP_OK) {return ret;}
vTaskDelay(10 / portTICK_PERIOD_MS);
i2c_write_register_8(CCS811_DEV_HANDLE, CCS811_REG_MEAS_MODE, 0x40); // MODE 1 interrupts vypnuté
ccs811_getStatus();
ret = i2c_write_register_8(CCS811_DEV_HANDLE, CCS811_REG_MEAS_MODE, 0x40); // MODE 1 interrupts vypnuté
if (ret != ESP_OK) {return ret;}
ret = ccs811_getStatus();
return ret;
}
esp_err_t ccs811_get_data(uint16_t *eCO2, uint16_t *tvoc, uint8_t *current, uint16_t *rawData)
{

View File

@@ -37,7 +37,7 @@ extern i2c_device_config_t CCS811_DEV_CFG;
extern i2c_master_dev_handle_t CCS811_DEV_HANDLE;
void ccs811_init();
esp_err_t ccs811_init();
esp_err_t ccs811_get_data(uint16_t *eCO2, uint16_t *tvoc, uint8_t *current, uint16_t *rawData);
esp_err_t ccs811_set_env_data(float temperature, float humidity);
#endif

View File

@@ -26,11 +26,11 @@ void gps_init()
.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
.rx_flow_ctrl_thresh = 122,
};
ESP_ERROR_CHECK(uart_param_config(GPS_UART_NUM, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(GPS_UART_NUM, GPS_TXD, GPS_RXD, GPS_RTS, GPS_CTS));
ESP_ERROR_CHECK_WITHOUT_ABORT(uart_param_config(GPS_UART_NUM, &uart_config));
ESP_ERROR_CHECK_WITHOUT_ABORT(uart_set_pin(GPS_UART_NUM, GPS_TXD, GPS_RXD, GPS_RTS, GPS_CTS));
const int uart_buffer_size = (1024 * 2);
ESP_ERROR_CHECK(uart_driver_install(GPS_UART_NUM, uart_buffer_size, uart_buffer_size, 10, &uart_queue, 0));
ESP_ERROR_CHECK_WITHOUT_ABORT(uart_driver_install(GPS_UART_NUM, uart_buffer_size, uart_buffer_size, 10, &uart_queue, 0));
}
@@ -49,9 +49,9 @@ void gps_task(void *arg)
line[line_pos] = '\0';
if (line[0] == '$') {
ESP_LOGV(TAG, "Received NMEA: %s", line);
ESP_LOGI(TAG, "Received NMEA: %s", line);
if (strstr(line, "$GPGGA") == line) {
if (strstr(line, "$GNGGA") == line) {
parse_gpgga(line);
parse_gpgga_to_struct(line, &gpsDataOut);
} else if (strstr(line, "$GPRMC") == line) {
@@ -72,8 +72,7 @@ void gps_task(void *arg)
}
}
void parse_gpgga(const char *nmea)
{
void parse_gpgga(const char *nmea) {
char *fields[15];
char temp[GPS_LINE_MAX_LEN];
strncpy(temp, nmea, GPS_LINE_MAX_LEN);
@@ -108,12 +107,11 @@ void parse_gpgga(const char *nmea)
// Altitude
const char *altitude = fields[9];
ESP_LOGI(TAG, "[GPGGA] Time: %s, Lat: %s %s, Lon: %s %s, Fix: %s, Sats: %s, Alt: %sm",
utc_time, lat, lat_dir, lon, lon_dir, fix_quality, num_satellites, altitude);
printf("[GPGGA] Time: %s, Lat: %s %s, Lon: %s %s, Fix: %s, Sats: %s, Alt: %sm\n",
utc_time, lat, lat_dir, lon, lon_dir, fix_quality, num_satellites, altitude);
}
void parse_gprmc(const char *nmea)
{
void parse_gprmc(const char *nmea) {
char *fields[13];
char temp[GPS_LINE_MAX_LEN];
strncpy(temp, nmea, GPS_LINE_MAX_LEN);
@@ -137,8 +135,8 @@ void parse_gprmc(const char *nmea)
const char *speed_knots = fields[7];
const char *date = fields[9];
ESP_LOGI(TAG, "[GPRMC] Date: %s, Time: %s, Lat: %s %s, Lon: %s %s, Speed: %s knots, Status: %s",
date, utc_time, lat, lat_dir, lon, lon_dir, speed_knots, status);
printf("[GPRMC] Date: %s, Time: %s, Lat: %s %s, Lon: %s %s, Speed: %s knots, Status: %s\n",
date, utc_time, lat, lat_dir, lon, lon_dir, speed_knots, status);
}
@@ -154,29 +152,34 @@ static uint32_t time_to_seconds_struct(const char *time_str) {
// Function to convert DMS (degrees minutes.decimalminutes) to centi-degrees
static int32_t dms_to_centi_degrees_struct(const char *dms_str, const char *direction) {
if (dms_str == NULL || direction == NULL || strlen(dms_str) < 7) return 0;
char degrees_str[4] = {0};
char minutes_decimal_str[10] = {0};
strncpy(degrees_str, dms_str, 2);
strncpy(minutes_decimal_str, dms_str + 2, strlen(dms_str) - 2);
double degrees = atof(degrees_str);
double minutes = atof(minutes_decimal_str);
double decimal_degrees = degrees + (minutes / 60.0);
if (direction[0] == 'S' || direction[0] == 'W') {
decimal_degrees *= -1.0;
char data_str[20] = {0};
char *dataStr = data_str;
for (int i = 0; i < 20; i++) {
if (dms_str[i] == 0) {
break;
}
if (dms_str[i] == '.') {
continue;
}
*(dataStr++) = dms_str[i];
}
return (int32_t)(decimal_degrees * 10000);
int32_t degrees = atoi(data_str);
if (direction[0] == 'S' || direction[0] == 'W') {
degrees *= -1;
}
return degrees;
}
// Function to convert altitude string to centi-meters
static int16_t altitude_to_centi_meters_struct(const char *alt_str) {
if (alt_str == NULL) return 0;
return (int16_t)(atof(alt_str) * 100);
return (int16_t) (atof(alt_str) * 100);
}
// Function to convert speed from knots to centi-knots
static uint16_t speed_to_centi_knots_struct(const char *speed_str) {
if (speed_str == NULL) return 0;
return (uint16_t)(atof(speed_str) * 100);
return (uint16_t) (atof(speed_str) * 100);
}
// Function to convert date string (ddmmyy) to yymmdd integer
@@ -190,8 +193,7 @@ static uint16_t date_to_yyddmm_struct(const char *date_str) {
}
// Function to parse GPGGA NMEA string and return the struct
void parse_gpgga_to_struct(const char *nmea, gps_binary_struct_t *data)
{
void parse_gpgga_to_struct(const char *nmea, gps_binary_struct_t *data) {
char *fields[15];
char temp[GPS_LINE_MAX_LEN];
strncpy(temp, nmea, GPS_LINE_MAX_LEN);
@@ -212,13 +214,12 @@ void parse_gpgga_to_struct(const char *nmea, gps_binary_struct_t *data)
data->num_satellites = atoi(fields[7]);
data->altitude_centi_meters = altitude_to_centi_meters_struct(fields[9]);
} else {
ESP_LOGW(TAG, "GPGGA: Not enough fields to parse struct");
printf("GPGGA: Not enough fields to parse struct");
}
}
// Function to parse GPRMC NMEA string and return the struct
void parse_gprmc_to_struct(const char *nmea, gps_binary_struct_t *data)
{
void parse_gprmc_to_struct(const char *nmea, gps_binary_struct_t *data) {
char *fields[13];
char temp[GPS_LINE_MAX_LEN];
strncpy(temp, nmea, GPS_LINE_MAX_LEN);
@@ -239,6 +240,6 @@ void parse_gprmc_to_struct(const char *nmea, gps_binary_struct_t *data)
data->speed_centi_knots = speed_to_centi_knots_struct(fields[7]);
// Fix quality and num_satellites are typically in GPGGA, so they might be 0 here.
} else {
ESP_LOGW(TAG, "GPRMC: Not enough fields to parse struct");
printf("GPRMC: Not enough fields to parse struct");
}
}

View File

@@ -5,7 +5,7 @@ i2c_master_bus_config_t i2c0_bus_cfg = {
.i2c_port = I2C_NUM_0,
.scl_io_num = HWI2C_SCL,
.sda_io_num = HWI2C_SDA,
.glitch_ignore_cnt = 7,
.glitch_ignore_cnt = 1,
.flags.enable_internal_pullup = true,
};
i2c_master_bus_handle_t i2c0_bus_hdl;

View File

@@ -2,26 +2,32 @@
i2c_device_config_t INA260_DEV_CFG = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = 0x40,
.device_address = INA260_ADDRESS,
.scl_speed_hz = 100000,
};
i2c_master_dev_handle_t INA260_DEV_HANDLE;
void ina260_reset() {
void ina260_reset()
{
i2c_write_register_16(INA260_DEV_HANDLE, 0x00, 0x0FFF); // set ina max averaging and max time
}
void ina260_init()
esp_err_t ina260_init()
{
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c0_bus_hdl, &INA260_DEV_CFG, &INA260_DEV_HANDLE));
i2c_write_register_16(INA260_DEV_HANDLE, INA260_CONFIG_REGISTER,
CONFIG_AVG_1024 | CONFIG_VBUSCT_8_244MS | CONFIG_ISHCT_8_244MS | CONFIG_MODE_CURRENT_VOLTAGE_CONTINOUS); // set ina max averaging and max time
esp_err_t ret = i2c_master_bus_add_device(i2c0_bus_hdl, &INA260_DEV_CFG, &INA260_DEV_HANDLE);
if (ret != ESP_OK)
{
ESP_LOGE(TAG_INA, "%s", esp_err_to_name(ret));
return ret;
}
ESP_LOGI(TAG_INA, "hehedstesfsewscdsfsrgerpodsvhdrsivhriuvjdreiv");
return i2c_write_register_16(INA260_DEV_HANDLE, INA260_CONFIG_REGISTER,
CONFIG_AVG_1024 | CONFIG_VBUSCT_8_244MS | CONFIG_ISHCT_8_244MS | CONFIG_MODE_CURRENT_VOLTAGE_CONTINOUS); // set ina max averaging and max time
}
esp_err_t i2c_master_read_register_transmit_receive(i2c_master_dev_handle_t device_handle, uint8_t reg_addr, uint8_t *data, size_t data_len) {
esp_err_t i2c_master_read_register_transmit_receive(i2c_master_dev_handle_t device_handle, uint8_t reg_addr, uint8_t *data, size_t data_len)
{
esp_err_t ret;
// The register address is what we want to send first (the "transmit" part)
@@ -34,11 +40,12 @@ esp_err_t i2c_master_read_register_transmit_receive(i2c_master_dev_handle_t devi
// Perform the combined write (register address) and read (register value)
ret = i2c_master_transmit_receive(INA260_DEV_HANDLE,
write_buffer, write_size,
read_buffer, read_size,
I2C_TIMEOUT_MS_VALUE);
write_buffer, write_size,
read_buffer, read_size,
I2C_TIMEOUT_MS_VALUE);
if (ret == ESP_OK) {
if (ret == ESP_OK)
{
// Copy the data from the temporary read buffer to the output buffer
memcpy(data, read_buffer, read_size);
}
@@ -48,29 +55,32 @@ esp_err_t i2c_master_read_register_transmit_receive(i2c_master_dev_handle_t devi
void ina260_readParams(uint16_t *volt, uint16_t *cur, uint16_t *pow)
{
*volt = 0;
*cur = 0;
*pow = 0;
for (uint8_t reg_addr = 1; reg_addr <= 3; reg_addr++)
if (INA260_DEV_HANDLE)
{
uint8_t reg_value[2] = {0}; // Buffer for storing register data
ESP_ERROR_CHECK(i2c_master_read_register_transmit_receive(INA260_DEV_HANDLE, reg_addr, reg_value, sizeof(reg_value)));
// Perform the register read
switch (reg_addr)
*volt = 0;
*cur = 0;
*pow = 0;
for (uint8_t reg_addr = 1; reg_addr <= 3; reg_addr++)
{
case 1:
*cur = (((uint16_t)(reg_value[0] & 0xFF)) << 8) | (reg_value[1] & 0xFF);
//*cur = *((uint16_t *)reg_value);
break;
case 2:
*volt = (((uint16_t)(reg_value[0] & 0xFF)) << 8) | (reg_value[1] & 0xFF);
break;
case 3:
*pow = (((uint16_t)(reg_value[0] & 0xFF)) << 8) | (reg_value[1] & 0xFF);
break;
default:
break;
uint8_t reg_value[2] = {0}; // Buffer for storing register data
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_read_register_transmit_receive(INA260_DEV_HANDLE, reg_addr, reg_value, sizeof(reg_value)));
// Perform the register read
switch (reg_addr)
{
case 1:
*cur = (((uint16_t)(reg_value[0] & 0xFF)) << 8) | (reg_value[1] & 0xFF);
//*cur = *((uint16_t *)reg_value);
break;
case 2:
*volt = (((uint16_t)(reg_value[0] & 0xFF)) << 8) | (reg_value[1] & 0xFF);
break;
case 3:
*pow = (((uint16_t)(reg_value[0] & 0xFF)) << 8) | (reg_value[1] & 0xFF);
break;
default:
break;
}
}
}
}
@@ -80,9 +90,7 @@ void ina260_printParams(uint16_t volt, uint16_t cur, uint16_t pow)
float miliVolts = volt * 1.25;
float miliAmps = cur * 1.25;
float power = pow * 10;
cur *= 125;
ESP_LOGI(TAG_INA, "Current: %.3f mA (raw %d)", miliAmps, volt);
cur *= 125;
ESP_LOGI(TAG_INA, "Voltage: %.3f mV (raw %d)", miliVolts, cur);
ESP_LOGI(TAG_INA, "Current: %.3f mA (raw %d)", miliAmps, cur);
ESP_LOGI(TAG_INA, "Voltage: %.3f mV (raw %d)", miliVolts, volt);
ESP_LOGI(TAG_INA, "Power: %.3f mW (raw %d)", power, pow);
}

View File

@@ -65,7 +65,7 @@ extern i2c_master_dev_handle_t INA260_DEV_HANDLE;
#define CONFIG_MODE_VOLTAGE_CONTINOUS 0x06
#define CONFIG_MODE_CURRENT_VOLTAGE_CONTINOUS 0x07
void ina260_init();
esp_err_t ina260_init();
void ina260_readParams(uint16_t *volt, uint16_t *cur, uint16_t *pow);
void ina260_printParams(uint16_t volt, uint16_t cur, uint16_t pow);

View File

@@ -1,11 +1,12 @@
#include "mcp23018.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "../components/sensors.h"
// Local buffer for tracking GPIO state
i2c_device_config_t MCP23018_DEV_CFG = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = 0x20,
.device_address = MCP23018_ADDRESS,
.scl_speed_hz = 100000,
};
@@ -13,8 +14,10 @@ i2c_master_dev_handle_t MCP23018_DEV_HANDLE;
uint8_t gpioa_state = 0x00; // All LOW initially
uint8_t gpiob_state = 0x00; // All LOW initially
void mcp23018_set_pin(i2c_master_dev_handle_t dev_handle, uint8_t pin, uint8_t value)
esp_err_t mcp23018_set_pin(i2c_master_dev_handle_t dev_handle, uint8_t pin, uint8_t value)
{
ESP_LOGI(TAG_MCP, "Setting %d to %d", pin, value);
esp_err_t ret = ESP_FAIL;
if (pin < 8)
{
// GPIOA (Pins 0-7)
@@ -24,7 +27,7 @@ void mcp23018_set_pin(i2c_master_dev_handle_t dev_handle, uint8_t pin, uint8_t v
gpioa_state &= ~(1 << pin); // Clear bit
// Write updated buffer to MCP23018
i2c_write_register_8(dev_handle, MCP23018_GPIOA, gpioa_state);
ret = i2c_write_register_8(dev_handle, MCP23018_GPIOA, gpioa_state);
}
else if (pin < 16)
{
@@ -36,19 +39,28 @@ void mcp23018_set_pin(i2c_master_dev_handle_t dev_handle, uint8_t pin, uint8_t v
gpiob_state &= ~(1 << pinB); // Clear bit
// Write updated buffer to MCP23018
i2c_write_register_8(dev_handle, MCP23018_GPIOB, gpiob_state);
ret = i2c_write_register_8(dev_handle, MCP23018_GPIOB, gpiob_state);
}
vTaskDelay(1 / portTICK_PERIOD_MS);
return ret;
}
void mcp23018_init()
esp_err_t mcp23018_init()
{
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c0_bus_hdl, &MCP23018_DEV_CFG, &MCP23018_DEV_HANDLE));
esp_err_t ret = i2c_master_bus_add_device(i2c0_bus_hdl, &MCP23018_DEV_CFG, &MCP23018_DEV_HANDLE);
if (ret != ESP_OK) {return ret;}
i2c_write_register_8(MCP23018_DEV_HANDLE, MCP23018_IODIRA, gpioa_state);
if (ret != ESP_OK) {return ret;}
i2c_write_register_8(MCP23018_DEV_HANDLE, MCP23018_IODIRB, gpiob_state);
if (ret != ESP_OK) {return ret;}
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_CS_ADC_CO, 1);
if (ret != ESP_OK) {return ret;}
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_CS_ADC_NH3, 1);
if (ret != ESP_OK) {return ret;}
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_CS_ADC_NO2, 1);
if (ret != ESP_OK) {return ret;}
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_CS_ADC_UVC, 1);
if (ret != ESP_OK) {return ret;}
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_LORA_RST, 1);
return ret;
}

View File

@@ -7,6 +7,7 @@
#define MCP23018_GPIOA 0x12 // GPIO Output A
#define MCP23018_GPIOB 0x13 // GPIO Output B
#define MCP_LORA_RST 4
#define MCP_MICS_POWER 5
#define MCP_CCS811_WAKE 6
@@ -25,7 +26,7 @@ extern i2c_master_dev_handle_t MCP23018_DEV_HANDLE;
extern uint8_t gpioa_state;
extern uint8_t gpiob_state;
void mcp23018_set_pin(i2c_master_dev_handle_t dev_handle, uint8_t pin, uint8_t value);
void mcp23018_init();
esp_err_t mcp23018_set_pin(i2c_master_dev_handle_t dev_handle, uint8_t pin, uint8_t value);
esp_err_t mcp23018_init();
#endif

View File

@@ -19,56 +19,149 @@ spi_device_handle_t mcp3550_handle;
void mcp3550_spi_init()
{
spi_device_interface_config_t devcfg = {
.clock_speed_hz = 100000,
.mode = 0,
.spics_io_num = -1, // We handle CS manually
.queue_size = 1,
};
// spi_device_interface_config_t devcfg = {
// .clock_speed_hz = 100000,
// .mode = 0,
// .spics_io_num = -1, // We handle CS manually
// .queue_size = 1,
// };
ESP_ERROR_CHECK(spi_bus_add_device(SPI2_HOST, &devcfg, &mcp3550_handle));
// ESP_ERROR_CHECK_WITHOUT_ABORT(spi_bus_add_device(SPI2_HOST, &devcfg, &mcp3550_handle));
// Set MISO pin for input (needed for polling)
gpio_set_direction(MCP3550_MISO_GPIO, GPIO_MODE_INPUT);
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_MICS_POWER, 1); // CS HIGH
}
// int32_t mcp3550_read(uint8_t cs_pin)
// {
// uint8_t rx_buf[4] = {0}; // 25 bits fits in 4 bytes
// int64_t start = esp_timer_get_time(); // in microseconds
// while (true) {
// mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 0); // CS LOW
// vTaskDelay(pdMS_TO_TICKS(30)); // Wait before retrying
// mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 1); // CS HIGH
// vTaskDelay(pdMS_TO_TICKS(200)); // Wait before retrying
// mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 0); // CS LOW
// esp_rom_delay_us(1000); // Wait before retrying
// spi_transaction_t trans = {
// .length = 25,
// .rx_buffer = rx_buf,
// };
// esp_err_t err = spi_device_transmit(mcp3550_handle, &trans);
// mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 1); // CS HIGH
// if (err != ESP_OK) {
// ESP_LOGE(TAG_MICS, "SPI transmit failed on CS pin %u", cs_pin);
// return INT32_MIN;
// }
// bool dr = (rx_buf[0] & 0x80) != 0;
// if (!dr) break;
// if ((esp_timer_get_time() - start) > (MCP3550_TIMEOUT_MS * 1000)) {
// ESP_LOGW(TAG_MICS, "Timeout waiting for DR=0 on CS pin %u", cs_pin);
// return INT32_MIN;
// }
// vTaskDelay(pdMS_TO_TICKS(10)); // Wait before retrying
// }
// // Combine 22-bit result (drop DR + status bits)
// uint32_t raw = ((rx_buf[0] & 0x3F) << 16) | (rx_buf[1] << 8) | rx_buf[2];
// // Sign-extend 22-bit value
// int32_t value = raw;
// if (value & (1 << 21)) value |= 0xFFC00000;
// return value;
// }
// int32_t mcp3550_read(uint8_t cs_pin)
// {
// uint8_t rx_buf[4] = {0};
// uint32_t timeout_us = MCP3550_TIMEOUT_MS * 1000;
// int64_t start = esp_timer_get_time();
// // Start conversion
// mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 0); // CS LOW
// // Wait until MISO/SDO goes LOW = DR ready
// while (gpio_get_level(MCP3550_MISO_GPIO)) {
// if ((esp_timer_get_time() - start) > timeout_us) {
// ESP_LOGW(TAG_MICS, "Timeout waiting for MISO=0 on CS %u", cs_pin);
// mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 1); // CS HIGH
// return INT32_MIN;
// }
// esp_rom_delay_us(10); // micro delay
// }
// // Data is ready, do full SPI read
// spi_transaction_t trans = {
// .length = 25, // 25 bits
// .rx_buffer = rx_buf,
// };
// esp_err_t err = spi_device_transmit(mcp3550_handle, &trans);
// mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 1); // CS HIGH to start next conversion
// if (err != ESP_OK) {
// ESP_LOGE(TAG_MICS, "SPI transmit failed");
// return INT32_MIN;
// }
// // Extract 22-bit result
// uint32_t raw = ((rx_buf[0] & 0x3F) << 16) | (rx_buf[1] << 8) | rx_buf[2];
// // Sign-extend 22-bit value
// int32_t value = raw;
// if (value & (1 << 21)) value |= 0xFFC00000;
// return value;
// }
int32_t mcp3550_read(uint8_t cs_pin)
{
uint8_t rx_buf[4] = {0}; // 25 bits fits in 4 bytes
uint32_t data = 0;
int64_t start = esp_timer_get_time();
uint32_t timeout_us = MCP3550_TIMEOUT_MS * 1000;
int64_t start = esp_timer_get_time(); // in microseconds
while (true) {
mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 0); // CS LOW
ESP_LOGI(TAG_MCP, "Starting read from ADC CS %d", cs_pin);
spi_transaction_t trans = {
.length = 25,
.rx_buffer = rx_buf,
};
// CS LOW
mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 0);
esp_err_t err = spi_device_transmit(mcp3550_handle, &trans);
vTaskDelay(pdMS_TO_TICKS(10));
mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 1); // CS HIGH
if (err != ESP_OK) {
ESP_LOGE(TAG_MICS, "SPI transmit failed on CS pin %u", cs_pin);
// Wait for DR (MISO LOW)
while (gpio_get_level(MCP3550_MISO_GPIO)) {
if ((esp_timer_get_time() - start) > timeout_us) {
ESP_LOGW(TAG_MICS, "Timeout waiting for MISO=0 on CS %u", cs_pin);
mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 1); // CS HIGH
return INT32_MIN;
}
bool dr = (rx_buf[0] & 0x80) != 0;
if (!dr) break;
if ((esp_timer_get_time() - start) > (MCP3550_TIMEOUT_MS * 1000)) {
ESP_LOGW(TAG_MICS, "Timeout waiting for DR=0 on CS pin %u", cs_pin);
return INT32_MIN;
}
vTaskDelay(pdMS_TO_TICKS(10)); // Wait before retrying
vTaskDelay(pdMS_TO_TICKS(10)); // Wait 1 tick (e.g., 1ms)
}
// Combine 22-bit result (drop DR + status bits)
uint32_t raw = ((rx_buf[0] & 0x3F) << 16) | (rx_buf[1] << 8) | rx_buf[2];
// Clock out 25 bits
for (int i = 0; i < 25; i++) {
gpio_set_level(MCP3550_SCK_GPIO, 1);
esp_rom_delay_us(5); // small delay to simulate clock high
data = (data << 1) | gpio_get_level(MCP3550_MISO_GPIO);
gpio_set_level(MCP3550_SCK_GPIO, 0);
esp_rom_delay_us(5); // small delay to simulate clock low
}
mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 1); // CS HIGH
// Extract 22-bit value (bits [23:2])
uint32_t raw = (data >> 2) & 0x3FFFFF;
// Sign-extend 22-bit value
int32_t value = raw;
@@ -78,6 +171,7 @@ int32_t mcp3550_read(uint8_t cs_pin)
}
float mcp3550_to_voltage(int32_t value, float vref)
{
return ((float)value / (1 << 21)) * vref;
@@ -107,10 +201,10 @@ void log_mics_adc_values(mics_adc_data_t *data)
{
ESP_LOGI(TAG_MICS,
"ADC Readings:\n"
" NH3 -> Raw: %8d, Voltage: %7.6f V\n"
" CO -> Raw: %8d, Voltage: %7.6f V\n"
" NO2 -> Raw: %8d, Voltage: %7.6f V\n"
" UVC -> Raw: %8d, Voltage: %7.6f V",
" NH3 -> Raw: %ld, Voltage: %f V\n"
" CO -> Raw: %ld, Voltage: %f V\n"
" NO2 -> Raw: %ld, Voltage: %f V\n"
" UVC -> Raw: %ld, Voltage: %f V",
data->raw_nh3, data->volts_nh3,
data->raw_co, data->volts_co,
data->raw_no2, data->volts_no2,

View File

@@ -7,8 +7,6 @@
#include "esp_log.h"
#include "buscfg.h"
#define CONFIG_FREERTOS_HZ 100
#define MCP3550_SPS 3.75f
#define MCP3550_CONVERSION_MS ((int)(1000.0f / MCP3550_SPS)) // ~267ms

View File

@@ -3,7 +3,7 @@
i2c_device_config_t MPU9250_DEV_CFG = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = 0x68,
.device_address = MPU9250_ADDRESS,
.scl_speed_hz = 100000,
};
@@ -57,9 +57,12 @@ void mpu9250_convert_data(int16_t *accel, int16_t *gyro, int16_t temp, int16_t *
*temp_out = (temp / 333.87) + 21.0; // Temperature in °C
}
void mpu9250_init()
esp_err_t mpu9250_init()
{
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c0_bus_hdl, &MPU9250_DEV_CFG, &MPU9250_DEV_HANDLE));
i2c_write_register_16(MPU9250_DEV_HANDLE, 0x6B, 0x0001); // zapni uz tu hovadinu
i2c_write_register_16(MPU9250_DEV_HANDLE, 0x0A, 0x0012); // zapni uz tu hovadinu
esp_err_t ret = i2c_master_bus_add_device(i2c0_bus_hdl, &MPU9250_DEV_CFG, &MPU9250_DEV_HANDLE);
if (ret != ESP_OK) {return ret;}
ret = i2c_write_register_16(MPU9250_DEV_HANDLE, 0x6B, 0x0001); // zapni uz tu hovadinu
if (ret != ESP_OK) {return ret;}
ret = i2c_write_register_16(MPU9250_DEV_HANDLE, 0x0A, 0x0012); // zapni uz tu hovadinu
return ret;
}

View File

@@ -10,6 +10,6 @@ extern i2c_master_dev_handle_t MPU9250_DEV_HANDLE;
esp_err_t mpu9250_read_sensor_data(i2c_master_dev_handle_t dev_handle, int16_t *accel, int16_t *gyro, int16_t *temp, int16_t *magnet);
void mpu9250_convert_data(int16_t *accel, int16_t *gyro, int16_t temp, int16_t *magnet, float *accel_out, float *gyro_out, float *temp_out, float *magnet_out);
void mpu9250_init();
esp_err_t mpu9250_init();
#endif

View File

@@ -4,12 +4,15 @@
#include <math.h>
#include <stdlib.h>
#include "../components/sensors.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <driver/spi_master.h>
#include <driver/gpio.h>
#include "esp_log.h"
#include "buscfg.h"
#include "sx1262.h"
@@ -17,13 +20,6 @@
#define HOST_ID SPI3_HOST
#define CONFIG_MISO_GPIO GPIO_NUM_11
#define CONFIG_MOSI_GPIO GPIO_NUM_10
#define CONFIG_SCLK_GPIO GPIO_NUM_9
#define CONFIG_NSS_GPIO GPIO_NUM_8
#define CONFIG_RST_GPIO GPIO_NUM_12
#define CONFIG_BUSY_GPIO GPIO_NUM_13
static spi_device_handle_t SpiHandle;
// Global Stuff
@@ -32,7 +28,6 @@ static bool txActive;
static int txLost = 0;
static bool debugPrint;
static int SX126x_SPI_SELECT;
static int SX126x_RESET;
static int SX126x_BUSY;
// Arduino compatible macros
@@ -55,16 +50,14 @@ __attribute__ ((weak, alias ("LoRaErrorDefault"))) void LoRaError(int error);
void LoRaInit(void)
{
ESP_LOGI(TAG, "CONFIG_MISO_GPIO=%d", CONFIG_MISO_GPIO);
ESP_LOGI(TAG, "CONFIG_MOSI_GPIO=%d", CONFIG_MOSI_GPIO);
ESP_LOGI(TAG, "CONFIG_SCLK_GPIO=%d", CONFIG_SCLK_GPIO);
ESP_LOGI(TAG, "CONFIG_NSS_GPIO=%d", CONFIG_NSS_GPIO);
ESP_LOGI(TAG, "CONFIG_RST_GPIO=%d", CONFIG_RST_GPIO);
ESP_LOGI(TAG, "CONFIG_BUSY_GPIO=%d", CONFIG_BUSY_GPIO);
ESP_LOGI(TAG, "HSPI_MISO_GPIO=%d", HSPI_MISO_GPIO);
ESP_LOGI(TAG, "HSPI_MOSI_GPIO=%d", HSPI_MOSI_GPIO);
ESP_LOGI(TAG, "HSPI_SCK_GPIO=%d", HSPI_SCK_GPIO);
ESP_LOGI(TAG, "HSPI_LORA_CS=%d", HSPI_LORA_CS);
ESP_LOGI(TAG, "LORA_BUSY=%d", LORA_BUSY);
SX126x_SPI_SELECT = CONFIG_NSS_GPIO;
SX126x_RESET = CONFIG_RST_GPIO;
SX126x_BUSY = CONFIG_BUSY_GPIO;
SX126x_SPI_SELECT = HSPI_LORA_CS;
SX126x_BUSY = LORA_BUSY;
txActive = false;
debugPrint = false;
@@ -72,17 +65,14 @@ void LoRaInit(void)
gpio_reset_pin(SX126x_SPI_SELECT);
gpio_set_direction(SX126x_SPI_SELECT, GPIO_MODE_OUTPUT);
gpio_set_level(SX126x_SPI_SELECT, 1);
gpio_reset_pin(SX126x_RESET);
gpio_set_direction(SX126x_RESET, GPIO_MODE_OUTPUT);
gpio_reset_pin(SX126x_BUSY);
gpio_set_direction(SX126x_BUSY, GPIO_MODE_INPUT);
spi_bus_config_t spi_bus_config = {
.sclk_io_num = CONFIG_SCLK_GPIO,
.mosi_io_num = CONFIG_MOSI_GPIO,
.miso_io_num = CONFIG_MISO_GPIO,
.sclk_io_num = HSPI_SCK_GPIO,
.mosi_io_num = HSPI_MOSI_GPIO,
.miso_io_num = HSPI_MISO_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1
};
@@ -91,7 +81,7 @@ void LoRaInit(void)
spi_device_interface_config_t devcfg = {
.clock_speed_hz = 9000000,
.mode = 0,
.spics_io_num = CONFIG_NSS_GPIO,
.spics_io_num = HSPI_LORA_CS,
.queue_size = 7,
.flags = 0,
.pre_cb = NULL
@@ -272,6 +262,8 @@ void LoRaConfig(uint8_t spreadingFactor, uint8_t bandwidth, uint8_t codingRate,
SX126X_IRQ_NONE //interrupts on DIO3
);
ESP_LOGI(TAG, "Almost done setting LoRa");
// Receive state no receive timeoout
SetRx(0xFFFFFF);
}
@@ -399,9 +391,9 @@ void SetTxPower(int8_t txPowerInDbm)
void Reset(void)
{
delay(10);
gpio_set_level(SX126x_RESET,0);
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_LORA_RST, 0);
delay(20);
gpio_set_level(SX126x_RESET,1);
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_LORA_RST, 1);
delay(10);
// ensure BUSY is low (state meachine ready)
WaitForIdle(BUSY_WAIT, "Reset", true);

View File

@@ -25,29 +25,32 @@
#include "hw/mcp23018.h"
#include "hw/mpu9250.h"
#include "hw/buscfg.h"
#include "components/sdcard.h"
#include "hw/gps.h"
#define TAG "cantest"
#define CONFIG_FREERTOS_HZ 100
void app_main(void)
{
ESP_LOGI("BOOT", "BRN Systems incorporated CanSat flight firmware build at %s %s", __DATE__, __TIME__);
/* instantiate i2c master bus 0 */
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c0_bus_cfg, &i2c0_bus_hdl));
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_new_master_bus(&i2c0_bus_cfg, &i2c0_bus_hdl));
spi_bus_config_t MCPBusCfg = {
.mosi_io_num = -1,
.miso_io_num = MCP3550_MISO_GPIO,
.sclk_io_num = MCP3550_SCK_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4,
};
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &MCPBusCfg, SPI_DMA_DISABLED));
// spi_bus_config_t MCPBusCfg = {
// .mosi_io_num = -1,
// .miso_io_num = MCP3550_MISO_GPIO,
// .sclk_io_num = MCP3550_SCK_GPIO,
// .quadwp_io_num = -1,
// .quadhd_io_num = -1,
// .max_transfer_sz = 4,
// };
// ESP_ERROR_CHECK_WITHOUT_ABORT(spi_bus_initialize(SPI2_HOST, &MCPBusCfg, SPI_DMA_DISABLED));
gpio_pullup_en(HSPI_MISO_GPIO);
gpio_pullup_en(HSPI_SD_CS);
spi_bus_config_t HighSpeedBusCfg = {
// CONNECTED to LoRa and SD card
.mosi_io_num = HSPI_MOSI_GPIO,
@@ -57,15 +60,19 @@ void app_main(void)
.quadhd_io_num = -1,
.max_transfer_sz = 64, // probably change
};
ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &HighSpeedBusCfg, SPI_DMA_CH_AUTO));
ESP_ERROR_CHECK_WITHOUT_ABORT(spi_bus_initialize(SPI3_HOST, &HighSpeedBusCfg, SPI_DMA_CH_AUTO));
/* scan i2c devices on i2c master bus 0 and print results */
ESP_ERROR_CHECK(i2c_master_bus_detect_devices(i2c0_bus_hdl));
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_bus_detect_devices(i2c0_bus_hdl));
mcp23018_init();
initSD();
void servoControllerInit();
ESP_LOGI(TAG, "BEGIN ESP TASKS");
/* create task pinned to the app core */
xTaskCreate(
i2c_sensors_task,

View File

@@ -426,39 +426,39 @@ static inline esp_err_t bme680_get_cal_factors(bme680_handle_t handle) {
ESP_ARG_CHECK( handle );
/* bme680 attempt to request T1-T3 calibration values from device */
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0xe9, &handle->dev_cal_factors->par_T1) );
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0x8a, (uint16_t *)&handle->dev_cal_factors->par_T2) );
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0x8c, (uint8_t *)&handle->dev_cal_factors->par_T3) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_word_from(handle, 0xe9, &handle->dev_cal_factors->par_T1) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_word_from(handle, 0x8a, (uint16_t *)&handle->dev_cal_factors->par_T2) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0x8c, (uint8_t *)&handle->dev_cal_factors->par_T3) );
/* bme680 attempt to request H1-H7 calibration values from device */
ESP_ERROR_CHECK( bme680_i2c_read_from(handle, 0xe2, rx, BIT16_UINT8_BUFFER_SIZE) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_from(handle, 0xe2, rx, BIT16_UINT8_BUFFER_SIZE) );
handle->dev_cal_factors->par_H1 = (uint16_t)(((uint16_t)rx[1] << 4) | (rx[0] & 0x0F));
ESP_ERROR_CHECK( bme680_i2c_read_from(handle, 0xe1, rx, BIT16_UINT8_BUFFER_SIZE) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_from(handle, 0xe1, rx, BIT16_UINT8_BUFFER_SIZE) );
handle->dev_cal_factors->par_H2 = (uint16_t)(((uint16_t)rx[0] << 4) | (rx[1] >> 4));
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xe4, (uint8_t *)&handle->dev_cal_factors->par_H3) );
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xe5, (uint8_t *)&handle->dev_cal_factors->par_H4) );
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xe6, (uint8_t *)&handle->dev_cal_factors->par_H5) );
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xe7, &handle->dev_cal_factors->par_H6) );
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xe8, (uint8_t *)&handle->dev_cal_factors->par_H7) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0xe4, (uint8_t *)&handle->dev_cal_factors->par_H3) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0xe5, (uint8_t *)&handle->dev_cal_factors->par_H4) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0xe6, (uint8_t *)&handle->dev_cal_factors->par_H5) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0xe7, &handle->dev_cal_factors->par_H6) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0xe8, (uint8_t *)&handle->dev_cal_factors->par_H7) );
/* bme680 attempt to request P1-P10 calibration values from device */
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0x8e, &handle->dev_cal_factors->par_P1) );
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0x90, (uint16_t *)&handle->dev_cal_factors->par_P2) );
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0x92, (uint8_t *)&handle->dev_cal_factors->par_P3) );
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0x94, (uint16_t *)&handle->dev_cal_factors->par_P4) );
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0x96, (uint16_t *)&handle->dev_cal_factors->par_P5) );
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0x99, (uint8_t *)&handle->dev_cal_factors->par_P6) );
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0x98, (uint8_t *)&handle->dev_cal_factors->par_P7) );
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0x9c, (uint16_t *)&handle->dev_cal_factors->par_P8) );
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0x9e, (uint16_t *)&handle->dev_cal_factors->par_P9) );
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xa0, &handle->dev_cal_factors->par_P10) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_word_from(handle, 0x8e, &handle->dev_cal_factors->par_P1) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_word_from(handle, 0x90, (uint16_t *)&handle->dev_cal_factors->par_P2) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0x92, (uint8_t *)&handle->dev_cal_factors->par_P3) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_word_from(handle, 0x94, (uint16_t *)&handle->dev_cal_factors->par_P4) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_word_from(handle, 0x96, (uint16_t *)&handle->dev_cal_factors->par_P5) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0x99, (uint8_t *)&handle->dev_cal_factors->par_P6) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0x98, (uint8_t *)&handle->dev_cal_factors->par_P7) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_word_from(handle, 0x9c, (uint16_t *)&handle->dev_cal_factors->par_P8) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_word_from(handle, 0x9e, (uint16_t *)&handle->dev_cal_factors->par_P9) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0xa0, &handle->dev_cal_factors->par_P10) );
/* bme680 attempt to request G1-G3 calibration values from device */
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xed, (uint8_t *)&handle->dev_cal_factors->par_G1) );
ESP_ERROR_CHECK( bme680_i2c_read_word_from(handle, 0xeb, (uint16_t *)&handle->dev_cal_factors->par_G2) );
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0xee, (uint8_t *)&handle->dev_cal_factors->par_G3) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0xed, (uint8_t *)&handle->dev_cal_factors->par_G1) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_word_from(handle, 0xeb, (uint16_t *)&handle->dev_cal_factors->par_G2) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0xee, (uint8_t *)&handle->dev_cal_factors->par_G3) );
/* bme680 attempt to request gas range and switching error values from device */
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0x02, &handle->dev_cal_factors->res_heat_range) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0x02, &handle->dev_cal_factors->res_heat_range) );
handle->dev_cal_factors->res_heat_range = (handle->dev_cal_factors->res_heat_range & 0x30) / 16;
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0x00, (uint8_t *)&handle->dev_cal_factors->res_heat_val) );
ESP_ERROR_CHECK( bme680_i2c_read_byte_from(handle, 0x04, (uint8_t *)&handle->dev_cal_factors->range_switching_error) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0x00, (uint8_t *)&handle->dev_cal_factors->res_heat_val) );
ESP_ERROR_CHECK_WITHOUT_ABORT( bme680_i2c_read_byte_from(handle, 0x04, (uint8_t *)&handle->dev_cal_factors->range_switching_error) );
handle->dev_cal_factors->range_switching_error = (handle->dev_cal_factors->range_switching_error & 0xf0) / 16;
/*