mirror of
https://github.com/grblHAL/core.git
synced 2026-02-05 16:40:45 +08:00
Added virtual Modbus API. Some internal settings handling improvements.
This commit is contained in:
@@ -7,6 +7,7 @@ target_sources(grbl INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/gcode.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/machine_limits.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/messages.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/modbus.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/motion_control.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/my_plugin.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/nuts_bolts.c
|
||||
|
||||
34
changelog.md
34
changelog.md
@@ -1,18 +1,46 @@
|
||||
## grblHAL changelog
|
||||
|
||||
<a name="20230610"/>Build 20230610
|
||||
|
||||
Core:
|
||||
|
||||
Added virtual Modbus API. Some internal settings handling improvements.
|
||||
|
||||
Drivers:
|
||||
|
||||
* iMXRT1062, STM32F7xx and RP2040: added Modbus TCP network support.
|
||||
|
||||
* STM32F1xx: rerouted _Reset_ signal as _Emergency stop_ per default. Can be overriden in _my_machine.h_ or by setting `COMPATIBILITY_LEVEL` > 1.
|
||||
|
||||
* STM32F4xx, ESP32, SAM3X8E and MSP432P401R: minor changes to handle new location of Modbus API.
|
||||
|
||||
Plugins:
|
||||
|
||||
* Spindle: refactored and renamed Modbus RTU code as a driver implementation for the core Modbus API.
|
||||
|
||||
* Networking: added Modbus TCP driver for core Modbus API with support for up to 8 devices. Default is four.
|
||||
Added WIZNet support for Modbus TCP.
|
||||
Modbus TCP is enabled by bit 2 in the `MODBUS_ENABLE` symbol in _my_machine.h_: `#define MOBUS_ENABLE 4`. This can be added to the previous define values for enabling Modbus RTU with or without RS 485 direction signal support.
|
||||
__NOTE:__ The new core API only supports the Modbus RTU protocol, this will be translated to/from Modbus TCP by the driver implementation.
|
||||
User code _can_ bypass the core API and transmit Modbus TCP messages directly if it wants/needs to.
|
||||
__NOTE:__ VFD spindle Modbus communication will be routed to Modbus TCP if the VFD device id \(unit id\) matches the Modbus TCP device id.
|
||||
For now this is untested and may lock up the controller since the networking stack comes up too late to avoid power up selftest \(POS\) failure.
|
||||
To be addressed in a later revision if someone with a Modbus TCP capable spindle is willing to test.
|
||||
|
||||
* Motors and encoder: updated for core setting handling improvements.
|
||||
|
||||
<a name="20230607"/>Build 20230607
|
||||
|
||||
Core:
|
||||
|
||||
* Added initial support for macro based automatic tool changes (ATC).
|
||||
Currently macros has to be stored on a SD card or in littlefs and [expression support](https://github.com/grblHAL/core/wiki/Expressions-and-flow-control) has to be enabled.
|
||||
|
||||
* Added core events for file system mount/unmount.
|
||||
|
||||
Plugins:
|
||||
|
||||
* SD Card, macro plugin: Implemented automatic hook to tool change functions when tool change macros are found in the root mount directory.
|
||||
Tool change macro: _tc.macro_, called on `M6`. \(required\)
|
||||
* SD Card, macro plugin: implemented automatic hook to tool change functions when tool change macros are found in the root mount directory.
|
||||
Tool change macro: _tc.macro_, called on `M6`. \(required\).
|
||||
Tool select macro: _ts.macro_, called on `T`. \(optional\).
|
||||
__NOTE:__ This functionality needs to be extensively tested by users having access to ATC hardware! [Discuss here](https://github.com/grblHAL/core/discussions/309).
|
||||
|
||||
|
||||
@@ -218,6 +218,15 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MODBUS_RTU_ENABLED 0b001
|
||||
#define MODBUS_RTU_DIR_ENABLED 0b010
|
||||
#define MODBUS_TCP_ENABLED 0b100
|
||||
|
||||
#if MODBUS_ENABLE == 2
|
||||
#undef MOBUS_ENABLE
|
||||
#define MOBUS_ENABLE 0b011
|
||||
#endif
|
||||
|
||||
#ifndef MODBUS_ENABLE
|
||||
#if VFD_ENABLE
|
||||
#define MODBUS_ENABLE 1
|
||||
@@ -371,6 +380,9 @@
|
||||
#ifndef NETWORK_HTTP_PORT
|
||||
#define NETWORK_HTTP_PORT 80
|
||||
#endif
|
||||
#ifndef NETWORK_MODBUS_PORT
|
||||
#define NETWORK_MODBUS_PORT 502
|
||||
#endif
|
||||
#ifndef NETWORK_MQTT_PORT
|
||||
#define NETWORK_MQTT_PORT 1883
|
||||
#endif
|
||||
|
||||
2
grbl.h
2
grbl.h
@@ -42,7 +42,7 @@
|
||||
#else
|
||||
#define GRBL_VERSION "1.1f"
|
||||
#endif
|
||||
#define GRBL_BUILD 20230607
|
||||
#define GRBL_BUILD 20230610
|
||||
|
||||
#define GRBL_URL "https://github.com/grblHAL"
|
||||
|
||||
|
||||
10
maslow.c
10
maslow.c
@@ -101,6 +101,8 @@ static float get_axis_setting (setting_id_t setting);
|
||||
static void maslow_settings_load (void);
|
||||
static void maslow_settings_restore (void);
|
||||
|
||||
#define AXIS_OPTS { .subgroups = On, .iterations = 1 }
|
||||
|
||||
static const setting_detail_t maslow_settings[] = {
|
||||
#if maslow_MIXED_DRIVERS
|
||||
{ Setting_maslowDriver, Group_MotorDriver, "maslow driver", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_NonCore, &maslow.driver_enable.mask },
|
||||
@@ -112,10 +114,10 @@ static const setting_detail_t maslow_settings[] = {
|
||||
{ (setting_id_t)Maslow_MotorOffsetY, Group_MotorDriver, "Motor offset Y", "mm", Format_Decimal, "###0.0", NULL, NULL, Setting_NonCore, &maslow.motorOffsetY, NULL },
|
||||
{ (setting_id_t)Maslow_AcorrScaling, Group_MotorDriver, "Acorr Scaling", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCore, &maslow.XcorrScaling, NULL },
|
||||
{ (setting_id_t)Maslow_BcorrScaling, Group_MotorDriver, "BcorrScaling", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCore, &maslow.XcorrScaling, NULL },
|
||||
{ (setting_id_t)AxisSetting_MaslowKP, Group_Axis0, "?-axis KP", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting },
|
||||
{ (setting_id_t)AxisSetting_MaslowKI, Group_Axis0, "?-axis KI", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting },
|
||||
{ (setting_id_t)AxisSetting_MaslowKD, Group_Axis0, "?-axis KIt", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting },
|
||||
{ (setting_id_t)AxisSetting_MaslowIMax, Group_Axis0, "?-axis I Max", "ma", Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting }
|
||||
{ (setting_id_t)AxisSetting_MaslowKP, Group_Axis0, "-axis KP", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting, AXIS_OPTS },
|
||||
{ (setting_id_t)AxisSetting_MaslowKI, Group_Axis0, "-axis KI", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting, AXIS_OPTS },
|
||||
{ (setting_id_t)AxisSetting_MaslowKD, Group_Axis0, "-axis KIt", NULL, Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting, AXIS_OPTS },
|
||||
{ (setting_id_t)AxisSetting_MaslowIMax, Group_Axis0, "-axis I Max", "ma", Format_Decimal, "###0.0", NULL, NULL, Setting_NonCoreFn, set_axis_setting, get_axis_setting, AXIS_OPTS }
|
||||
};
|
||||
|
||||
static void maslow_settings_save (void)
|
||||
|
||||
89
modbus.c
Normal file
89
modbus.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
|
||||
modbus.h - a lightweight ModBus implementation, interface wrapper
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2023 Terje Io
|
||||
|
||||
Grbl 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.
|
||||
|
||||
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include "modbus.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define N_MODBUS_API 2
|
||||
|
||||
static uint_fast16_t n_api = 0, tcp_api = N_MODBUS_API, rtu_api = N_MODBUS_API;
|
||||
static modbus_api_t modbus[N_MODBUS_API] = {0};
|
||||
|
||||
bool modbus_isup (void)
|
||||
{
|
||||
bool ok = n_api > 0;
|
||||
uint_fast16_t idx = n_api;
|
||||
|
||||
if(idx) do {
|
||||
ok &= modbus[--idx].is_up();
|
||||
} while(idx);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool modbus_enabled (void)
|
||||
{
|
||||
return n_api > 0;
|
||||
}
|
||||
|
||||
void modbus_flush_queue (void)
|
||||
{
|
||||
uint_fast16_t idx = n_api;
|
||||
|
||||
if(idx) do {
|
||||
modbus[--idx].flush_queue();
|
||||
} while(idx);
|
||||
}
|
||||
|
||||
void modbus_set_silence (const modbus_silence_timeout_t *timeout)
|
||||
{
|
||||
if(rtu_api != N_MODBUS_API)
|
||||
modbus[rtu_api].set_silence(timeout);
|
||||
}
|
||||
|
||||
bool modbus_send (modbus_message_t *msg, const modbus_callbacks_t *callbacks, bool block)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if(tcp_api != N_MODBUS_API)
|
||||
ok = modbus[tcp_api].send(msg, callbacks, block);
|
||||
|
||||
return ok || (rtu_api != N_MODBUS_API && modbus[rtu_api].send(msg, callbacks, block));
|
||||
}
|
||||
|
||||
bool modbus_register_api (const modbus_api_t *api)
|
||||
{
|
||||
bool ok;
|
||||
|
||||
if((ok = n_api < N_MODBUS_API)) {
|
||||
memcpy(&modbus[n_api], api, sizeof(modbus_api_t));
|
||||
if(api->interface == Modbus_InterfaceTCP)
|
||||
tcp_api = n_api;
|
||||
else if(api->interface == Modbus_InterfaceRTU)
|
||||
rtu_api = n_api;
|
||||
n_api++;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
101
modbus.h
Normal file
101
modbus.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
|
||||
modbus.h - a lightweight ModBus implementation
|
||||
|
||||
Part of grblHAL
|
||||
|
||||
Copyright (c) 2023 Terje Io
|
||||
|
||||
Grbl 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.
|
||||
|
||||
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _MODBUS_H_
|
||||
#define _MODBUS_H_
|
||||
|
||||
#ifndef MODBUS_MAX_ADU_SIZE
|
||||
#define MODBUS_MAX_ADU_SIZE 10
|
||||
#endif
|
||||
#ifndef MODBUS_QUEUE_LENGTH
|
||||
#define MODBUS_QUEUE_LENGTH 8
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
Modbus_InterfaceRTU = 0,
|
||||
Modbus_InterfaceASCII,
|
||||
Modbus_InterfaceTCP
|
||||
} modbus_if_t;
|
||||
|
||||
typedef enum {
|
||||
ModBus_ReadCoils = 1,
|
||||
ModBus_ReadDiscreteInputs = 2,
|
||||
ModBus_ReadHoldingRegisters = 3,
|
||||
ModBus_ReadInputRegisters = 4,
|
||||
ModBus_WriteCoil = 5,
|
||||
ModBus_WriteRegister = 6,
|
||||
ModBus_ReadExceptionStatus = 7,
|
||||
ModBus_Diagnostics = 8,
|
||||
ModBus_WriteCoils = 15,
|
||||
ModBus_WriteRegisters = 16
|
||||
} modbus_function_t;
|
||||
|
||||
typedef struct {
|
||||
void *context;
|
||||
bool crc_check;
|
||||
uint8_t tx_length;
|
||||
uint8_t rx_length;
|
||||
char adu[MODBUS_MAX_ADU_SIZE];
|
||||
} modbus_message_t;
|
||||
|
||||
typedef struct {
|
||||
void (*on_rx_packet)(modbus_message_t *msg);
|
||||
void (*on_rx_exception)(uint8_t code, void *context);
|
||||
} modbus_callbacks_t;
|
||||
|
||||
typedef union {
|
||||
uint16_t timeout[6];
|
||||
struct {
|
||||
uint16_t b2400;
|
||||
uint16_t b4800;
|
||||
uint16_t b9600;
|
||||
uint16_t b19200;
|
||||
uint16_t b38400;
|
||||
uint16_t b115200;
|
||||
};
|
||||
} modbus_silence_timeout_t;
|
||||
|
||||
typedef bool (*modbus_is_up_ptr)(void);
|
||||
typedef void (*modbus_flush_queue_ptr)(void);
|
||||
typedef void (*modbus_set_silence_ptr)(const modbus_silence_timeout_t *timeout);
|
||||
typedef bool (*modbus_send_ptr)(modbus_message_t *msg, const modbus_callbacks_t *callbacks, bool block);
|
||||
|
||||
typedef struct {
|
||||
modbus_if_t interface;
|
||||
modbus_is_up_ptr is_up;
|
||||
modbus_flush_queue_ptr flush_queue;
|
||||
modbus_set_silence_ptr set_silence;
|
||||
modbus_send_ptr send;
|
||||
} modbus_api_t;
|
||||
|
||||
bool modbus_isup (void);
|
||||
bool modbus_enabled (void);
|
||||
void modbus_flush_queue (void);
|
||||
void modbus_set_silence (const modbus_silence_timeout_t *timeout);
|
||||
bool modbus_send (modbus_message_t *msg, const modbus_callbacks_t *callbacks, bool block);
|
||||
bool modbus_register_api (const modbus_api_t *api);
|
||||
|
||||
#endif
|
||||
14
plugins.h
14
plugins.h
@@ -136,6 +136,20 @@ typedef struct {
|
||||
uint32_t rx_timeout;
|
||||
} modbus_settings_t;
|
||||
|
||||
#define MODBUS_TCP_SETTINGS_INCREMENT 5
|
||||
|
||||
typedef enum {
|
||||
Setting_ModbusIpAddress = 0,
|
||||
Setting_ModbusPort = 1,
|
||||
Setting_ModbusId = 2
|
||||
} modbus_tcp_setting_id_t;
|
||||
|
||||
typedef struct {
|
||||
char ip[16];
|
||||
uint16_t port;
|
||||
uint8_t id;
|
||||
} modbus_tcp_settings_t;
|
||||
|
||||
// Quadrature encoder interface
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
trinamic_init();
|
||||
#endif
|
||||
|
||||
#if MODBUS_ENABLE
|
||||
extern void modbus_init (void);
|
||||
modbus_init();
|
||||
#if MODBUS_ENABLE && MODBUS_ENABLE & 0x01
|
||||
extern void modbus_rtu_init (void);
|
||||
modbus_rtu_init();
|
||||
#endif
|
||||
|
||||
#if CANBUS_ENABLE
|
||||
|
||||
48
report.c
48
report.c
@@ -1427,8 +1427,23 @@ static void write_quoted (const char *s, const char *sep)
|
||||
hal.stream.write(sep);
|
||||
}
|
||||
|
||||
static void write_name (const char *s, uint_fast8_t offset)
|
||||
{
|
||||
char *q = hal.stream.write_n ? strchr(s, '?') : NULL;
|
||||
|
||||
if(q) {
|
||||
if(q != s)
|
||||
hal.stream.write_n(s, q - s);
|
||||
hal.stream.write(uitoa(offset + 1));
|
||||
hal.stream.write(q + 1);
|
||||
} else
|
||||
hal.stream.write(s);
|
||||
}
|
||||
|
||||
static void report_settings_detail (settings_format_t format, const setting_detail_t *setting, uint_fast8_t offset)
|
||||
{
|
||||
uint_fast8_t suboffset = setting->flags.subgroups ? offset / setting->flags.increment : offset;
|
||||
|
||||
switch(format)
|
||||
{
|
||||
case SettingsFormat_HumanReadable:
|
||||
@@ -1437,7 +1452,7 @@ static void report_settings_detail (settings_format_t format, const setting_deta
|
||||
hal.stream.write(": ");
|
||||
if(setting->group == Group_Axis0)
|
||||
hal.stream.write(axis_letter[offset]);
|
||||
hal.stream.write(setting->name[0] == '?' ? &setting->name[1] : setting->name); // temporary hack for ? prefix...
|
||||
write_name(setting->name, suboffset);
|
||||
|
||||
switch(setting_datatype_to_external(setting->datatype)) {
|
||||
|
||||
@@ -1526,11 +1541,11 @@ static void report_settings_detail (settings_format_t format, const setting_deta
|
||||
hal.stream.write("[SETTING:");
|
||||
hal.stream.write(uitoa(setting->id + offset));
|
||||
hal.stream.write(vbar);
|
||||
hal.stream.write(uitoa(setting->group + (setting->group == Group_Axis0 ? offset : 0)));
|
||||
hal.stream.write(uitoa(setting->group + (setting->flags.subgroups ? suboffset : 0)));
|
||||
hal.stream.write(vbar);
|
||||
if(setting->group == Group_Axis0)
|
||||
hal.stream.write(axis_letter[offset]);
|
||||
hal.stream.write(setting->name[0] == '?' ? &setting->name[1] : setting->name); // temporary hack for ? prefix...
|
||||
write_name(setting->name, suboffset);
|
||||
hal.stream.write(vbar);
|
||||
if(setting->unit)
|
||||
hal.stream.write(setting->unit);
|
||||
@@ -1558,7 +1573,7 @@ static void report_settings_detail (settings_format_t format, const setting_deta
|
||||
hal.stream.write("\"");
|
||||
if(setting->group == Group_Axis0)
|
||||
hal.stream.write(axis_letter[offset]);
|
||||
hal.stream.write(setting->name[0] == '?' ? &setting->name[1] : setting->name); // temporary hack for ? prefix...
|
||||
write_name(setting->name, suboffset);
|
||||
hal.stream.write("\",");
|
||||
if(setting->unit) {
|
||||
write_quoted(setting->unit, ",");
|
||||
@@ -1582,7 +1597,7 @@ static void report_settings_detail (settings_format_t format, const setting_deta
|
||||
|
||||
if(setting->group == Group_Axis0)
|
||||
hal.stream.write(axis_letter[offset]);
|
||||
hal.stream.write(setting->name[0] == '?' ? &setting->name[1] : setting->name); // temporary hack for ? prefix...
|
||||
write_name(setting->name, suboffset);
|
||||
|
||||
hal.stream.write("\t");
|
||||
|
||||
@@ -1949,7 +1964,7 @@ static void print_setting_group (const setting_group_detail_t *group, char *pref
|
||||
hal.stream.write(vbar);
|
||||
hal.stream.write(group->name);
|
||||
hal.stream.write("]" ASCII_EOL);
|
||||
} else if(group->id != Group_Root && settings_is_group_available(group->id)) {
|
||||
} else if(group->id != Group_Root) {
|
||||
hal.stream.write(prefix);
|
||||
hal.stream.write(group->name);
|
||||
hal.stream.write(ASCII_EOL);
|
||||
@@ -1959,12 +1974,23 @@ static void print_setting_group (const setting_group_detail_t *group, char *pref
|
||||
|
||||
static int cmp_setting_group_id (const void *a, const void *b)
|
||||
{
|
||||
return (*(setting_detail_t **)(a))->id - (*(setting_detail_t **)(b))->id;
|
||||
return (*(setting_group_detail_t **)(a))->id - (*(setting_group_detail_t **)(b))->id;
|
||||
}
|
||||
|
||||
static int cmp_setting_group_name (const void *a, const void *b)
|
||||
{
|
||||
return strcmp((*(setting_detail_t **)(a))->name, (*(setting_detail_t **)(b))->name);
|
||||
return strcmp((*(setting_group_detail_t **)(a))->name, (*(setting_group_detail_t **)(b))->name);
|
||||
}
|
||||
|
||||
static bool group_is_dup (setting_group_detail_t **groups, setting_group_t group)
|
||||
{
|
||||
while(*groups) {
|
||||
if((*groups)->id == group)
|
||||
return true;
|
||||
groups++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
status_code_t report_setting_group_details (bool by_id, char *prefix)
|
||||
@@ -1984,8 +2010,10 @@ status_code_t report_setting_group_details (bool by_id, char *prefix)
|
||||
uint_fast16_t idx;
|
||||
|
||||
do {
|
||||
for(idx = 0; idx < details->n_groups; idx++)
|
||||
*group++ = (setting_group_detail_t *)&details->groups[idx];
|
||||
for(idx = 0; idx < details->n_groups; idx++) {
|
||||
if(!group_is_dup(all_groups, details->groups[idx].id))
|
||||
*group++ = (setting_group_detail_t *)&details->groups[idx];
|
||||
}
|
||||
} while((details = details->next));
|
||||
|
||||
qsort(all_groups, n_groups, sizeof(setting_group_detail_t *), by_id ? cmp_setting_group_id : cmp_setting_group_name);
|
||||
|
||||
205
settings.c
205
settings.c
@@ -304,51 +304,56 @@ PROGMEM const settings_t defaults = {
|
||||
.safety_door.coolant_on_delay = DEFAULT_SAFETY_DOOR_COOLANT_DELAY
|
||||
};
|
||||
|
||||
static bool group_is_available (const setting_group_detail_t *group)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
PROGMEM static const setting_group_detail_t setting_group_detail [] = {
|
||||
{ Group_Root, Group_Root, "Root"},
|
||||
{ Group_Root, Group_General, "General"},
|
||||
{ Group_Root, Group_ControlSignals, "Control signals"},
|
||||
{ Group_Root, Group_Limits, "Limits"},
|
||||
{ Group_Limits, Group_Limits_DualAxis, "Dual axis"},
|
||||
{ Group_Root, Group_Coolant, "Coolant"},
|
||||
{ Group_Root, Group_Spindle, "Spindle"},
|
||||
{ Group_Spindle, Group_Spindle_Sync, "Spindle sync"},
|
||||
{ Group_Root, Group_Toolchange, "Tool change"},
|
||||
{ Group_Root, Group_Homing, "Homing"},
|
||||
{ Group_Root, Group_Probing, "Probing"},
|
||||
{ Group_Root, Group_SafetyDoor, "Safety door"},
|
||||
{ Group_Root, Group_Root, "Root", group_is_available },
|
||||
{ Group_Root, Group_General, "General", group_is_available },
|
||||
{ Group_Root, Group_ControlSignals, "Control signals" },
|
||||
{ Group_Root, Group_Limits, "Limits" },
|
||||
{ Group_Limits, Group_Limits_DualAxis, "Dual axis" },
|
||||
{ Group_Root, Group_Coolant, "Coolant" },
|
||||
{ Group_Root, Group_Spindle, "Spindle" },
|
||||
{ Group_Spindle, Group_Spindle_Sync, "Spindle sync" },
|
||||
{ Group_Root, Group_Toolchange, "Tool change" },
|
||||
{ Group_Root, Group_Homing, "Homing" },
|
||||
{ Group_Root, Group_Probing, "Probing" },
|
||||
{ Group_Root, Group_SafetyDoor, "Safety door" },
|
||||
{ Group_Root, Group_Jogging, "Jogging"},
|
||||
{ Group_Root, Group_Stepper, "Stepper"},
|
||||
{ Group_Root, Group_MotorDriver, "Stepper driver"},
|
||||
{ Group_Root, Group_Axis, "Axis"},
|
||||
{ Group_Axis, Group_XAxis, "X-axis"},
|
||||
{ Group_Axis, Group_YAxis, "Y-axis"},
|
||||
{ Group_Axis, Group_ZAxis, "Z-axis"},
|
||||
{ Group_Root, Group_Stepper, "Stepper" },
|
||||
{ Group_Root, Group_MotorDriver, "Stepper driver" },
|
||||
{ Group_Root, Group_Axis, "Axis", group_is_available },
|
||||
{ Group_Axis, Group_XAxis, "X-axis", group_is_available },
|
||||
{ Group_Axis, Group_YAxis, "Y-axis", group_is_available },
|
||||
{ Group_Axis, Group_ZAxis, "Z-axis", group_is_available },
|
||||
#if !AXIS_REMAP_ABC2UVW
|
||||
#ifdef A_AXIS
|
||||
{ Group_Axis, Group_AAxis, "A-axis"},
|
||||
{ Group_Axis, Group_AAxis, "A-axis", group_is_available },
|
||||
#endif
|
||||
#ifdef B_AXIS
|
||||
{ Group_Axis, Group_BAxis, "B-axis"},
|
||||
{ Group_Axis, Group_BAxis, "B-axis", group_is_available },
|
||||
#endif
|
||||
#ifdef C_AXIS
|
||||
{ Group_Axis, Group_CAxis, "C-axis"},
|
||||
{ Group_Axis, Group_CAxis, "C-axis", group_is_available },
|
||||
#endif
|
||||
#ifdef U_AXIS
|
||||
{ Group_Axis, Group_UAxis, "U-axis"},
|
||||
{ Group_Axis, Group_UAxis, "U-axis", group_is_available },
|
||||
#endif
|
||||
#ifdef V_AXIS
|
||||
{ Group_Axis, Group_VAxis, "V-axis"}
|
||||
{ Group_Axis, Group_VAxis, "V-axis", group_is_available }
|
||||
#endif
|
||||
#else
|
||||
#ifdef A_AXIS
|
||||
{ Group_Axis, Group_AAxis, "U-axis"},
|
||||
{ Group_Axis, Group_AAxis, "U-axis", group_is_available },
|
||||
#endif
|
||||
#ifdef B_AXIS
|
||||
{ Group_Axis, Group_BAxis, "V-axis"},
|
||||
{ Group_Axis, Group_BAxis, "V-axis", group_is_available },
|
||||
#endif
|
||||
#ifdef C_AXIS
|
||||
{ Group_Axis, Group_CAxis, "W-axis"},
|
||||
{ Group_Axis, Group_CAxis, "W-axis", group_is_available },
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
@@ -420,6 +425,8 @@ static char axis_rate[8] = "mm/min";
|
||||
static char axis_accel[10] = "mm/sec^2";
|
||||
static char axis_steps[9] = "step/mm";
|
||||
|
||||
#define AXIS_OPTS { .subgroups = On, .increment = 1 }
|
||||
|
||||
PROGMEM static const setting_detail_t setting_detail[] = {
|
||||
{ Setting_PulseMicroseconds, Group_Stepper, "Step pulse time", "microseconds", Format_Decimal, "#0.0", "2.0", NULL, Setting_IsLegacy, &settings.steppers.pulse_microseconds, NULL, NULL },
|
||||
{ Setting_StepperIdleLockTime, Group_Stepper, "Step idle delay", "milliseconds", Format_Int16, "####0", NULL, "65535", Setting_IsLegacy, &settings.steppers.idle_lock_time, NULL, NULL },
|
||||
@@ -532,14 +539,14 @@ PROGMEM static const setting_detail_t setting_detail[] = {
|
||||
{ Setting_PositionIGain, Group_Spindle_Sync, "Spindle sync I-gain", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.position.pid.i_gain, NULL, is_group_available },
|
||||
{ Setting_PositionDGain, Group_Spindle_Sync, "Spindle sync D-gain", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.position.pid.d_gain, NULL, is_group_available },
|
||||
{ Setting_PositionIMaxError, Group_Spindle_Sync, "Spindle sync PID max I error", NULL, Format_Decimal, "###0.000", NULL, NULL, Setting_IsExtended, &settings.position.pid.i_max_error, NULL, is_group_available },
|
||||
{ Setting_AxisStepsPerMM, Group_Axis0, "?-axis travel resolution", axis_steps, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL },
|
||||
{ Setting_AxisMaxRate, Group_Axis0, "?-axis maximum rate", axis_rate, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL },
|
||||
{ Setting_AxisAcceleration, Group_Axis0, "?-axis acceleration", axis_accel, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL },
|
||||
{ Setting_AxisMaxTravel, Group_Axis0, "?-axis maximum travel", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL },
|
||||
{ Setting_AxisStepsPerMM, Group_Axis0, "-axis travel resolution", axis_steps, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
|
||||
{ Setting_AxisMaxRate, Group_Axis0, "-axis maximum rate", axis_rate, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
|
||||
{ Setting_AxisAcceleration, Group_Axis0, "-axis acceleration", axis_accel, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
|
||||
{ Setting_AxisMaxTravel, Group_Axis0, "-axis maximum travel", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsLegacyFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
|
||||
#if ENABLE_BACKLASH_COMPENSATION
|
||||
{ Setting_AxisBacklash, Group_Axis0, "?-axis backlash compensation", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL },
|
||||
{ Setting_AxisBacklash, Group_Axis0, "-axis backlash compensation", axis_dist, Format_Decimal, "#####0.000", NULL, NULL, Setting_IsExtendedFn, set_axis_setting, get_float, NULL, AXIS_OPTS },
|
||||
#endif
|
||||
{ Setting_AxisAutoSquareOffset, Group_Axis0, "?-axis dual axis offset", "mm", Format_Decimal, "-0.000", "-10", "10", Setting_IsExtendedFn, set_axis_setting, get_float, is_setting_available },
|
||||
{ Setting_AxisAutoSquareOffset, Group_Axis0, "-axis dual axis offset", "mm", Format_Decimal, "-0.000", "-10", "10", Setting_IsExtendedFn, set_axis_setting, get_float, is_setting_available, AXIS_OPTS },
|
||||
{ Setting_SpindleAtSpeedTolerance, Group_Spindle, "Spindle at speed tolerance", "percent", Format_Decimal, "##0.0", NULL, NULL, Setting_IsExtended, &settings.spindle.at_speed_tolerance, NULL, is_setting_available },
|
||||
{ Setting_ToolChangeMode, Group_Toolchange, "Tool change mode", NULL, Format_RadioButtons, "Normal,Manual touch off,Manual touch off @ G59.3,Automatic touch off @ G59.3,Ignore M6", NULL, NULL, Setting_IsExtendedFn, set_tool_change_mode, get_int, NULL },
|
||||
{ Setting_ToolChangeProbingDistance, Group_Toolchange, "Tool change probing distance", "mm", Format_Decimal, "#####0.0", NULL, NULL, Setting_IsExtendedFn, set_tool_change_probing_distance, get_float, NULL },
|
||||
@@ -1282,6 +1289,8 @@ inline static setting_id_t normalize_id (setting_id_t id)
|
||||
id -= id % AXIS_SETTINGS_INCREMENT;
|
||||
else if(id > Setting_EncoderSettingsBase && id <= Setting_EncoderSettingsMax)
|
||||
id = (setting_id_t)(Setting_EncoderSettingsBase + (id % ENCODER_SETTINGS_INCREMENT));
|
||||
else if(id > Setting_ModbusTCPBase && id <= Setting_ModbusTCPMax)
|
||||
id = (setting_id_t)(Setting_ModbusTCPBase + (id % MODBUS_TCP_SETTINGS_INCREMENT));
|
||||
|
||||
return id;
|
||||
}
|
||||
@@ -2071,21 +2080,21 @@ static bool is_group_available (const setting_detail_t *setting)
|
||||
return settings_is_group_available(setting->group);
|
||||
}
|
||||
|
||||
bool settings_is_group_available (setting_group_t group)
|
||||
bool settings_is_group_available (setting_group_t id)
|
||||
{
|
||||
bool available = false;
|
||||
const setting_group_detail_t *group = setting_get_group_details(id);
|
||||
|
||||
switch(group) {
|
||||
if(!group)
|
||||
return false;
|
||||
|
||||
bool available = group->is_available ? group->is_available(group) : false;
|
||||
|
||||
if(!available) switch(group->id) {
|
||||
|
||||
case Group_Probing:
|
||||
available = hal.probe.get_state != NULL;
|
||||
break;
|
||||
|
||||
case Group_Encoders:
|
||||
case Group_Encoder0:
|
||||
available = hal.encoder.get_n_encoders && hal.encoder.get_n_encoders() > 0;
|
||||
break;
|
||||
|
||||
case Group_Spindle_Sync:
|
||||
available = hal.driver_cap.spindle_sync;
|
||||
break;
|
||||
@@ -2098,42 +2107,23 @@ bool settings_is_group_available (setting_group_t group)
|
||||
available = hal.stepper.get_ganged && hal.stepper.get_ganged(true).mask != 0;
|
||||
break;
|
||||
|
||||
case Group_General:
|
||||
case Group_Homing:
|
||||
case Group_Jogging:
|
||||
case Group_Limits:
|
||||
case Group_ControlSignals:
|
||||
case Group_Spindle:
|
||||
case Group_Axis:
|
||||
case Group_XAxis:
|
||||
case Group_YAxis:
|
||||
case Group_ZAxis:
|
||||
#ifdef A_AXIS
|
||||
case Group_AAxis:
|
||||
#endif
|
||||
#ifdef B_AXIS
|
||||
case Group_BAxis:
|
||||
#endif
|
||||
#ifdef C_AXIS
|
||||
case Group_CAxis:
|
||||
#endif
|
||||
#ifdef U_AXIS
|
||||
case Group_UAxis:
|
||||
#endif
|
||||
#ifdef V_AXIS
|
||||
case Group_VAxis:
|
||||
#endif
|
||||
available = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
uint_fast16_t idx;
|
||||
setting_details_t *details = settings_get_details();
|
||||
setting_details_t *details = &setting_details;
|
||||
|
||||
do {
|
||||
if(details->settings) {
|
||||
for(idx = 0; idx < details->n_settings; idx++) {
|
||||
if(details->settings[idx].group == group && (available = is_available(&details->settings[idx])))
|
||||
if(details->settings[idx].group == id && (available = is_available(&details->settings[idx])))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2150,78 +2140,28 @@ setting_group_t settings_normalize_group (setting_group_t group)
|
||||
return (group > Group_Axis0 && group < Group_Axis0 + N_AXIS) ? Group_Axis0 : group;
|
||||
}
|
||||
|
||||
/*
|
||||
setting_group_t settings_get_parent_group (setting_group_t group)
|
||||
{
|
||||
uint_fast16_t idx;
|
||||
setting_details_t *settings = settings_get_details();
|
||||
|
||||
for(idx = 0; idx < settings->n_groups; idx++) {
|
||||
if(settings->groups[idx].id == group) {
|
||||
group = settings->groups[idx].parent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
*/
|
||||
|
||||
bool settings_iterator (const setting_detail_t *setting, setting_output_ptr callback, void *data)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
switch(setting->id) {
|
||||
if(setting->group == Group_Axis0) {
|
||||
|
||||
case Setting_AxisStepsPerMM:
|
||||
case Setting_AxisMaxRate:
|
||||
case Setting_AxisAcceleration:
|
||||
case Setting_AxisMaxTravel:
|
||||
case Setting_AxisStepperCurrent:
|
||||
case Setting_AxisMicroSteps:
|
||||
case Setting_AxisBacklash:
|
||||
case Setting_AxisAutoSquareOffset:
|
||||
case Setting_AxisHomingFeedRate:
|
||||
case Setting_AxisHomingSeekRate:
|
||||
case Setting_AxisExtended0:
|
||||
case Setting_AxisExtended1:
|
||||
case Setting_AxisExtended2:
|
||||
case Setting_AxisExtended3:
|
||||
case Setting_AxisExtended4:
|
||||
case Setting_AxisExtended5:
|
||||
case Setting_AxisExtended6:
|
||||
case Setting_AxisExtended7:
|
||||
case Setting_AxisExtended8:
|
||||
case Setting_AxisExtended9:
|
||||
{
|
||||
uint_fast8_t axis_idx = 0;
|
||||
for(axis_idx = 0; axis_idx < N_AXIS; axis_idx++) {
|
||||
uint_fast8_t axis_idx = 0;
|
||||
|
||||
for(axis_idx = 0; axis_idx < N_AXIS; axis_idx++) {
|
||||
#if N_AXIS > 3
|
||||
set_axis_setting_unit(setting, axis_idx);
|
||||
set_axis_setting_unit(setting, axis_idx);
|
||||
#endif
|
||||
if(callback(setting, axis_idx, data))
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Setting_EncoderModeBase:
|
||||
case Setting_EncoderCPRBase:
|
||||
case Setting_EncoderCPDBase:
|
||||
case Setting_EncoderDblClickWindowBase:
|
||||
{
|
||||
uint_fast8_t encoder_idx = 0, n_encoders = hal.encoder.get_n_encoders();
|
||||
for(encoder_idx = 0; encoder_idx < n_encoders; encoder_idx++) {
|
||||
if(callback(setting, encoder_idx * ENCODER_SETTINGS_INCREMENT, data))
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ok = callback(setting, 0, data);
|
||||
break;
|
||||
}
|
||||
if(callback(setting, axis_idx, data))
|
||||
ok = true;
|
||||
}
|
||||
} else if(setting->flags.increment) {
|
||||
setting_details_t *set;
|
||||
setting = setting_get_details(setting->id, &set);
|
||||
if(set->iterator)
|
||||
ok = set->iterator(setting, callback, data);
|
||||
} else
|
||||
ok = callback(setting, 0, data);
|
||||
|
||||
return ok;
|
||||
}
|
||||
@@ -2240,7 +2180,7 @@ const setting_detail_t *setting_get_details (setting_id_t id, setting_details_t
|
||||
if(details->settings[idx].group == Group_Axis0)
|
||||
set_axis_setting_unit(&details->settings[idx], offset);
|
||||
#endif
|
||||
if(offset && offset >= (details->settings[idx].group == Group_Encoder0 ? hal.encoder.get_n_encoders() : N_AXIS))
|
||||
if(offset && details->iterator == NULL && offset >= (details->settings[idx].group == Group_Encoder0 ? hal.encoder.get_n_encoders() : N_AXIS))
|
||||
return NULL;
|
||||
if(set)
|
||||
*set = details;
|
||||
@@ -2298,6 +2238,15 @@ const setting_group_detail_t *setting_get_group_details (setting_group_t id)
|
||||
return detail;
|
||||
}
|
||||
|
||||
/*
|
||||
setting_group_t setting_get_parent_group (setting_group_t id)
|
||||
{
|
||||
const setting_group_detail_t *group = setting_get_group_details(id);
|
||||
|
||||
return group ? group->parent : Group_Unknown;
|
||||
}
|
||||
*/
|
||||
|
||||
static status_code_t validate_value (const setting_detail_t *setting, float value)
|
||||
{
|
||||
float val;
|
||||
|
||||
72
settings.h
72
settings.h
@@ -381,6 +381,12 @@ typedef enum {
|
||||
Setting_Panel_Encoder3_Cpd = 559,
|
||||
Setting_Panel_SettingsMax = 579,
|
||||
|
||||
Setting_ModbusTCPBase = 600, // Reserving settings values 600 to 639 for ModBus TCP (8 sets)
|
||||
Setting_ModbusIpAddressBase = Setting_ModbusTCPBase + Setting_ModbusIpAddress,
|
||||
Setting_ModbusPortBase = Setting_ModbusTCPBase + Setting_ModbusPort,
|
||||
Setting_ModbusIdBase = Setting_ModbusTCPBase + Setting_ModbusId,
|
||||
Setting_ModbusTCPMax = 639,
|
||||
|
||||
Setting_SettingsMax,
|
||||
Setting_SettingsAll = Setting_SettingsMax,
|
||||
|
||||
@@ -722,40 +728,49 @@ typedef enum {
|
||||
Group_Bluetooth, //!< 17
|
||||
Group_AuxPorts, //!< 18
|
||||
Group_ModBus, //!< 19
|
||||
Group_Encoders, //!< 20
|
||||
Group_Encoder0, //!< 21
|
||||
Group_Encoder1, //!< 22
|
||||
Group_Encoder2, //!< 23
|
||||
Group_Encoder3, //!< 24
|
||||
Group_Encoder4, //!< 25
|
||||
Group_UserSettings, //!< 26
|
||||
Group_Stepper, //!< 27
|
||||
Group_MotorDriver, //!< 28
|
||||
Group_VFD, //!< 29
|
||||
Group_CANbus, //!< 30
|
||||
Group_Embroidery, //!< 31
|
||||
Group_Panel, //!< 32
|
||||
Group_Axis, //!< 33
|
||||
Group_ModBusUnit0, //!< 20
|
||||
Group_ModBusUnit1, //!< 21
|
||||
Group_ModBusUnit2, //!< 22
|
||||
Group_ModBusUnit3, //!< 23
|
||||
Group_ModBusUnit4, //!< 24
|
||||
Group_ModBusUnit5, //!< 25
|
||||
Group_ModBusUnit6, //!< 26
|
||||
Group_ModBusUnit7, //!< 27
|
||||
Group_Encoders, //!< 28
|
||||
Group_Encoder0, //!< 29
|
||||
Group_Encoder1, //!< 30
|
||||
Group_Encoder2, //!< 31
|
||||
Group_Encoder3, //!< 32
|
||||
Group_Encoder4, //!< 33
|
||||
Group_UserSettings, //!< 34
|
||||
Group_Stepper, //!< 35
|
||||
Group_MotorDriver, //!< 36
|
||||
Group_VFD, //!< 37
|
||||
Group_CANbus, //!< 38
|
||||
Group_Embroidery, //!< 39
|
||||
Group_Panel, //!< 40
|
||||
Group_Axis, //!< 41
|
||||
// NOTE: axis groups MUST be sequential AND last
|
||||
Group_Axis0, //!< 34
|
||||
Group_XAxis = Group_Axis0, //!< 35
|
||||
Group_YAxis, //!< 36
|
||||
Group_ZAxis, //!< 37
|
||||
Group_Axis0, //!< 42
|
||||
Group_XAxis = Group_Axis0, //!< 43
|
||||
Group_YAxis, //!< 44
|
||||
Group_ZAxis, //!< 45
|
||||
#ifdef A_AXIS
|
||||
Group_AAxis, //!< 38
|
||||
Group_AAxis, //!< 46
|
||||
#endif
|
||||
#ifdef B_AXIS
|
||||
Group_BAxis, //!< 39
|
||||
Group_BAxis, //!< 47
|
||||
#endif
|
||||
#ifdef C_AXIS
|
||||
Group_CAxis, //!< 40
|
||||
Group_CAxis, //!< 48
|
||||
#endif
|
||||
#ifdef U_AXIS
|
||||
Group_UAxis, //!< 41
|
||||
Group_UAxis, //!< 49
|
||||
#endif
|
||||
#ifdef V_AXIS
|
||||
Group_VAxis, //!< 42
|
||||
Group_VAxis, //!< 50
|
||||
#endif
|
||||
Group_Unknown = 99, //!< 99
|
||||
Group_All = Group_Root //!< 0
|
||||
} setting_group_t;
|
||||
|
||||
@@ -775,10 +790,11 @@ typedef enum {
|
||||
Format_Int16,
|
||||
} setting_datatype_t;
|
||||
|
||||
typedef struct {
|
||||
typedef struct setting_group_detail {
|
||||
setting_group_t parent;
|
||||
setting_group_t id;
|
||||
const char *name;
|
||||
bool (*is_available)(const struct setting_group_detail *group);
|
||||
} setting_group_detail_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -801,8 +817,10 @@ typedef union {
|
||||
uint8_t value;
|
||||
struct {
|
||||
uint8_t reboot_required :1,
|
||||
allow_null: 1,
|
||||
unused :6;
|
||||
allow_null :1,
|
||||
subgroups :1,
|
||||
increment :4,
|
||||
unused :1;
|
||||
};
|
||||
} setting_detail_flags_t;
|
||||
|
||||
@@ -854,6 +872,7 @@ typedef void (*settings_changed_ptr)(settings_t *settings, settings_changed_flag
|
||||
typedef void (*driver_settings_load_ptr)(void);
|
||||
typedef void (*driver_settings_save_ptr)(void);
|
||||
typedef void (*driver_settings_restore_ptr)(void);
|
||||
typedef bool (*driver_settings_iterator_ptr)(const setting_detail_t *setting, setting_output_ptr callback, void *data);
|
||||
|
||||
typedef struct setting_details {
|
||||
const uint8_t n_groups;
|
||||
@@ -870,6 +889,7 @@ typedef struct setting_details {
|
||||
driver_settings_save_ptr save;
|
||||
driver_settings_load_ptr load;
|
||||
driver_settings_restore_ptr restore;
|
||||
driver_settings_iterator_ptr iterator;
|
||||
} setting_details_t;
|
||||
|
||||
// NOTE: this must match the signature of on_get_settings in the setting_details_t structure above!
|
||||
|
||||
Reference in New Issue
Block a user