1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-09 21:33:48 +01:00

feat: add FRAM support to DynamicLampComponent for enhanced functionality

This commit is contained in:
Oliver Kleinecke
2025-02-18 11:29:29 +01:00
parent 8b579d77ef
commit 8af0107943
5 changed files with 862 additions and 1 deletions

View File

@@ -1,5 +1,6 @@
import esphome.codegen as cg
from esphome.components import output
from esphome.components.fram import FRAM
from esphome.components.time import RealTimeClock
import esphome.config_validation as cv
from esphome.const import CONF_ID
@@ -12,11 +13,13 @@ DynamicLampComponent = dynamic_lamp_ns.class_('DynamicLampComponent', cg.Compone
CONF_DYNAMIC_LAMP_ID = "dynamic_lamp_id"
CONF_RTC = 'rtc'
CONF_FRAM = 'fram'
CONF_SAVE_MODE = 'save_mode'
CONF_AVAILABLE_OUTPUTS = 'available_outputs'
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(CONF_ID): cv.declare_id(DynamicLampComponent),
cv.Required(CONF_RTC): cv.use_id(RealTimeClock),
cv.Required(CONF_FRAM): cv.use_id(FRAM),
cv.Required(CONF_AVAILABLE_OUTPUTS): [cv.use_id(output.FloatOutput)],
cv.Optional(CONF_SAVE_MODE, default=0): cv.int_range(0, 1),
}).extend(cv.COMPONENT_SCHEMA)
@@ -26,6 +29,7 @@ async def to_code(config):
var = cg.new_Pvariable(
config[CONF_ID],
await cg.get_variable(config[CONF_RTC]),
await cg.get_variable(config[CONF_FRAM]),
)
await cg.register_component(var, config)
for outputPointer in config.get(CONF_AVAILABLE_OUTPUTS, []):

View File

@@ -109,6 +109,7 @@ class DynamicLampComponent : public Component {
protected:
friend class DynamicLamp;
time::RealTimeClock *rtc_;
FRAM *fram_;
void restore_lamp_values_(uint8_t lamp_number);
void set_lamp_values_(uint8_t lamp_number, bool active, uint16_t selected_outputs, uint8_t mode, uint8_t mode_value);
bool write_state_(uint8_t lamp_number, float state);
@@ -117,7 +118,6 @@ class DynamicLampComponent : public Component {
LinkedOutput available_outputs_[16];
uint8_t save_mode_;
uint8_t lamp_count_ = 0;
};

View File

@@ -0,0 +1,629 @@
//
// FILE: FRAM.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.5.3
// DATE: 2018-01-24
// PURPOSE: Arduino library for I2C FRAM
// URL: https://github.com/RobTillaart/FRAM_I2C
//
// ESPHome port: https://github.com/sharkydog/esphome-fram
#include "FRAM.h"
namespace esphome {
namespace fram {
// used for metadata and sleep
const uint8_t FRAM_SLAVE_ID_ = 0x7C; // == 0xF8
const uint8_t FRAM_SLEEP_CMD = 0x86; //
static const char * const TAG = "fram";
/////////////////////////////////////////////////////////////////////////////
//
// FRAM PUBLIC
//
void FRAM::setup()
{
if (!this->isConnected())
{
ESP_LOGE(TAG, "Device on address 0x%x not found!", this->address_);
this->mark_failed();
}
else if (!this->getSize())
{
ESP_LOGW(TAG, "Device on address 0x%x returned 0 size, set size in config!", this->address_);
}
}
void FRAM::dump_config()
{
ESP_LOGCONFIG(TAG, "FRAM:");
ESP_LOGCONFIG(TAG, " Address: 0x%x", this->address_);
bool ok = this->isConnected();
if (!ok) {
ESP_LOGE(TAG, " Device not found!");
}
if (this->_sizeBytes) {
ESP_LOGCONFIG(TAG, " Size: %uKiB", this->_sizeBytes / 1024UL);
} else if(ok) {
ESP_LOGW(TAG, " Size: 0KiB, set size in config!");
}
}
bool FRAM::isConnected()
{
i2c::ErrorCode err = this->bus_->write(this->address_, nullptr, 0, true);
return (err == i2c::ERROR_OK);
}
void FRAM::write8(uint16_t memaddr, uint8_t value)
{
uint8_t val = value;
this->_writeBlock(memaddr, (uint8_t *)&val, sizeof(uint8_t));
}
void FRAM::write16(uint16_t memaddr, uint16_t value)
{
uint16_t val = value;
this->_writeBlock(memaddr, (uint8_t *)&val, sizeof(uint16_t));
}
void FRAM::write32(uint16_t memaddr, uint32_t value)
{
uint32_t val = value;
this->_writeBlock(memaddr, (uint8_t *)&val, sizeof(uint32_t));
}
void FRAM::writeFloat(uint16_t memaddr, float value)
{
float val = value;
this->_writeBlock(memaddr, (uint8_t *)&val, sizeof(float));
}
void FRAM::writeDouble(uint16_t memaddr, double value)
{
double val = value;
this->_writeBlock(memaddr, (uint8_t *)&val, sizeof(double));
}
void FRAM::write(uint16_t memaddr, uint8_t * obj, uint16_t size)
{
const int blocksize = 24;
uint8_t * p = obj;
while (size >= blocksize)
{
this->_writeBlock(memaddr, p, blocksize);
memaddr += blocksize;
p += blocksize;
size -= blocksize;
}
// remaining
if (size > 0)
{
this->_writeBlock(memaddr, p, size);
}
}
uint8_t FRAM::read8(uint16_t memaddr)
{
uint8_t val;
this->_readBlock(memaddr, (uint8_t *)&val, sizeof(uint8_t));
return val;
}
uint16_t FRAM::read16(uint16_t memaddr)
{
uint16_t val;
this->_readBlock(memaddr, (uint8_t *)&val, sizeof(uint16_t));
return val;
}
uint32_t FRAM::read32(uint16_t memaddr)
{
uint32_t val;
this->_readBlock(memaddr, (uint8_t *)&val, sizeof(uint32_t));
return val;
}
float FRAM::readFloat(uint16_t memaddr)
{
float val;
this->_readBlock(memaddr, (uint8_t *)&val, sizeof(float));
return val;
}
double FRAM::readDouble(uint16_t memaddr)
{
double val;
this->_readBlock(memaddr, (uint8_t *)&val, sizeof(double));
return val;
}
void FRAM::read(uint16_t memaddr, uint8_t * obj, uint16_t size)
{
const uint8_t blocksize = 24;
uint8_t * p = obj;
while (size >= blocksize)
{
this->_readBlock(memaddr, p, blocksize);
memaddr += blocksize;
p += blocksize;
size -= blocksize;
}
// remainder
if (size > 0)
{
this->_readBlock(memaddr, p, size);
}
}
////////////////////////////////////////////////////////////////////////
int32_t FRAM::readUntil(uint16_t memaddr, char * buf, uint16_t buflen, char separator)
{
// read and fill the buffer at once.
this->read(memaddr, (uint8_t *)buf, buflen);
for (uint16_t length = 0; length < buflen; length++)
{
if (buf[length] == separator)
{
buf[length] = 0; // replace separator => \0 EndChar
return length;
}
}
// entry does not fit in given buffer.
return (int32_t)-1;
}
int32_t FRAM::readLine(uint16_t memaddr, char * buf, uint16_t buflen)
{
// read and fill the buffer at once.
this->read(memaddr, (uint8_t *)buf, buflen);
for (uint16_t length = 0; length < buflen-1; length++)
{
if (buf[length] == '\n')
{
buf[length + 1] = 0; // add \0 EndChar after '\n'
return length + 1;
}
}
// entry does not fit in given buffer.
return (int32_t)-1;
}
////////////////////////////////////////////////////////////////////////
uint16_t FRAM::getManufacturerID()
{
return this->_getMetaData(0);
}
uint16_t FRAM::getProductID()
{
return this->_getMetaData(1);
}
// NOTE: returns the size in kiloBYTE
uint16_t FRAM::getSize()
{
uint16_t density = this->_getMetaData(2);
uint16_t size = 0;
if (density > 0)
{
size = (1UL << density);
this->_sizeBytes = size * 1024UL;
}
return size;
}
uint32_t FRAM::getSizeBytes()
{
return this->_sizeBytes;
}
// override to be used when getSize() fails == 0
void FRAM::setSizeBytes(uint32_t value)
{
this->_sizeBytes = value;
}
uint32_t FRAM::clear(uint8_t value)
{
uint8_t buffer[16];
for (uint8_t i = 0; i < 16; i++) buffer[i] = value;
uint32_t start = 0;
uint32_t end = this->_sizeBytes;
for (uint32_t address = start; address < end; address += 16)
{
this->_writeBlock(address, buffer, 16);
}
return end - start;
}
// EXPERIMENTAL - to be confirmed
// page 12 datasheet
// command = S 0xF8 A address A S 86 A P (A = Ack from slave )
void FRAM::sleep()
{
uint8_t addr = this->address_ << 1;
this->bus_->write(FRAM_SLAVE_ID_, &addr, 1, false);
this->bus_->write(FRAM_SLEEP_CMD >> 1, nullptr, 0, true);
}
// page 12 datasheet trec <= 400us
bool FRAM::wakeup(uint32_t trec)
{
bool b = this->isConnected(); // wakeup
if (trec == 0) return b;
// wait recovery time
delayMicroseconds(trec);
return this->isConnected(); // check recovery OK
}
/////////////////////////////////////////////////////////////////////////////
//
// FRAM PROTECTED
//
// metadata is packed as [....MMMM][MMMMDDDD][PPPPPPPP]
// M = manufacturerID
// D = density => memory size = 2^D KB
// P = product ID (together with D)
// P part might be proprietary
uint16_t FRAM::_getMetaData(uint8_t field)
{
if (field > 2) return 0;
uint8_t addr = this->address_ << 1;
this->bus_->write(FRAM_SLAVE_ID_, &addr, 1, false);
uint8_t data[3] = {0,0,0};
i2c::ErrorCode err = this->bus_->read(FRAM_SLAVE_ID_, data, 3);
if (err != i2c::ERROR_OK) return 0;
// MANUFACTURER
if (field == 0) return (data[0] << 4) + (data[1] >> 4);
// PRODUCT ID
if (field == 1) return ((data[1] & 0x0F) << 8) + data[2];
// DENSITY
// Fujitsu data sheet
// 3 => MB85RC64 = 64 Kbit.
// 5 => MB85RC256
// 6 => MB85RC512
// 7 => MB85RC1M
if (field == 2) return data[1] & 0x0F;
return 0;
}
void FRAM::_writeBlock(uint16_t memaddr, uint8_t * obj, uint8_t size)
{
i2c::WriteBuffer buff[2];
uint8_t maddr[] = { (uint8_t)(memaddr >> 8), (uint8_t)(memaddr & 0xFF) };
buff[0].data = maddr;
buff[0].len = 2;
buff[1].data = obj;
buff[1].len = size;
this->bus_->writev(this->address_, buff, 2, true);
}
void FRAM::_readBlock(uint16_t memaddr, uint8_t * obj, uint8_t size)
{
uint8_t maddr[] = { (uint8_t)(memaddr >> 8), (uint8_t)(memaddr & 0xFF) };
this->bus_->write(this->address_, maddr, 2, false);
this->bus_->read(this->address_, obj, size);
}
/////////////////////////////////////////////////////////////////////////////
//
// FRAM32 PUBLIC
//
void FRAM32::write8(uint32_t memaddr, uint8_t value)
{
uint8_t val = value;
this->_writeBlock(memaddr, (uint8_t *)&val, sizeof(uint8_t));
}
void FRAM32::write16(uint32_t memaddr, uint16_t value)
{
uint16_t val = value;
this->_writeBlock(memaddr, (uint8_t *)&val, sizeof(uint16_t));
}
void FRAM32::write32(uint32_t memaddr, uint32_t value)
{
uint32_t val = value;
this->_writeBlock(memaddr, (uint8_t *)&val, sizeof(uint32_t));
}
void FRAM32::writeFloat(uint32_t memaddr, float value)
{
float val = value;
this->_writeBlock(memaddr, (uint8_t *)&val, sizeof(float));
}
void FRAM32::writeDouble(uint32_t memaddr, double value)
{
double val = value;
this->_writeBlock(memaddr, (uint8_t *)&val, sizeof(double));
}
void FRAM32::write(uint32_t memaddr, uint8_t * obj, uint16_t size)
{
const int blocksize = 24;
uint8_t * p = obj;
while (size >= blocksize)
{
this->_writeBlock(memaddr, p, blocksize);
memaddr += blocksize;
p += blocksize;
size -= blocksize;
}
// remaining
if (size > 0)
{
this->_writeBlock(memaddr, p, size);
}
}
uint8_t FRAM32::read8(uint32_t memaddr)
{
uint8_t val;
this->_readBlock(memaddr, (uint8_t *)&val, sizeof(uint8_t));
return val;
}
uint16_t FRAM32::read16(uint32_t memaddr)
{
uint16_t val;
this->_readBlock(memaddr, (uint8_t *)&val, sizeof(uint16_t));
return val;
}
uint32_t FRAM32::read32(uint32_t memaddr)
{
uint32_t val;
this->_readBlock(memaddr, (uint8_t *)&val, sizeof(uint32_t));
return val;
}
float FRAM32::readFloat(uint32_t memaddr)
{
float val;
this->_readBlock(memaddr, (uint8_t *)&val, sizeof(float));
return val;
}
double FRAM32::readDouble(uint32_t memaddr)
{
double val;
this->_readBlock(memaddr, (uint8_t *)&val, sizeof(double));
return val;
}
void FRAM32::read(uint32_t memaddr, uint8_t * obj, uint16_t size)
{
const uint8_t blocksize = 24;
uint8_t * p = obj;
while (size >= blocksize)
{
this->_readBlock(memaddr, p, blocksize);
memaddr += blocksize;
p += blocksize;
size -= blocksize;
}
// remainder
if (size > 0)
{
this->_readBlock(memaddr, p, size);
}
}
int32_t FRAM32::readUntil(uint32_t memaddr, char * buf, uint16_t buflen, char separator)
{
// read and fill the buffer at once.
this->read(memaddr, (uint8_t *)buf, buflen);
for (uint16_t length = 0; length < buflen; length++)
{
if (buf[length] == separator)
{
buf[length] = 0; // replace separator => \0 EndChar
return length;
}
}
// entry does not fit in given buffer.
return (int32_t)-1;
}
int32_t FRAM32::readLine(uint32_t memaddr, char * buf, uint16_t buflen)
{
// read and fill the buffer at once.
this->read(memaddr, (uint8_t *)buf, buflen);
for (uint16_t length = 0; length < buflen-1; length++)
{
if (buf[length] == '\n')
{
buf[length + 1] = 0; // add \0 EndChar after '\n'
return length + 1;
}
}
// entry does not fit in given buffer.
return (int32_t)-1;
}
template <class T> uint32_t FRAM32::writeObject(uint32_t memaddr, T &obj)
{
this->write(memaddr, (uint8_t *) &obj, sizeof(obj));
return memaddr + sizeof(obj);
};
template <class T> uint32_t FRAM32::readObject(uint32_t memaddr, T &obj)
{
this->read(memaddr, (uint8_t *) &obj, sizeof(obj));
return memaddr + sizeof(obj);
}
/////////////////////////////////////////////////////////////////////////////
//
// FRAM32 PROTECTED
//
void FRAM32::_writeBlock(uint32_t memaddr, uint8_t * obj, uint8_t size)
{
uint8_t _addr = this->address_;
if (memaddr & 0x00010000) _addr += 0x01;
i2c::WriteBuffer buff[2];
uint8_t maddr[] = { (uint8_t)(memaddr >> 8), (uint8_t)(memaddr & 0xFF) };
buff[0].data = maddr;
buff[0].len = 2;
buff[1].data = obj;
buff[1].len = size;
this->bus_->writev(_addr, buff, 2, true);
}
void FRAM32::_readBlock(uint32_t memaddr, uint8_t * obj, uint8_t size)
{
uint8_t _addr = this->address_;
if (memaddr & 0x00010000) _addr += 0x01;
uint8_t maddr[] = { (uint8_t)(memaddr >> 8), (uint8_t)(memaddr & 0xFF) };
this->bus_->write(this->address_, maddr, 2, false);
this->bus_->read(_addr, obj, size);
}
/////////////////////////////////////////////////////////////////////////////
//
// FRAM11
//
/////////////////////////////////////////////////////////////////////////////
//
// FRAM11 PROTECTED
//
void FRAM11::_writeBlock(uint16_t memaddr, uint8_t * obj, uint8_t size)
{
// Device uses Address Pages
uint8_t DeviceAddrWithPageBits = this->address_ | ((memaddr & 0x0700) >> 8);
i2c::WriteBuffer buff[2];
uint8_t maddr = memaddr & 0xFF;
buff[0].data = &maddr;
buff[0].len = 1;
buff[1].data = obj;
buff[1].len = size;
this->bus_->writev(DeviceAddrWithPageBits, buff, 2, true);
}
void FRAM11::_readBlock(uint16_t memaddr, uint8_t * obj, uint8_t size)
{
// Device uses Address Pages
uint8_t DeviceAddrWithPageBits = this->address_ | ((memaddr & 0x0700) >> 8);
uint8_t maddr = memaddr & 0xFF;
this->bus_->write(DeviceAddrWithPageBits, &maddr, 1, false);
this->bus_->read(DeviceAddrWithPageBits, obj, size);
}
/////////////////////////////////////////////////////////////////////////////
//
// FRAM9
//
/////////////////////////////////////////////////////////////////////////////
//
// FRAM9 PROTECTED
//
void FRAM9::_writeBlock(uint16_t memaddr, uint8_t * obj, uint8_t size)
{
// Device uses Address Pages
uint8_t DeviceAddrWithPageBits = this->address_ | ((memaddr & 0x0100) >> 8);
i2c::WriteBuffer buff[2];
uint8_t maddr = memaddr & 0xFF;
buff[0].data = &maddr;
buff[0].len = 1;
buff[1].data = obj;
buff[1].len = size;
this->bus_->writev(DeviceAddrWithPageBits, buff, 2, true);
}
void FRAM9::_readBlock(uint16_t memaddr, uint8_t * obj, uint8_t size)
{
// Device uses Address Pages
uint8_t DeviceAddrWithPageBits = this->address_ | ((memaddr & 0x0100) >> 8);
uint8_t maddr = memaddr & 0xFF;
this->bus_->write(DeviceAddrWithPageBits, &maddr, 1, false);
this->bus_->read(DeviceAddrWithPageBits, obj, size);
}
} // namespace fram
} // namespace esphome
// -- END OF FILE --

View File

@@ -0,0 +1,164 @@
#pragma once
//
// FILE: FRAM.h
// AUTHOR: Rob Tillaart
// VERSION: 0.5.3
// DATE: 2018-01-24
// PURPOSE: Arduino library for I2C FRAM
// URL: https://github.com/RobTillaart/FRAM_I2C
//
// ESPHome port: https://github.com/sharkydog/esphome-fram
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#include "esphome/core/component.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace fram {
class FRAM : public Component, public i2c::I2CDevice
{
public:
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::BUS; }
bool isConnected();
void write8(uint16_t memaddr, uint8_t value);
void write16(uint16_t memaddr, uint16_t value);
void write32(uint16_t memaddr, uint32_t value);
void writeFloat(uint16_t memaddr, float value);
void writeDouble(uint16_t memaddr, double value);
void write(uint16_t memaddr, uint8_t * obj, uint16_t size);
uint8_t read8(uint16_t memaddr);
uint16_t read16(uint16_t memaddr);
uint32_t read32(uint16_t memaddr);
float readFloat(uint16_t memaddr);
double readDouble(uint16_t memaddr);
void read(uint16_t memaddr, uint8_t * obj, uint16_t size);
// Experimental 0.5.1
// readUntil returns length 0.. n of the buffer.
// readUntil does NOT include the separator character.
// readUntil returns -1 if data does not fit into buffer,
// => separator not encountered.
int32_t readUntil(uint16_t memaddr, char * buf, uint16_t buflen, char separator);
// readLine returns length 0.. n of the buffer.
// readLine does include '\n' as end character.
// readLine returns -1 if data does not fit into buffer.
// buffer needs one place for end char '\0'.
int32_t readLine(uint16_t memaddr, char * buf, uint16_t buflen);
template <class T> uint16_t writeObject(uint16_t memaddr, T &obj)
{
this->write(memaddr, (uint8_t *) &obj, sizeof(obj));
return memaddr + sizeof(obj);
};
template <class T> uint16_t readObject(uint16_t memaddr, T &obj)
{
this->read(memaddr, (uint8_t *) &obj, sizeof(obj));
return memaddr + sizeof(obj);
}
// meta info
// Fujitsu = 0x000A, Ramtron = 0x004
uint16_t getManufacturerID();
// Proprietary
uint16_t getProductID();
// Returns size in KILO-BYTE (or 0)
// Verify for all manufacturers.
uint16_t getSize();
// Returns size in BYTE
uint32_t getSizeBytes();
// override when getSize() fails == 0 (see readme.md)
void setSizeBytes(uint32_t value);
// fills FRAM with value, default 0.
uint32_t clear(uint8_t value = 0);
// 0.3.6
void sleep();
// trec <= 400us P12
bool wakeup(uint32_t trec = 400);
protected:
uint32_t _sizeBytes{0};
uint16_t _getMetaData(uint8_t id);
// virtual so derived classes FRAM9/11 use their implementation.
virtual void _writeBlock(uint16_t memaddr, uint8_t * obj, uint8_t size);
virtual void _readBlock(uint16_t memaddr, uint8_t * obj, uint8_t size);
};
/////////////////////////////////////////////////////////////////////////////
//
// FRAM32
//
class FRAM32 : public FRAM
{
public:
void write8(uint32_t memaddr, uint8_t value);
void write16(uint32_t memaddr, uint16_t value);
void write32(uint32_t memaddr, uint32_t value);
void writeFloat(uint32_t memaddr, float value);
void writeDouble(uint32_t memaddr, double value);
void write(uint32_t memaddr, uint8_t * obj, uint16_t size);
uint8_t read8(uint32_t memaddr);
uint16_t read16(uint32_t memaddr);
uint32_t read32(uint32_t memaddr);
float readFloat(uint32_t memaddr);
double readDouble(uint32_t memaddr);
void read(uint32_t memaddr, uint8_t * obj, uint16_t size);
// readUntil returns length 0.. n of the buffer.
// readUntil returns -1 if data does not fit into buffer,
// => separator not encountered.
int32_t readUntil(uint32_t memaddr, char * buf, uint16_t buflen, char separator);
// buffer needs one place for end char '\0'.
int32_t readLine(uint32_t memaddr, char * buf, uint16_t buflen);
template <class T> uint32_t writeObject(uint32_t memaddr, T &obj);
template <class T> uint32_t readObject(uint32_t memaddr, T &obj);
protected:
void _writeBlock(uint32_t memaddr, uint8_t * obj, uint8_t size);
void _readBlock(uint32_t memaddr, uint8_t * obj, uint8_t size);
};
/////////////////////////////////////////////////////////////////////////////
//
// FRAM11 for FRAM that use 11 bits addresses - e.g. MB85RC16
//
class FRAM11 : public FRAM
{
protected:
void _writeBlock(uint16_t memaddr, uint8_t * obj, uint8_t size);
void _readBlock(uint16_t memaddr, uint8_t * obj, uint8_t size);
};
/////////////////////////////////////////////////////////////////////////////
//
// FRAM9 for FRAM that use 9 bits addresses - e.g. MB85RC04
//
class FRAM9 : public FRAM
{
protected:
void _writeBlock(uint16_t memaddr, uint8_t * obj, uint8_t size);
void _readBlock(uint16_t memaddr, uint8_t * obj, uint8_t size);
};
} // namespace fram
} // namespace esphome
// -- END OF FILE --

View File

@@ -0,0 +1,64 @@
import esphome.codegen as cg
import esphome.config_validation as cv
import re
from esphome.components import i2c
from esphome.const import CONF_ID, CONF_TYPE, CONF_SIZE
DEPENDENCIES = ["i2c"]
MULTI_CONF = True
fram_ns = cg.esphome_ns.namespace("fram")
FRAMComponent = fram_ns.class_("FRAM", cg.Component, i2c.I2CDevice)
FRAM9Component = fram_ns.class_("FRAM9", FRAMComponent)
FRAM11Component = fram_ns.class_("FRAM11", FRAMComponent)
FRAM32Component = fram_ns.class_("FRAM32", FRAMComponent)
def validate_bytes_1024(value):
value = cv.string(value).lower()
match = re.match(r"^([0-9]+)\s*(\w*)$", value)
if match is None:
raise cv.Invalid(f"Expected number of bytes with unit, got {value}")
SUFF_LIST = ["B","KB","KiB","MB","MiB"]
SUFF = {
"": 1,
"b": 1,
"kb": 1000,
"kib": 1024,
"mb": pow(1000,2),
"mib": pow(1024,2)
}
if match.group(2) not in SUFF:
raise cv.Invalid(f"Invalid metric suffix {match.group(2)}, valid: {SUFF_LIST}")
return int(int(match.group(1)) * SUFF[match.group(2)])
FRAM_SCHEMA = cv.Schema({
cv.Optional(CONF_SIZE): validate_bytes_1024
}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x50))
CONFIG_SCHEMA = cv.typed_schema({
"FRAM": FRAM_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(FRAMComponent)
}),
"FRAM9": FRAM_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(FRAM9Component)
}),
"FRAM11": FRAM_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(FRAM11Component)
}),
"FRAM32": FRAM_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(FRAM32Component)
})
}, key=CONF_TYPE, default_type="FRAM", upper=True)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
if CONF_SIZE in config:
cg.add(var.setSizeBytes(config[CONF_SIZE]))