mirror of
https://github.com/esphome/esphome.git
synced 2024-11-25 16:38:16 +01:00
Canbus + MCP2515 including ExtID support (#1384)
This commit is contained in:
parent
63c420254a
commit
498b59e998
10 changed files with 1457 additions and 0 deletions
|
@ -19,6 +19,7 @@ esphome/components/async_tcp/* @OttoWinter
|
||||||
esphome/components/atc_mithermometer/* @ahpohl
|
esphome/components/atc_mithermometer/* @ahpohl
|
||||||
esphome/components/bang_bang/* @OttoWinter
|
esphome/components/bang_bang/* @OttoWinter
|
||||||
esphome/components/binary_sensor/* @esphome/core
|
esphome/components/binary_sensor/* @esphome/core
|
||||||
|
esphome/components/canbus/* @danielschramm @mvturnho
|
||||||
esphome/components/captive_portal/* @OttoWinter
|
esphome/components/captive_portal/* @OttoWinter
|
||||||
esphome/components/climate/* @esphome/core
|
esphome/components/climate/* @esphome/core
|
||||||
esphome/components/climate_ir/* @glmnet
|
esphome/components/climate_ir/* @glmnet
|
||||||
|
@ -43,6 +44,7 @@ esphome/components/light/* @esphome/core
|
||||||
esphome/components/logger/* @esphome/core
|
esphome/components/logger/* @esphome/core
|
||||||
esphome/components/mcp23s08/* @SenexCrenshaw
|
esphome/components/mcp23s08/* @SenexCrenshaw
|
||||||
esphome/components/mcp23s17/* @SenexCrenshaw
|
esphome/components/mcp23s17/* @SenexCrenshaw
|
||||||
|
esphome/components/mcp2515/* @danielschramm @mvturnho
|
||||||
esphome/components/mcp9808/* @k7hpn
|
esphome/components/mcp9808/* @k7hpn
|
||||||
esphome/components/network/* @esphome/core
|
esphome/components/network/* @esphome/core
|
||||||
esphome/components/ota/* @esphome/core
|
esphome/components/ota/* @esphome/core
|
||||||
|
|
124
esphome/components/canbus/__init__.py
Normal file
124
esphome/components/canbus/__init__.py
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome import automation
|
||||||
|
from esphome.core import CORE, coroutine
|
||||||
|
from esphome.const import CONF_ID, CONF_TRIGGER_ID, CONF_DATA
|
||||||
|
|
||||||
|
CODEOWNERS = ['@mvturnho', '@danielschramm']
|
||||||
|
IS_PLATFORM_COMPONENT = True
|
||||||
|
|
||||||
|
CONF_CAN_ID = 'can_id'
|
||||||
|
CONF_USE_EXTENDED_ID = 'use_extended_id'
|
||||||
|
CONF_CANBUS_ID = 'canbus_id'
|
||||||
|
CONF_BIT_RATE = 'bit_rate'
|
||||||
|
CONF_ON_FRAME = 'on_frame'
|
||||||
|
CONF_CANBUS_SEND = 'canbus.send'
|
||||||
|
|
||||||
|
|
||||||
|
def validate_id(id_value, id_ext):
|
||||||
|
if not id_ext:
|
||||||
|
if id_value > 0x7ff:
|
||||||
|
raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)")
|
||||||
|
|
||||||
|
|
||||||
|
def validate_raw_data(value):
|
||||||
|
if isinstance(value, str):
|
||||||
|
return value.encode('utf-8')
|
||||||
|
if isinstance(value, list):
|
||||||
|
return cv.Schema([cv.hex_uint8_t])(value)
|
||||||
|
raise cv.Invalid("data must either be a string wrapped in quotes or a list of bytes")
|
||||||
|
|
||||||
|
|
||||||
|
canbus_ns = cg.esphome_ns.namespace('canbus')
|
||||||
|
CanbusComponent = canbus_ns.class_('CanbusComponent', cg.Component)
|
||||||
|
CanbusTrigger = canbus_ns.class_('CanbusTrigger',
|
||||||
|
automation.Trigger.template(cg.std_vector.template(cg.uint8)),
|
||||||
|
cg.Component)
|
||||||
|
CanSpeed = canbus_ns.enum('CAN_SPEED')
|
||||||
|
|
||||||
|
CAN_SPEEDS = {
|
||||||
|
'5KBPS': CanSpeed.CAN_5KBPS,
|
||||||
|
'10KBPS': CanSpeed.CAN_10KBPS,
|
||||||
|
'20KBPS': CanSpeed.CAN_20KBPS,
|
||||||
|
'31K25BPS': CanSpeed.CAN_31K25BPS,
|
||||||
|
'33KBPS': CanSpeed.CAN_33KBPS,
|
||||||
|
'40KBPS': CanSpeed.CAN_40KBPS,
|
||||||
|
'50KBPS': CanSpeed.CAN_50KBPS,
|
||||||
|
'80KBPS': CanSpeed.CAN_80KBPS,
|
||||||
|
'83K3BPS': CanSpeed.CAN_83K3BPS,
|
||||||
|
'95KBPS': CanSpeed.CAN_95KBPS,
|
||||||
|
'100KBPS': CanSpeed.CAN_100KBPS,
|
||||||
|
'125KBPS': CanSpeed.CAN_125KBPS,
|
||||||
|
'200KBPS': CanSpeed.CAN_200KBPS,
|
||||||
|
'250KBPS': CanSpeed.CAN_250KBPS,
|
||||||
|
'500KBPS': CanSpeed.CAN_500KBPS,
|
||||||
|
'1000KBPS': CanSpeed.CAN_1000KBPS,
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.Schema({
|
||||||
|
cv.GenerateID(): cv.declare_id(CanbusComponent),
|
||||||
|
cv.Required(CONF_CAN_ID): cv.int_range(min=0, max=0x1fffffff),
|
||||||
|
cv.Optional(CONF_BIT_RATE, default='125KBPS'): cv.enum(CAN_SPEEDS, upper=True),
|
||||||
|
cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_ON_FRAME): automation.validate_automation({
|
||||||
|
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CanbusTrigger),
|
||||||
|
cv.GenerateID(CONF_CAN_ID): cv.int_range(min=0, max=0x1fffffff),
|
||||||
|
cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean,
|
||||||
|
}),
|
||||||
|
}).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
|
||||||
|
@coroutine
|
||||||
|
def setup_canbus_core_(var, config):
|
||||||
|
validate_id(config[CONF_CAN_ID], config[CONF_USE_EXTENDED_ID])
|
||||||
|
yield cg.register_component(var, config)
|
||||||
|
cg.add(var.set_can_id([config[CONF_CAN_ID]]))
|
||||||
|
cg.add(var.set_use_extended_id([config[CONF_USE_EXTENDED_ID]]))
|
||||||
|
cg.add(var.set_bitrate(CAN_SPEEDS[config[CONF_BIT_RATE]]))
|
||||||
|
|
||||||
|
for conf in config.get(CONF_ON_FRAME, []):
|
||||||
|
can_id = conf[CONF_CAN_ID]
|
||||||
|
ext_id = conf[CONF_USE_EXTENDED_ID]
|
||||||
|
validate_id(can_id, ext_id)
|
||||||
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, can_id, ext_id)
|
||||||
|
yield cg.register_component(trigger, conf)
|
||||||
|
yield automation.build_automation(trigger, [(cg.std_vector.template(cg.uint8), 'x')], conf)
|
||||||
|
|
||||||
|
|
||||||
|
@coroutine
|
||||||
|
def register_canbus(var, config):
|
||||||
|
if not CORE.has_id(config[CONF_ID]):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID], var)
|
||||||
|
yield setup_canbus_core_(var, config)
|
||||||
|
|
||||||
|
|
||||||
|
# Actions
|
||||||
|
@automation.register_action(CONF_CANBUS_SEND,
|
||||||
|
canbus_ns.class_('CanbusSendAction', automation.Action),
|
||||||
|
cv.maybe_simple_value({
|
||||||
|
cv.GenerateID(CONF_CANBUS_ID): cv.use_id(CanbusComponent),
|
||||||
|
cv.Optional(CONF_CAN_ID): cv.int_range(min=0, max=0x1fffffff),
|
||||||
|
cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean,
|
||||||
|
cv.Required(CONF_DATA): cv.templatable(validate_raw_data),
|
||||||
|
}, key=CONF_DATA))
|
||||||
|
def canbus_action_to_code(config, action_id, template_arg, args):
|
||||||
|
validate_id(config[CONF_CAN_ID], config[CONF_USE_EXTENDED_ID])
|
||||||
|
var = cg.new_Pvariable(action_id, template_arg)
|
||||||
|
yield cg.register_parented(var, config[CONF_CANBUS_ID])
|
||||||
|
|
||||||
|
if CONF_CAN_ID in config:
|
||||||
|
can_id = yield cg.templatable(config[CONF_CAN_ID], args, cg.uint32)
|
||||||
|
cg.add(var.set_can_id(can_id))
|
||||||
|
|
||||||
|
use_extended_id = yield cg.templatable(config[CONF_USE_EXTENDED_ID], args, cg.uint32)
|
||||||
|
cg.add(var.set_use_extended_id(use_extended_id))
|
||||||
|
|
||||||
|
data = config[CONF_DATA]
|
||||||
|
if isinstance(data, bytes):
|
||||||
|
data = [int(x) for x in data]
|
||||||
|
if cg.is_template(data):
|
||||||
|
templ = yield cg.templatable(data, args, cg.std_vector.template(cg.uint8))
|
||||||
|
cg.add(var.set_data_template(templ))
|
||||||
|
else:
|
||||||
|
cg.add(var.set_data_static(data))
|
||||||
|
yield var
|
87
esphome/components/canbus/canbus.cpp
Normal file
87
esphome/components/canbus/canbus.cpp
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#include "canbus.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace canbus {
|
||||||
|
|
||||||
|
static const char *TAG = "canbus";
|
||||||
|
|
||||||
|
void Canbus::setup() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Setting up Canbus...");
|
||||||
|
if (!this->setup_internal()) {
|
||||||
|
ESP_LOGE(TAG, "setup error!");
|
||||||
|
this->mark_failed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canbus::dump_config() {
|
||||||
|
if (this->use_extended_id_) {
|
||||||
|
ESP_LOGCONFIG(TAG, "config extended id=0x%08x", this->can_id_);
|
||||||
|
} else {
|
||||||
|
ESP_LOGCONFIG(TAG, "config standard id=0x%03x", this->can_id_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canbus::send_data(uint32_t can_id, bool use_extended_id, const std::vector<uint8_t> &data) {
|
||||||
|
struct CanFrame can_message;
|
||||||
|
|
||||||
|
uint8_t size = static_cast<uint8_t>(data.size());
|
||||||
|
if (use_extended_id) {
|
||||||
|
ESP_LOGD(TAG, "send extended id=0x%08x size=%d", can_id, size);
|
||||||
|
} else {
|
||||||
|
ESP_LOGD(TAG, "send extended id=0x%03x size=%d", can_id, size);
|
||||||
|
}
|
||||||
|
if (size > CAN_MAX_DATA_LENGTH)
|
||||||
|
size = CAN_MAX_DATA_LENGTH;
|
||||||
|
can_message.can_data_length_code = size;
|
||||||
|
can_message.can_id = can_id;
|
||||||
|
can_message.use_extended_id = use_extended_id;
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
can_message.data[i] = data[i];
|
||||||
|
ESP_LOGVV(TAG, " data[%d]=%02x", i, can_message.data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->send_message(&can_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canbus::add_trigger(CanbusTrigger *trigger) {
|
||||||
|
if (trigger->use_extended_id_) {
|
||||||
|
ESP_LOGVV(TAG, "add trigger for extended canid=0x%08x", trigger->can_id_);
|
||||||
|
} else {
|
||||||
|
ESP_LOGVV(TAG, "add trigger for std canid=0x%03x", trigger->can_id_);
|
||||||
|
}
|
||||||
|
this->triggers_.push_back(trigger);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Canbus::loop() {
|
||||||
|
struct CanFrame can_message;
|
||||||
|
// readmessage
|
||||||
|
if (this->read_message(&can_message) == canbus::ERROR_OK) {
|
||||||
|
if (can_message.use_extended_id) {
|
||||||
|
ESP_LOGD(TAG, "received can message extended can_id=0x%x size=%d", can_message.can_id,
|
||||||
|
can_message.can_data_length_code);
|
||||||
|
} else {
|
||||||
|
ESP_LOGD(TAG, "received can message std can_id=0x%x size=%d", can_message.can_id,
|
||||||
|
can_message.can_data_length_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
// show data received
|
||||||
|
for (int i = 0; i < can_message.can_data_length_code; i++) {
|
||||||
|
ESP_LOGV(TAG, " can_message.data[%d]=%02x", i, can_message.data[i]);
|
||||||
|
data.push_back(can_message.data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fire all triggers
|
||||||
|
for (auto trigger : this->triggers_) {
|
||||||
|
if ((trigger->can_id_ == can_message.can_id) && (trigger->use_extended_id_ == can_message.use_extended_id)) {
|
||||||
|
trigger->trigger(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace canbus
|
||||||
|
} // namespace esphome
|
134
esphome/components/canbus/canbus.h
Normal file
134
esphome/components/canbus/canbus.h
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/automation.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/optional.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace canbus {
|
||||||
|
|
||||||
|
enum Error : uint8_t {
|
||||||
|
ERROR_OK = 0,
|
||||||
|
ERROR_FAIL = 1,
|
||||||
|
ERROR_ALLTXBUSY = 2,
|
||||||
|
ERROR_FAILINIT = 3,
|
||||||
|
ERROR_FAILTX = 4,
|
||||||
|
ERROR_NOMSG = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CanSpeed : uint8_t {
|
||||||
|
CAN_5KBPS,
|
||||||
|
CAN_10KBPS,
|
||||||
|
CAN_20KBPS,
|
||||||
|
CAN_31K25BPS,
|
||||||
|
CAN_33KBPS,
|
||||||
|
CAN_40KBPS,
|
||||||
|
CAN_50KBPS,
|
||||||
|
CAN_80KBPS,
|
||||||
|
CAN_83K3BPS,
|
||||||
|
CAN_95KBPS,
|
||||||
|
CAN_100KBPS,
|
||||||
|
CAN_125KBPS,
|
||||||
|
CAN_200KBPS,
|
||||||
|
CAN_250KBPS,
|
||||||
|
CAN_500KBPS,
|
||||||
|
CAN_1000KBPS
|
||||||
|
};
|
||||||
|
|
||||||
|
class CanbusTrigger;
|
||||||
|
template<typename... Ts> class CanbusSendAction;
|
||||||
|
|
||||||
|
/* CAN payload length definitions according to ISO 11898-1 */
|
||||||
|
static const uint8_t CAN_MAX_DATA_LENGTH = 8;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Can Frame describes a normative CAN Frame
|
||||||
|
The RTR = Remote Transmission Request is implemented in every CAN controller but rarely used
|
||||||
|
So currently the flag is passed to and from the hardware but currently ignored to the user application.
|
||||||
|
*/
|
||||||
|
struct CanFrame {
|
||||||
|
bool use_extended_id = false;
|
||||||
|
bool remote_transmission_request = false;
|
||||||
|
uint32_t can_id; /* 29 or 11 bit CAN_ID */
|
||||||
|
uint8_t can_data_length_code; /* frame payload length in byte (0 .. CAN_MAX_DATA_LENGTH) */
|
||||||
|
uint8_t data[CAN_MAX_DATA_LENGTH] __attribute__((aligned(8)));
|
||||||
|
};
|
||||||
|
|
||||||
|
class Canbus : public Component {
|
||||||
|
public:
|
||||||
|
Canbus(){};
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||||
|
void loop() override;
|
||||||
|
|
||||||
|
void send_data(uint32_t can_id, bool use_extended_id, const std::vector<uint8_t> &data);
|
||||||
|
void set_can_id(uint32_t can_id) { this->can_id_ = can_id; }
|
||||||
|
void set_use_extended_id(bool use_extended_id) { this->use_extended_id_ = use_extended_id; }
|
||||||
|
void set_bitrate(CanSpeed bit_rate) { this->bit_rate_ = bit_rate; }
|
||||||
|
|
||||||
|
void add_trigger(CanbusTrigger *trigger);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template<typename... Ts> friend class CanbusSendAction;
|
||||||
|
std::vector<CanbusTrigger *> triggers_{};
|
||||||
|
uint32_t can_id_;
|
||||||
|
bool use_extended_id_;
|
||||||
|
CanSpeed bit_rate_;
|
||||||
|
|
||||||
|
virtual bool setup_internal();
|
||||||
|
virtual Error send_message(struct CanFrame *frame);
|
||||||
|
virtual Error read_message(struct CanFrame *frame);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts> class CanbusSendAction : public Action<Ts...>, public Parented<Canbus> {
|
||||||
|
public:
|
||||||
|
void set_data_template(const std::function<std::vector<uint8_t>(Ts...)> func) {
|
||||||
|
this->data_func_ = func;
|
||||||
|
this->static_ = false;
|
||||||
|
}
|
||||||
|
void set_data_static(const std::vector<uint8_t> &data) {
|
||||||
|
this->data_static_ = data;
|
||||||
|
this->static_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_can_id(uint32_t can_id) { this->can_id_ = can_id; }
|
||||||
|
|
||||||
|
void set_use_extended_id(bool use_extended_id) { this->use_extended_id_ = use_extended_id; }
|
||||||
|
|
||||||
|
void play(Ts... x) override {
|
||||||
|
auto can_id = this->can_id_.has_value() ? *this->can_id_ : this->parent_->can_id_;
|
||||||
|
auto use_extended_id =
|
||||||
|
this->use_extended_id_.has_value() ? *this->use_extended_id_ : this->parent_->use_extended_id_;
|
||||||
|
if (this->static_) {
|
||||||
|
this->parent_->send_data(can_id, use_extended_id, this->data_static_);
|
||||||
|
} else {
|
||||||
|
auto val = this->data_func_(x...);
|
||||||
|
this->parent_->send_data(can_id, use_extended_id, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
optional<uint32_t> can_id_{};
|
||||||
|
optional<bool> use_extended_id_{};
|
||||||
|
bool static_{false};
|
||||||
|
std::function<std::vector<uint8_t>(Ts...)> data_func_{};
|
||||||
|
std::vector<uint8_t> data_static_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class CanbusTrigger : public Trigger<std::vector<uint8_t>>, public Component {
|
||||||
|
friend class Canbus;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CanbusTrigger(Canbus *parent, const std::uint32_t can_id, const bool use_extended_id)
|
||||||
|
: parent_(parent), can_id_(can_id), use_extended_id_(use_extended_id){};
|
||||||
|
void setup() override { this->parent_->add_trigger(this); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Canbus *parent_;
|
||||||
|
uint32_t can_id_;
|
||||||
|
bool use_extended_id_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace canbus
|
||||||
|
} // namespace esphome
|
0
esphome/components/mcp2515/__init__.py
Normal file
0
esphome/components/mcp2515/__init__.py
Normal file
47
esphome/components/mcp2515/canbus.py
Normal file
47
esphome/components/mcp2515/canbus.py
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import spi, canbus
|
||||||
|
from esphome.const import CONF_ID, CONF_MODE
|
||||||
|
from esphome.components.canbus import CanbusComponent
|
||||||
|
|
||||||
|
CODEOWNERS = ['@mvturnho', '@danielschramm']
|
||||||
|
DEPENDENCIES = ['spi']
|
||||||
|
|
||||||
|
CONF_CLOCK = 'clock'
|
||||||
|
|
||||||
|
mcp2515_ns = cg.esphome_ns.namespace('mcp2515')
|
||||||
|
mcp2515 = mcp2515_ns.class_('MCP2515', CanbusComponent, spi.SPIDevice)
|
||||||
|
CanClock = mcp2515_ns.enum('CAN_CLOCK')
|
||||||
|
McpMode = mcp2515_ns.enum('CANCTRL_REQOP_MODE')
|
||||||
|
|
||||||
|
CAN_CLOCK = {
|
||||||
|
'8MHZ': CanClock.MCP_8MHZ,
|
||||||
|
'16MHZ': CanClock.MCP_16MHZ,
|
||||||
|
'20MHZ': CanClock.MCP_20MHZ,
|
||||||
|
}
|
||||||
|
|
||||||
|
MCP_MODE = {
|
||||||
|
'NORMAL': McpMode.CANCTRL_REQOP_NORMAL,
|
||||||
|
'LOOPBACK': McpMode.CANCTRL_REQOP_LOOPBACK,
|
||||||
|
'LISTENONLY': McpMode.CANCTRL_REQOP_LISTENONLY,
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = canbus.CONFIG_SCHEMA.extend({
|
||||||
|
cv.GenerateID(): cv.declare_id(mcp2515),
|
||||||
|
cv.Optional(CONF_CLOCK, default='8MHZ'): cv.enum(CAN_CLOCK, upper=True),
|
||||||
|
cv.Optional(CONF_MODE, default='NORMAL'): cv.enum(MCP_MODE, upper=True),
|
||||||
|
}).extend(spi.spi_device_schema(True))
|
||||||
|
|
||||||
|
|
||||||
|
def to_code(config):
|
||||||
|
rhs = mcp2515.new()
|
||||||
|
var = cg.Pvariable(config[CONF_ID], rhs)
|
||||||
|
yield canbus.register_canbus(var, config)
|
||||||
|
if CONF_CLOCK in config:
|
||||||
|
canclock = CAN_CLOCK[config[CONF_CLOCK]]
|
||||||
|
cg.add(var.set_mcp_clock(canclock))
|
||||||
|
if CONF_MODE in config:
|
||||||
|
mode = MCP_MODE[config[CONF_MODE]]
|
||||||
|
cg.add(var.set_mcp_mode(mode))
|
||||||
|
|
||||||
|
yield spi.register_spi_device(var, config)
|
612
esphome/components/mcp2515/mcp2515.cpp
Normal file
612
esphome/components/mcp2515/mcp2515.cpp
Normal file
|
@ -0,0 +1,612 @@
|
||||||
|
#include "mcp2515.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace mcp2515 {
|
||||||
|
|
||||||
|
static const char *TAG = "mcp2515";
|
||||||
|
|
||||||
|
const struct MCP2515::TxBnRegs MCP2515::TXB[N_TXBUFFERS] = {{MCP_TXB0CTRL, MCP_TXB0SIDH, MCP_TXB0DATA},
|
||||||
|
{MCP_TXB1CTRL, MCP_TXB1SIDH, MCP_TXB1DATA},
|
||||||
|
{MCP_TXB2CTRL, MCP_TXB2SIDH, MCP_TXB2DATA}};
|
||||||
|
|
||||||
|
const struct MCP2515::RxBnRegs MCP2515::RXB[N_RXBUFFERS] = {{MCP_RXB0CTRL, MCP_RXB0SIDH, MCP_RXB0DATA, CANINTF_RX0IF},
|
||||||
|
{MCP_RXB1CTRL, MCP_RXB1SIDH, MCP_RXB1DATA, CANINTF_RX1IF}};
|
||||||
|
|
||||||
|
bool MCP2515::setup_internal() {
|
||||||
|
this->spi_setup();
|
||||||
|
|
||||||
|
if (this->reset_() == canbus::ERROR_FAIL)
|
||||||
|
return false;
|
||||||
|
this->set_bitrate_(this->bit_rate_, this->mcp_clock_);
|
||||||
|
this->set_mode_(this->mcp_mode_);
|
||||||
|
ESP_LOGV(TAG, "setup done");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
canbus::Error MCP2515::reset_() {
|
||||||
|
this->enable();
|
||||||
|
this->transfer_byte(INSTRUCTION_RESET);
|
||||||
|
this->disable();
|
||||||
|
ESP_LOGV(TAG, "reset_()");
|
||||||
|
delay(10);
|
||||||
|
|
||||||
|
ESP_LOGV(TAG, "reset() CLEAR ALL TXB registers");
|
||||||
|
|
||||||
|
uint8_t zeros[14];
|
||||||
|
memset(zeros, 0, sizeof(zeros));
|
||||||
|
set_registers_(MCP_TXB0CTRL, zeros, 14);
|
||||||
|
set_registers_(MCP_TXB1CTRL, zeros, 14);
|
||||||
|
set_registers_(MCP_TXB2CTRL, zeros, 14);
|
||||||
|
ESP_LOGD(TAG, "reset() CLEARED TXB registers");
|
||||||
|
|
||||||
|
set_register_(MCP_RXB0CTRL, 0);
|
||||||
|
set_register_(MCP_RXB1CTRL, 0);
|
||||||
|
|
||||||
|
set_register_(MCP_CANINTE, CANINTF_RX0IF | CANINTF_RX1IF | CANINTF_ERRIF | CANINTF_MERRF);
|
||||||
|
|
||||||
|
modify_register_(MCP_RXB0CTRL, RXB_CTRL_RXM_MASK | RXB_0_CTRL_BUKT, RXB_CTRL_RXM_STDEXT | RXB_0_CTRL_BUKT);
|
||||||
|
modify_register_(MCP_RXB1CTRL, RXB_CTRL_RXM_MASK, RXB_CTRL_RXM_STDEXT);
|
||||||
|
|
||||||
|
return canbus::ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t MCP2515::read_register_(const REGISTER reg) {
|
||||||
|
this->enable();
|
||||||
|
this->transfer_byte(INSTRUCTION_READ);
|
||||||
|
this->transfer_byte(reg);
|
||||||
|
uint8_t ret = this->transfer_byte(0x00);
|
||||||
|
this->disable();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP2515::read_registers_(const REGISTER reg, uint8_t values[], const uint8_t n) {
|
||||||
|
this->enable();
|
||||||
|
this->transfer_byte(INSTRUCTION_READ);
|
||||||
|
this->transfer_byte(reg);
|
||||||
|
// this->transfer_array(values, n);
|
||||||
|
// mcp2515 has auto - increment of address - pointer
|
||||||
|
for (uint8_t i = 0; i < n; i++) {
|
||||||
|
values[i] = this->transfer_byte(0x00);
|
||||||
|
}
|
||||||
|
this->disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP2515::set_register_(const REGISTER reg, const uint8_t value) {
|
||||||
|
this->enable();
|
||||||
|
this->transfer_byte(INSTRUCTION_WRITE);
|
||||||
|
this->transfer_byte(reg);
|
||||||
|
this->transfer_byte(value);
|
||||||
|
this->disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP2515::set_registers_(const REGISTER reg, uint8_t values[], const uint8_t n) {
|
||||||
|
this->enable();
|
||||||
|
this->transfer_byte(INSTRUCTION_WRITE);
|
||||||
|
this->transfer_byte(reg);
|
||||||
|
// this->transfer_array(values, n);
|
||||||
|
for (uint8_t i = 0; i < n; i++) {
|
||||||
|
this->transfer_byte(values[i]);
|
||||||
|
}
|
||||||
|
this->disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP2515::modify_register_(const REGISTER reg, const uint8_t mask, const uint8_t data) {
|
||||||
|
this->enable();
|
||||||
|
this->transfer_byte(INSTRUCTION_BITMOD);
|
||||||
|
this->transfer_byte(reg);
|
||||||
|
this->transfer_byte(mask);
|
||||||
|
this->transfer_byte(data);
|
||||||
|
this->disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t MCP2515::get_status_() {
|
||||||
|
this->enable();
|
||||||
|
this->transfer_byte(INSTRUCTION_READ_STATUS);
|
||||||
|
uint8_t i = this->transfer_byte(0x00);
|
||||||
|
this->disable();
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
canbus::Error MCP2515::set_mode_(const CanctrlReqopMode mode) {
|
||||||
|
modify_register_(MCP_CANCTRL, CANCTRL_REQOP, mode);
|
||||||
|
|
||||||
|
unsigned long end_time = millis() + 10;
|
||||||
|
bool mode_match = false;
|
||||||
|
while (millis() < end_time) {
|
||||||
|
uint8_t new_mode = read_register_(MCP_CANSTAT);
|
||||||
|
new_mode &= CANSTAT_OPMOD;
|
||||||
|
mode_match = new_mode == mode;
|
||||||
|
if (mode_match) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mode_match ? canbus::ERROR_OK : canbus::ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
canbus::Error MCP2515::set_clk_out_(const CanClkOut divisor) {
|
||||||
|
canbus::Error res;
|
||||||
|
uint8_t cfg3;
|
||||||
|
|
||||||
|
if (divisor == CLKOUT_DISABLE) {
|
||||||
|
/* Turn off CLKEN */
|
||||||
|
modify_register_(MCP_CANCTRL, CANCTRL_CLKEN, 0x00);
|
||||||
|
|
||||||
|
/* Turn on CLKOUT for SOF */
|
||||||
|
modify_register_(MCP_CNF3, CNF3_SOF, CNF3_SOF);
|
||||||
|
return canbus::ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the prescaler (CLKPRE) */
|
||||||
|
modify_register_(MCP_CANCTRL, CANCTRL_CLKPRE, divisor);
|
||||||
|
|
||||||
|
/* Turn on CLKEN */
|
||||||
|
modify_register_(MCP_CANCTRL, CANCTRL_CLKEN, CANCTRL_CLKEN);
|
||||||
|
|
||||||
|
/* Turn off CLKOUT for SOF */
|
||||||
|
modify_register_(MCP_CNF3, CNF3_SOF, 0x00);
|
||||||
|
return canbus::ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP2515::prepare_id_(uint8_t *buffer, const bool extended, const uint32_t id) {
|
||||||
|
uint16_t canid = (uint16_t)(id & 0x0FFFF);
|
||||||
|
|
||||||
|
if (extended) {
|
||||||
|
buffer[MCP_EID0] = (uint8_t)(canid & 0xFF);
|
||||||
|
buffer[MCP_EID8] = (uint8_t)(canid >> 8);
|
||||||
|
canid = (uint16_t)(id >> 16);
|
||||||
|
buffer[MCP_SIDL] = (uint8_t)(canid & 0x03);
|
||||||
|
buffer[MCP_SIDL] += (uint8_t)((canid & 0x1C) << 3);
|
||||||
|
buffer[MCP_SIDL] |= TXB_EXIDE_MASK;
|
||||||
|
buffer[MCP_SIDH] = (uint8_t)(canid >> 5);
|
||||||
|
} else {
|
||||||
|
buffer[MCP_SIDH] = (uint8_t)(canid >> 3);
|
||||||
|
buffer[MCP_SIDL] = (uint8_t)((canid & 0x07) << 5);
|
||||||
|
buffer[MCP_EID0] = 0;
|
||||||
|
buffer[MCP_EID8] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canbus::Error MCP2515::set_filter_mask_(const MASK mask, const bool extended, const uint32_t ul_data) {
|
||||||
|
canbus::Error res = set_mode_(CANCTRL_REQOP_CONFIG);
|
||||||
|
if (res != canbus::ERROR_OK) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t tbufdata[4];
|
||||||
|
prepare_id_(tbufdata, extended, ul_data);
|
||||||
|
|
||||||
|
REGISTER reg;
|
||||||
|
switch (mask) {
|
||||||
|
case MASK0:
|
||||||
|
reg = MCP_RXM0SIDH;
|
||||||
|
break;
|
||||||
|
case MASK1:
|
||||||
|
reg = MCP_RXM1SIDH;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return canbus::ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_registers_(reg, tbufdata, 4);
|
||||||
|
|
||||||
|
return canbus::ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
canbus::Error MCP2515::set_filter_(const RXF num, const bool extended, const uint32_t ul_data) {
|
||||||
|
canbus::Error res = set_mode_(CANCTRL_REQOP_CONFIG);
|
||||||
|
if (res != canbus::ERROR_OK) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER reg;
|
||||||
|
|
||||||
|
switch (num) {
|
||||||
|
case RXF0:
|
||||||
|
reg = MCP_RXF0SIDH;
|
||||||
|
break;
|
||||||
|
case RXF1:
|
||||||
|
reg = MCP_RXF1SIDH;
|
||||||
|
break;
|
||||||
|
case RXF2:
|
||||||
|
reg = MCP_RXF2SIDH;
|
||||||
|
break;
|
||||||
|
case RXF3:
|
||||||
|
reg = MCP_RXF3SIDH;
|
||||||
|
break;
|
||||||
|
case RXF4:
|
||||||
|
reg = MCP_RXF4SIDH;
|
||||||
|
break;
|
||||||
|
case RXF5:
|
||||||
|
reg = MCP_RXF5SIDH;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return canbus::ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t tbufdata[4];
|
||||||
|
prepare_id_(tbufdata, extended, ul_data);
|
||||||
|
set_registers_(reg, tbufdata, 4);
|
||||||
|
|
||||||
|
return canbus::ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
canbus::Error MCP2515::send_message_(TXBn txbn, struct canbus::CanFrame *frame) {
|
||||||
|
const struct TxBnRegs *txbuf = &TXB[txbn];
|
||||||
|
|
||||||
|
uint8_t data[13];
|
||||||
|
|
||||||
|
prepare_id_(data, frame->use_extended_id, frame->can_id);
|
||||||
|
data[MCP_DLC] =
|
||||||
|
frame->remote_transmission_request ? (frame->can_data_length_code | RTR_MASK) : frame->can_data_length_code;
|
||||||
|
memcpy(&data[MCP_DATA], frame->data, frame->can_data_length_code);
|
||||||
|
set_registers_(txbuf->SIDH, data, 5 + frame->can_data_length_code);
|
||||||
|
modify_register_(txbuf->CTRL, TXB_TXREQ, TXB_TXREQ);
|
||||||
|
|
||||||
|
return canbus::ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
canbus::Error MCP2515::send_message(struct canbus::CanFrame *frame) {
|
||||||
|
if (frame->can_data_length_code > canbus::CAN_MAX_DATA_LENGTH) {
|
||||||
|
return canbus::ERROR_FAILTX;
|
||||||
|
}
|
||||||
|
TXBn tx_buffers[N_TXBUFFERS] = {TXB0, TXB1, TXB2};
|
||||||
|
|
||||||
|
for (auto &tx_buffer : tx_buffers) {
|
||||||
|
const struct TxBnRegs *txbuf = &TXB[tx_buffer];
|
||||||
|
uint8_t ctrlval = read_register_(txbuf->CTRL);
|
||||||
|
if ((ctrlval & TXB_TXREQ) == 0) {
|
||||||
|
return send_message_(tx_buffer, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return canbus::ERROR_FAILTX;
|
||||||
|
}
|
||||||
|
|
||||||
|
canbus::Error MCP2515::read_message_(RXBn rxbn, struct canbus::CanFrame *frame) {
|
||||||
|
const struct RxBnRegs *rxb = &RXB[rxbn];
|
||||||
|
|
||||||
|
uint8_t tbufdata[5];
|
||||||
|
|
||||||
|
read_registers_(rxb->SIDH, tbufdata, 5);
|
||||||
|
|
||||||
|
uint32_t id = (tbufdata[MCP_SIDH] << 3) + (tbufdata[MCP_SIDL] >> 5);
|
||||||
|
bool use_extended_id = false;
|
||||||
|
bool remote_transmission_request = false;
|
||||||
|
|
||||||
|
if ((tbufdata[MCP_SIDL] & TXB_EXIDE_MASK) == TXB_EXIDE_MASK) {
|
||||||
|
id = (id << 2) + (tbufdata[MCP_SIDL] & 0x03);
|
||||||
|
id = (id << 8) + tbufdata[MCP_EID8];
|
||||||
|
id = (id << 8) + tbufdata[MCP_EID0];
|
||||||
|
// id |= canbus::CAN_EFF_FLAG;
|
||||||
|
use_extended_id = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dlc = (tbufdata[MCP_DLC] & DLC_MASK);
|
||||||
|
if (dlc > canbus::CAN_MAX_DATA_LENGTH) {
|
||||||
|
return canbus::ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ctrl = read_register_(rxb->CTRL);
|
||||||
|
if (ctrl & RXB_CTRL_RTR) {
|
||||||
|
// id |= canbus::CAN_RTR_FLAG;
|
||||||
|
remote_transmission_request = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->can_id = id;
|
||||||
|
frame->can_data_length_code = dlc;
|
||||||
|
frame->use_extended_id = use_extended_id;
|
||||||
|
frame->remote_transmission_request = remote_transmission_request;
|
||||||
|
|
||||||
|
read_registers_(rxb->DATA, frame->data, dlc);
|
||||||
|
|
||||||
|
modify_register_(MCP_CANINTF, rxb->CANINTF_RXnIF, 0);
|
||||||
|
|
||||||
|
return canbus::ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
canbus::Error MCP2515::read_message(struct canbus::CanFrame *frame) {
|
||||||
|
canbus::Error rc;
|
||||||
|
uint8_t stat = get_status_();
|
||||||
|
|
||||||
|
if (stat & STAT_RX0IF) {
|
||||||
|
rc = read_message_(RXB0, frame);
|
||||||
|
} else if (stat & STAT_RX1IF) {
|
||||||
|
rc = read_message_(RXB1, frame);
|
||||||
|
} else {
|
||||||
|
rc = canbus::ERROR_NOMSG;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MCP2515::check_receive_() {
|
||||||
|
uint8_t res = get_status_();
|
||||||
|
return (res & STAT_RXIF_MASK) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MCP2515::check_error_() {
|
||||||
|
uint8_t eflg = get_error_flags_();
|
||||||
|
return (eflg & EFLG_ERRORMASK) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t MCP2515::get_error_flags_() { return read_register_(MCP_EFLG); }
|
||||||
|
|
||||||
|
void MCP2515::clear_rx_n_ovr_flags_() { modify_register_(MCP_EFLG, EFLG_RX0OVR | EFLG_RX1OVR, 0); }
|
||||||
|
|
||||||
|
uint8_t MCP2515::get_int_() { return read_register_(MCP_CANINTF); }
|
||||||
|
|
||||||
|
void MCP2515::clear_int_() { set_register_(MCP_CANINTF, 0); }
|
||||||
|
|
||||||
|
uint8_t MCP2515::get_int_mask_() { return read_register_(MCP_CANINTE); }
|
||||||
|
|
||||||
|
void MCP2515::clear_tx_int_() { modify_register_(MCP_CANINTF, (CANINTF_TX0IF | CANINTF_TX1IF | CANINTF_TX2IF), 0); }
|
||||||
|
|
||||||
|
void MCP2515::clear_rx_n_ovr_() {
|
||||||
|
uint8_t eflg = get_error_flags_();
|
||||||
|
if (eflg != 0) {
|
||||||
|
clear_rx_n_ovr_flags_();
|
||||||
|
clear_int_();
|
||||||
|
// modify_register_(MCP_CANINTF, CANINTF_ERRIF, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP2515::clear_merr_() {
|
||||||
|
// modify_register_(MCP_EFLG, EFLG_RX0OVR | EFLG_RX1OVR, 0);
|
||||||
|
// clear_int_();
|
||||||
|
modify_register_(MCP_CANINTF, CANINTF_MERRF, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP2515::clear_errif_() {
|
||||||
|
// modify_register_(MCP_EFLG, EFLG_RX0OVR | EFLG_RX1OVR, 0);
|
||||||
|
// clear_int_();
|
||||||
|
modify_register_(MCP_CANINTF, CANINTF_ERRIF, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
canbus::Error MCP2515::set_bitrate_(canbus::CanSpeed can_speed) { return this->set_bitrate_(can_speed, MCP_16MHZ); }
|
||||||
|
|
||||||
|
canbus::Error MCP2515::set_bitrate_(canbus::CanSpeed can_speed, CanClock can_clock) {
|
||||||
|
canbus::Error error = set_mode_(CANCTRL_REQOP_CONFIG);
|
||||||
|
if (error != canbus::ERROR_OK) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t set, cfg1, cfg2, cfg3;
|
||||||
|
set = 1;
|
||||||
|
switch (can_clock) {
|
||||||
|
case (MCP_8MHZ):
|
||||||
|
switch (can_speed) {
|
||||||
|
case (canbus::CAN_5KBPS): // 5KBPS
|
||||||
|
cfg1 = MCP_8MHZ_5KBPS_CFG1;
|
||||||
|
cfg2 = MCP_8MHZ_5KBPS_CFG2;
|
||||||
|
cfg3 = MCP_8MHZ_5KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_10KBPS): // 10KBPS
|
||||||
|
cfg1 = MCP_8MHZ_10KBPS_CFG1;
|
||||||
|
cfg2 = MCP_8MHZ_10KBPS_CFG2;
|
||||||
|
cfg3 = MCP_8MHZ_10KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_20KBPS): // 20KBPS
|
||||||
|
cfg1 = MCP_8MHZ_20KBPS_CFG1;
|
||||||
|
cfg2 = MCP_8MHZ_20KBPS_CFG2;
|
||||||
|
cfg3 = MCP_8MHZ_20KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_31K25BPS): // 31.25KBPS
|
||||||
|
cfg1 = MCP_8MHZ_31K25BPS_CFG1;
|
||||||
|
cfg2 = MCP_8MHZ_31K25BPS_CFG2;
|
||||||
|
cfg3 = MCP_8MHZ_31K25BPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_33KBPS): // 33.333KBPS
|
||||||
|
cfg1 = MCP_8MHZ_33K3BPS_CFG1;
|
||||||
|
cfg2 = MCP_8MHZ_33K3BPS_CFG2;
|
||||||
|
cfg3 = MCP_8MHZ_33K3BPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_40KBPS): // 40Kbps
|
||||||
|
cfg1 = MCP_8MHZ_40KBPS_CFG1;
|
||||||
|
cfg2 = MCP_8MHZ_40KBPS_CFG2;
|
||||||
|
cfg3 = MCP_8MHZ_40KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_50KBPS): // 50Kbps
|
||||||
|
cfg1 = MCP_8MHZ_50KBPS_CFG1;
|
||||||
|
cfg2 = MCP_8MHZ_50KBPS_CFG2;
|
||||||
|
cfg3 = MCP_8MHZ_50KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_80KBPS): // 80Kbps
|
||||||
|
cfg1 = MCP_8MHZ_80KBPS_CFG1;
|
||||||
|
cfg2 = MCP_8MHZ_80KBPS_CFG2;
|
||||||
|
cfg3 = MCP_8MHZ_80KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_100KBPS): // 100Kbps
|
||||||
|
cfg1 = MCP_8MHZ_100KBPS_CFG1;
|
||||||
|
cfg2 = MCP_8MHZ_100KBPS_CFG2;
|
||||||
|
cfg3 = MCP_8MHZ_100KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_125KBPS): // 125Kbps
|
||||||
|
cfg1 = MCP_8MHZ_125KBPS_CFG1;
|
||||||
|
cfg2 = MCP_8MHZ_125KBPS_CFG2;
|
||||||
|
cfg3 = MCP_8MHZ_125KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_200KBPS): // 200Kbps
|
||||||
|
cfg1 = MCP_8MHZ_200KBPS_CFG1;
|
||||||
|
cfg2 = MCP_8MHZ_200KBPS_CFG2;
|
||||||
|
cfg3 = MCP_8MHZ_200KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_250KBPS): // 250Kbps
|
||||||
|
cfg1 = MCP_8MHZ_250KBPS_CFG1;
|
||||||
|
cfg2 = MCP_8MHZ_250KBPS_CFG2;
|
||||||
|
cfg3 = MCP_8MHZ_250KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_500KBPS): // 500Kbps
|
||||||
|
cfg1 = MCP_8MHZ_500KBPS_CFG1;
|
||||||
|
cfg2 = MCP_8MHZ_500KBPS_CFG2;
|
||||||
|
cfg3 = MCP_8MHZ_500KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_1000KBPS): // 1Mbps
|
||||||
|
cfg1 = MCP_8MHZ_1000KBPS_CFG1;
|
||||||
|
cfg2 = MCP_8MHZ_1000KBPS_CFG2;
|
||||||
|
cfg3 = MCP_8MHZ_1000KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
set = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (MCP_16MHZ):
|
||||||
|
switch (can_speed) {
|
||||||
|
case (canbus::CAN_5KBPS): // 5Kbps
|
||||||
|
cfg1 = MCP_16MHZ_5KBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHZ_5KBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHZ_5KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_10KBPS): // 10Kbps
|
||||||
|
cfg1 = MCP_16MHZ_10KBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHZ_10KBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHZ_10KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_20KBPS): // 20Kbps
|
||||||
|
cfg1 = MCP_16MHZ_20KBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHZ_20KBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHZ_20KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_33KBPS): // 33.333Kbps
|
||||||
|
cfg1 = MCP_16MHZ_33K3BPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHZ_33K3BPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHZ_33K3BPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_40KBPS): // 40Kbps
|
||||||
|
cfg1 = MCP_16MHZ_40KBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHZ_40KBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHZ_40KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_50KBPS): // 50Kbps
|
||||||
|
cfg2 = MCP_16MHZ_50KBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHZ_50KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_80KBPS): // 80Kbps
|
||||||
|
cfg1 = MCP_16MHZ_80KBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHZ_80KBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHZ_80KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_83K3BPS): // 83.333Kbps
|
||||||
|
cfg1 = MCP_16MHZ_83K3BPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHZ_83K3BPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHZ_83K3BPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_100KBPS): // 100Kbps
|
||||||
|
cfg1 = MCP_16MHZ_100KBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHZ_100KBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHZ_100KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_125KBPS): // 125Kbps
|
||||||
|
cfg1 = MCP_16MHZ_125KBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHZ_125KBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHZ_125KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_200KBPS): // 200Kbps
|
||||||
|
cfg1 = MCP_16MHZ_200KBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHZ_200KBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHZ_200KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_250KBPS): // 250Kbps
|
||||||
|
cfg1 = MCP_16MHZ_250KBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHZ_250KBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHZ_250KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_500KBPS): // 500Kbps
|
||||||
|
cfg1 = MCP_16MHZ_500KBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHZ_500KBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHZ_500KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_1000KBPS): // 1Mbps
|
||||||
|
cfg1 = MCP_16MHZ_1000KBPS_CFG1;
|
||||||
|
cfg2 = MCP_16MHZ_1000KBPS_CFG2;
|
||||||
|
cfg3 = MCP_16MHZ_1000KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
set = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (MCP_20MHZ):
|
||||||
|
switch (can_speed) {
|
||||||
|
case (canbus::CAN_33KBPS): // 33.333Kbps
|
||||||
|
cfg1 = MCP_20MHZ_33K3BPS_CFG1;
|
||||||
|
cfg2 = MCP_20MHZ_33K3BPS_CFG2;
|
||||||
|
cfg3 = MCP_20MHZ_33K3BPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_40KBPS): // 40Kbps
|
||||||
|
cfg1 = MCP_20MHZ_40KBPS_CFG1;
|
||||||
|
cfg2 = MCP_20MHZ_40KBPS_CFG2;
|
||||||
|
cfg3 = MCP_20MHZ_40KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_50KBPS): // 50Kbps
|
||||||
|
cfg1 = MCP_20MHZ_50KBPS_CFG1;
|
||||||
|
cfg2 = MCP_20MHZ_50KBPS_CFG2;
|
||||||
|
cfg3 = MCP_20MHZ_50KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_80KBPS): // 80Kbps
|
||||||
|
cfg1 = MCP_20MHZ_80KBPS_CFG1;
|
||||||
|
cfg2 = MCP_20MHZ_80KBPS_CFG2;
|
||||||
|
cfg3 = MCP_20MHZ_80KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_83K3BPS): // 83.333Kbps
|
||||||
|
cfg1 = MCP_20MHZ_83K3BPS_CFG1;
|
||||||
|
cfg2 = MCP_20MHZ_83K3BPS_CFG2;
|
||||||
|
cfg3 = MCP_20MHZ_83K3BPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_100KBPS): // 100Kbps
|
||||||
|
cfg1 = MCP_20MHZ_100KBPS_CFG1;
|
||||||
|
cfg2 = MCP_20MHZ_100KBPS_CFG2;
|
||||||
|
cfg3 = MCP_20MHZ_100KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_125KBPS): // 125Kbps
|
||||||
|
cfg1 = MCP_20MHZ_125KBPS_CFG1;
|
||||||
|
cfg2 = MCP_20MHZ_125KBPS_CFG2;
|
||||||
|
cfg3 = MCP_20MHZ_125KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_200KBPS): // 200Kbps
|
||||||
|
cfg1 = MCP_20MHZ_200KBPS_CFG1;
|
||||||
|
cfg2 = MCP_20MHZ_200KBPS_CFG2;
|
||||||
|
cfg3 = MCP_20MHZ_200KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_250KBPS): // 250Kbps
|
||||||
|
cfg1 = MCP_20MHZ_250KBPS_CFG1;
|
||||||
|
cfg2 = MCP_20MHZ_250KBPS_CFG2;
|
||||||
|
cfg3 = MCP_20MHZ_250KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_500KBPS): // 500Kbps
|
||||||
|
cfg1 = MCP_20MHZ_500KBPS_CFG1;
|
||||||
|
cfg2 = MCP_20MHZ_500KBPS_CFG2;
|
||||||
|
cfg3 = MCP_20MHZ_500KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
case (canbus::CAN_1000KBPS): // 1Mbps
|
||||||
|
cfg1 = MCP_20MHZ_1000KBPS_CFG1;
|
||||||
|
cfg2 = MCP_20MHZ_1000KBPS_CFG2;
|
||||||
|
cfg3 = MCP_20MHZ_1000KBPS_CFG3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
set = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
set = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set) {
|
||||||
|
set_register_(MCP_CNF1, cfg1);
|
||||||
|
set_register_(MCP_CNF2, cfg2);
|
||||||
|
set_register_(MCP_CNF3, cfg3);
|
||||||
|
return canbus::ERROR_OK;
|
||||||
|
} else {
|
||||||
|
return canbus::ERROR_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace mcp2515
|
||||||
|
} // namespace esphome
|
112
esphome/components/mcp2515/mcp2515.h
Normal file
112
esphome/components/mcp2515/mcp2515.h
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/canbus/canbus.h"
|
||||||
|
#include "esphome/components/spi/spi.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "mcp2515_defs.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace mcp2515 {
|
||||||
|
static const uint32_t SPI_CLOCK = 10000000; // 10MHz
|
||||||
|
|
||||||
|
static const int N_TXBUFFERS = 3;
|
||||||
|
static const int N_RXBUFFERS = 2;
|
||||||
|
enum CanClock { MCP_20MHZ, MCP_16MHZ, MCP_8MHZ };
|
||||||
|
enum MASK { MASK0, MASK1 };
|
||||||
|
enum RXF { RXF0 = 0, RXF1 = 1, RXF2 = 2, RXF3 = 3, RXF4 = 4, RXF5 = 5 };
|
||||||
|
enum RXBn { RXB0 = 0, RXB1 = 1 };
|
||||||
|
enum TXBn { TXB0 = 0, TXB1 = 1, TXB2 = 2 };
|
||||||
|
|
||||||
|
enum CanClkOut {
|
||||||
|
CLKOUT_DISABLE = -1,
|
||||||
|
CLKOUT_DIV1 = 0x0,
|
||||||
|
CLKOUT_DIV2 = 0x1,
|
||||||
|
CLKOUT_DIV4 = 0x2,
|
||||||
|
CLKOUT_DIV8 = 0x3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CANINTF : uint8_t {
|
||||||
|
CANINTF_RX0IF = 0x01,
|
||||||
|
CANINTF_RX1IF = 0x02,
|
||||||
|
CANINTF_TX0IF = 0x04,
|
||||||
|
CANINTF_TX1IF = 0x08,
|
||||||
|
CANINTF_TX2IF = 0x10,
|
||||||
|
CANINTF_ERRIF = 0x20,
|
||||||
|
CANINTF_WAKIF = 0x40,
|
||||||
|
CANINTF_MERRF = 0x80
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EFLG : uint8_t {
|
||||||
|
EFLG_RX1OVR = (1 << 7),
|
||||||
|
EFLG_RX0OVR = (1 << 6),
|
||||||
|
EFLG_TXBO = (1 << 5),
|
||||||
|
EFLG_TXEP = (1 << 4),
|
||||||
|
EFLG_RXEP = (1 << 3),
|
||||||
|
EFLG_TXWAR = (1 << 2),
|
||||||
|
EFLG_RXWAR = (1 << 1),
|
||||||
|
EFLG_EWARN = (1 << 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum STAT : uint8_t { STAT_RX0IF = (1 << 0), STAT_RX1IF = (1 << 1) };
|
||||||
|
|
||||||
|
static const uint8_t STAT_RXIF_MASK = STAT_RX0IF | STAT_RX1IF;
|
||||||
|
static const uint8_t EFLG_ERRORMASK = EFLG_RX1OVR | EFLG_RX0OVR | EFLG_TXBO | EFLG_TXEP | EFLG_RXEP;
|
||||||
|
|
||||||
|
class MCP2515 : public canbus::Canbus,
|
||||||
|
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
|
||||||
|
spi::DATA_RATE_8MHZ> {
|
||||||
|
public:
|
||||||
|
MCP2515(){};
|
||||||
|
void set_mcp_clock(CanClock clock) { this->mcp_clock_ = clock; };
|
||||||
|
void set_mcp_mode(const CanctrlReqopMode mode) { this->mcp_mode_ = mode; }
|
||||||
|
static const struct TxBnRegs {
|
||||||
|
REGISTER CTRL;
|
||||||
|
REGISTER SIDH;
|
||||||
|
REGISTER DATA;
|
||||||
|
} TXB[N_TXBUFFERS];
|
||||||
|
|
||||||
|
static const struct RxBnRegs {
|
||||||
|
REGISTER CTRL;
|
||||||
|
REGISTER SIDH;
|
||||||
|
REGISTER DATA;
|
||||||
|
CANINTF CANINTF_RXnIF;
|
||||||
|
} RXB[N_RXBUFFERS];
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CanClock mcp_clock_{MCP_8MHZ};
|
||||||
|
CanctrlReqopMode mcp_mode_ = CANCTRL_REQOP_NORMAL;
|
||||||
|
bool setup_internal() override;
|
||||||
|
canbus::Error set_mode_(CanctrlReqopMode mode);
|
||||||
|
|
||||||
|
uint8_t read_register_(REGISTER reg);
|
||||||
|
void read_registers_(REGISTER reg, uint8_t values[], uint8_t n);
|
||||||
|
void set_register_(REGISTER reg, uint8_t value);
|
||||||
|
void set_registers_(REGISTER reg, uint8_t values[], uint8_t n);
|
||||||
|
void modify_register_(REGISTER reg, uint8_t mask, uint8_t data);
|
||||||
|
|
||||||
|
void prepare_id_(uint8_t *buffer, bool extended, uint32_t id);
|
||||||
|
canbus::Error reset_();
|
||||||
|
canbus::Error set_clk_out_(CanClkOut divisor);
|
||||||
|
canbus::Error set_bitrate_(canbus::CanSpeed can_speed);
|
||||||
|
canbus::Error set_bitrate_(canbus::CanSpeed can_speed, CanClock can_clock);
|
||||||
|
canbus::Error set_filter_mask_(MASK mask, bool extended, uint32_t ul_data);
|
||||||
|
canbus::Error set_filter_(RXF num, bool extended, uint32_t ul_data);
|
||||||
|
canbus::Error send_message_(TXBn txbn, struct canbus::CanFrame *frame);
|
||||||
|
canbus::Error send_message(struct canbus::CanFrame *frame) override;
|
||||||
|
canbus::Error read_message_(RXBn rxbn, struct canbus::CanFrame *frame);
|
||||||
|
canbus::Error read_message(struct canbus::CanFrame *frame) override;
|
||||||
|
bool check_receive_();
|
||||||
|
bool check_error_();
|
||||||
|
uint8_t get_error_flags_();
|
||||||
|
void clear_rx_n_ovr_flags_();
|
||||||
|
uint8_t get_int_();
|
||||||
|
uint8_t get_int_mask_();
|
||||||
|
void clear_int_();
|
||||||
|
void clear_tx_int_();
|
||||||
|
uint8_t get_status_();
|
||||||
|
void clear_rx_n_ovr_();
|
||||||
|
void clear_merr_();
|
||||||
|
void clear_errif_();
|
||||||
|
};
|
||||||
|
} // namespace mcp2515
|
||||||
|
} // namespace esphome
|
317
esphome/components/mcp2515/mcp2515_defs.h
Normal file
317
esphome/components/mcp2515/mcp2515_defs.h
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace mcp2515 {
|
||||||
|
|
||||||
|
static const uint8_t CANCTRL_REQOP = 0xE0;
|
||||||
|
static const uint8_t CANCTRL_ABAT = 0x10;
|
||||||
|
static const uint8_t CANCTRL_OSM = 0x08;
|
||||||
|
static const uint8_t CANCTRL_CLKEN = 0x04;
|
||||||
|
static const uint8_t CANCTRL_CLKPRE = 0x03;
|
||||||
|
|
||||||
|
enum CanctrlReqopMode : uint8_t {
|
||||||
|
CANCTRL_REQOP_NORMAL = 0x00,
|
||||||
|
CANCTRL_REQOP_SLEEP = 0x20,
|
||||||
|
CANCTRL_REQOP_LOOPBACK = 0x40,
|
||||||
|
CANCTRL_REQOP_LISTENONLY = 0x60,
|
||||||
|
CANCTRL_REQOP_CONFIG = 0x80,
|
||||||
|
CANCTRL_REQOP_POWERUP = 0xE0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TxbNCtrl : uint8_t {
|
||||||
|
TXB_ABTF = 0x40,
|
||||||
|
TXB_MLOA = 0x20,
|
||||||
|
TXB_TXERR = 0x10,
|
||||||
|
TXB_TXREQ = 0x08,
|
||||||
|
TXB_TXIE = 0x04,
|
||||||
|
TXB_TXP = 0x03
|
||||||
|
};
|
||||||
|
|
||||||
|
enum INSTRUCTION : uint8_t {
|
||||||
|
INSTRUCTION_WRITE = 0x02,
|
||||||
|
INSTRUCTION_READ = 0x03,
|
||||||
|
INSTRUCTION_BITMOD = 0x05,
|
||||||
|
INSTRUCTION_LOAD_TX0 = 0x40,
|
||||||
|
INSTRUCTION_LOAD_TX1 = 0x42,
|
||||||
|
INSTRUCTION_LOAD_TX2 = 0x44,
|
||||||
|
INSTRUCTION_RTS_TX0 = 0x81,
|
||||||
|
INSTRUCTION_RTS_TX1 = 0x82,
|
||||||
|
INSTRUCTION_RTS_TX2 = 0x84,
|
||||||
|
INSTRUCTION_RTS_ALL = 0x87,
|
||||||
|
INSTRUCTION_READ_RX0 = 0x90,
|
||||||
|
INSTRUCTION_READ_RX1 = 0x94,
|
||||||
|
INSTRUCTION_READ_STATUS = 0xA0,
|
||||||
|
INSTRUCTION_RX_STATUS = 0xB0,
|
||||||
|
INSTRUCTION_RESET = 0xC0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum REGISTER : uint8_t {
|
||||||
|
MCP_RXF0SIDH = 0x00,
|
||||||
|
MCP_RXF0SIDL = 0x01,
|
||||||
|
MCP_RXF0EID8 = 0x02,
|
||||||
|
MCP_RXF0EID0 = 0x03,
|
||||||
|
MCP_RXF1SIDH = 0x04,
|
||||||
|
MCP_RXF1SIDL = 0x05,
|
||||||
|
MCP_RXF1EID8 = 0x06,
|
||||||
|
MCP_RXF1EID0 = 0x07,
|
||||||
|
MCP_RXF2SIDH = 0x08,
|
||||||
|
MCP_RXF2SIDL = 0x09,
|
||||||
|
MCP_RXF2EID8 = 0x0A,
|
||||||
|
MCP_RXF2EID0 = 0x0B,
|
||||||
|
MCP_CANSTAT = 0x0E,
|
||||||
|
MCP_CANCTRL = 0x0F,
|
||||||
|
MCP_RXF3SIDH = 0x10,
|
||||||
|
MCP_RXF3SIDL = 0x11,
|
||||||
|
MCP_RXF3EID8 = 0x12,
|
||||||
|
MCP_RXF3EID0 = 0x13,
|
||||||
|
MCP_RXF4SIDH = 0x14,
|
||||||
|
MCP_RXF4SIDL = 0x15,
|
||||||
|
MCP_RXF4EID8 = 0x16,
|
||||||
|
MCP_RXF4EID0 = 0x17,
|
||||||
|
MCP_RXF5SIDH = 0x18,
|
||||||
|
MCP_RXF5SIDL = 0x19,
|
||||||
|
MCP_RXF5EID8 = 0x1A,
|
||||||
|
MCP_RXF5EID0 = 0x1B,
|
||||||
|
MCP_TEC = 0x1C,
|
||||||
|
MCP_REC = 0x1D,
|
||||||
|
MCP_RXM0SIDH = 0x20,
|
||||||
|
MCP_RXM0SIDL = 0x21,
|
||||||
|
MCP_RXM0EID8 = 0x22,
|
||||||
|
MCP_RXM0EID0 = 0x23,
|
||||||
|
MCP_RXM1SIDH = 0x24,
|
||||||
|
MCP_RXM1SIDL = 0x25,
|
||||||
|
MCP_RXM1EID8 = 0x26,
|
||||||
|
MCP_RXM1EID0 = 0x27,
|
||||||
|
MCP_CNF3 = 0x28,
|
||||||
|
MCP_CNF2 = 0x29,
|
||||||
|
MCP_CNF1 = 0x2A,
|
||||||
|
MCP_CANINTE = 0x2B,
|
||||||
|
MCP_CANINTF = 0x2C,
|
||||||
|
MCP_EFLG = 0x2D,
|
||||||
|
MCP_TXB0CTRL = 0x30,
|
||||||
|
MCP_TXB0SIDH = 0x31,
|
||||||
|
MCP_TXB0SIDL = 0x32,
|
||||||
|
MCP_TXB0EID8 = 0x33,
|
||||||
|
MCP_TXB0EID0 = 0x34,
|
||||||
|
MCP_TXB0DLC = 0x35,
|
||||||
|
MCP_TXB0DATA = 0x36,
|
||||||
|
MCP_TXB1CTRL = 0x40,
|
||||||
|
MCP_TXB1SIDH = 0x41,
|
||||||
|
MCP_TXB1SIDL = 0x42,
|
||||||
|
MCP_TXB1EID8 = 0x43,
|
||||||
|
MCP_TXB1EID0 = 0x44,
|
||||||
|
MCP_TXB1DLC = 0x45,
|
||||||
|
MCP_TXB1DATA = 0x46,
|
||||||
|
MCP_TXB2CTRL = 0x50,
|
||||||
|
MCP_TXB2SIDH = 0x51,
|
||||||
|
MCP_TXB2SIDL = 0x52,
|
||||||
|
MCP_TXB2EID8 = 0x53,
|
||||||
|
MCP_TXB2EID0 = 0x54,
|
||||||
|
MCP_TXB2DLC = 0x55,
|
||||||
|
MCP_TXB2DATA = 0x56,
|
||||||
|
MCP_RXB0CTRL = 0x60,
|
||||||
|
MCP_RXB0SIDH = 0x61,
|
||||||
|
MCP_RXB0SIDL = 0x62,
|
||||||
|
MCP_RXB0EID8 = 0x63,
|
||||||
|
MCP_RXB0EID0 = 0x64,
|
||||||
|
MCP_RXB0DLC = 0x65,
|
||||||
|
MCP_RXB0DATA = 0x66,
|
||||||
|
MCP_RXB1CTRL = 0x70,
|
||||||
|
MCP_RXB1SIDH = 0x71,
|
||||||
|
MCP_RXB1SIDL = 0x72,
|
||||||
|
MCP_RXB1EID8 = 0x73,
|
||||||
|
MCP_RXB1EID0 = 0x74,
|
||||||
|
MCP_RXB1DLC = 0x75,
|
||||||
|
MCP_RXB1DATA = 0x76
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t CANSTAT_OPMOD = 0xE0;
|
||||||
|
static const uint8_t CANSTAT_ICOD = 0x0E;
|
||||||
|
|
||||||
|
static const uint8_t CNF3_SOF = 0x80;
|
||||||
|
|
||||||
|
static const uint8_t TXB_EXIDE_MASK = 0x08;
|
||||||
|
static const uint8_t DLC_MASK = 0x0F;
|
||||||
|
static const uint8_t RTR_MASK = 0x40;
|
||||||
|
|
||||||
|
static const uint8_t RXB_CTRL_RXM_STD = 0x20;
|
||||||
|
static const uint8_t RXB_CTRL_RXM_EXT = 0x40;
|
||||||
|
static const uint8_t RXB_CTRL_RXM_STDEXT = 0x00;
|
||||||
|
static const uint8_t RXB_CTRL_RXM_MASK = 0x60;
|
||||||
|
static const uint8_t RXB_CTRL_RTR = 0x08;
|
||||||
|
static const uint8_t RXB_0_CTRL_BUKT = 0x04;
|
||||||
|
|
||||||
|
static const uint8_t MCP_SIDH = 0;
|
||||||
|
static const uint8_t MCP_SIDL = 1;
|
||||||
|
static const uint8_t MCP_EID8 = 2;
|
||||||
|
static const uint8_t MCP_EID0 = 3;
|
||||||
|
static const uint8_t MCP_DLC = 4;
|
||||||
|
static const uint8_t MCP_DATA = 5;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Speed 8M
|
||||||
|
*/
|
||||||
|
static const uint8_t MCP_8MHZ_1000KBPS_CFG1 = 0x00;
|
||||||
|
static const uint8_t MCP_8MHZ_1000KBPS_CFG2 = 0x80;
|
||||||
|
static const uint8_t MCP_8MHZ_1000KBPS_CFG3 = 0x80;
|
||||||
|
|
||||||
|
static const uint8_t MCP_8MHZ_500KBPS_CFG1 = 0x00;
|
||||||
|
static const uint8_t MCP_8MHZ_500KBPS_CFG2 = 0x90;
|
||||||
|
static const uint8_t MCP_8MHZ_500KBPS_CFG3 = 0x82;
|
||||||
|
|
||||||
|
static const uint8_t MCP_8MHZ_250KBPS_CFG1 = 0x00;
|
||||||
|
static const uint8_t MCP_8MHZ_250KBPS_CFG2 = 0xB1;
|
||||||
|
static const uint8_t MCP_8MHZ_250KBPS_CFG3 = 0x85;
|
||||||
|
|
||||||
|
static const uint8_t MCP_8MHZ_200KBPS_CFG1 = 0x00;
|
||||||
|
static const uint8_t MCP_8MHZ_200KBPS_CFG2 = 0xB4;
|
||||||
|
static const uint8_t MCP_8MHZ_200KBPS_CFG3 = 0x86;
|
||||||
|
|
||||||
|
static const uint8_t MCP_8MHZ_125KBPS_CFG1 = 0x01;
|
||||||
|
static const uint8_t MCP_8MHZ_125KBPS_CFG2 = 0xB1;
|
||||||
|
static const uint8_t MCP_8MHZ_125KBPS_CFG3 = 0x85;
|
||||||
|
|
||||||
|
static const uint8_t MCP_8MHZ_100KBPS_CFG1 = 0x01;
|
||||||
|
static const uint8_t MCP_8MHZ_100KBPS_CFG2 = 0xB4;
|
||||||
|
static const uint8_t MCP_8MHZ_100KBPS_CFG3 = 0x86;
|
||||||
|
|
||||||
|
static const uint8_t MCP_8MHZ_80KBPS_CFG1 = 0x01;
|
||||||
|
static const uint8_t MCP_8MHZ_80KBPS_CFG2 = 0xBF;
|
||||||
|
static const uint8_t MCP_8MHZ_80KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_8MHZ_50KBPS_CFG1 = 0x03;
|
||||||
|
static const uint8_t MCP_8MHZ_50KBPS_CFG2 = 0xB4;
|
||||||
|
static const uint8_t MCP_8MHZ_50KBPS_CFG3 = 0x86;
|
||||||
|
|
||||||
|
static const uint8_t MCP_8MHZ_40KBPS_CFG1 = 0x03;
|
||||||
|
static const uint8_t MCP_8MHZ_40KBPS_CFG2 = 0xBF;
|
||||||
|
static const uint8_t MCP_8MHZ_40KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_8MHZ_33K3BPS_CFG1 = 0x47;
|
||||||
|
static const uint8_t MCP_8MHZ_33K3BPS_CFG2 = 0xE2;
|
||||||
|
static const uint8_t MCP_8MHZ_33K3BPS_CFG3 = 0x85;
|
||||||
|
|
||||||
|
static const uint8_t MCP_8MHZ_31K25BPS_CFG1 = 0x07;
|
||||||
|
static const uint8_t MCP_8MHZ_31K25BPS_CFG2 = 0xA4;
|
||||||
|
static const uint8_t MCP_8MHZ_31K25BPS_CFG3 = 0x84;
|
||||||
|
|
||||||
|
static const uint8_t MCP_8MHZ_20KBPS_CFG1 = 0x07;
|
||||||
|
static const uint8_t MCP_8MHZ_20KBPS_CFG2 = 0xBF;
|
||||||
|
static const uint8_t MCP_8MHZ_20KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_8MHZ_10KBPS_CFG1 = 0x0F;
|
||||||
|
static const uint8_t MCP_8MHZ_10KBPS_CFG2 = 0xBF;
|
||||||
|
static const uint8_t MCP_8MHZ_10KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_8MHZ_5KBPS_CFG1 = 0x1F;
|
||||||
|
static const uint8_t MCP_8MHZ_5KBPS_CFG2 = 0xBF;
|
||||||
|
static const uint8_t MCP_8MHZ_5KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* speed 16M
|
||||||
|
*/
|
||||||
|
static const uint8_t MCP_16MHZ_1000KBPS_CFG1 = 0x00;
|
||||||
|
static const uint8_t MCP_16MHZ_1000KBPS_CFG2 = 0xD0;
|
||||||
|
static const uint8_t MCP_16MHZ_1000KBPS_CFG3 = 0x82;
|
||||||
|
|
||||||
|
static const uint8_t MCP_16MHZ_500KBPS_CFG1 = 0x00;
|
||||||
|
static const uint8_t MCP_16MHZ_500KBPS_CFG2 = 0xF0;
|
||||||
|
static const uint8_t MCP_16MHZ_500KBPS_CFG3 = 0x86;
|
||||||
|
|
||||||
|
static const uint8_t MCP_16MHZ_250KBPS_CFG1 = 0x41;
|
||||||
|
static const uint8_t MCP_16MHZ_250KBPS_CFG2 = 0xF1;
|
||||||
|
static const uint8_t MCP_16MHZ_250KBPS_CFG3 = 0x85;
|
||||||
|
|
||||||
|
static const uint8_t MCP_16MHZ_200KBPS_CFG1 = 0x01;
|
||||||
|
static const uint8_t MCP_16MHZ_200KBPS_CFG2 = 0xFA;
|
||||||
|
static const uint8_t MCP_16MHZ_200KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_16MHZ_125KBPS_CFG1 = 0x03;
|
||||||
|
static const uint8_t MCP_16MHZ_125KBPS_CFG2 = 0xF0;
|
||||||
|
static const uint8_t MCP_16MHZ_125KBPS_CFG3 = 0x86;
|
||||||
|
|
||||||
|
static const uint8_t MCP_16MHZ_100KBPS_CFG1 = 0x03;
|
||||||
|
static const uint8_t MCP_16MHZ_100KBPS_CFG2 = 0xFA;
|
||||||
|
static const uint8_t MCP_16MHZ_100KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_16MHZ_80KBPS_CFG1 = 0x03;
|
||||||
|
static const uint8_t MCP_16MHZ_80KBPS_CFG2 = 0xFF;
|
||||||
|
static const uint8_t MCP_16MHZ_80KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_16MHZ_83K3BPS_CFG1 = 0x03;
|
||||||
|
static const uint8_t MCP_16MHZ_83K3BPS_CFG2 = 0xBE;
|
||||||
|
static const uint8_t MCP_16MHZ_83K3BPS_CFG3 = 0x07;
|
||||||
|
|
||||||
|
static const uint8_t MCP_16MHZ_50KBPS_CFG1 = 0x07;
|
||||||
|
static const uint8_t MCP_16MHZ_50KBPS_CFG2 = 0xFA;
|
||||||
|
static const uint8_t MCP_16MHZ_50KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_16MHZ_40KBPS_CFG1 = 0x07;
|
||||||
|
static const uint8_t MCP_16MHZ_40KBPS_CFG2 = 0xFF;
|
||||||
|
static const uint8_t MCP_16MHZ_40KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_16MHZ_33K3BPS_CFG1 = 0x4E;
|
||||||
|
static const uint8_t MCP_16MHZ_33K3BPS_CFG2 = 0xF1;
|
||||||
|
static const uint8_t MCP_16MHZ_33K3BPS_CFG3 = 0x85;
|
||||||
|
|
||||||
|
static const uint8_t MCP_16MHZ_20KBPS_CFG1 = 0x0F;
|
||||||
|
static const uint8_t MCP_16MHZ_20KBPS_CFG2 = 0xFF;
|
||||||
|
static const uint8_t MCP_16MHZ_20KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_16MHZ_10KBPS_CFG1 = 0x1F;
|
||||||
|
static const uint8_t MCP_16MHZ_10KBPS_CFG2 = 0xFF;
|
||||||
|
static const uint8_t MCP_16MHZ_10KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_16MHZ_5KBPS_CFG1 = 0x3F;
|
||||||
|
static const uint8_t MCP_16MHZ_5KBPS_CFG2 = 0xFF;
|
||||||
|
static const uint8_t MCP_16MHZ_5KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* speed 20M
|
||||||
|
*/
|
||||||
|
static const uint8_t MCP_20MHZ_1000KBPS_CFG1 = 0x00;
|
||||||
|
static const uint8_t MCP_20MHZ_1000KBPS_CFG2 = 0xD9;
|
||||||
|
static const uint8_t MCP_20MHZ_1000KBPS_CFG3 = 0x82;
|
||||||
|
|
||||||
|
static const uint8_t MCP_20MHZ_500KBPS_CFG1 = 0x00;
|
||||||
|
static const uint8_t MCP_20MHZ_500KBPS_CFG2 = 0xFA;
|
||||||
|
static const uint8_t MCP_20MHZ_500KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_20MHZ_250KBPS_CFG1 = 0x41;
|
||||||
|
static const uint8_t MCP_20MHZ_250KBPS_CFG2 = 0xFB;
|
||||||
|
static const uint8_t MCP_20MHZ_250KBPS_CFG3 = 0x86;
|
||||||
|
|
||||||
|
static const uint8_t MCP_20MHZ_200KBPS_CFG1 = 0x01;
|
||||||
|
static const uint8_t MCP_20MHZ_200KBPS_CFG2 = 0xFF;
|
||||||
|
static const uint8_t MCP_20MHZ_200KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_20MHZ_125KBPS_CFG1 = 0x03;
|
||||||
|
static const uint8_t MCP_20MHZ_125KBPS_CFG2 = 0xFA;
|
||||||
|
static const uint8_t MCP_20MHZ_125KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_20MHZ_100KBPS_CFG1 = 0x04;
|
||||||
|
static const uint8_t MCP_20MHZ_100KBPS_CFG2 = 0xFA;
|
||||||
|
static const uint8_t MCP_20MHZ_100KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_20MHZ_83K3BPS_CFG1 = 0x04;
|
||||||
|
static const uint8_t MCP_20MHZ_83K3BPS_CFG2 = 0xFE;
|
||||||
|
static const uint8_t MCP_20MHZ_83K3BPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_20MHZ_80KBPS_CFG1 = 0x04;
|
||||||
|
static const uint8_t MCP_20MHZ_80KBPS_CFG2 = 0xFF;
|
||||||
|
static const uint8_t MCP_20MHZ_80KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_20MHZ_50KBPS_CFG1 = 0x09;
|
||||||
|
static const uint8_t MCP_20MHZ_50KBPS_CFG2 = 0xFA;
|
||||||
|
static const uint8_t MCP_20MHZ_50KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_20MHZ_40KBPS_CFG1 = 0x09;
|
||||||
|
static const uint8_t MCP_20MHZ_40KBPS_CFG2 = 0xFF;
|
||||||
|
static const uint8_t MCP_20MHZ_40KBPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
static const uint8_t MCP_20MHZ_33K3BPS_CFG1 = 0x0B;
|
||||||
|
static const uint8_t MCP_20MHZ_33K3BPS_CFG2 = 0xFF;
|
||||||
|
static const uint8_t MCP_20MHZ_33K3BPS_CFG3 = 0x87;
|
||||||
|
|
||||||
|
} // namespace mcp2515
|
||||||
|
} // namespace esphome
|
|
@ -1890,6 +1890,9 @@ text_sensor:
|
||||||
- globals.set:
|
- globals.set:
|
||||||
id: glob_int
|
id: glob_int
|
||||||
value: '0'
|
value: '0'
|
||||||
|
- canbus.send:
|
||||||
|
can_id: 23
|
||||||
|
data: [ 0x10, 0x20, 0x30 ]
|
||||||
- platform: template
|
- platform: template
|
||||||
name: Template Text Sensor
|
name: Template Text Sensor
|
||||||
id: template_text
|
id: template_text
|
||||||
|
@ -1916,3 +1919,22 @@ sn74hc595:
|
||||||
|
|
||||||
rtttl:
|
rtttl:
|
||||||
output: gpio_19
|
output: gpio_19
|
||||||
|
|
||||||
|
canbus:
|
||||||
|
- platform: mcp2515
|
||||||
|
cs_pin: GPIO17
|
||||||
|
can_id: 4
|
||||||
|
bit_rate: 50kbps
|
||||||
|
on_frame:
|
||||||
|
- can_id: 500
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
std::string b(x.begin(), x.end());
|
||||||
|
ESP_LOGD("canid 500", "%s", &b[0] );
|
||||||
|
- can_id: 23
|
||||||
|
then:
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: 'return x[0] == 0x11;'
|
||||||
|
then:
|
||||||
|
light.toggle: living_room_lights
|
||||||
|
|
Loading…
Reference in a new issue