Added virtual Modbus API. Some internal settings handling improvements.

This commit is contained in:
Terje Io
2023-06-13 19:47:02 +02:00
parent 0a8c51ebe9
commit 8c7f841840
12 changed files with 419 additions and 175 deletions

View File

@@ -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

View File

@@ -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).

View File

@@ -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
View File

@@ -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"

View File

@@ -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
View 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
View 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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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!