Compare commits
12 Commits
35a11734e2
...
main
Author | SHA1 | Date | |
---|---|---|---|
22d9f1f32a | |||
ee54abb663
|
|||
76eb216716
|
|||
c26e5e012c | |||
5ea05fa209 | |||
8b9e72ef71
|
|||
0c71409c30
|
|||
3457b76938
|
|||
af4d8654de
|
|||
cb339e6b66 | |||
5853bf849f
|
|||
9104869ecf
|
15
.vscode/settings.json
vendored
15
.vscode/settings.json
vendored
@@ -29,6 +29,19 @@
|
|||||||
"esp_mac.h": "c",
|
"esp_mac.h": "c",
|
||||||
"gpio.h": "c",
|
"gpio.h": "c",
|
||||||
"chrono": "c",
|
"chrono": "c",
|
||||||
"cstdint": "c"
|
"cstdint": "c",
|
||||||
|
"task.h": "c",
|
||||||
|
"compare": "c",
|
||||||
|
"uart_struct.h": "c",
|
||||||
|
"uart.h": "c",
|
||||||
|
"gpio_num.h": "c",
|
||||||
|
"mcp3550.h": "c",
|
||||||
|
"esp_timer.h": "c",
|
||||||
|
"math.h": "c",
|
||||||
|
"esp_check.h": "c",
|
||||||
|
"radio.h": "c",
|
||||||
|
"sx1262.h": "c",
|
||||||
|
"gps.h": "c",
|
||||||
|
"servocontroller.h": "c"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +0,0 @@
|
|||||||
set(component_srcs "ra01s.c")
|
|
||||||
|
|
||||||
idf_component_register(SRCS "${component_srcs}"
|
|
||||||
PRIV_REQUIRES driver
|
|
||||||
INCLUDE_DIRS ".")
|
|
@@ -1,163 +0,0 @@
|
|||||||
menu "SX126X Configuration"
|
|
||||||
|
|
||||||
config GPIO_RANGE_MAX
|
|
||||||
int
|
|
||||||
default 33 if IDF_TARGET_ESP32
|
|
||||||
default 46 if IDF_TARGET_ESP32S2
|
|
||||||
default 48 if IDF_TARGET_ESP32S3
|
|
||||||
default 18 if IDF_TARGET_ESP32C2
|
|
||||||
default 19 if IDF_TARGET_ESP32C3
|
|
||||||
default 30 if IDF_TARGET_ESP32C6
|
|
||||||
|
|
||||||
choice FREQUENCY
|
|
||||||
prompt "Frequency to use"
|
|
||||||
default 433MHZ
|
|
||||||
help
|
|
||||||
Select Frequency to use.
|
|
||||||
config 433MHZ
|
|
||||||
bool "433MHz"
|
|
||||||
help
|
|
||||||
Frequency is 433MHz.
|
|
||||||
config 866MHZ
|
|
||||||
bool "866MHz"
|
|
||||||
help
|
|
||||||
Frequency is 866MHz.
|
|
||||||
config 915MHZ
|
|
||||||
bool "915MHz"
|
|
||||||
help
|
|
||||||
Frequency is 915MHz.
|
|
||||||
config OTHER
|
|
||||||
bool "Other"
|
|
||||||
help
|
|
||||||
Other Frequency.
|
|
||||||
endchoice
|
|
||||||
|
|
||||||
config OTHER_FREQUENCY
|
|
||||||
depends on OTHER
|
|
||||||
int "Frequency to use[MHz]"
|
|
||||||
range 1 999
|
|
||||||
default 433
|
|
||||||
help
|
|
||||||
Frequency to use[MHz].
|
|
||||||
|
|
||||||
config ADVANCED
|
|
||||||
bool "Enable Advanced settings"
|
|
||||||
default false
|
|
||||||
help
|
|
||||||
Enable Advanced settings.
|
|
||||||
|
|
||||||
config CODING_RATE
|
|
||||||
depends on ADVANCED
|
|
||||||
int "Error coding rate"
|
|
||||||
range 1 4
|
|
||||||
default 1
|
|
||||||
help
|
|
||||||
Error coding rate.
|
|
||||||
|
|
||||||
config BANDWIDTH
|
|
||||||
depends on ADVANCED
|
|
||||||
int "Signal Bandwidth"
|
|
||||||
range 0 6
|
|
||||||
default 4
|
|
||||||
help
|
|
||||||
Signal Bandwidth.
|
|
||||||
|
|
||||||
config SF_RATE
|
|
||||||
depends on ADVANCED
|
|
||||||
int "Spreading Factor"
|
|
||||||
range 5 12
|
|
||||||
default 7
|
|
||||||
help
|
|
||||||
Spreading Factor.
|
|
||||||
|
|
||||||
config USE_TCXO
|
|
||||||
bool "Enable TCXO"
|
|
||||||
default false
|
|
||||||
help
|
|
||||||
Enable Temperature-Compensated Crystal Oscillator.
|
|
||||||
|
|
||||||
config MISO_GPIO
|
|
||||||
int "SX126X MISO GPIO"
|
|
||||||
range 0 GPIO_RANGE_MAX
|
|
||||||
default 19 if IDF_TARGET_ESP32
|
|
||||||
default 37 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
|
||||||
default 4 # C3 and others
|
|
||||||
help
|
|
||||||
Pin Number to be used as the MISO SPI signal.
|
|
||||||
|
|
||||||
config SCLK_GPIO
|
|
||||||
int "SX126X SCLK GPIO"
|
|
||||||
range 0 GPIO_RANGE_MAX
|
|
||||||
default 18 if IDF_TARGET_ESP32
|
|
||||||
default 36 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
|
||||||
default 5 # C3 and others
|
|
||||||
help
|
|
||||||
Pin Number to be used as the SCLK SPI signal.
|
|
||||||
|
|
||||||
config MOSI_GPIO
|
|
||||||
int "SX126X MOSI GPIO"
|
|
||||||
range 0 GPIO_RANGE_MAX
|
|
||||||
default 23 if IDF_TARGET_ESP32
|
|
||||||
default 35 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
|
||||||
default 6 # C3 and others
|
|
||||||
help
|
|
||||||
Pin Number to be used as the MOSI SPI signal.
|
|
||||||
|
|
||||||
config NSS_GPIO
|
|
||||||
int "SX126X NSS GPIO"
|
|
||||||
range 0 GPIO_RANGE_MAX
|
|
||||||
default 15 if IDF_TARGET_ESP32
|
|
||||||
default 34 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
|
||||||
default 7 # C3 and others
|
|
||||||
help
|
|
||||||
Pin Number to be used as the NSS SPI signal.
|
|
||||||
|
|
||||||
config RST_GPIO
|
|
||||||
int "SX126X RST GPIO"
|
|
||||||
range 0 GPIO_RANGE_MAX
|
|
||||||
default 16 if IDF_TARGET_ESP32
|
|
||||||
default 38 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
|
||||||
default 2 # C3 and others
|
|
||||||
help
|
|
||||||
Pin Number to be used as the RST signal.
|
|
||||||
|
|
||||||
config BUSY_GPIO
|
|
||||||
int "SX126X BUSY GPIO"
|
|
||||||
range 0 GPIO_RANGE_MAX
|
|
||||||
default 17 if IDF_TARGET_ESP32
|
|
||||||
default 39 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
|
||||||
default 3 # C3 and others
|
|
||||||
help
|
|
||||||
Pin Number to be used as the BUSY signal.
|
|
||||||
|
|
||||||
config TXEN_GPIO
|
|
||||||
int "SX126X TXEN GPIO"
|
|
||||||
range -1 GPIO_RANGE_MAX
|
|
||||||
default -1
|
|
||||||
help
|
|
||||||
Pin Number to be used as the TXEN signal.
|
|
||||||
|
|
||||||
config RXEN_GPIO
|
|
||||||
int "SX126X RXEN GPIO"
|
|
||||||
range -1 GPIO_RANGE_MAX
|
|
||||||
default -1
|
|
||||||
help
|
|
||||||
Pin Number to be used as the RXEN signal.
|
|
||||||
|
|
||||||
choice SPI_HOST
|
|
||||||
prompt "SPI peripheral that controls this bus"
|
|
||||||
default SPI2_HOST
|
|
||||||
help
|
|
||||||
Select SPI peripheral that controls this bus.
|
|
||||||
config SPI2_HOST
|
|
||||||
bool "SPI2_HOST"
|
|
||||||
help
|
|
||||||
Use SPI2_HOST. This is also called HSPI_HOST.
|
|
||||||
config SPI3_HOST
|
|
||||||
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
|
||||||
bool "SPI3_HOST"
|
|
||||||
help
|
|
||||||
USE SPI3_HOST. This is also called VSPI_HOST
|
|
||||||
endchoice
|
|
||||||
|
|
||||||
endmenu
|
|
@@ -13,8 +13,20 @@ idf_component_register(SRCS
|
|||||||
"hw/mcp23018.h"
|
"hw/mcp23018.h"
|
||||||
"hw/mpu9250.c"
|
"hw/mpu9250.c"
|
||||||
"hw/mpu9250.h"
|
"hw/mpu9250.h"
|
||||||
|
"hw/gps.c"
|
||||||
|
"hw/gps.h"
|
||||||
|
"hw/mcp3550.c"
|
||||||
|
"hw/mcp3550.h"
|
||||||
|
"hw/sx1262.c"
|
||||||
|
"hw/sx1262.h"
|
||||||
"components/sensors.c"
|
"components/sensors.c"
|
||||||
"components/sensors.h"
|
"components/sensors.h"
|
||||||
|
"components/servocontroller.c"
|
||||||
|
"components/servocontroller.h"
|
||||||
|
"components/radio.c"
|
||||||
|
"components/radio.h"
|
||||||
|
"components/sdcard.c"
|
||||||
|
"components/sdcard.h"
|
||||||
"main.c"
|
"main.c"
|
||||||
|
|
||||||
INCLUDE_DIRS ".")
|
INCLUDE_DIRS ".")
|
||||||
|
127
main/components/packets.h
Normal file
127
main/components/packets.h
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
#ifndef PACKETS_STRUCTS
|
||||||
|
#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))
|
||||||
|
{
|
||||||
|
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;//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;//41
|
||||||
|
uint16_t tvoc;//43
|
||||||
|
uint8_t currentCCS;//44
|
||||||
|
uint16_t rawCCSData;//46
|
||||||
|
|
||||||
|
// INA data
|
||||||
|
uint16_t volts;//48
|
||||||
|
uint16_t current;//50
|
||||||
|
uint16_t power;//52
|
||||||
|
|
||||||
|
// BME DATA
|
||||||
|
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 //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 //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; //130
|
||||||
|
int32_t CO; //134
|
||||||
|
int32_t NO2; //138
|
||||||
|
int32_t UVC; //142
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
uint8_t powerMode;
|
||||||
|
uint8_t controlMode;
|
||||||
|
uint16_t servoA;
|
||||||
|
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
|
396
main/components/radio.c
Normal file
396
main/components/radio.c
Normal file
@@ -0,0 +1,396 @@
|
|||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "../hw/sx1262.h"
|
||||||
|
#include "radio.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "esp_timer.h"
|
||||||
|
#include "esp_rom_crc.h"
|
||||||
|
#include <hw/buscfg.h>
|
||||||
|
#include "sensors.h"
|
||||||
|
#include "sdcard.h"
|
||||||
|
|
||||||
|
#define TAG "LoRa"
|
||||||
|
|
||||||
|
#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;
|
||||||
|
|
||||||
|
volatile bool ackReceived = false;
|
||||||
|
uint32_t lastAckIndex = 0;
|
||||||
|
|
||||||
|
SemaphoreHandle_t loraRadioMutex;
|
||||||
|
|
||||||
|
void setup_lora(void)
|
||||||
|
{
|
||||||
|
LoRaInit();
|
||||||
|
|
||||||
|
int8_t txPowerInDbm = 20;
|
||||||
|
uint32_t frequencyInHz = 869525000;
|
||||||
|
float tcxoVoltage = 2.2;
|
||||||
|
bool useRegulatorLDO = true;
|
||||||
|
|
||||||
|
ESP_LOGW(TAG, "Enable TCXO");
|
||||||
|
LoRaDebugPrint(false);
|
||||||
|
|
||||||
|
if (LoRaBegin(frequencyInHz, txPowerInDbm, tcxoVoltage, useRegulatorLDO) != 0)
|
||||||
|
{
|
||||||
|
ESP_LOGE(TAG, "LoRa module not recognized. Halting.");
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
vTaskDelay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t spreadingFactor = 8;
|
||||||
|
uint8_t bandwidth = SX126X_LORA_BW_250_0;
|
||||||
|
uint8_t codingRate = SX126X_LORA_CR_4_8;
|
||||||
|
uint16_t preambleLength = 4;
|
||||||
|
bool crcOn = true;
|
||||||
|
bool invertIrq = false;
|
||||||
|
|
||||||
|
LoRaConfig(spreadingFactor, bandwidth, codingRate, preambleLength, 0, crcOn, invertIrq);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
writeFile(sensFile, data, size);
|
||||||
|
|
||||||
|
if (!LoRaSend(data, size, SX126x_TXMODE_SYNC))
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "LoRaSend failed");
|
||||||
|
xSemaphoreGive(loraRadioMutex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "%d byte packet sent", size);
|
||||||
|
xSemaphoreGive(loraRadioMutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGE(TAG, "Failed to send packet after %d retries", MAX_RETRIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
vTaskDelay(pdMS_TO_TICKS((interval_us - elapsed) / 1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
main/components/radio.h
Normal file
21
main/components/radio.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef RADIO_COMPONENT
|
||||||
|
#define RADIO_COMPONENT
|
||||||
|
|
||||||
|
#define LORA_POWER_LOW 2
|
||||||
|
#define LORA_POWER_HIGH 20
|
||||||
|
#define LORA_POWER_MAX_MAYBE_UNSAFE 22
|
||||||
|
|
||||||
|
#define LORA_TX_POWER LORA_POWER_LOW
|
||||||
|
|
||||||
|
#define TAG_RADIO "RADIO"
|
||||||
|
|
||||||
|
#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
128
main/components/sdcard.c
Normal 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
26
main/components/sdcard.h
Normal 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
|
@@ -1,76 +1,237 @@
|
|||||||
#include "sensors.h"
|
#include "sensors.h"
|
||||||
|
#include "esp_timer.h"
|
||||||
|
#include "radio.h"
|
||||||
|
#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
|
#define BLINK_GPIO 2
|
||||||
|
|
||||||
|
// uint8_t powerMode = LOW_POWER_MODE;
|
||||||
|
uint8_t powerMode = HIGH_POWER_MODE;
|
||||||
|
|
||||||
static uint8_t s_led_state = 0;
|
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)
|
static void configure_led(void)
|
||||||
{
|
{
|
||||||
gpio_reset_pin(BLINK_GPIO);
|
gpio_reset_pin(BLINK_GPIO);
|
||||||
gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
|
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)
|
void i2c_sensors_task(void *pvParameters)
|
||||||
{
|
{
|
||||||
// initialize the xLastWakeTime variable with the current time.
|
|
||||||
TickType_t last_wake_time = xTaskGetTickCount();
|
|
||||||
const TickType_t I2C0_TASK_SAMPLING_RATE = 5;
|
|
||||||
//
|
memset(foundDevices, 0, sizeof(foundDevices));
|
||||||
// initialize i2c device configuration
|
memset(prevDevices, 0, sizeof(prevDevices));
|
||||||
|
|
||||||
bme680b_init();
|
bme680b_init();
|
||||||
mpu9250_init();
|
mpu9250_init();
|
||||||
mcp23018_init();
|
|
||||||
ina260_init();
|
|
||||||
ccs811_init();
|
ccs811_init();
|
||||||
|
ina260_init();
|
||||||
|
|
||||||
|
// update_devices();
|
||||||
|
// init_connected();
|
||||||
|
// initialize the xLastWakeTime variable with the current time.
|
||||||
|
const int64_t interval_us = 50000; // 50 ms
|
||||||
|
int64_t start_time, end_time, elapsed;
|
||||||
|
|
||||||
|
//
|
||||||
|
// initialize i2c device configuration
|
||||||
|
|
||||||
configure_led();
|
configure_led();
|
||||||
|
|
||||||
int16_t accel[3], gyro[3], temp;
|
int16_t accel[3], gyro[3], temp, magnet[3];
|
||||||
float accel_f[3], gyro_f[3], temp_f;
|
float accel_f[3], gyro_f[3], temp_f, magnet_f[3];
|
||||||
|
|
||||||
uint16_t eCO2;
|
uint16_t eCO2;
|
||||||
uint16_t tvoc;
|
uint16_t tvoc;
|
||||||
|
uint8_t currentCCS;
|
||||||
|
uint16_t rawData;
|
||||||
|
|
||||||
uint16_t volts;
|
uint16_t volts;
|
||||||
uint16_t current;
|
uint16_t current;
|
||||||
uint16_t power;
|
uint16_t power;
|
||||||
|
|
||||||
|
bme680_data_t bmeData;
|
||||||
|
|
||||||
|
mics_adc_data_t ADCData;
|
||||||
// task loop entry point
|
// task loop entry point
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
start_time = esp_timer_get_time(); // µs since boot
|
||||||
|
|
||||||
|
uint8_t presentDevices = 0xFF;
|
||||||
|
// update_devices();
|
||||||
|
// init_connected();
|
||||||
|
|
||||||
//
|
//
|
||||||
// handle sensor
|
// handle sensor
|
||||||
|
|
||||||
|
presentDevices |= BME680_PRESENT_BIT;
|
||||||
|
|
||||||
if (BME680_DEV_HANDLE)
|
if (BME680_DEV_HANDLE)
|
||||||
{
|
{
|
||||||
bme680_data_t data;
|
esp_err_t result = bme680_get_data(BME680_DEV_HANDLE, &bmeData);
|
||||||
esp_err_t result = bme680_get_data(BME680_DEV_HANDLE, &data);
|
|
||||||
if (result != ESP_OK)
|
if (result != ESP_OK)
|
||||||
{
|
{
|
||||||
ESP_LOGE(TAG_BME, "bme680 device read failed (%s)", esp_err_to_name(result));
|
ESP_LOGE(TAG_BME, "bme680 device read failed (%s)", esp_err_to_name(result));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
data.barometric_pressure = data.barometric_pressure / 100;
|
bmeData.barometric_pressure = bmeData.barometric_pressure / 100;
|
||||||
// ESP_LOGI(TAG, "dewpoint temperature:%.2f °C", data.dewpoint_temperature);
|
ESP_LOGI(TAG_BME, "dewpoint temperature:%.2f °C", bmeData.dewpoint_temperature);
|
||||||
ESP_LOGI(TAG_BME, "air temperature: %.2f °C", data.air_temperature);
|
ESP_LOGI(TAG_BME, "air temperature: %.2f °C", bmeData.air_temperature);
|
||||||
ESP_LOGI(TAG_BME, "relative humidity: %.2f %%", data.relative_humidity);
|
ESP_LOGI(TAG_BME, "relative humidity: %.2f %%", bmeData.relative_humidity);
|
||||||
ESP_LOGI(TAG_BME, "barometric pressure: %.2f hPa", data.barometric_pressure);
|
ESP_LOGI(TAG_BME, "barometric pressure: %.2f hPa", bmeData.barometric_pressure);
|
||||||
// ESP_LOGI(TAG, "gas resistance: %.2f kOhms", data.gas_resistance / 1000);
|
ccs811_set_env_data(bmeData.air_temperature, bmeData.relative_humidity);
|
||||||
// ESP_LOGI(TAG, "iaq score: %u (%s)", data.iaq_score, bme680_air_quality_to_string(data.iaq_score));
|
ESP_LOGI(TAG_BME, "gas resistance: %.2f kOhms", bmeData.gas_resistance / 1000);
|
||||||
|
ESP_LOGI(TAG_BME, "iaq score: %u (%s)", bmeData.iaq_score, bme680_air_quality_to_string(bmeData.iaq_score));
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
bme680b_init();
|
bme680b_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
ccs811_get_data(&eCO2, &tvoc);
|
presentDevices |= CCS811_PRESENT_BIT;
|
||||||
|
ccs811_get_data(&eCO2, &tvoc, ¤tCCS, &rawData);
|
||||||
ESP_LOGI(TAG_CCS, "eCO₂: %d ppm, TVOC: %d ppb", eCO2, tvoc);
|
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);
|
||||||
|
|
||||||
if (mpu9250_read_sensor_data(MPU9250_DEV_HANDLE, accel, gyro, &temp) == ESP_OK)
|
presentDevices |= MPU9250_PRESENT_BIT;
|
||||||
|
if (mpu9250_read_sensor_data(MPU9250_DEV_HANDLE, accel, gyro, &temp, magnet) == ESP_OK)
|
||||||
{
|
{
|
||||||
mpu9250_convert_data(accel, gyro, temp, accel_f, gyro_f, &temp_f);
|
mpu9250_convert_data(accel, gyro, temp, magnet, accel_f, gyro_f, &temp_f, magnet_f);
|
||||||
|
|
||||||
ESP_LOGI(TAG_MPU, "Accel: X=%.2f g, Y=%.2f g, Z=%.2f g", accel_f[0], accel_f[1], accel_f[2]);
|
ESP_LOGI(TAG_MPU, "Accel: X=%.2f g, Y=%.2f g, Z=%.2f g", accel_f[0], accel_f[1], accel_f[2]);
|
||||||
ESP_LOGI(TAG_MPU, "Gyro: X=%.2f°/s, Y=%.2f°/s, Z=%.2f°/s", gyro_f[0], gyro_f[1], gyro_f[2]);
|
ESP_LOGI(TAG_MPU, "Gyro: X=%.2f°/s, Y=%.2f°/s, Z=%.2f°/s", gyro_f[0], gyro_f[1], gyro_f[2]);
|
||||||
|
ESP_LOGI(TAG_MPU, "Magnet: X=%.2fμT, Y=%.2fμT, Z=%.2fμT", magnet_f[0], magnet_f[1], magnet_f[2]);
|
||||||
ESP_LOGI(TAG_MPU, "Temperature: %.2f °C", temp_f);
|
ESP_LOGI(TAG_MPU, "Temperature: %.2f °C", temp_f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -78,13 +239,97 @@ void i2c_sensors_task(void *pvParameters)
|
|||||||
ESP_LOGE(TAG_MPU, "Failed to read sensor data");
|
ESP_LOGE(TAG_MPU, "Failed to read sensor data");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
presentDevices |= INA260_PRESENT_BIT;
|
||||||
ina260_readParams(&volts, ¤t, &power);
|
ina260_readParams(&volts, ¤t, &power);
|
||||||
ina260_printParams(volts, current, power);
|
ina260_printParams(volts, current, power);
|
||||||
|
|
||||||
gpio_set_level(BLINK_GPIO, s_led_state);
|
presentDevices |= MCP23018_PRESENT_BIT;
|
||||||
/* Toggle the LED state */
|
float VREFVoltage = 2.5;
|
||||||
|
ADCData = mcp3550_read_all(VREFVoltage);
|
||||||
|
|
||||||
|
log_mics_adc_values(&ADCData);
|
||||||
|
|
||||||
|
if (packetReadiness == 0)
|
||||||
|
{
|
||||||
|
memset(&telemetryPacket, 0, sizeof(telemetryPacket));
|
||||||
|
telemetryPacket.accelerationX = accel[0];
|
||||||
|
telemetryPacket.accelerationY = accel[1];
|
||||||
|
telemetryPacket.accelerationZ = accel[2];
|
||||||
|
|
||||||
|
telemetryPacket.gyroX = gyro[0];
|
||||||
|
telemetryPacket.gyroX = gyro[1];
|
||||||
|
telemetryPacket.gyroX = gyro[2];
|
||||||
|
|
||||||
|
telemetryPacket.magnetX = gyro[0];
|
||||||
|
telemetryPacket.magnetX = gyro[1];
|
||||||
|
telemetryPacket.magnetX = gyro[2];
|
||||||
|
|
||||||
|
telemetryPacket.accelerometer_temperature = temp;
|
||||||
|
|
||||||
|
telemetryPacket.eCO2 = eCO2;
|
||||||
|
telemetryPacket.tvoc = tvoc;
|
||||||
|
telemetryPacket.currentCCS = currentCCS;
|
||||||
|
telemetryPacket.rawCCSData = rawData;
|
||||||
|
|
||||||
|
telemetryPacket.volts = volts;
|
||||||
|
telemetryPacket.current = current;
|
||||||
|
telemetryPacket.power = power;
|
||||||
|
|
||||||
|
telemetryPacket.temperature = bmeData.raw_data.temperature;
|
||||||
|
telemetryPacket.humidity = bmeData.raw_data.humidity;
|
||||||
|
telemetryPacket.pressure = bmeData.raw_data.pressure;
|
||||||
|
telemetryPacket.gas = bmeData.raw_data.gas;
|
||||||
|
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
|
||||||
|
telemetryPacket.time_seconds = gpsDataOut.time_seconds;
|
||||||
|
telemetryPacket.latitude_centi_degrees = gpsDataOut.latitude_centi_degrees;
|
||||||
|
telemetryPacket.longitude_centi_degrees = gpsDataOut.longitude_centi_degrees;
|
||||||
|
telemetryPacket.fix_quality = gpsDataOut.fix_quality;
|
||||||
|
telemetryPacket.num_satellites = gpsDataOut.num_satellites;
|
||||||
|
telemetryPacket.altitude_centi_meters = gpsDataOut.altitude_centi_meters;
|
||||||
|
telemetryPacket.date_yyddmm = gpsDataOut.date_yyddmm;
|
||||||
|
telemetryPacket.speed_centi_knots = gpsDataOut.speed_centi_knots;
|
||||||
|
|
||||||
|
telemetryPacket.predicted_altitude_centi_meters = predictedPosition.altitude_centi_meters;
|
||||||
|
telemetryPacket.predicted_latitude_centi_degrees = predictedPosition.latitude_centi_degrees;
|
||||||
|
telemetryPacket.predicted_longitude_centi_degrees = predictedPosition.longitude_centi_degrees;
|
||||||
|
|
||||||
|
telemetryPacket.targetServoA = servoState.targetServoA;
|
||||||
|
telemetryPacket.targetServoB = servoState.targetServoB;
|
||||||
|
telemetryPacket.currentServoA = servoState.currentServoA;
|
||||||
|
telemetryPacket.currentServoB = servoState.currentServoB;
|
||||||
|
|
||||||
|
telemetryPacket.presentDevices = presentDevices;
|
||||||
|
|
||||||
|
telemetryPacket.telemetryIndex = telemetryIndex++;
|
||||||
|
}
|
||||||
|
packetReadiness = 1;
|
||||||
|
|
||||||
s_led_state = !s_led_state;
|
s_led_state = !s_led_state;
|
||||||
vTaskDelaySecUntil(&last_wake_time, I2C0_TASK_SAMPLING_RATE);
|
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
|
// free resources
|
||||||
|
@@ -7,6 +7,8 @@
|
|||||||
#include <bme680.h>
|
#include <bme680.h>
|
||||||
#include "esp_mac.h"
|
#include "esp_mac.h"
|
||||||
|
|
||||||
|
#include "../hw/mcp3550.h"
|
||||||
|
|
||||||
#include "../hw/bme680b.h"
|
#include "../hw/bme680b.h"
|
||||||
#include "../hw/ccs811.h"
|
#include "../hw/ccs811.h"
|
||||||
#include "../hw/i2cbrn.h"
|
#include "../hw/i2cbrn.h"
|
||||||
@@ -16,8 +18,18 @@
|
|||||||
#include "../hw/mpu9250.h"
|
#include "../hw/mpu9250.h"
|
||||||
#include "esp_log.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);
|
void i2c_sensors_task(void *pvParameters);
|
||||||
|
|
||||||
#endif
|
#endif
|
10
main/components/servocontroller.c
Normal file
10
main/components/servocontroller.c
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include "servocontroller.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
ServoState servoState;
|
||||||
|
|
||||||
|
//TODO add a task and implement
|
||||||
|
|
||||||
|
void servoControllerInit() {
|
||||||
|
memset(&servoState, 0, sizeof(servoState));
|
||||||
|
}
|
19
main/components/servocontroller.h
Normal file
19
main/components/servocontroller.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef SERVO_CONTROLLER_COMPONENT
|
||||||
|
#define SERVO_CONTROLLER_COMPONENT
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int16_t currentServoA;
|
||||||
|
int16_t targetServoA;
|
||||||
|
int16_t currentServoB;
|
||||||
|
int16_t targetServoB;
|
||||||
|
} ServoState;
|
||||||
|
|
||||||
|
|
||||||
|
extern ServoState servoState;
|
||||||
|
|
||||||
|
void servoControllerInit();
|
||||||
|
|
||||||
|
#endif
|
@@ -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));
|
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
|
// 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)
|
if (BME680_DEV_HANDLE == NULL)
|
||||||
{
|
{
|
||||||
ESP_LOGE(TAG_BME, "bme680 handle init failed");
|
ESP_LOGE(TAG_BME, "bme680 handle init failed");
|
||||||
} else {
|
} else {
|
||||||
bme680_print_registers(BME680_DEV_HANDLE);
|
bme680_print_registers(BME680_DEV_HANDLE);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
@@ -8,6 +8,6 @@ extern bme680_config_t BME680_DEV_CFG;
|
|||||||
extern bme680_handle_t BME680_DEV_HANDLE;
|
extern bme680_handle_t BME680_DEV_HANDLE;
|
||||||
|
|
||||||
void bme680_print_registers(bme680_handle_t handle);
|
void bme680_print_registers(bme680_handle_t handle);
|
||||||
void bme680b_init();
|
esp_err_t bme680b_init();
|
||||||
|
|
||||||
#endif
|
#endif
|
80
main/hw/buscfg.h
Normal file
80
main/hw/buscfg.h
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#ifndef BUSCFG_FILE
|
||||||
|
#define BUSCFG_FILE
|
||||||
|
|
||||||
|
#include "soc/gpio_num.h"
|
||||||
|
|
||||||
|
#define ESP_USB_DP GPIO_NUM_20
|
||||||
|
#define ESP_USB_DM GPIO_NUM_19
|
||||||
|
#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
|
||||||
|
#define ESP_CONNECTOR_P4 GPIO_NUM_39
|
||||||
|
#define ESP_CONNECTOR_P5 GPIO_NUM_38
|
||||||
|
#define ESP_CONNECTOR_P6 HSPI_UNKNOWN_CS
|
||||||
|
#define ESP_CONNECTOR_P9 HSPI_MISO_GPIO
|
||||||
|
#define ESP_CONNECTOR_P10 MCP3550_MOSI_GPIO
|
||||||
|
#define ESP_CONNECTOR_P11 MCP3550_SCK_GPIO
|
||||||
|
#define ESP_CONNECTOR_P12 HSPI_SD_CS
|
||||||
|
#define ESP_CONNECTOR_P13 HSPI_LORA_CS
|
||||||
|
#define ESP_CONNECTOR_P17 HWI2C_SDA
|
||||||
|
#define ESP_CONNECTOR_P18 HWI2C_SCL
|
||||||
|
#define ESP_CONNECTOR_P19 I2C2_SDA
|
||||||
|
#define ESP_CONNECTOR_P20 I2C2_SCL
|
||||||
|
#define ESP_CONNECTOR_P25 LORA_DIO1
|
||||||
|
#define ESP_CONNECTOR_P26 LORA_BUSY
|
||||||
|
#define ESP_CONNECTOR_P27 LORA_RXEN_MANUAL
|
||||||
|
#define ESP_CONNECTOR_P28 GPIO_NUM_6
|
||||||
|
#define ESP_CONNECTOR_P29 GPIO_NUM_5
|
||||||
|
#define ESP_CONNECTOR_P30 GPIO_NUM_4
|
||||||
|
#define ESP_CONNECTOR_P47 GPS_RXD
|
||||||
|
#define ESP_CONNECTOR_P48 GPS_TXD
|
||||||
|
#define ESP_CONNECTOR_P51 ESP_RXD0
|
||||||
|
#define ESP_CONNECTOR_P52 ESP_TXD0
|
||||||
|
#define ESP_CONNECTOR_P57 ESP_USB_DP
|
||||||
|
#define ESP_CONNECTOR_P58 ESP_USB_DM
|
||||||
|
|
||||||
|
|
||||||
|
#define HSPI_UNKNOWN_CS GPIO_NUM_42
|
||||||
|
#define LORA_RXEN_MANUAL GPIO_NUM_7
|
||||||
|
|
||||||
|
#define HSPI_MISO_GPIO GPIO_NUM_13
|
||||||
|
#define HSPI_MOSI_GPIO GPIO_NUM_11
|
||||||
|
|
||||||
|
#define HSPI_SCK_GPIO GPIO_NUM_12
|
||||||
|
#define HSPI_LORA_CS GPIO_NUM_48
|
||||||
|
#define LORA_DIO1 GPIO_NUM_16
|
||||||
|
#define LORA_BUSY GPIO_NUM_15
|
||||||
|
#define HSPI_SD_CS GPIO_NUM_10
|
||||||
|
|
||||||
|
#define MCP3550_MOSI_GPIO GPIO_NUM_35
|
||||||
|
#define MCP3550_SCK_GPIO GPIO_NUM_36
|
||||||
|
#define MCP3550_MISO_GPIO GPIO_NUM_37
|
||||||
|
|
||||||
|
#define GPS_TXD GPIO_NUM_17
|
||||||
|
#define GPS_RXD GPIO_NUM_18
|
||||||
|
#define GPS_RTS UART_PIN_NO_CHANGE
|
||||||
|
#define GPS_CTS UART_PIN_NO_CHANGE
|
||||||
|
|
||||||
|
#define GPS_UART_NUM UART_NUM_2
|
||||||
|
|
||||||
|
#define HWI2C_SDA GPIO_NUM_8
|
||||||
|
#define HWI2C_SCL GPIO_NUM_9
|
||||||
|
#define I2C2_SDA GPIO_NUM_40
|
||||||
|
#define I2C2_SCL GPIO_NUM_41
|
||||||
|
|
||||||
|
#endif
|
102
main/hw/ccs811.c
102
main/hw/ccs811.c
@@ -1,46 +1,86 @@
|
|||||||
#include "ccs811.h"
|
#include "ccs811.h"
|
||||||
|
|
||||||
#define CONFIG_FREERTOS_HZ 100
|
|
||||||
|
|
||||||
i2c_device_config_t CCS811_DEV_CFG = {
|
i2c_device_config_t CCS811_DEV_CFG = {
|
||||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||||
.device_address = 0x5A,
|
.device_address = CCS811_ADDRESS,
|
||||||
.scl_speed_hz = 100000,
|
.scl_speed_hz = 100000,
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c_master_dev_handle_t CCS811_DEV_HANDLE;
|
i2c_master_dev_handle_t CCS811_DEV_HANDLE;
|
||||||
|
|
||||||
void ccs811_init()
|
esp_err_t ccs811_getStatus()
|
||||||
{
|
{
|
||||||
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c0_bus_hdl, &CCS811_DEV_CFG, &CCS811_DEV_HANDLE));
|
uint8_t errorID;
|
||||||
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_CCS811_WAKE, 0);
|
|
||||||
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_CCS811_POWER, 1);
|
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
||||||
uint8_t reset_seq[4] = {0x11, 0xE5, 0x72, 0x8A};
|
|
||||||
i2c_write_register(CCS811_DEV_HANDLE, 0xFF, reset_seq, sizeof(reset_seq)); //Reset
|
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
|
uint8_t hardwareVersion;
|
||||||
uint16_t version;
|
uint16_t version;
|
||||||
i2c_read_register_8(CCS811_DEV_HANDLE, 0x00, &status);
|
uint16_t bootVersion;
|
||||||
i2c_read_register_16(CCS811_DEV_HANDLE, 0x24, &version);
|
|
||||||
ESP_LOGW(TAG_CCS, "CCS811 status: %d, version: %d", status, version);
|
|
||||||
i2c_write_register(CCS811_DEV_HANDLE, 0xF4, NULL, 0); //start
|
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
||||||
i2c_write_register_8(CCS811_DEV_HANDLE, 0x10, 0x0001); // MODE 1 interrupts vypnuté
|
|
||||||
i2c_read_register_8(CCS811_DEV_HANDLE, 0x00, &status);
|
|
||||||
i2c_read_register_16(CCS811_DEV_HANDLE, 0x24, &version);
|
|
||||||
ESP_LOGW(TAG_CCS, "CCS811 status: %d, version: %d", status, version);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t ccs811_get_data(uint16_t * eCO2, uint16_t * tvoc)
|
esp_err_t ret = i2c_read_register_8(CCS811_DEV_HANDLE, CCS811_REG_STATUS, &status);
|
||||||
{
|
if (ret != ESP_OK) {return ret;}
|
||||||
uint8_t ccsResult[8];
|
ret = i2c_read_register_16(CCS811_DEV_HANDLE, CCS811_REG_FW_APP_VERSION, &version);
|
||||||
esp_err_t ret = i2c_read_register(CCS811_DEV_HANDLE, 0x05, ccsResult, 8);
|
if (ret != ESP_OK) {return ret;}
|
||||||
if (ret == ESP_OK)
|
ret = i2c_read_register_16(CCS811_DEV_HANDLE, CCS811_REG_FW_BOOT_VERSION, &bootVersion);
|
||||||
{
|
if (ret != ESP_OK) {return ret;}
|
||||||
*eCO2 = (((uint16_t)(ccsResult[0] & 0xFF)) << 8) | (ccsResult[1] & 0xFF);
|
ret = i2c_read_register_8(CCS811_DEV_HANDLE, CCS811_REG_HW_VERSION, &hardwareVersion);
|
||||||
*tvoc = (((uint16_t)(ccsResult[2] & 0xFF)) << 8) | (ccsResult[3] & 0xFF);
|
if (ret != ESP_OK) {return ret;}
|
||||||
ESP_LOGI(TAG_CCS, "CCS Status: %d, Error %d", ccsResult[4], ccsResult[5]);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t ccs811_init()
|
||||||
|
{
|
||||||
|
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};
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
uint8_t algResultData[8];
|
||||||
|
esp_err_t ret = i2c_read_register(CCS811_DEV_HANDLE, CCS811_REG_ALG_RESULT_DATA, algResultData, 8);
|
||||||
|
|
||||||
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
|
*eCO2 = ((uint16_t)algResultData[0] << 8) | algResultData[1];
|
||||||
|
*tvoc = ((uint16_t)algResultData[2] << 8) | algResultData[3];
|
||||||
|
*current = algResultData[6] >> 2;
|
||||||
|
*rawData = ((uint16_t)(algResultData[6] & 0x03) << 8) | algResultData[7];
|
||||||
|
|
||||||
|
ESP_LOGI(TAG_CCS, "CCS Status: %d, Error: %d", algResultData[4], algResultData[5]);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t ccs811_set_env_data(float temperature, float humidity)
|
||||||
|
{
|
||||||
|
uint8_t envData[4];
|
||||||
|
|
||||||
|
// Convert humidity: %RH × 512 (rounding)
|
||||||
|
uint16_t hum_conv = (uint16_t)(humidity * 512.0f + 0.5f);
|
||||||
|
envData[0] = (hum_conv >> 8) & 0xFF;
|
||||||
|
envData[1] = hum_conv & 0xFF;
|
||||||
|
|
||||||
|
// Convert temperature: (°C + 25) × 512
|
||||||
|
uint16_t temp_conv = (uint16_t)((temperature + 25.0f) * 512.0f + 0.5f);
|
||||||
|
envData[2] = (temp_conv >> 8) & 0xFF;
|
||||||
|
envData[3] = temp_conv & 0xFF;
|
||||||
|
|
||||||
|
return i2c_write_register(CCS811_DEV_HANDLE, CCS811_REG_ENV_DATA, envData, 4);
|
||||||
|
}
|
||||||
|
@@ -5,11 +5,39 @@
|
|||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#define TAG_CCS "CCS811"
|
#define TAG_CCS "CCS811"
|
||||||
|
|
||||||
|
// CCS811 Registers
|
||||||
|
#define CCS811_REG_STATUS 0x00
|
||||||
|
#define CCS811_REG_MEAS_MODE 0x01
|
||||||
|
#define CCS811_REG_ALG_RESULT_DATA 0x02
|
||||||
|
#define CCS811_REG_RAW_DATA 0x03
|
||||||
|
#define CCS811_REG_ENV_DATA 0x05
|
||||||
|
#define CCS811_REG_THRESHOLDS 0x10
|
||||||
|
#define CCS811_REG_BASELINE 0x11
|
||||||
|
#define CCS811_REG_HW_ID 0x20
|
||||||
|
#define CCS811_REG_HW_VERSION 0x21
|
||||||
|
#define CCS811_REG_FW_BOOT_VERSION 0x23
|
||||||
|
#define CCS811_REG_FW_APP_VERSION 0x24
|
||||||
|
#define CCS811_REG_INTERNAL_STATE 0xA0
|
||||||
|
#define CCS811_REG_ERROR_ID 0xE0
|
||||||
|
#define CCS811_REG_APP_ERASE 0xF1
|
||||||
|
#define CCS811_REG_APP_DATA 0xF2
|
||||||
|
#define CCS811_REG_APP_VERIFY 0xF3
|
||||||
|
#define CCS811_REG_APP_START 0xF4
|
||||||
|
#define CCS811_REG_SW_RESET 0xFF
|
||||||
|
|
||||||
|
// Measurement Modes
|
||||||
|
#define CCS811_MODE_IDLE 0x00
|
||||||
|
#define CCS811_MODE_CONSTANT_1S 0x10
|
||||||
|
#define CCS811_MODE_CONSTANT_10S 0x20
|
||||||
|
#define CCS811_MODE_CONSTANT_60S 0x30
|
||||||
|
#define CCS811_MODE_WAKEUP 0x40
|
||||||
|
|
||||||
extern i2c_device_config_t CCS811_DEV_CFG;
|
extern i2c_device_config_t CCS811_DEV_CFG;
|
||||||
|
|
||||||
extern i2c_master_dev_handle_t CCS811_DEV_HANDLE;
|
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);
|
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
|
#endif
|
245
main/hw/gps.c
Normal file
245
main/hw/gps.c
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
#include "driver/uart.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "gps.h"
|
||||||
|
|
||||||
|
#define TAG "GPS"
|
||||||
|
#define BUF_SIZE 1024
|
||||||
|
#define GPS_LINE_MAX_LEN 128
|
||||||
|
|
||||||
|
gps_binary_struct_t gpsDataOut;
|
||||||
|
static QueueHandle_t uart_queue;
|
||||||
|
|
||||||
|
predicted_binary_position_struct_t predictedPosition;
|
||||||
|
|
||||||
|
// Initializes UART for GPS
|
||||||
|
void gps_init()
|
||||||
|
{
|
||||||
|
memset(&gpsDataOut, 0, sizeof(gpsDataOut));
|
||||||
|
uart_config_t uart_config = {
|
||||||
|
.baud_rate = 9600,
|
||||||
|
.data_bits = UART_DATA_8_BITS,
|
||||||
|
.parity = UART_PARITY_DISABLE,
|
||||||
|
.stop_bits = UART_STOP_BITS_1,
|
||||||
|
.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
|
||||||
|
.rx_flow_ctrl_thresh = 122,
|
||||||
|
};
|
||||||
|
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_WITHOUT_ABORT(uart_driver_install(GPS_UART_NUM, uart_buffer_size, uart_buffer_size, 10, &uart_queue, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void gps_task(void *arg)
|
||||||
|
{
|
||||||
|
uint8_t byte;
|
||||||
|
char line[GPS_LINE_MAX_LEN];
|
||||||
|
size_t line_pos = 0;
|
||||||
|
|
||||||
|
gps_init();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int len = uart_read_bytes(GPS_UART_NUM, &byte, 1, pdMS_TO_TICKS(1000));
|
||||||
|
if (len > 0) {
|
||||||
|
if (byte == '\n') {
|
||||||
|
line[line_pos] = '\0';
|
||||||
|
|
||||||
|
if (line[0] == '$') {
|
||||||
|
ESP_LOGI(TAG, "Received NMEA: %s", line);
|
||||||
|
|
||||||
|
if (strstr(line, "$GNGGA") == line) {
|
||||||
|
parse_gpgga(line);
|
||||||
|
parse_gpgga_to_struct(line, &gpsDataOut);
|
||||||
|
} else if (strstr(line, "$GPRMC") == line) {
|
||||||
|
parse_gprmc(line);
|
||||||
|
parse_gprmc_to_struct(line, &gpsDataOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
line_pos = 0;
|
||||||
|
} else if (byte != '\r' && line_pos < (GPS_LINE_MAX_LEN - 1)) {
|
||||||
|
line[line_pos++] = byte;
|
||||||
|
} else if (line_pos >= GPS_LINE_MAX_LEN - 1) {
|
||||||
|
ESP_LOGW(TAG, "Line too long, discarded");
|
||||||
|
line_pos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_gpgga(const char *nmea) {
|
||||||
|
char *fields[15];
|
||||||
|
char temp[GPS_LINE_MAX_LEN];
|
||||||
|
strncpy(temp, nmea, GPS_LINE_MAX_LEN);
|
||||||
|
temp[GPS_LINE_MAX_LEN - 1] = '\0';
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
char *token = strtok(temp, ",");
|
||||||
|
while (token != NULL && i < 15) {
|
||||||
|
fields[i++] = token;
|
||||||
|
token = strtok(NULL, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < 10) return; // Not enough fields
|
||||||
|
|
||||||
|
// Time (hhmmss.sss)
|
||||||
|
const char *utc_time = fields[1];
|
||||||
|
|
||||||
|
// Latitude (ddmm.mmmm)
|
||||||
|
const char *lat = fields[2];
|
||||||
|
const char *lat_dir = fields[3];
|
||||||
|
|
||||||
|
// Longitude (dddmm.mmmm)
|
||||||
|
const char *lon = fields[4];
|
||||||
|
const char *lon_dir = fields[5];
|
||||||
|
|
||||||
|
// Fix quality (0 = invalid, 1 = GPS fix, 2 = DGPS fix)
|
||||||
|
const char *fix_quality = fields[6];
|
||||||
|
|
||||||
|
// Number of satellites
|
||||||
|
const char *num_satellites = fields[7];
|
||||||
|
|
||||||
|
// Altitude
|
||||||
|
const char *altitude = fields[9];
|
||||||
|
|
||||||
|
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) {
|
||||||
|
char *fields[13];
|
||||||
|
char temp[GPS_LINE_MAX_LEN];
|
||||||
|
strncpy(temp, nmea, GPS_LINE_MAX_LEN);
|
||||||
|
temp[GPS_LINE_MAX_LEN - 1] = '\0';
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
char *token = strtok(temp, ",");
|
||||||
|
while (token != NULL && i < 13) {
|
||||||
|
fields[i++] = token;
|
||||||
|
token = strtok(NULL, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < 12) return;
|
||||||
|
|
||||||
|
const char *utc_time = fields[1];
|
||||||
|
const char *status = fields[2]; // A = active, V = void
|
||||||
|
const char *lat = fields[3];
|
||||||
|
const char *lat_dir = fields[4];
|
||||||
|
const char *lon = fields[5];
|
||||||
|
const char *lon_dir = fields[6];
|
||||||
|
const char *speed_knots = fields[7];
|
||||||
|
const char *date = fields[9];
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Function to convert time string (hhmmss.sss) to seconds since start of day
|
||||||
|
static uint32_t time_to_seconds_struct(const char *time_str) {
|
||||||
|
if (time_str == NULL || strlen(time_str) < 6) return 0;
|
||||||
|
uint32_t hours = (time_str[0] - '0') * 10 + (time_str[1] - '0');
|
||||||
|
uint32_t minutes = (time_str[2] - '0') * 10 + (time_str[3] - '0');
|
||||||
|
uint32_t seconds = (time_str[4] - '0') * 10 + (time_str[5] - '0');
|
||||||
|
return hours * 3600 + minutes * 60 + seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 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];
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to convert date string (ddmmyy) to yymmdd integer
|
||||||
|
static uint16_t date_to_yyddmm_struct(const char *date_str) {
|
||||||
|
if (date_str == NULL || strlen(date_str) != 6) return 0;
|
||||||
|
uint16_t day = (date_str[0] - '0') * 10 + (date_str[1] - '0');
|
||||||
|
uint16_t month = (date_str[2] - '0') * 10 + (date_str[3] - '0');
|
||||||
|
uint16_t year_short = (date_str[4] - '0') * 10 + (date_str[5] - '0');
|
||||||
|
// Assuming year is in the 21st century for simplicity
|
||||||
|
return (2000 + year_short) * 10000 + month * 100 + day;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to parse GPGGA NMEA string and return the struct
|
||||||
|
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);
|
||||||
|
temp[GPS_LINE_MAX_LEN - 1] = '\0';
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
char *token = strtok(temp, ",");
|
||||||
|
while (token != NULL && i < 15) {
|
||||||
|
fields[i++] = token;
|
||||||
|
token = strtok(NULL, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= 10) {
|
||||||
|
data->time_seconds = time_to_seconds_struct(fields[1]);
|
||||||
|
data->latitude_centi_degrees = dms_to_centi_degrees_struct(fields[2], fields[3]);
|
||||||
|
data->longitude_centi_degrees = dms_to_centi_degrees_struct(fields[4], fields[5]);
|
||||||
|
data->fix_quality = atoi(fields[6]);
|
||||||
|
data->num_satellites = atoi(fields[7]);
|
||||||
|
data->altitude_centi_meters = altitude_to_centi_meters_struct(fields[9]);
|
||||||
|
} else {
|
||||||
|
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) {
|
||||||
|
char *fields[13];
|
||||||
|
char temp[GPS_LINE_MAX_LEN];
|
||||||
|
strncpy(temp, nmea, GPS_LINE_MAX_LEN);
|
||||||
|
temp[GPS_LINE_MAX_LEN - 1] = '\0';
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
char *token = strtok(temp, ",");
|
||||||
|
while (token != NULL && i < 13) {
|
||||||
|
fields[i++] = token;
|
||||||
|
token = strtok(NULL, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= 12) {
|
||||||
|
data->time_seconds = time_to_seconds_struct(fields[1]);
|
||||||
|
data->latitude_centi_degrees = dms_to_centi_degrees_struct(fields[3], fields[4]);
|
||||||
|
data->longitude_centi_degrees = dms_to_centi_degrees_struct(fields[5], fields[6]);
|
||||||
|
data->date_yyddmm = date_to_yyddmm_struct(fields[9]);
|
||||||
|
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 {
|
||||||
|
printf("GPRMC: Not enough fields to parse struct");
|
||||||
|
}
|
||||||
|
}
|
39
main/hw/gps.h
Normal file
39
main/hw/gps.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef GPS_COMPONENT
|
||||||
|
#define GPS_COMPONENT
|
||||||
|
|
||||||
|
#include "driver/uart.h"
|
||||||
|
#include "soc/uart_struct.h"
|
||||||
|
#include "buscfg.h"
|
||||||
|
|
||||||
|
// Structure to hold parsed GPS data in a compact binary format
|
||||||
|
typedef struct {
|
||||||
|
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
|
||||||
|
uint8_t fix_quality;
|
||||||
|
uint8_t num_satellites;
|
||||||
|
int16_t altitude_centi_meters; // Altitude * 100
|
||||||
|
uint16_t date_yyddmm; // YYDDMM (from GPRMC)
|
||||||
|
uint16_t speed_centi_knots; // Speed * 100 (from GPRMC)
|
||||||
|
} gps_binary_struct_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t latitude_centi_degrees; // Latitude * 10,000
|
||||||
|
int32_t longitude_centi_degrees; // Longitude * 10,000
|
||||||
|
int16_t altitude_centi_meters; // Altitude * 100
|
||||||
|
} predicted_binary_position_struct_t;
|
||||||
|
|
||||||
|
extern gps_binary_struct_t gpsDataOut;
|
||||||
|
|
||||||
|
extern predicted_binary_position_struct_t predictedPosition;
|
||||||
|
|
||||||
|
void gps_task(void *arg);
|
||||||
|
void parse_gpgga(const char *nmea);
|
||||||
|
void parse_gprmc(const char *nmea);
|
||||||
|
|
||||||
|
void parse_gprmc_to_struct(const char *nmea, gps_binary_struct_t *data);
|
||||||
|
void parse_gpgga_to_struct(const char *nmea, gps_binary_struct_t *data);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
100
main/hw/i2cbrn.c
100
main/hw/i2cbrn.c
@@ -3,50 +3,84 @@
|
|||||||
i2c_master_bus_config_t i2c0_bus_cfg = {
|
i2c_master_bus_config_t i2c0_bus_cfg = {
|
||||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||||
.i2c_port = I2C_NUM_0,
|
.i2c_port = I2C_NUM_0,
|
||||||
.scl_io_num = GPIO_NUM_9,
|
.scl_io_num = HWI2C_SCL,
|
||||||
.sda_io_num = GPIO_NUM_8,
|
.sda_io_num = HWI2C_SDA,
|
||||||
.glitch_ignore_cnt = 7,
|
.glitch_ignore_cnt = 1,
|
||||||
.flags.enable_internal_pullup = true,
|
.flags.enable_internal_pullup = true,
|
||||||
};
|
};
|
||||||
i2c_master_bus_handle_t i2c0_bus_hdl;
|
i2c_master_bus_handle_t i2c0_bus_hdl;
|
||||||
|
|
||||||
esp_err_t i2c_master_bus_detect_devices(i2c_master_bus_handle_t handle)
|
// esp_err_t i2c_master_bus_detect_devices(i2c_master_bus_handle_t handle)
|
||||||
{
|
// {
|
||||||
const uint16_t probe_timeout_ms = 50; // timeout in milliseconds
|
// const uint16_t probe_timeout_ms = 20; // timeout in milliseconds
|
||||||
uint8_t address;
|
// uint8_t address;
|
||||||
|
|
||||||
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n");
|
// printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n");
|
||||||
|
|
||||||
for (int i = 0; i < 128; i += 16)
|
// for (int i = 0; i < 128; i += 16)
|
||||||
{
|
// {
|
||||||
printf("%02x: ", i);
|
// printf("%02x: ", i);
|
||||||
|
|
||||||
for (int j = 0; j < 16; j++)
|
// for (int j = 0; j < 16; j++)
|
||||||
{
|
// {
|
||||||
fflush(stdout);
|
// fflush(stdout);
|
||||||
|
|
||||||
address = i + j;
|
// address = i + j;
|
||||||
|
|
||||||
esp_err_t ret = i2c_master_probe(handle, address, probe_timeout_ms);
|
// esp_err_t ret = i2c_master_probe(handle, address, probe_timeout_ms);
|
||||||
|
|
||||||
if (ret == ESP_OK)
|
// if (ret == ESP_OK)
|
||||||
{
|
// {
|
||||||
printf("%02x ", address);
|
// printf("%02x ", address);
|
||||||
}
|
// }
|
||||||
else if (ret == ESP_ERR_TIMEOUT)
|
// else if (ret == ESP_ERR_TIMEOUT)
|
||||||
{
|
// {
|
||||||
printf("UU ");
|
// printf("UU ");
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
printf("-- ");
|
// printf("-- ");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
printf("\r\n");
|
// printf("\r\n");
|
||||||
}
|
// }
|
||||||
|
|
||||||
return ESP_OK;
|
// return ESP_OK;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i2c master initialization
|
||||||
|
*/
|
||||||
|
|
||||||
|
esp_err_t i2c_master_bus_detect_devices(i2c_master_bus_handle_t handle)
|
||||||
|
{
|
||||||
|
uint8_t address;
|
||||||
|
bool found_any = false;
|
||||||
|
|
||||||
|
printf("Scanning I2C bus...\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < 128; i++)
|
||||||
|
{
|
||||||
|
fflush(stdout);
|
||||||
|
address = i;
|
||||||
|
|
||||||
|
esp_err_t ret = i2c_master_probe(handle, address, 20);
|
||||||
|
|
||||||
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
|
printf("Found device at 0x%02X\n", address);
|
||||||
|
found_any = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_any)
|
||||||
|
{
|
||||||
|
printf("No I2C devices found.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Writes data to a specific register of an I2C device.
|
* @brief Writes data to a specific register of an I2C device.
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
#define I2C_TIMEOUT_MS_VALUE 20
|
#define I2C_TIMEOUT_MS_VALUE 20
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "buscfg.h"
|
||||||
|
|
||||||
#define TAG_I2C "cani2c"
|
#define TAG_I2C "cani2c"
|
||||||
|
|
||||||
|
@@ -2,25 +2,32 @@
|
|||||||
|
|
||||||
i2c_device_config_t INA260_DEV_CFG = {
|
i2c_device_config_t INA260_DEV_CFG = {
|
||||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||||
.device_address = 0x40,
|
.device_address = INA260_ADDRESS,
|
||||||
.scl_speed_hz = 100000,
|
.scl_speed_hz = 100000,
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c_master_dev_handle_t INA260_DEV_HANDLE;
|
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
|
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));
|
esp_err_t ret = i2c_master_bus_add_device(i2c0_bus_hdl, &INA260_DEV_CFG, &INA260_DEV_HANDLE);
|
||||||
i2c_write_register_16(INA260_DEV_HANDLE, INA260_CONFIG_REGISTER, 0x0FFF); // set ina max averaging and max time
|
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;
|
esp_err_t ret;
|
||||||
|
|
||||||
// The register address is what we want to send first (the "transmit" part)
|
// The register address is what we want to send first (the "transmit" part)
|
||||||
@@ -33,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)
|
// Perform the combined write (register address) and read (register value)
|
||||||
ret = i2c_master_transmit_receive(INA260_DEV_HANDLE,
|
ret = i2c_master_transmit_receive(INA260_DEV_HANDLE,
|
||||||
write_buffer, write_size,
|
write_buffer, write_size,
|
||||||
read_buffer, read_size,
|
read_buffer, read_size,
|
||||||
I2C_TIMEOUT_MS_VALUE);
|
I2C_TIMEOUT_MS_VALUE);
|
||||||
|
|
||||||
if (ret == ESP_OK) {
|
if (ret == ESP_OK)
|
||||||
|
{
|
||||||
// Copy the data from the temporary read buffer to the output buffer
|
// Copy the data from the temporary read buffer to the output buffer
|
||||||
memcpy(data, read_buffer, read_size);
|
memcpy(data, read_buffer, read_size);
|
||||||
}
|
}
|
||||||
@@ -47,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)
|
void ina260_readParams(uint16_t *volt, uint16_t *cur, uint16_t *pow)
|
||||||
{
|
{
|
||||||
*volt = 0;
|
if (INA260_DEV_HANDLE)
|
||||||
*cur = 0;
|
|
||||||
*pow = 0;
|
|
||||||
for (uint8_t reg_addr = 1; reg_addr <= 3; reg_addr++)
|
|
||||||
{
|
{
|
||||||
uint8_t reg_value[2] = {0}; // Buffer for storing register data
|
*volt = 0;
|
||||||
|
*cur = 0;
|
||||||
ESP_ERROR_CHECK(i2c_master_read_register_transmit_receive(INA260_DEV_HANDLE, reg_addr, reg_value, sizeof(reg_value)));
|
*pow = 0;
|
||||||
// Perform the register read
|
for (uint8_t reg_addr = 1; reg_addr <= 3; reg_addr++)
|
||||||
switch (reg_addr)
|
|
||||||
{
|
{
|
||||||
case 1:
|
uint8_t reg_value[2] = {0}; // Buffer for storing register data
|
||||||
*cur = (((uint16_t)(reg_value[0] & 0xFF)) << 8) | (reg_value[1] & 0xFF);
|
|
||||||
//*cur = *((uint16_t *)reg_value);
|
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_read_register_transmit_receive(INA260_DEV_HANDLE, reg_addr, reg_value, sizeof(reg_value)));
|
||||||
break;
|
// Perform the register read
|
||||||
case 2:
|
switch (reg_addr)
|
||||||
*volt = (((uint16_t)(reg_value[0] & 0xFF)) << 8) | (reg_value[1] & 0xFF);
|
{
|
||||||
break;
|
case 1:
|
||||||
case 3:
|
*cur = (((uint16_t)(reg_value[0] & 0xFF)) << 8) | (reg_value[1] & 0xFF);
|
||||||
*pow = (((uint16_t)(reg_value[0] & 0xFF)) << 8) | (reg_value[1] & 0xFF);
|
//*cur = *((uint16_t *)reg_value);
|
||||||
break;
|
break;
|
||||||
default:
|
case 2:
|
||||||
break;
|
*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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,9 +90,7 @@ void ina260_printParams(uint16_t volt, uint16_t cur, uint16_t pow)
|
|||||||
float miliVolts = volt * 1.25;
|
float miliVolts = volt * 1.25;
|
||||||
float miliAmps = cur * 1.25;
|
float miliAmps = cur * 1.25;
|
||||||
float power = pow * 10;
|
float power = pow * 10;
|
||||||
cur *= 125;
|
ESP_LOGI(TAG_INA, "Current: %.3f mA (raw %d)", miliAmps, cur);
|
||||||
ESP_LOGI(TAG_INA, "Current: %.3f mA (raw %d)", miliAmps, volt);
|
ESP_LOGI(TAG_INA, "Voltage: %.3f mV (raw %d)", miliVolts, volt);
|
||||||
cur *= 125;
|
|
||||||
ESP_LOGI(TAG_INA, "Voltage: %.3f mV (raw %d)", miliVolts, cur);
|
|
||||||
ESP_LOGI(TAG_INA, "Power: %.3f mW (raw %d)", power, pow);
|
ESP_LOGI(TAG_INA, "Power: %.3f mW (raw %d)", power, pow);
|
||||||
}
|
}
|
@@ -16,60 +16,57 @@ extern i2c_master_dev_handle_t INA260_DEV_HANDLE;
|
|||||||
#define INA260_DIE_ID_REGISTER (0xFF)
|
#define INA260_DIE_ID_REGISTER (0xFF)
|
||||||
|
|
||||||
// Bit masks
|
// Bit masks
|
||||||
#define CONFIG_RST_BIT (1 << 15)
|
#define CONFIG_RST_BIT (1 << 15)
|
||||||
#define CONFIG_AVG_MASK (0x7 << 9)
|
#define CONFIG_AVG_MASK (0x7 << 9)
|
||||||
#define CONFIG_VBUSCT_MASK (0x7 << 6)
|
#define CONFIG_VBUSCT_MASK (0x7 << 6)
|
||||||
#define CONFIG_ISHCT_MASK (0x7 << 3)
|
#define CONFIG_ISHCT_MASK (0x7 << 3)
|
||||||
#define CONFIG_MODE_MASK (0x7 << 0)
|
#define CONFIG_MODE_MASK (0x7 << 0)
|
||||||
|
|
||||||
// Read-only bits
|
// Read-only bits
|
||||||
#define CONFIG_RESERVED_BITS (0x7 << 12) // Bits 14–12 = 110b
|
#define CONFIG_RESERVED_BITS (0x7 << 12) // Bits 14–12 = 110b
|
||||||
|
|
||||||
// Averaging modes (AVG)
|
// Averaging modes (AVG)
|
||||||
#define CONFIG_AVG_1 (0x0 << 9)
|
#define CONFIG_AVG_1 (0x0 << 9)
|
||||||
#define CONFIG_AVG_4 (0x1 << 9)
|
#define CONFIG_AVG_4 (0x1 << 9)
|
||||||
#define CONFIG_AVG_16 (0x2 << 9)
|
#define CONFIG_AVG_16 (0x2 << 9)
|
||||||
#define CONFIG_AVG_64 (0x3 << 9)
|
#define CONFIG_AVG_64 (0x3 << 9)
|
||||||
#define CONFIG_AVG_128 (0x4 << 9)
|
#define CONFIG_AVG_128 (0x4 << 9)
|
||||||
#define CONFIG_AVG_256 (0x5 << 9)
|
#define CONFIG_AVG_256 (0x5 << 9)
|
||||||
#define CONFIG_AVG_512 (0x6 << 9)
|
#define CONFIG_AVG_512 (0x6 << 9)
|
||||||
#define CONFIG_AVG_1024 (0x7 << 9)
|
#define CONFIG_AVG_1024 (0x7 << 9)
|
||||||
|
|
||||||
// Bus voltage conversion time (VBUSCT)
|
// Bus voltage conversion time (VBUSCT)
|
||||||
#define CONFIG_VBUSCT_140US (0x0 << 6)
|
#define CONFIG_VBUSCT_140US (0x0 << 6)
|
||||||
#define CONFIG_VBUSCT_204US (0x1 << 6)
|
#define CONFIG_VBUSCT_204US (0x1 << 6)
|
||||||
#define CONFIG_VBUSCT_332US (0x2 << 6)
|
#define CONFIG_VBUSCT_332US (0x2 << 6)
|
||||||
#define CONFIG_VBUSCT_588US (0x3 << 6)
|
#define CONFIG_VBUSCT_588US (0x3 << 6)
|
||||||
#define CONFIG_VBUSCT_1_1MS (0x4 << 6)
|
#define CONFIG_VBUSCT_1_1MS (0x4 << 6)
|
||||||
#define CONFIG_VBUSCT_2_116MS (0x5 << 6)
|
#define CONFIG_VBUSCT_2_116MS (0x5 << 6)
|
||||||
#define CONFIG_VBUSCT_4_156MS (0x6 << 6)
|
#define CONFIG_VBUSCT_4_156MS (0x6 << 6)
|
||||||
#define CONFIG_VBUSCT_8_244MS (0x7 << 6)
|
#define CONFIG_VBUSCT_8_244MS (0x7 << 6)
|
||||||
|
|
||||||
// Shunt current conversion time (ISHCT)
|
// Shunt current conversion time (ISHCT)
|
||||||
#define CONFIG_ISHCT_140US (0x0 << 3)
|
#define CONFIG_ISHCT_140US (0x0 << 3)
|
||||||
#define CONFIG_ISHCT_204US (0x1 << 3)
|
#define CONFIG_ISHCT_204US (0x1 << 3)
|
||||||
#define CONFIG_ISHCT_332US (0x2 << 3)
|
#define CONFIG_ISHCT_332US (0x2 << 3)
|
||||||
#define CONFIG_ISHCT_588US (0x3 << 3)
|
#define CONFIG_ISHCT_588US (0x3 << 3)
|
||||||
#define CONFIG_ISHCT_1_1MS (0x4 << 3)
|
#define CONFIG_ISHCT_1_1MS (0x4 << 3)
|
||||||
#define CONFIG_ISHCT_2_116MS (0x5 << 3)
|
#define CONFIG_ISHCT_2_116MS (0x5 << 3)
|
||||||
#define CONFIG_ISHCT_4_156MS (0x6 << 3)
|
#define CONFIG_ISHCT_4_156MS (0x6 << 3)
|
||||||
#define CONFIG_ISHCT_8_244MS (0x7 << 3)
|
#define CONFIG_ISHCT_8_244MS (0x7 << 3)
|
||||||
|
|
||||||
// Operating mode (MODE)
|
// Operating mode (MODE)
|
||||||
#define CONFIG_MODE_POWERDOWN (0x0 << 0)
|
#define CONFIG_MODE_POWERDOWN 0x00
|
||||||
#define CONFIG_MODE_CURRENT_TRIGGER (0x1 << 0)
|
#define CONFIG_MODE_CURRENT_TRIGGER 0x01
|
||||||
#define CONFIG_MODE_VOLTAGE_TRIGGER (0x2 << 0)
|
#define CONFIG_MODE_VOLTAGE_TRIGGER 0x02
|
||||||
#define CONFIG_MODE_CURRENT_VOLTAGE_TRIGGER (0x3 << 0)
|
#define CONFIG_MODE_CURRENT_VOLTAGE_TRIGGER 0x03
|
||||||
#define CONFIG_MODE_POWERDOWN2 (0x4 << 0)
|
#define CONFIG_MODE_POWERDOWN2 0x04
|
||||||
#define CONFIG_MODE_POWERDOWN (0x5 << 0)
|
#define CONFIG_MODE_CURRENT_CONTINOUS 0x05
|
||||||
#define CONFIG_MODE_POWERDOWN (0x6 << 0)
|
#define CONFIG_MODE_VOLTAGE_CONTINOUS 0x06
|
||||||
#define CONFIG_MODE_POWERDOWN (0x7 << 0)
|
#define CONFIG_MODE_CURRENT_VOLTAGE_CONTINOUS 0x07
|
||||||
|
|
||||||
|
esp_err_t ina260_init();
|
||||||
|
|
||||||
void ina260_init();
|
|
||||||
void ina260_readParams(uint16_t *volt, uint16_t *cur, uint16_t *pow);
|
void ina260_readParams(uint16_t *volt, uint16_t *cur, uint16_t *pow);
|
||||||
void ina260_printParams(uint16_t volt, uint16_t cur, uint16_t pow);
|
void ina260_printParams(uint16_t volt, uint16_t cur, uint16_t pow);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@@ -1,9 +1,12 @@
|
|||||||
#include "mcp23018.h"
|
#include "mcp23018.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "../components/sensors.h"
|
||||||
// Local buffer for tracking GPIO state
|
// Local buffer for tracking GPIO state
|
||||||
|
|
||||||
i2c_device_config_t MCP23018_DEV_CFG = {
|
i2c_device_config_t MCP23018_DEV_CFG = {
|
||||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||||
.device_address = 0x20,
|
.device_address = MCP23018_ADDRESS,
|
||||||
.scl_speed_hz = 100000,
|
.scl_speed_hz = 100000,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -11,8 +14,10 @@ i2c_master_dev_handle_t MCP23018_DEV_HANDLE;
|
|||||||
uint8_t gpioa_state = 0x00; // All LOW initially
|
uint8_t gpioa_state = 0x00; // All LOW initially
|
||||||
uint8_t gpiob_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)
|
if (pin < 8)
|
||||||
{
|
{
|
||||||
// GPIOA (Pins 0-7)
|
// GPIOA (Pins 0-7)
|
||||||
@@ -22,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
|
gpioa_state &= ~(1 << pin); // Clear bit
|
||||||
|
|
||||||
// Write updated buffer to MCP23018
|
// 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)
|
else if (pin < 16)
|
||||||
{
|
{
|
||||||
@@ -34,18 +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
|
gpiob_state &= ~(1 << pinB); // Clear bit
|
||||||
|
|
||||||
// Write updated buffer to MCP23018
|
// 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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_LORA_RST, 1);
|
||||||
|
return ret;
|
||||||
}
|
}
|
@@ -7,6 +7,7 @@
|
|||||||
#define MCP23018_GPIOA 0x12 // GPIO Output A
|
#define MCP23018_GPIOA 0x12 // GPIO Output A
|
||||||
#define MCP23018_GPIOB 0x13 // GPIO Output B
|
#define MCP23018_GPIOB 0x13 // GPIO Output B
|
||||||
|
|
||||||
|
|
||||||
#define MCP_LORA_RST 4
|
#define MCP_LORA_RST 4
|
||||||
#define MCP_MICS_POWER 5
|
#define MCP_MICS_POWER 5
|
||||||
#define MCP_CCS811_WAKE 6
|
#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 gpioa_state;
|
||||||
extern uint8_t gpiob_state;
|
extern uint8_t gpiob_state;
|
||||||
|
|
||||||
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);
|
||||||
void mcp23018_init();
|
esp_err_t mcp23018_init();
|
||||||
|
|
||||||
#endif
|
#endif
|
212
main/hw/mcp3550.c
Normal file
212
main/hw/mcp3550.c
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
#include "mcp3550.h"
|
||||||
|
#include "mcp23018.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include <esp_timer.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define TAG_MICS "MICS_ADC"
|
||||||
|
#define MCP3550_SPS 3.75f
|
||||||
|
#define MCP3550_CONVERSION_MS ((int)(1000.0f / MCP3550_SPS)) // ~267ms
|
||||||
|
#define MCP3550_TIMEOUT_MS 400
|
||||||
|
|
||||||
|
#define ADC_COUNT 4
|
||||||
|
const uint8_t adc_cs_pins[ADC_COUNT] = {
|
||||||
|
MCP_CS_ADC_NH3, MCP_CS_ADC_CO, MCP_CS_ADC_NO2, MCP_CS_ADC_UVC
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
uint32_t data = 0;
|
||||||
|
int64_t start = esp_timer_get_time();
|
||||||
|
uint32_t timeout_us = MCP3550_TIMEOUT_MS * 1000;
|
||||||
|
|
||||||
|
ESP_LOGI(TAG_MCP, "Starting read from ADC CS %d", cs_pin);
|
||||||
|
|
||||||
|
// CS LOW
|
||||||
|
mcp23018_set_pin(MCP23018_DEV_HANDLE, cs_pin, 0);
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10)); // Wait 1 tick (e.g., 1ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
if (value & (1 << 21)) value |= 0xFFC00000;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
float mcp3550_to_voltage(int32_t value, float vref)
|
||||||
|
{
|
||||||
|
return ((float)value / (1 << 21)) * vref;
|
||||||
|
}
|
||||||
|
|
||||||
|
mics_adc_data_t mcp3550_read_all(float vref)
|
||||||
|
{
|
||||||
|
mics_adc_data_t data;
|
||||||
|
int32_t raw[ADC_COUNT];
|
||||||
|
float volts[ADC_COUNT];
|
||||||
|
|
||||||
|
for (int i = 0; i < ADC_COUNT; i++) {
|
||||||
|
raw[i] = mcp3550_read(adc_cs_pins[i]);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10)); // Wait before retrying
|
||||||
|
volts[i] = mcp3550_to_voltage(raw[i], vref);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.raw_nh3 = raw[0]; data.volts_nh3 = volts[0];
|
||||||
|
data.raw_co = raw[1]; data.volts_co = volts[1];
|
||||||
|
data.raw_no2 = raw[2]; data.volts_no2 = volts[2];
|
||||||
|
data.raw_uvc = raw[3]; data.volts_uvc = volts[3];
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_mics_adc_values(mics_adc_data_t *data)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG_MICS,
|
||||||
|
"ADC Readings:\n"
|
||||||
|
" 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,
|
||||||
|
data->raw_uvc, data->volts_uvc);
|
||||||
|
}
|
36
main/hw/mcp3550.h
Normal file
36
main/hw/mcp3550.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef MPC3550_COMPONENT
|
||||||
|
#define MPC3550_COMPONENT
|
||||||
|
|
||||||
|
#include "driver/spi_master.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "buscfg.h"
|
||||||
|
|
||||||
|
#define MCP3550_SPS 3.75f
|
||||||
|
#define MCP3550_CONVERSION_MS ((int)(1000.0f / MCP3550_SPS)) // ~267ms
|
||||||
|
|
||||||
|
|
||||||
|
extern spi_device_handle_t mcp3550_handle;
|
||||||
|
|
||||||
|
void mcp3550_spi_init();
|
||||||
|
int32_t mcp3550_read(uint8_t cs_pin);
|
||||||
|
float mcp3550_to_voltage(int32_t value, float vref);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t raw_nh3;
|
||||||
|
int32_t raw_co;
|
||||||
|
int32_t raw_no2;
|
||||||
|
int32_t raw_uvc;
|
||||||
|
float volts_nh3;
|
||||||
|
float volts_co;
|
||||||
|
float volts_no2;
|
||||||
|
float volts_uvc;
|
||||||
|
} mics_adc_data_t;
|
||||||
|
|
||||||
|
extern spi_device_handle_t mcp3550_handle;
|
||||||
|
|
||||||
|
void log_mics_adc_values(mics_adc_data_t *data);
|
||||||
|
mics_adc_data_t mcp3550_read_all(float vref);
|
||||||
|
|
||||||
|
#endif
|
@@ -1,14 +1,17 @@
|
|||||||
#include "mpu9250.h"
|
#include "mpu9250.h"
|
||||||
|
#include "esp_timer.h"
|
||||||
|
|
||||||
i2c_device_config_t MPU9250_DEV_CFG = {
|
i2c_device_config_t MPU9250_DEV_CFG = {
|
||||||
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
||||||
.device_address = 0x68,
|
.device_address = MPU9250_ADDRESS,
|
||||||
.scl_speed_hz = 100000,
|
.scl_speed_hz = 100000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MAG_SCALE (4912.0f / 32760.0f)
|
||||||
|
|
||||||
i2c_master_dev_handle_t MPU9250_DEV_HANDLE;
|
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)
|
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)
|
||||||
{
|
{
|
||||||
uint8_t buffer[14]; // 6 (Accel) + 2 (Temp) + 6 (Gyro)
|
uint8_t buffer[14]; // 6 (Accel) + 2 (Temp) + 6 (Gyro)
|
||||||
esp_err_t ret = i2c_read_register(dev_handle, 0x3B, buffer, 14);
|
esp_err_t ret = i2c_read_register(dev_handle, 0x3B, buffer, 14);
|
||||||
@@ -16,18 +19,28 @@ esp_err_t mpu9250_read_sensor_data(i2c_master_dev_handle_t dev_handle, int16_t *
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
// Convert raw data (Big-Endian)
|
// Convert raw data (Big-Endian)
|
||||||
accel[0] = (((uint16_t)(buffer[0] & 0xFF)) << 8) | (buffer[1] & 0xFF); // Accel X
|
accel[0] = (((uint16_t)(buffer[0] & 0xFF)) << 8) | (buffer[1] & 0xFF); // Accel X
|
||||||
accel[1] = (((uint16_t)(buffer[2] & 0xFF)) << 8) | (buffer[3] & 0xFF); // Accel Y
|
accel[1] = (((uint16_t)(buffer[2] & 0xFF)) << 8) | (buffer[3] & 0xFF); // Accel Y
|
||||||
accel[2] = (((uint16_t)(buffer[4] & 0xFF)) << 8) | (buffer[5] & 0xFF); // Accel Z
|
accel[2] = (((uint16_t)(buffer[4] & 0xFF)) << 8) | (buffer[5] & 0xFF); // Accel Z
|
||||||
*temp = (((uint16_t)(buffer[6] & 0xFF)) << 8) | (buffer[7] & 0xFF); // Temperature
|
*temp = (((uint16_t)(buffer[6] & 0xFF)) << 8) | (buffer[7] & 0xFF); // Temperature
|
||||||
gyro[0] = (((uint16_t)(buffer[8] & 0xFF)) << 8) | (buffer[9] & 0xFF);; // Gyro X
|
gyro[0] = (((uint16_t)(buffer[8] & 0xFF)) << 8) | (buffer[9] & 0xFF);
|
||||||
gyro[1] = (((uint16_t)(buffer[10] & 0xFF)) << 8) | (buffer[11] & 0xFF);; // Gyro Y
|
; // Gyro X
|
||||||
gyro[2] = (((uint16_t)(buffer[12] & 0xFF)) << 8) | (buffer[13] & 0xFF);; // Gyro Z
|
gyro[1] = (((uint16_t)(buffer[10] & 0xFF)) << 8) | (buffer[11] & 0xFF);
|
||||||
|
; // Gyro Y
|
||||||
|
gyro[2] = (((uint16_t)(buffer[12] & 0xFF)) << 8) | (buffer[13] & 0xFF);
|
||||||
|
; // Gyro Z
|
||||||
|
|
||||||
|
ret = i2c_read_register(dev_handle, 0x03, buffer, 6);
|
||||||
|
if (ret != ESP_OK)
|
||||||
|
return ret;
|
||||||
|
magnet[0] = (((uint16_t)(buffer[0] & 0xFF)) << 8) | (buffer[1] & 0xFF); // Magnet X
|
||||||
|
magnet[1] = (((uint16_t)(buffer[2] & 0xFF)) << 8) | (buffer[3] & 0xFF); // Magnet Y
|
||||||
|
magnet[2] = (((uint16_t)(buffer[4] & 0xFF)) << 8) | (buffer[5] & 0xFF); // Magnet Z
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mpu9250_convert_data(int16_t *accel, int16_t *gyro, int16_t temp, float *accel_out, float *gyro_out, float *temp_out)
|
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)
|
||||||
{
|
{
|
||||||
accel_out[0] = accel[0] / 16384.0; // Accel X in g
|
accel_out[0] = accel[0] / 16384.0; // Accel X in g
|
||||||
accel_out[1] = accel[1] / 16384.0; // Accel Y in g
|
accel_out[1] = accel[1] / 16384.0; // Accel Y in g
|
||||||
@@ -37,10 +50,19 @@ void mpu9250_convert_data(int16_t *accel, int16_t *gyro, int16_t temp, float *ac
|
|||||||
gyro_out[1] = gyro[1] / 131.0; // Gyro Y in deg/s
|
gyro_out[1] = gyro[1] / 131.0; // Gyro Y in deg/s
|
||||||
gyro_out[2] = gyro[2] / 131.0; // Gyro Z in deg/s
|
gyro_out[2] = gyro[2] / 131.0; // Gyro Z in deg/s
|
||||||
|
|
||||||
|
magnet_out[0] = magnet[0] * MAG_SCALE; // Gyro X in deg/s
|
||||||
|
magnet_out[1] = magnet[1] * MAG_SCALE; // Gyro Y in deg/s
|
||||||
|
magnet_out[2] = magnet[2] * MAG_SCALE; // Gyro Z in deg/s
|
||||||
|
|
||||||
*temp_out = (temp / 333.87) + 21.0; // Temperature in °C
|
*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
|
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;
|
||||||
}
|
}
|
@@ -8,8 +8,8 @@ extern i2c_device_config_t MPU9250_DEV_CFG;
|
|||||||
extern i2c_master_dev_handle_t MPU9250_DEV_HANDLE;
|
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);
|
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, float *accel_out, float *gyro_out, float *temp_out);
|
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
|
#endif
|
93
components/ra01s/ra01s.c → main/hw/sx1262.c
Executable file → Normal file
93
components/ra01s/ra01s.c → main/hw/sx1262.c
Executable file → Normal file
@@ -4,23 +4,21 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "../components/sensors.h"
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
|
|
||||||
#include <driver/spi_master.h>
|
#include <driver/spi_master.h>
|
||||||
#include <driver/gpio.h>
|
#include <driver/gpio.h>
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "buscfg.h"
|
||||||
|
|
||||||
#include "ra01s.h"
|
#include "sx1262.h"
|
||||||
|
|
||||||
#define TAG "RA01S"
|
#define TAG "SX1262"
|
||||||
|
|
||||||
// SPI Stuff
|
|
||||||
#if CONFIG_SPI2_HOST
|
|
||||||
#define HOST_ID SPI2_HOST
|
|
||||||
#elif CONFIG_SPI3_HOST
|
|
||||||
#define HOST_ID SPI3_HOST
|
#define HOST_ID SPI3_HOST
|
||||||
#endif
|
|
||||||
|
|
||||||
static spi_device_handle_t SpiHandle;
|
static spi_device_handle_t SpiHandle;
|
||||||
|
|
||||||
@@ -30,10 +28,7 @@ static bool txActive;
|
|||||||
static int txLost = 0;
|
static int txLost = 0;
|
||||||
static bool debugPrint;
|
static bool debugPrint;
|
||||||
static int SX126x_SPI_SELECT;
|
static int SX126x_SPI_SELECT;
|
||||||
static int SX126x_RESET;
|
|
||||||
static int SX126x_BUSY;
|
static int SX126x_BUSY;
|
||||||
static int SX126x_TXEN;
|
|
||||||
static int SX126x_RXEN;
|
|
||||||
|
|
||||||
// Arduino compatible macros
|
// Arduino compatible macros
|
||||||
#define delayMicroseconds(us) esp_rom_delay_us(us)
|
#define delayMicroseconds(us) esp_rom_delay_us(us)
|
||||||
@@ -55,20 +50,14 @@ __attribute__ ((weak, alias ("LoRaErrorDefault"))) void LoRaError(int error);
|
|||||||
|
|
||||||
void LoRaInit(void)
|
void LoRaInit(void)
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "CONFIG_MISO_GPIO=%d", CONFIG_MISO_GPIO);
|
ESP_LOGI(TAG, "HSPI_MISO_GPIO=%d", HSPI_MISO_GPIO);
|
||||||
ESP_LOGI(TAG, "CONFIG_MOSI_GPIO=%d", CONFIG_MOSI_GPIO);
|
ESP_LOGI(TAG, "HSPI_MOSI_GPIO=%d", HSPI_MOSI_GPIO);
|
||||||
ESP_LOGI(TAG, "CONFIG_SCLK_GPIO=%d", CONFIG_SCLK_GPIO);
|
ESP_LOGI(TAG, "HSPI_SCK_GPIO=%d", HSPI_SCK_GPIO);
|
||||||
ESP_LOGI(TAG, "CONFIG_NSS_GPIO=%d", CONFIG_NSS_GPIO);
|
ESP_LOGI(TAG, "HSPI_LORA_CS=%d", HSPI_LORA_CS);
|
||||||
ESP_LOGI(TAG, "CONFIG_RST_GPIO=%d", CONFIG_RST_GPIO);
|
ESP_LOGI(TAG, "LORA_BUSY=%d", LORA_BUSY);
|
||||||
ESP_LOGI(TAG, "CONFIG_BUSY_GPIO=%d", CONFIG_BUSY_GPIO);
|
|
||||||
ESP_LOGI(TAG, "CONFIG_TXEN_GPIO=%d", CONFIG_TXEN_GPIO);
|
|
||||||
ESP_LOGI(TAG, "CONFIG_RXEN_GPIO=%d", CONFIG_RXEN_GPIO);
|
|
||||||
|
|
||||||
SX126x_SPI_SELECT = CONFIG_NSS_GPIO;
|
SX126x_SPI_SELECT = HSPI_LORA_CS;
|
||||||
SX126x_RESET = CONFIG_RST_GPIO;
|
SX126x_BUSY = LORA_BUSY;
|
||||||
SX126x_BUSY = CONFIG_BUSY_GPIO;
|
|
||||||
SX126x_TXEN = CONFIG_TXEN_GPIO;
|
|
||||||
SX126x_RXEN = CONFIG_RXEN_GPIO;
|
|
||||||
|
|
||||||
txActive = false;
|
txActive = false;
|
||||||
debugPrint = false;
|
debugPrint = false;
|
||||||
@@ -77,39 +66,22 @@ void LoRaInit(void)
|
|||||||
gpio_set_direction(SX126x_SPI_SELECT, GPIO_MODE_OUTPUT);
|
gpio_set_direction(SX126x_SPI_SELECT, GPIO_MODE_OUTPUT);
|
||||||
gpio_set_level(SX126x_SPI_SELECT, 1);
|
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_reset_pin(SX126x_BUSY);
|
||||||
gpio_set_direction(SX126x_BUSY, GPIO_MODE_INPUT);
|
gpio_set_direction(SX126x_BUSY, GPIO_MODE_INPUT);
|
||||||
|
|
||||||
if (SX126x_TXEN != -1) {
|
|
||||||
gpio_reset_pin(SX126x_TXEN);
|
|
||||||
gpio_set_direction(SX126x_TXEN, GPIO_MODE_OUTPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SX126x_RXEN != -1) {
|
|
||||||
gpio_reset_pin(SX126x_RXEN);
|
|
||||||
gpio_set_direction(SX126x_RXEN, GPIO_MODE_OUTPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
spi_bus_config_t spi_bus_config = {
|
spi_bus_config_t spi_bus_config = {
|
||||||
.sclk_io_num = CONFIG_SCLK_GPIO,
|
.sclk_io_num = HSPI_SCK_GPIO,
|
||||||
.mosi_io_num = CONFIG_MOSI_GPIO,
|
.mosi_io_num = HSPI_MOSI_GPIO,
|
||||||
.miso_io_num = CONFIG_MISO_GPIO,
|
.miso_io_num = HSPI_MISO_GPIO,
|
||||||
.quadwp_io_num = -1,
|
.quadwp_io_num = -1,
|
||||||
.quadhd_io_num = -1
|
.quadhd_io_num = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
ret = spi_bus_initialize( HOST_ID, &spi_bus_config, SPI_DMA_CH_AUTO );
|
|
||||||
ESP_LOGI(TAG, "spi_bus_initialize=%d",ret);
|
|
||||||
assert(ret==ESP_OK);
|
|
||||||
|
|
||||||
spi_device_interface_config_t devcfg = {
|
spi_device_interface_config_t devcfg = {
|
||||||
.clock_speed_hz = 9000000,
|
.clock_speed_hz = 9000000,
|
||||||
.mode = 0,
|
.mode = 0,
|
||||||
.spics_io_num = CONFIG_NSS_GPIO,
|
.spics_io_num = HSPI_LORA_CS,
|
||||||
.queue_size = 7,
|
.queue_size = 7,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.pre_cb = NULL
|
.pre_cb = NULL
|
||||||
@@ -290,6 +262,8 @@ void LoRaConfig(uint8_t spreadingFactor, uint8_t bandwidth, uint8_t codingRate,
|
|||||||
SX126X_IRQ_NONE //interrupts on DIO3
|
SX126X_IRQ_NONE //interrupts on DIO3
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Almost done setting LoRa");
|
||||||
// Receive state no receive timeoout
|
// Receive state no receive timeoout
|
||||||
SetRx(0xFFFFFF);
|
SetRx(0xFFFFFF);
|
||||||
}
|
}
|
||||||
@@ -417,9 +391,9 @@ void SetTxPower(int8_t txPowerInDbm)
|
|||||||
void Reset(void)
|
void Reset(void)
|
||||||
{
|
{
|
||||||
delay(10);
|
delay(10);
|
||||||
gpio_set_level(SX126x_RESET,0);
|
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_LORA_RST, 0);
|
||||||
delay(20);
|
delay(20);
|
||||||
gpio_set_level(SX126x_RESET,1);
|
mcp23018_set_pin(MCP23018_DEV_HANDLE, MCP_LORA_RST, 1);
|
||||||
delay(10);
|
delay(10);
|
||||||
// ensure BUSY is low (state meachine ready)
|
// ensure BUSY is low (state meachine ready)
|
||||||
WaitForIdle(BUSY_WAIT, "Reset", true);
|
WaitForIdle(BUSY_WAIT, "Reset", true);
|
||||||
@@ -705,7 +679,6 @@ void SetRx(uint32_t timeout)
|
|||||||
ESP_LOGI(TAG, "----- SetRx timeout=%"PRIu32, timeout);
|
ESP_LOGI(TAG, "----- SetRx timeout=%"PRIu32, timeout);
|
||||||
}
|
}
|
||||||
SetStandby(SX126X_STANDBY_RC);
|
SetStandby(SX126X_STANDBY_RC);
|
||||||
SetRxEnable();
|
|
||||||
uint8_t buf[3];
|
uint8_t buf[3];
|
||||||
buf[0] = (uint8_t)((timeout >> 16) & 0xFF);
|
buf[0] = (uint8_t)((timeout >> 16) & 0xFF);
|
||||||
buf[1] = (uint8_t)((timeout >> 8) & 0xFF);
|
buf[1] = (uint8_t)((timeout >> 8) & 0xFF);
|
||||||
@@ -723,25 +696,12 @@ void SetRx(uint32_t timeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SetRxEnable(void)
|
|
||||||
{
|
|
||||||
if (debugPrint) {
|
|
||||||
ESP_LOGI(TAG, "SetRxEnable:SX126x_TXEN=%d SX126x_RXEN=%d", SX126x_TXEN, SX126x_RXEN);
|
|
||||||
}
|
|
||||||
if ((SX126x_TXEN != -1) && (SX126x_RXEN != -1)) {
|
|
||||||
gpio_set_level(SX126x_RXEN, HIGH);
|
|
||||||
gpio_set_level(SX126x_TXEN, LOW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SetTx(uint32_t timeoutInMs)
|
void SetTx(uint32_t timeoutInMs)
|
||||||
{
|
{
|
||||||
if (debugPrint) {
|
if (debugPrint) {
|
||||||
ESP_LOGI(TAG, "----- SetTx timeoutInMs=%"PRIu32, timeoutInMs);
|
ESP_LOGI(TAG, "----- SetTx timeoutInMs=%"PRIu32, timeoutInMs);
|
||||||
}
|
}
|
||||||
SetStandby(SX126X_STANDBY_RC);
|
SetStandby(SX126X_STANDBY_RC);
|
||||||
SetTxEnable();
|
|
||||||
uint8_t buf[3];
|
uint8_t buf[3];
|
||||||
uint32_t tout = timeoutInMs;
|
uint32_t tout = timeoutInMs;
|
||||||
if (timeoutInMs != 0) {
|
if (timeoutInMs != 0) {
|
||||||
@@ -766,19 +726,6 @@ void SetTx(uint32_t timeoutInMs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SetTxEnable(void)
|
|
||||||
{
|
|
||||||
if (debugPrint) {
|
|
||||||
ESP_LOGI(TAG, "SetTxEnable:SX126x_TXEN=%d SX126x_RXEN=%d", SX126x_TXEN, SX126x_RXEN);
|
|
||||||
}
|
|
||||||
if ((SX126x_TXEN != -1) && (SX126x_RXEN != -1)){
|
|
||||||
gpio_set_level(SX126x_RXEN, LOW);
|
|
||||||
gpio_set_level(SX126x_TXEN, HIGH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int GetPacketLost()
|
int GetPacketLost()
|
||||||
{
|
{
|
||||||
return txLost;
|
return txLost;
|
2
components/ra01s/ra01s.h → main/hw/sx1262.h
Executable file → Normal file
2
components/ra01s/ra01s.h → main/hw/sx1262.h
Executable file → Normal file
@@ -412,8 +412,6 @@ void SetCad();
|
|||||||
uint8_t GetStatus(void);
|
uint8_t GetStatus(void);
|
||||||
uint16_t GetIrqStatus(void);
|
uint16_t GetIrqStatus(void);
|
||||||
void ClearIrqStatus(uint16_t irq);
|
void ClearIrqStatus(uint16_t irq);
|
||||||
void SetTxEnable(void);
|
|
||||||
void SetRxEnable(void);
|
|
||||||
void SetRx(uint32_t timeout);
|
void SetRx(uint32_t timeout);
|
||||||
void SetTx(uint32_t timeoutInMs);
|
void SetTx(uint32_t timeoutInMs);
|
||||||
int GetPacketLost();
|
int GetPacketLost();
|
65
main/main.c
65
main/main.c
@@ -15,6 +15,7 @@
|
|||||||
#include "esp_mac.h"
|
#include "esp_mac.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "components/radio.h"
|
||||||
#include "components/sensors.h"
|
#include "components/sensors.h"
|
||||||
#include "components/util.h"
|
#include "components/util.h"
|
||||||
#include "hw/bme680b.h"
|
#include "hw/bme680b.h"
|
||||||
@@ -23,31 +24,79 @@
|
|||||||
#include "hw/ina260.h"
|
#include "hw/ina260.h"
|
||||||
#include "hw/mcp23018.h"
|
#include "hw/mcp23018.h"
|
||||||
#include "hw/mpu9250.h"
|
#include "hw/mpu9250.h"
|
||||||
|
#include "hw/buscfg.h"
|
||||||
|
#include "components/sdcard.h"
|
||||||
|
|
||||||
|
#include "hw/gps.h"
|
||||||
|
|
||||||
#define TAG "cantest"
|
#define TAG "cantest"
|
||||||
|
|
||||||
|
|
||||||
#define CONFIG_FREERTOS_HZ 100
|
|
||||||
|
|
||||||
|
|
||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
ESP_LOGI("BOOT", "BRN Systems incorporated CanSat flight firmware build at %s %s", __DATE__, __TIME__);
|
||||||
|
|
||||||
/* instantiate i2c master bus 0 */
|
/* 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_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,
|
||||||
|
.miso_io_num = HSPI_MISO_GPIO,
|
||||||
|
.sclk_io_num = HSPI_SCK_GPIO,
|
||||||
|
.quadwp_io_num = -1,
|
||||||
|
.quadhd_io_num = -1,
|
||||||
|
.max_transfer_sz = 64, // probably change
|
||||||
|
};
|
||||||
|
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 */
|
/* 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 */
|
/* create task pinned to the app core */
|
||||||
xTaskCreatePinnedToCore(
|
xTaskCreate(
|
||||||
i2c_sensors_task,
|
i2c_sensors_task,
|
||||||
"I2CTaskBME",
|
"I2CTaskBME",
|
||||||
8192,
|
8192,
|
||||||
NULL,
|
NULL,
|
||||||
(tskIDLE_PRIORITY + 2),
|
(tskIDLE_PRIORITY + 2),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
xTaskCreate(
|
||||||
|
lora_comms_task,
|
||||||
|
"LoraCommsTask",
|
||||||
|
8192,
|
||||||
NULL,
|
NULL,
|
||||||
APP_CPU_NUM);
|
(tskIDLE_PRIORITY + 2),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
xTaskCreate(
|
||||||
|
gps_task,
|
||||||
|
"gps_task",
|
||||||
|
8192,
|
||||||
|
NULL,
|
||||||
|
(tskIDLE_PRIORITY + 2),
|
||||||
|
NULL);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
@@ -426,39 +426,39 @@ static inline esp_err_t bme680_get_cal_factors(bme680_handle_t handle) {
|
|||||||
ESP_ARG_CHECK( handle );
|
ESP_ARG_CHECK( handle );
|
||||||
|
|
||||||
/* bme680 attempt to request T1-T3 calibration values from device */
|
/* 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_WITHOUT_ABORT( 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_WITHOUT_ABORT( 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_byte_from(handle, 0x8c, (uint8_t *)&handle->dev_cal_factors->par_T3) );
|
||||||
/* bme680 attempt to request H1-H7 calibration values from device */
|
/* 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));
|
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));
|
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_WITHOUT_ABORT( 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_WITHOUT_ABORT( 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_WITHOUT_ABORT( 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_WITHOUT_ABORT( 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, 0xe8, (uint8_t *)&handle->dev_cal_factors->par_H7) );
|
||||||
/* bme680 attempt to request P1-P10 calibration values from device */
|
/* 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_WITHOUT_ABORT( 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_WITHOUT_ABORT( 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_WITHOUT_ABORT( 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_WITHOUT_ABORT( 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_WITHOUT_ABORT( 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_WITHOUT_ABORT( 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_WITHOUT_ABORT( 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_WITHOUT_ABORT( 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_WITHOUT_ABORT( 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_byte_from(handle, 0xa0, &handle->dev_cal_factors->par_P10) );
|
||||||
/* bme680 attempt to request G1-G3 calibration values from device */
|
/* 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_WITHOUT_ABORT( 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_WITHOUT_ABORT( 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, 0xee, (uint8_t *)&handle->dev_cal_factors->par_G3) );
|
||||||
/* bme680 attempt to request gas range and switching error values from device */
|
/* 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;
|
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_WITHOUT_ABORT( 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, 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;
|
handle->dev_cal_factors->range_switching_error = (handle->dev_cal_factors->range_switching_error & 0xf0) / 16;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1091,6 +1091,8 @@ esp_err_t bme680_get_data(bme680_handle_t handle, bme680_data_t *const data) {
|
|||||||
data->heater_stable = adc_data.heater_stable;
|
data->heater_stable = adc_data.heater_stable;
|
||||||
data->gas_valid = adc_data.gas_valid;
|
data->gas_valid = adc_data.gas_valid;
|
||||||
|
|
||||||
|
data->raw_data = adc_data;
|
||||||
|
|
||||||
/* compute scores */
|
/* compute scores */
|
||||||
bme680_compute_iaq(data);
|
bme680_compute_iaq(data);
|
||||||
|
|
||||||
|
@@ -308,6 +308,22 @@ typedef struct bme680_cal_factors_s {
|
|||||||
int8_t range_switching_error;
|
int8_t range_switching_error;
|
||||||
} bme680_cal_factors_t;
|
} bme680_cal_factors_t;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief BME680 ADC data structure definition.
|
||||||
|
*/
|
||||||
|
typedef struct bme680_adc_data_s {
|
||||||
|
uint32_t temperature;
|
||||||
|
uint16_t humidity;
|
||||||
|
uint32_t pressure;
|
||||||
|
uint16_t gas;
|
||||||
|
bool gas_valid;
|
||||||
|
uint8_t gas_range;
|
||||||
|
uint8_t gas_index;
|
||||||
|
bool heater_stable;
|
||||||
|
} bme680_adc_data_t;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief BME680 data structure definition.
|
* @brief BME680 data structure definition.
|
||||||
*/
|
*/
|
||||||
@@ -325,22 +341,9 @@ typedef struct bme680_data_s {
|
|||||||
float temperature_score;
|
float temperature_score;
|
||||||
float humidity_score;
|
float humidity_score;
|
||||||
float gas_score;
|
float gas_score;
|
||||||
|
bme680_adc_data_t raw_data;
|
||||||
} bme680_data_t;
|
} bme680_data_t;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief BME680 ADC data structure definition.
|
|
||||||
*/
|
|
||||||
typedef struct bme680_adc_data_s {
|
|
||||||
uint32_t temperature;
|
|
||||||
uint16_t humidity;
|
|
||||||
uint32_t pressure;
|
|
||||||
uint16_t gas;
|
|
||||||
bool gas_valid;
|
|
||||||
uint8_t gas_range;
|
|
||||||
uint8_t gas_index;
|
|
||||||
bool heater_stable;
|
|
||||||
} bme680_adc_data_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief BME680 configuration structure definition.
|
* @brief BME680 configuration structure definition.
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user