Files
grblHAL/canbus.c
Terje Io c681661516 Fix for all $RST command variants resetting driver settings to default when only $RST=* and $RST=& should. Ref. issue #659.
Changed behaviour of $RST=# to not reset coordinate systems locked by setting $486.
2025-01-10 21:10:47 +01:00

209 lines
5.4 KiB
C

/*
canbus.c -
Part of grblHAL
Copyright (c) 2022 Jon Escombe
Copyright (c) 2024-2025 Terje Io
grblHAL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
grblHAL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with grblHAL. If not, see <http://www.gnu.org/licenses/>.
*/
#include "hal.h"
#include "task.h"
#include "protocol.h"
#include "canbus.h"
#ifndef CANBUS_BUFFER_LEN
#define CANBUS_BUFFER_LEN 8
#endif
#ifndef CANBUS_BAUDRATE
#define CANBUS_BAUDRATE 0 // 125000
#endif
typedef struct {
volatile canbus_message_t message;
can_rx_ptr callback;
} canbus_rx_message;
typedef struct {
volatile canbus_message_t message;
bool ext_id;
} canbus_tx_message;
typedef struct {
volatile uint8_t head;
volatile uint8_t tail;
volatile canbus_tx_message tx[CANBUS_BUFFER_LEN];
} canbus_tx_buffer_t;
typedef struct {
volatile uint8_t head;
volatile uint8_t tail;
volatile canbus_rx_message rx[CANBUS_BUFFER_LEN];
} canbus_rx_buffer_t;
static bool isEnabled = false;
static const uint32_t baud[] = { 125000, 250000, 500000, 1000000 };
static canbus_tx_buffer_t tx_buffer = {0};
static canbus_rx_buffer_t rx_buffer = {0};
// Weak implementations of low level functions to be provided by the driver
__attribute__((weak)) bool can_start (uint32_t baud, can_rx_enqueue_fn callback)
{
return false;
}
__attribute__((weak)) bool can_stop (void)
{
return false;
}
__attribute__((weak)) bool can_set_baud (uint32_t baud)
{
return false;
}
__attribute__((weak)) bool can_put (canbus_message_t msg, bool ext_id)
{
return false;
}
__attribute__((weak)) bool can_add_filter (uint32_t id, uint32_t mask, bool ext_id, can_rx_ptr callback)
{
return false;
}
// ---
ISR_CODE static bool ISR_FUNC(canbus_queue_rx)(canbus_message_t message, can_rx_ptr callback)
{
bool ok;
uint8_t next_head = (rx_buffer.head + 1) % CANBUS_BUFFER_LEN;
if((ok = next_head != rx_buffer.tail)) {
rx_buffer.rx[rx_buffer.head].callback = callback;
rx_buffer.rx[rx_buffer.head].message = message;
rx_buffer.head = next_head;
}
return ok;
}
// called every 1 ms
static void canbus_poll (void *data)
{
/* if have TX data, sends one message per iteration.. */
if(tx_buffer.head != tx_buffer.tail && can_put(tx_buffer.tx[tx_buffer.tail].message, tx_buffer.tx[tx_buffer.tail].ext_id))
tx_buffer.tail = (tx_buffer.tail + 1) % CANBUS_BUFFER_LEN;
/* if have RX data, process one message per iteration.. */
if(rx_buffer.head != rx_buffer.tail) {
if(rx_buffer.rx[rx_buffer.tail].callback)
rx_buffer.rx[rx_buffer.tail].callback(rx_buffer.rx[rx_buffer.tail].message);
rx_buffer.tail = (rx_buffer.tail + 1) % CANBUS_BUFFER_LEN;
}
}
static bool canbus_start (uint32_t baud)
{
if((isEnabled = can_start(baud, canbus_queue_rx)))
task_add_systick(canbus_poll, NULL);
return isEnabled;
}
static status_code_t canbus_set_baud (setting_id_t id, uint_fast16_t value)
{
settings.canbus_baud = value;
return can_set_baud(baud[settings.canbus_baud]) ? Status_OK : Status_SettingValueOutOfRange;
}
static uint32_t canbus_get_baud (setting_id_t setting)
{
return settings.canbus_baud < (sizeof(baud) / sizeof(uint32_t)) ? settings.canbus_baud : CANBUS_BAUDRATE;
}
static const setting_group_detail_t canbus_groups [] = {
{ Group_Root, Group_CANbus, "CAN bus"}
};
static const setting_detail_t canbus_setting_detail[] = {
{ Setting_CANbus_BaudRate, Group_CANbus, "CAN bus baud rate", NULL, Format_RadioButtons, "125000,250000,500000,1000000", NULL, NULL, Setting_NonCoreFn, canbus_set_baud, canbus_get_baud, NULL },
};
static void canbus_settings_restore (void)
{
settings.canbus_baud = CANBUS_BAUDRATE;
settings_write_global();
}
static void canbus_settings_load (void)
{
canbus_start(baud[canbus_get_baud(Setting_CANbus_BaudRate)]);
}
// Public API
bool canbus_enabled (void)
{
return isEnabled;
}
bool canbus_queue_tx (canbus_message_t message, bool ext_id)
{
bool ok;
uint8_t next_head = (tx_buffer.head + 1) % CANBUS_BUFFER_LEN;
if((ok = next_head != tx_buffer.tail)) {
tx_buffer.tx[tx_buffer.head].ext_id = ext_id;
tx_buffer.tx[tx_buffer.head].message = message;
tx_buffer.head = next_head;
}
return ok;
}
bool canbus_add_filter (uint32_t id, uint32_t mask, bool ext_id, can_rx_ptr callback)
{
return can_add_filter(id, mask, ext_id, callback);
}
void canbus_init (void)
{
static setting_details_t setting_details = {
.is_core = true,
.groups = canbus_groups,
.n_groups = sizeof(canbus_groups) / sizeof(setting_group_detail_t),
.settings = canbus_setting_detail,
.n_settings = sizeof(canbus_setting_detail) / sizeof(setting_detail_t),
.save = settings_write_global,
.load = canbus_settings_load,
.restore = canbus_settings_restore
};
static bool init_ok = false;
if(!init_ok) {
init_ok = true;
settings_register(&setting_details);
}
}