Skip to content

Commit 5bef504

Browse files
committed
Merge branch '2.9'
2 parents 2760a8c + 0efd226 commit 5bef504

9 files changed

Lines changed: 328 additions & 3 deletions

File tree

docs/man/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ man9/demux.9
9797
man9/differential.9
9898
man9/div2.9
9999
man9/edge.9
100+
man9/enum.9
100101
man9/eoffset_per_angle.9
101102
man9/estop_latch.9
102103
man9/feedcomp.9

docs/src/gui/qtvcp-vcp-panels.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ When using python command option in Action Button widgets of an embedded panel:
371371

372372
*'MAIN_INSTANCE'*::
373373
refers to the main screen window.
374-
E.g., `INSTANCE.my_main_screen_handler_function_call(True)`
374+
E.g., `MAIN_INSTANCE.my_main_screen_handler_function_call(True)`
375375

376376
If the panel is not embedded, both refer to the panel window. +
377377

docs/src/man/man9/enum.9.adoc

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
= enum(9)
2+
3+
== NAME
4+
5+
enum - enumerate integer values into bits
6+
7+
== SYNOPSIS
8+
9+
*loadrt enum enums=E;enum1pin1;enum1pin2;;;enum1pin3,D;;;enum2pin1;enum2pin2 [names=name1,name2]*
10+
11+
== DESCRIPTION
12+
13+
*enum* converts integer values into bits and vice versa.
14+
15+
The component is especially suitable for encoding and decoding register
16+
values for modbus devices, where control commands and status are frequently
17+
encoded as enumerations rather than bits. For example 0 = stop, 1 =
18+
forwards, 2 = backwards, 3 = jog-forwards etc.
19+
20+
The pins created and the behaviour of the component are controlled by
21+
the load-time modparams "enums=" and "names="
22+
23+
The *enums=* parameter should be a comma-separated list of semicolon-
24+
separated pin labels. The enumerated values will increase in sequence
25+
starting at zero. To skip a value use a zero-length label, ie two
26+
consecutive semicolons, as shown in the examples.
27+
28+
There should be no spaces in the "enums=" list.
29+
30+
"names=" is an optional list of component instance names. If "names=" is
31+
omitted the functions and pins will be named "enum-decode...." or
32+
"enum-encode...."
33+
34+
Taking the example configuration above, if *enum-decode.01.enum2pin1-in*
35+
is set to *TRUE* then the output pin *enum-decode.01.output* will be set
36+
to the value 2. If *enum-decode.01.enum2pin2-in* is set to true then the
37+
output would be 3.
38+
39+
Conversely, if *enum-encode.00.input* is set to 4 then the pin
40+
*enum-encode.00.enum1pin3-out* will be set to *TRUE*.
41+
42+
== OPTIONS
43+
44+
Preceding the list of labels should be the control-codes "D" for decode
45+
or "E" for encode. A D-type enum will set the value of HAL bit pins in
46+
response to changes to the enum-decode.NN.input value, whereas an E-type
47+
enum will set the value of the enum-encode.NN.output integer depending
48+
on which enum-encode.NN.label-bit value is set.
49+
50+
If more than one label-bit input pin is set the output value will
51+
correspond to the pin label later in the list.
52+
53+
E and D-type enumerations may be freely mixed in separate instances.
54+
55+
== FUNCTIONS
56+
57+
*enum-decode._NN_.decode* - if instance type = "D"
58+
59+
*enum-encode._NN_.encode* - if instance type = "E"
60+
61+
== PINS
62+
63+
*enum-decode._NN_.input* - The integer value to be decoded
64+
65+
*enum-decode._NN_.label-out* - output bits of a decode instance
66+
67+
*enum-decode._NN_.label-val* - The enumeration value corresponding to
68+
each specific bit output. These are
69+
populated in sequence during loading
70+
but may be over-ridden in HAL if
71+
convenient.
72+
73+
*enum-encode._NN_.label-in* - input bits of a decode instance
74+
75+
*enum-encode._NN_.label-val* - The enumeration value corresponding to
76+
each specified bit input. These are
77+
populated in sequence during loading
78+
but may be over-ridden in HAL if
79+
convenient.
80+
81+
*enum-decode._NN_.output* - The integer value corresponding to the
82+
set bit input.
83+
84+
== BUGS
85+
86+
If no bits are set the output value will be zero even if zero is a
87+
defined enumeration.
88+
89+
== AUTHOR
90+
91+
Andy Pugh
92+
93+
== REPORTING BUGS
94+
Report bugs to at the LinuxCNC github issues list:
95+
https://github.com/LinuxCNC/linuxcnc/issues
96+
97+
== COPYRIGHT
98+
Copyright © 2023 Andy Pugh. This is free software; see the
99+
source for copying conditions. There is NO warranty; not even for
100+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
101+

share/qtvcp/screens/qtdragon/qtdragon_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ def init_pins(self):
253253
pin.value_changed.connect(self.spindle_fault_changed)
254254
pin = QHAL.newpin("spindle-modbus-errors", QHAL.HAL_U32, QHAL.HAL_IN)
255255
pin.value_changed.connect(self.mb_errors_changed)
256-
pin = QHAL.newpin("spindle-modbus-connection", QHAL.HAL_U32, QHAL.HAL_IN)
256+
pin = QHAL.newpin("spindle-modbus-connection", QHAL.HAL_BIT, QHAL.HAL_IN)
257257
pin.value_changed.connect(self.mb_connection_changed)
258258
QHAL.newpin("spindle-inhibit", QHAL.HAL_BIT, QHAL.HAL_OUT)
259259
# external offset control pins

share/qtvcp/screens/qtdragon_hd/qtdragon_hd_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ def init_pins(self):
214214
pin = QHAL.newpin("spindle-modbus-errors", QHAL.HAL_U32, QHAL.HAL_IN)
215215
pin.value_changed.connect(self.mb_errors_changed)
216216
QHAL.newpin("spindle-inhibit", QHAL.HAL_BIT, QHAL.HAL_OUT)
217-
pin = QHAL.newpin("spindle-modbus-connection", QHAL.HAL_U32, QHAL.HAL_IN)
217+
pin = QHAL.newpin("spindle-modbus-connection", QHAL.HAL_BIT, QHAL.HAL_IN)
218218
pin.value_changed.connect(self.mb_connection_changed)
219219

220220
# external offset control pins

src/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,8 @@ obj-$(CONFIG_DEBOUNCE) += debounce.o
922922
debounce-objs := hal/components/debounce.o $(MATHSTUB)
923923
obj-$(CONFIG_ENCODER) += encoder.o
924924
encoder-objs := hal/components/encoder.o $(MATHSTUB)
925+
obj-$(CONFIG_ENUM) += enum.o
926+
enum-objs := hal/components/enum.o $(MATHSTUB)
925927
obj-$(CONFIG_COUNTER) += counter.o
926928
counter-objs := hal/components/counter.o $(MATHSTUB)
927929
obj-$(CONFIG_ENCODER_RATIO) += encoder_ratio.o
@@ -1267,6 +1269,7 @@ endif
12671269
../rtlib/boss_plc$(MODULE_EXT): $(addprefix objects/rt,$(boss_plc-objs))
12681270
../rtlib/debounce$(MODULE_EXT): $(addprefix objects/rt,$(debounce-objs))
12691271
../rtlib/encoder$(MODULE_EXT): $(addprefix objects/rt,$(encoder-objs))
1272+
../rtlib/enum$(MODULE_EXT): $(addprefix objects/rt,$(enum-objs))
12701273
../rtlib/counter$(MODULE_EXT): $(addprefix objects/rt,$(counter-objs))
12711274
../rtlib/encoder_ratio$(MODULE_EXT): $(addprefix objects/rt,$(encoder_ratio-objs))
12721275
../rtlib/stepgen$(MODULE_EXT): $(addprefix objects/rt,$(stepgen-objs))

src/Makefile.inc.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ CONFIG_BLOCKS=m
174174
CONFIG_BOSS_PLC=m
175175
CONFIG_DEBOUNCE=m
176176
CONFIG_ENCODER=m
177+
CONFIG_ENUM=m
177178
CONFIG_COUNTER=m
178179
CONFIG_ENCODER_RATIO=m
179180
CONFIG_STEPGEN=m

src/hal/components/enum.c

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
// Copyright (C) 2023 Andy Pugh
2+
3+
// This program is free software; you can redistribute it and/or modify
4+
// it under the terms of the GNU General Public License as published by
5+
// the Free Software Foundation; either version 2 of the License, or
6+
// (at your option) any later version.
7+
//
8+
// This program is distributed in the hope that it will be useful,
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
// GNU General Public License for more details.
12+
//
13+
// You should have received a copy of the GNU General Public License
14+
// along with this program; if not, write to the Free Software
15+
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16+
//
17+
18+
/* A configurable component to use Mesa PktUART for modbus control */
19+
20+
21+
#include "rtapi.h"
22+
#include "rtapi_slab.h"
23+
#include "rtapi_app.h"
24+
#include "rtapi_string.h"
25+
#include "hal.h"
26+
27+
#if !defined(__KERNEL__)
28+
#include <stdio.h>
29+
#include <stdlib.h>
30+
#endif
31+
32+
/* module information */
33+
MODULE_AUTHOR("Andy Pugh");
34+
MODULE_DESCRIPTION("convert enumerated types to HAL_BIT pins");
35+
MODULE_LICENSE("GPL");
36+
37+
#define MAX_CHAN 256
38+
39+
typedef struct {
40+
hal_bit_t *bit;
41+
hal_u32_t *en; // note use index 0 differently
42+
} enum_hal_t;
43+
44+
typedef struct{
45+
int dir;
46+
int num_pins;
47+
enum_hal_t *hal;
48+
} enum_inst_t;
49+
50+
typedef struct {
51+
int num_insts;
52+
enum_inst_t *insts;
53+
} enum_t;
54+
55+
static int comp_id;
56+
57+
static enum_t e;
58+
59+
static char *enums[MAX_CHAN] = {0,};
60+
RTAPI_MP_ARRAY_STRING(enums, MAX_CHAN, "states, ; delimited");
61+
static char *names[MAX_CHAN] = {0,};
62+
RTAPI_MP_ARRAY_STRING(names, MAX_CHAN, "component names (optional)");
63+
64+
static void decode(void *inst, long period);
65+
static void encode(void *inst, long period);
66+
67+
int rtapi_app_main(void){
68+
int i, j, v;
69+
int retval;
70+
char *token;
71+
72+
if (!enums[0]) {
73+
rtapi_print_msg(RTAPI_MSG_ERR, "The enum_decode component requires at least"
74+
" one enumeration list\n");
75+
return -EINVAL;
76+
}
77+
78+
// count instances
79+
e.num_insts = MAX_CHAN;
80+
for (i = 0; i < MAX_CHAN; i++){
81+
if (! enums[i] && ! names[i]){
82+
e.num_insts = i;
83+
rtapi_print_msg(RTAPI_MSG_ERR, "making %i instances\n", e.num_insts);
84+
break;
85+
}
86+
if ((! enums[i] && names[i]) || ( ! names[i] && names[0] && enums[i])){
87+
rtapi_print_msg(RTAPI_MSG_ERR, "Inconsistent number of names and enums\n");
88+
return -EINVAL;
89+
}
90+
}
91+
92+
comp_id = hal_init("enum");
93+
94+
if (comp_id < 0) {
95+
rtapi_print_msg(RTAPI_MSG_ERR, "ERROR: hal_init() failed\n");
96+
return -EINVAL;
97+
}
98+
// allocate memory for the base struct
99+
e.insts = (enum_inst_t *)rtapi_kmalloc(e.num_insts * sizeof(enum_inst_t), RTAPI_GFP_KERNEL);
100+
for (i = 0; i < e.num_insts; i++){
101+
enum_inst_t *inst = &(e.insts[i]);
102+
char this[HAL_NAME_LEN];
103+
char func[HAL_NAME_LEN];
104+
105+
// Count the pins
106+
inst->num_pins = 0;
107+
inst->dir = HAL_OUT; // direction of bit pin, out for decode
108+
for (j = strlen(enums[i]); j > 0; j--){
109+
if (enums[i][j] == ';'){
110+
if (enums[i][j-1] != ';' ) inst->num_pins++;
111+
// insert a string terminator
112+
enums[i][j] = 0;
113+
}
114+
}
115+
inst->hal = (enum_hal_t *)hal_malloc((inst->num_pins + 1) * sizeof(enum_hal_t));
116+
token = enums[i];
117+
switch (*token){
118+
case 'E':
119+
case 'e': // encode
120+
inst->dir = HAL_IN;
121+
break;
122+
case 'D':
123+
case 'd':
124+
inst->dir = HAL_OUT;
125+
break;
126+
default:
127+
rtapi_print_msg(RTAPI_MSG_ERR, "Each enum string must start"
128+
"with either E; or D; to define the mode\n");
129+
goto fail0;
130+
}
131+
132+
if (names[i]) {
133+
rtapi_snprintf(this, HAL_NAME_LEN, "%s", names[i]);
134+
} else if (inst->dir == HAL_IN) {
135+
rtapi_snprintf(this, HAL_NAME_LEN, "enum-encode.%02i", i);
136+
} else {
137+
rtapi_snprintf(this, HAL_NAME_LEN, "enum-decode.%02i", i);
138+
}
139+
140+
// create single per-instance int pin in index 0
141+
if (inst->dir == HAL_OUT) {
142+
retval = hal_pin_u32_newf(HAL_IN, &(inst->hal[0].en), comp_id,
143+
"%s.input", this);
144+
} else {
145+
retval = hal_pin_u32_newf(HAL_OUT, &(inst->hal[0].en), comp_id,
146+
"%s.output", this);
147+
}
148+
v = 0;
149+
for (j = 1; j <= inst->num_pins; j++){ // 1-based indexing
150+
// skip to the next pin name
151+
while (*(++token) != 0){}
152+
//increment for skipped enumerations
153+
while (*(++token) == 0) v++;
154+
155+
retval = hal_pin_bit_newf(inst->dir, &(inst->hal[j].bit),
156+
comp_id, "%s.%s-%s",this, token,
157+
(inst->dir == HAL_IN)?"in":"out");
158+
retval += hal_pin_u32_newf(HAL_IN, &(inst->hal[j].en),
159+
comp_id, "%s.%s-val",this, token);
160+
*(inst->hal[j].en) = v++;
161+
162+
if (retval < 0){
163+
rtapi_print_msg(RTAPI_MSG_ERR, "Failed to create HAL pins\n");
164+
goto fail0;
165+
}
166+
}
167+
if (inst->dir == HAL_OUT){
168+
retval = rtapi_snprintf(func, HAL_NAME_LEN, "%s.decode", this);
169+
hal_export_funct(func, decode, inst, 0, 0, comp_id);
170+
} else {
171+
retval = rtapi_snprintf(func, HAL_NAME_LEN, "%s.encode", this);
172+
hal_export_funct(func, encode, inst, 0, 0, comp_id);
173+
}
174+
if (retval < 0){
175+
rtapi_print_msg(RTAPI_MSG_ERR, "Failed to export functions\n");
176+
goto fail0;
177+
}
178+
}
179+
180+
181+
hal_ready(comp_id);
182+
return 0;
183+
184+
fail0:
185+
free(e.insts);
186+
hal_exit(comp_id);
187+
return -1;
188+
189+
}
190+
191+
static void decode(void *v_inst, long period){;
192+
enum_inst_t *inst = v_inst;
193+
for (int i = 1; i <= inst->num_pins; i++){
194+
if (*(inst->hal[0].en) == *(inst->hal[i].en)){
195+
*(inst->hal[i].bit) = 1;
196+
} else {
197+
*(inst->hal[i].bit) = 0;
198+
}
199+
}
200+
}
201+
static void encode(void *v_inst, long period){;
202+
enum_inst_t *inst = v_inst;
203+
*(inst->hal[0].en) = 0;
204+
for (int i = 1; i <= inst->num_pins; i++){
205+
if (*(inst->hal[i].bit)){
206+
*(inst->hal[0].en) = *(inst->hal[i].en);
207+
}
208+
}
209+
}

src/hal/user_comps/mqtt-publisher.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,18 @@ def create_pins(self, keys):
8484
def update_mqtt(self):
8585
"Run the endless loop fetching pin data and sending it to MQTT."
8686
running = True
87+
missing = {}
8788
while hal.component_exists('halui') and running:
8889
data = {}
8990
if self.hal['enable']:
91+
for key in self.keys:
92+
try:
93+
data[key] = hal.get_value(key)
94+
except RuntimeError as e:
95+
# Only print warning once
96+
if key not in missing:
97+
print(f"warning: Missing pin {key} not sent to MQTT")
98+
missing[key] = True
9099
data['mqtt-publisher.period'] = self.hal['period']
91100
if not self.dryrun:
92101
print(f"info: Publishing MQTT message ({self.mqtt_prefix}):", json.dumps(data))
@@ -107,6 +116,7 @@ def usage():
107116
@staticmethod
108117
def main():
109118
from optparse import Option, OptionParser
119+
keys={}
110120
options = [
111121
Option( '--dryrun', dest='dryrun', action='store_true',
112122
help='Dryrun, only collect HAL pin values, do not send them to MQTT.'),

0 commit comments

Comments
 (0)