diff --git a/CLC-qthing/SiliconTorch/Hardware/AS3935.cpp b/CLC-qthing/SiliconTorch/Hardware/AS3935.cpp index de26a0de5372f69a11345c5aa38367162db4ef5f..8bcf7a8268d4479c704641c3be1f38a67892552a 100644 --- a/CLC-qthing/SiliconTorch/Hardware/AS3935.cpp +++ b/CLC-qthing/SiliconTorch/Hardware/AS3935.cpp @@ -8,6 +8,8 @@ #include "esp_err.h" #include "driver/i2c.h" #include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" // project specific #include <SpiderLib.hpp> @@ -20,13 +22,14 @@ + static const char* TAG = "AS3935"; namespace AS3935 { - AS3935::AS3935(u8 SDA, u8 SCL, u8 IRQ, u8 i2cAddr, u8 i2cChannel, u32 i2cFrequency) : i2cAddr(i2cAddr & I2C_ADDR_MASK), i2cChannel(i2cChannel) { + AS3935::AS3935(u8 SDA, u8 SCL, u8 IRQ, u8 i2cAddr, u8 i2cChannel, u32 i2cFrequency) : ioIRQ(IRQ), i2cAddr(i2cAddr & I2C_ADDR_MASK), i2cChannel(i2cChannel) { i2c_config_t cfg; @@ -62,6 +65,15 @@ namespace AS3935 { } + void AS3935::mainLoop() { + while (true) { + + + vTaskDelay(100 / portTICK_PERIOD_MS); + } + } + + bool AS3935::clearStatistics() { return mutex.runReturn<bool> ([&]() { R0x02 reg; @@ -200,4 +212,9 @@ namespace AS3935 { return i2cAddr << 1; } + + bool AS3935::getIRQState() { + return gpio_get_level((gpio_num_t)ioIRQ); + } + } diff --git a/CLC-qthing/SiliconTorch/Hardware/AS3935.hpp b/CLC-qthing/SiliconTorch/Hardware/AS3935.hpp index f922e0f15125dbf705d7c2e04c0a0d1406030503..ed4b63769c50cad1a9e45fa3b3cdda7bd3c5abbe 100644 --- a/CLC-qthing/SiliconTorch/Hardware/AS3935.hpp +++ b/CLC-qthing/SiliconTorch/Hardware/AS3935.hpp @@ -201,9 +201,13 @@ namespace AS3935 { bool i2cWriteByteMutex(u8 regAddr, u8 value); // TMP public for debug protected: + const u8 ioIRQ; const u8 i2cAddr; const u8 i2cChannel; + bool getIRQState(); + + void mainLoop(); //bool i2cReadByte (u8 regAddr, u8* value); //bool i2cWriteByte (u8 regAddr, u8 value); @@ -213,6 +217,8 @@ namespace AS3935 { // Used to synchronize I²C calls (the IDF driver don't likes multithreading) SpiderLib::ManagedMutex mutex; + SpiderLib::Util::LambdaTask* loopTask = NULL; + }; } diff --git a/CLC-qthing/SiliconTorch/Hardware/MAX31856.cpp b/CLC-qthing/SiliconTorch/Hardware/MAX31856.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e953230baa60e887a48be028ba4d69077af4212d --- /dev/null +++ b/CLC-qthing/SiliconTorch/Hardware/MAX31856.cpp @@ -0,0 +1,268 @@ +#include "MAX31856.hpp" + +// C++ system level +// #include <functional> + +// ESP32 specific +#include "esp_log.h" +#include "esp_err.h" +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +// project specific +#include <SpiderLib.hpp> + +// qthing stuff +// #include <qthing> + +// misc +// #include "" + + + + +static const char* TAG = "MAX31856"; + + +namespace MAX31856 { + + + SoftSPI::SoftSPI(u8 miso, u8 mosi, u8 sclk, u8 cs) : miso(miso), mosi(mosi), sclk(sclk), cs(cs) { + + // gpio init + mutex.run ([&]() { + + gpio_config_t cfg; + u8 init_ios[] = {mosi, sclk, cs}; + + cfg.pin_bit_mask = 0; + for (u8 i = 0; i < 3; i++) + cfg.pin_bit_mask |= 1ULL << init_ios[i]; + + cfg.mode = GPIO_MODE_OUTPUT; + cfg.intr_type = GPIO_INTR_DISABLE; + cfg.pull_up_en = GPIO_PULLUP_DISABLE; + cfg.pull_down_en = GPIO_PULLDOWN_DISABLE; + + gpio_config(&cfg); + + setCS(1); + setMOSI(0); + setSCLK(0); + + }); + } + + + void SoftSPI::writeU8(u8 addr, u8 value) { + mutex.run ([&]() { + + addr = (addr & 0x0F) | 0x80; + u16 data = (addr << 8) | value; + + setCS(0); + + for (i8 n = 15; n >= 0; n--) { + setSCLK(1); + setMOSI((data >> n) & 1); + setSCLK(0); + } + + //setSCLK(0); + setMOSI(0); + setCS(1); + }); + } + + + u8 SoftSPI::readU8(u8 addr) { + return mutex.runReturn<u8> ([&]() { + + addr &= 0x0F; // mask out write adresses + u8 value = 0x00; + + setCS(0); + + for (i8 n = 7; n >= 0; n--) { + setSCLK(1); + setMOSI((addr >> n) & 1); + setSCLK(0); + } + + setMOSI(0); + + for (i8 n = 7; n >= 0; n--) { + setSCLK(1); + value |= getMISO() << n; + setSCLK(0); + } + + //setSCLK(0); + setCS(1); + + return value; + }); + } + + void SoftSPI::setMOSI(bool value) { + gpio_set_level((gpio_num_t)mosi, value); + } + + void SoftSPI::setSCLK(bool value) { + gpio_set_level((gpio_num_t)sclk, value); + } + + void SoftSPI::setCS(bool value) { + gpio_set_level((gpio_num_t)cs, value); + } + + bool SoftSPI::getMISO() { + return gpio_get_level((gpio_num_t)miso); + } + + + + MAX31856::MAX31856(u8 miso, u8 mosi, u8 sclk, u8 cs) : miso(miso), mosi(mosi), sclk(sclk), cs(cs) { + + spi = new SoftSPI(miso, mosi, sclk, cs); + + setPwrLnRjFrq(F50Hz); + + //return; + + for (u8 addr = 0; addr < (0x0F+1); addr++) { + + u8 data = spi->readU8(addr); + + ESP_LOGI(TAG, "Addr[ 0x%02X ] ~~> Data[ 0x%02X ]", addr, data); + } + + setPwrLnRjFrq(F60Hz); + ESP_LOGI(TAG, "----"); + + + for (u8 addr = 0; addr < (0x0F+1); addr++) { + + u8 data = spi->readU8(addr); + + ESP_LOGI(TAG, "Addr[ 0x%02X ] ~~> Data[ 0x%02X ]", addr, data); + } + + } + + + + + +/* + + void MAX31856::setThermocoupleType(ThermocoupleType tc) { + return mutex.run ([&]() { + + CR1 reg; + reg.value = spi->readU8(CR1::addr); + + + if (pfr == F60Hz) reg.PWRLNRJ = 0; + else reg.PWRLNRJ = 1; + + spi->writeU8(CR1::addr, reg.value); + }); + } + + ThermocoupleType MAX31856::getThermocoupleType() { + return mutex.runReturn<ThermocoupleType> ([&]() { + + CR1 reg; + reg.value = spi->readU8(CR1::addr); + + // TODO: Can this be done by casting? + if (reg.PWRLNRJ == 0) return F60Hz; + else return F50Hz; + }); + } + + + + + +*/ + + + + + + + + + + void MAX31856::setPwrLnRjFrq(PowerlineFrequencyRejection pfr) { + return mutex.run ([&]() { + + CR0 reg; + reg.value = spi->readU8(CR0::addr); + + reg.PWRLNRJ = pfr; + + + //if (pfr == F60Hz) reg.PWRLNRJ = 0; + //else reg.PWRLNRJ = 1; + + spi->writeU8(CR0::addr, reg.value); + }); + } + + PowerlineFrequencyRejection MAX31856::getPwrLnRjFrq() { + return mutex.runReturn<PowerlineFrequencyRejection> ([&]() { + + CR0 reg; + reg.value = spi->readU8(CR0::addr); + + // TODO: Can this be done by casting? + //if (reg.PWRLNRJ == 0) return F60Hz; + //else return F50Hz; + return (PowerlineFrequencyRejection)reg.PWRLNRJ; + }); + } + + + + + + + + + + + + + + + + + + + + + + + void MAX31856::mainLoop() { + while (true) { + + + + + + ESP_LOGI(TAG, "LoL"); + + vTaskDelay(100 / portTICK_PERIOD_MS); + } + } + + + // bool MAX31856::getIRQState() { + // return gpio_get_level((gpio_num_t)ioIRQ); + // } + +} diff --git a/CLC-qthing/SiliconTorch/Hardware/MAX31856.hpp b/CLC-qthing/SiliconTorch/Hardware/MAX31856.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2112de9342883f310965aa3a5947cd1f13582f5f --- /dev/null +++ b/CLC-qthing/SiliconTorch/Hardware/MAX31856.hpp @@ -0,0 +1,257 @@ +#pragma once + +// C++ system level +// #include <functional> + +// ESP32 specific +// #include "esp_log.h" + +// project specific +#include <SpiderLib.hpp> + +// qthing stuff +// #include <qthing> + +// misc +// #include "" + + +namespace MAX31856 { + + + enum PowerlineFrequencyRejection : u8 { + F60Hz = 0, + F50Hz = 1 + }; + + enum ThermocoupleType : u8 { + B_Type = 0x00, + E_TYPE = 0x01, + J_TYPE = 0x02, + K_TYPE = 0x03, + N_TYPE = 0x04, + R_TYPE = 0x05, + S_TYPE = 0x06, + T_TYPE = 0x07 + }; + + + union CR0 { + + struct __attribute__((packed)) { + u8 PWRLNRJ : 1; // Power Line Rejection Mode (0 = 60Hz; 1 = 50Hz) + u8 FAULTCLR : 1; + u8 FAULT : 1; + u8 CJ : 1; + u8 OCFAULT : 2; + u8 ONESHOT : 1; + u8 CMODE : 1; + }; + + u8 value = 0x00; + + static constexpr u8 addr = 0x00; + + }; + + + union CR1 { + + struct __attribute__((packed)) { + u8 TCTYPE : 4; // see enum: ThermocoupleType + u8 AVGSEL : 3; + u8 _reserved_ : 1; + }; + + u8 value = 0x00; + + static constexpr u8 addr = 0x01; + + }; + + + union MASK { + + struct __attribute__((packed)) { + }; + + u8 value = 0x00; + + static constexpr u8 addr = 0x02; + + }; + + + union CJHF { + + struct __attribute__((packed)) { + }; + + u8 value = 0x00; + + static constexpr u8 addr = 0x03; + + }; + + + union CJLF { + + struct __attribute__((packed)) { + }; + + u8 value = 0x00; + + static constexpr u8 addr = 0x04; + + }; + + + union LTHFTH { + + struct __attribute__((packed)) { + }; + + u8 value = 0x00; + + static constexpr u8 addr = 0x05; + + }; + + union LTHFTL { + + struct __attribute__((packed)) { + }; + + u8 value = 0x00; + + static constexpr u8 addr = 0x06; + + }; + + union LTLFTH { + + struct __attribute__((packed)) { + }; + + u8 value = 0x00; + + static constexpr u8 addr = 0x07; + + }; + + union LTLFTL { + + struct __attribute__((packed)) { + }; + + u8 value = 0x00; + + static constexpr u8 addr = 0x08; + + }; + + + + + + + + + + + + + + + + +/* + + union _ { + + struct __attribute__((packed)) { + }; + + u8 value = 0x00; + + static constexpr u8 addr = 0x00; + + }; + +*/ + + + + + class SoftSPI { + public: + + SoftSPI(u8 miso, u8 mosi, u8 sclk, u8 cs); + + void writeU8(u8 addr, u8 value); + u8 readU8(u8 addr); + + const u8 cs; + const u8 mosi; + const u8 miso; + const u8 sclk; + + + protected: + + void setMOSI(bool value); + void setSCLK(bool value); + void setCS(bool value); + + bool getMISO(); + + SpiderLib::ManagedMutex mutex; + + }; + + + + class MAX31856 { + + public: + + MAX31856(u8 miso, u8 mosi, u8 sclk, u8 cs); + + // Methods below are semi-public: From a hidden-box model perspective they should be protected + // but from my POV they can be public as the user CANNOT misuse them in any way + // TODO: elaborate on this… + + u8 readAddr (); + u8 writeAddr(); + + + void setPwrLnRjFrq(PowerlineFrequencyRejection pfr); // TODO: Better Name…?! + PowerlineFrequencyRejection getPwrLnRjFrq(); // TODO: Better Name…?! + + + + void mainLoop(); + + const u8 cs; + const u8 mosi; + const u8 miso; + const u8 sclk; + + protected: + + + SoftSPI* spi; + + + + // bool getIRQState(); + + //void mainLoop(); + + SpiderLib::ManagedMutex mutex; + + SpiderLib::Util::LambdaTask* loopTask = NULL; + + }; + +}