Skip to content

Commit 494112f

Browse files
committed
[WIP] improving shell to get/set values
1 parent 72fa6c7 commit 494112f

File tree

4 files changed

+233
-74
lines changed

4 files changed

+233
-74
lines changed

zephyr/include/bacnet_settings/bacnet_storage.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ int bacnet_storage_handler_commit(void);
4444
int bacnet_storage_handler_export(int (*cb)(const char *name, const void *value, size_t val_len));
4545

4646
bool bacnet_storage_strtoul(const char *search_name, unsigned long *long_value);
47+
bool bacnet_storage_strtol(const char *search_name, long *long_value);
48+
bool bacnet_storage_strtof(const char *search_name, float *float_value);
4749

4850
void bacnet_storage_key_init(BACNET_STORAGE_KEY *key, uint16_t object_type,
4951
uint32_t object_instance, uint32_t property_id, uint32_t array_index);

zephyr/samples/profiles/b-ld/src/main.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ void BACnet_Lighting_Output_Tracking_Value_Handler(uint32_t object_instance, flo
7373
static bool Settings_Restore_Callback(BACNET_WRITE_PROPERTY_DATA *wp_data, void *context)
7474
{
7575
(void)context;
76+
if (wp_data == NULL) {
77+
return false;
78+
}
79+
if ((wp_data->object_type == OBJECT_DEVICE) &&
80+
(wp_data->object_instance == BACNET_MAX_INSTANCE)) {
81+
wp_data->object_instance = Device_Object_Instance_Number();
82+
}
83+
7684
return Device_Write_Property(wp_data);
7785
}
7886

zephyr/subsys/bacnet_settings/bacnet_shell.c

Lines changed: 142 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
/**
22
* @file
3-
* @brief The BACnet shell commands for debugging and testing
3+
* @brief The BACnet shell commands for debugging and testing settings
44
* @author Steve Karg <[email protected]>
55
* @date May 2024
66
* @copyright SPDX-License-Identifier: Apache-2.0
77
*/
88
#include <stdlib.h>
99
#include <stdint.h>
1010
#include <errno.h>
11+
#include <ctype.h>
1112
#include <zephyr/shell/shell.h>
1213
#include <bacnet_settings/bacnet_storage.h>
1314
#include <bacnet/bactext.h>
@@ -25,13 +26,14 @@ static const char Storage_Base_Name[] = CONFIG_BACNET_STORAGE_BASE_NAME;
2526
*/
2627
static int cmd_key(BACNET_STORAGE_KEY *key, const struct shell *sh, size_t argc, char **argv)
2728
{
28-
uint16_t object_type;
29-
uint32_t object_instance;
30-
uint32_t property_id = 77;
29+
uint16_t object_type = 0;
30+
uint32_t object_instance = 0;
31+
uint32_t property_id = 75;
3132
uint32_t array_index = BACNET_STORAGE_ARRAY_INDEX_NONE;
3233
long value = 0;
3334
unsigned long unsigned_value = 0;
34-
int found_index = 0;
35+
int found_index = 0, scan_count = 0;
36+
char property_name[80] = {0};
3537

3638
if (argc < 3) {
3739
shell_error(sh, "Usage: %s <object-type> <instance> <property> [value]", argv[0]);
@@ -57,33 +59,30 @@ static int cmd_key(BACNET_STORAGE_KEY *key, const struct shell *sh, size_t argc,
5759
return -EINVAL;
5860
}
5961
object_instance = (uint32_t)unsigned_value;
60-
/* property can have @ to denote priority or array */
61-
char *at_ptr = strchr(argv[3], '@');
62-
if (at_ptr) {
63-
if (!bacnet_storage_strtoul(at_ptr + 1, &unsigned_value)) {
64-
shell_error(sh, "Invalid array-index: \"%s\"", at_ptr);
62+
/* property can have [] to denote priority or array */
63+
scan_count = sscanf(argv[3], "%lu[%u]", &unsigned_value, &array_index);
64+
if (scan_count < 1) {
65+
scan_count = sscanf(argv[3], "%80s[%u]", property_name, &array_index);
66+
if (scan_count < 1) {
67+
shell_error(sh, "Invalid property: %s.", argv[3]);
6568
return -EINVAL;
6669
}
67-
if (unsigned_value > UINT32_MAX) {
68-
shell_error(sh, "Invalid array-index: \"%s\". Must be 0-4294967295.",
69-
at_ptr);
70+
if (bactext_property_strtol(property_name, &found_index)) {
71+
value = found_index;
72+
} else {
73+
shell_error(sh, "Invalid property: %s.", property_name);
7074
return -EINVAL;
7175
}
72-
array_index = (uint32_t)unsigned_value;
73-
/* null terminate the string at the @ symbol */
74-
*at_ptr = 0;
75-
}
76-
if (bactext_property_strtol(argv[3], &found_index)) {
77-
value = found_index;
78-
} else {
79-
shell_error(sh, "Invalid property: %s.", argv[1]);
80-
return -EINVAL;
76+
if (value > UINT32_MAX) {
77+
shell_error(sh, "Invalid property: %s. Must be 0-4294967295.", argv[3]);
78+
return -EINVAL;
79+
}
80+
unsigned_value = (uint32_t)value;
8181
}
82-
if (value > UINT32_MAX) {
83-
shell_error(sh, "Invalid property: %s. Must be 0-4294967295.", argv[3]);
84-
return -EINVAL;
82+
if (scan_count < 2) {
83+
array_index = BACNET_STORAGE_ARRAY_INDEX_NONE;
8584
}
86-
property_id = (uint32_t)value;
85+
property_id = (uint32_t)unsigned_value;
8786
/* setup the storage key */
8887
bacnet_storage_key_init(key, object_type, object_instance, property_id, array_index);
8988

@@ -102,39 +101,59 @@ static int cmd_value(const struct shell *sh, size_t argc, char **argv)
102101
char key_name[BACNET_STORAGE_KEY_SIZE_MAX + 1] = {0};
103102
uint8_t data[BACNET_STORAGE_VALUE_SIZE_MAX + 1] = {0};
104103
BACNET_STORAGE_KEY key = {0};
105-
int rc;
104+
int rc, len, data_len;
106105
unsigned enumerated_value = 0;
106+
unsigned long unsigned_value = 0;
107+
float real_value = 0.0f;
108+
long signed_value = 0;
109+
int scan_count = 0;
110+
unsigned object_type = 0;
111+
unsigned instance = 0;
107112
bool status = false;
108-
bool null_value = false;
109113
BACNET_APPLICATION_DATA_VALUE value = {0};
110114
BACNET_OBJECT_PROPERTY_VALUE object_value = {0};
111115
char value_name[80] = {0};
112116
char *value_string = NULL;
113-
uint8_t value_tag;
114-
int len;
115117

116118
rc = cmd_key(&key, sh, argc, argv);
117119
if (rc < 0) {
118120
return rc;
119121
}
122+
/* read the current value which also determines
123+
the tag when setting the value */
124+
rc = bacnet_storage_get(&key, data, sizeof(data));
125+
if (rc < 0) {
126+
shell_error(sh, "Unable to get %s", key_name);
127+
return -EINVAL;
128+
}
129+
data_len = rc;
120130
/* convert the key to a string for the shell to print */
121131
(void)bacnet_storage_key_encode(key_name, sizeof(key_name), &key);
122-
if (argc > 4) {
132+
/* check for an assigned tag */
133+
if ((argc > 5) && bacnet_storage_strtoul(argv[4], &unsigned_value)) {
134+
value.tag = unsigned_value;
135+
value_string = argv[5];
136+
} else if (argc > 4) {
123137
value_string = argv[4];
124-
if (property_list_commandable_member(key.object_type, key.property_id)) {
125-
/* check for case insensitive NULL string */
126-
if (bacnet_strnicmp(value_string, "NULL", 4) == 0) {
127-
null_value = true;
128-
}
129-
}
138+
}
139+
if (value_string) {
140+
len = bacapp_decode_application_data(data, data_len, &value);
130141
/* convert the string value into a tagged union value */
131-
if (null_value) {
132-
value.tag = BACNET_APPLICATION_TAG_NULL;
133-
status = true;
134-
} else {
135-
value_tag = bacapp_known_property_tag(key.object_type, key.property_id);
136-
/* check for known property types */
137-
if (value_tag == BACNET_APPLICATION_TAG_ENUMERATED) {
142+
if (isalpha(value_string[0])) {
143+
if (property_list_commandable_member(key.object_type, key.property_id) &&
144+
(bacnet_strnicmp(value_string, "NULL", 4) == 0)) {
145+
/* check for case insensitive NULL string */
146+
value.tag = BACNET_APPLICATION_TAG_NULL;
147+
status = true;
148+
} else if (bacnet_stricmp(value_string, "true") == 0) {
149+
value.type.Boolean = true;
150+
value.tag = BACNET_APPLICATION_TAG_BOOLEAN;
151+
status = true;
152+
} else if (bacnet_stricmp(value_string, "false") == 0) {
153+
value.type.Boolean = false;
154+
value.tag = BACNET_APPLICATION_TAG_BOOLEAN;
155+
status = true;
156+
} else {
138157
status = bactext_object_property_strtoul(
139158
(BACNET_OBJECT_TYPE)key.object_type,
140159
(BACNET_PROPERTY_ID)key.property_id, value_string,
@@ -143,9 +162,63 @@ static int cmd_value(const struct shell *sh, size_t argc, char **argv)
143162
value.tag = BACNET_APPLICATION_TAG_ENUMERATED;
144163
value.type.Enumerated = (uint32_t)enumerated_value;
145164
}
146-
} else {
147-
status = bacapp_parse_application_data(value_tag, value_string,
148-
&value);
165+
}
166+
}
167+
if (!status) {
168+
switch (value.tag) {
169+
case BACNET_APPLICATION_TAG_ENUMERATED:
170+
if (bacnet_storage_strtoul(value_string, &unsigned_value)) {
171+
value.type.Enumerated = (uint32_t)unsigned_value;
172+
status = true;
173+
}
174+
break;
175+
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
176+
if (bacnet_storage_strtoul(value_string, &unsigned_value)) {
177+
value.type.Unsigned_Int = (uint32_t)unsigned_value;
178+
status = true;
179+
}
180+
break;
181+
case BACNET_APPLICATION_TAG_SIGNED_INT:
182+
if (bacnet_storage_strtol(value_string, &signed_value)) {
183+
value.type.Signed_Int = (int32_t)signed_value;
184+
status = true;
185+
}
186+
break;
187+
case BACNET_APPLICATION_TAG_REAL:
188+
if (bacnet_storage_strtof(value_string, &real_value)) {
189+
value.type.Real = (float)real_value;
190+
status = true;
191+
}
192+
break;
193+
case BACNET_APPLICATION_TAG_BIT_STRING:
194+
status = bitstring_init_ascii(&value.type.Bit_String, value_string);
195+
break;
196+
case BACNET_APPLICATION_TAG_OCTET_STRING:
197+
status = octetstring_init_ascii_hex(&value.type.Octet_String,
198+
value_string);
199+
break;
200+
case BACNET_APPLICATION_TAG_CHARACTER_STRING:
201+
status = characterstring_init_ansi(&value.type.Character_String,
202+
value_string);
203+
break;
204+
case BACNET_APPLICATION_TAG_DATE:
205+
status = datetime_date_init_ascii(&value.type.Date, value_string);
206+
break;
207+
case BACNET_APPLICATION_TAG_TIME:
208+
status = datetime_time_init_ascii(&value.type.Time, value_string);
209+
break;
210+
case BACNET_APPLICATION_TAG_OBJECT_ID:
211+
scan_count =
212+
sscanf(value_string, "%4d:%7u", &object_type, &instance);
213+
if (scan_count == 2) {
214+
value.type.Object_Id.type = (uint16_t)object_type;
215+
value.type.Object_Id.instance = instance;
216+
} else {
217+
status = false;
218+
}
219+
break;
220+
default:
221+
break;
149222
}
150223
}
151224
if (status) {
@@ -171,14 +244,9 @@ static int cmd_value(const struct shell *sh, size_t argc, char **argv)
171244
return -EINVAL;
172245
}
173246
} else {
174-
rc = bacnet_storage_get(&key, data, sizeof(data));
175-
if (rc < 0) {
176-
shell_error(sh, "Unable to get %s", key_name);
177-
return -EINVAL;
178-
}
179247
/* convert to printable value */
180-
len = bacapp_decode_known_array_property(data, rc, &value, key.object_type,
181-
key.property_id, key.array_index);
248+
len = bacapp_decode_known_property(data, rc, &value, key.object_type,
249+
key.property_id);
182250
if (len < 0) {
183251
shell_error(sh, "Unable to decode value for %s", key_name);
184252
return -EINVAL;
@@ -287,13 +355,21 @@ static int cmd_delete(const struct shell *sh, size_t argc, char **argv)
287355
static int print_storage_data(BACNET_STORAGE_KEY *key, const void *data, size_t data_len,
288356
void *context)
289357
{
358+
char data_string[80] = {0};
359+
char hex_string[3] = {0};
360+
unsigned i;
290361
const struct shell *sh = context;
362+
363+
for (i = 0; i < data_len && i < ((sizeof(data_string) / 2) - 1); i++) {
364+
snprintf(hex_string, sizeof(hex_string), "%02X", ((const uint8_t *)data)[i]);
365+
strcat(data_string, hex_string);
366+
}
291367
if (key->array_index == BACNET_STORAGE_ARRAY_INDEX_NONE) {
292-
shell_print(sh, "%s/%u/%u/%u", Storage_Base_Name, key->object_type,
293-
key->object_instance, key->property_id);
368+
shell_print(sh, "%s/%u/%u/%u=%s", Storage_Base_Name, key->object_type,
369+
key->object_instance, key->property_id, data_string);
294370
} else {
295-
shell_print(sh, "%s/%u/%u/%u/%u", Storage_Base_Name, key->object_type,
296-
key->object_instance, key->property_id, key->array_index);
371+
shell_print(sh, "%s/%u/%u/%u/%u=%s", Storage_Base_Name, key->object_type,
372+
key->object_instance, key->property_id, key->array_index, data_string);
297373
}
298374

299375
return 0;
@@ -326,9 +402,14 @@ static int cmd_list(const struct shell *sh, size_t argc, char **argv)
326402

327403
SHELL_STATIC_SUBCMD_SET_CREATE(
328404
sub_bacnet_settings_cmds, SHELL_CMD(list, NULL, "list BACnet storage strings", cmd_list),
329-
SHELL_CMD(value, NULL, "get or set BACnet storage value", cmd_value),
330-
SHELL_CMD(string, NULL, "get or set BACnet storage string", cmd_string),
331-
SHELL_CMD(delete, NULL, "delete BACnet storage string", cmd_delete), SHELL_SUBCMD_SET_END);
405+
SHELL_CMD(value, NULL, "<object type> <object instance> <property id>[array index] [value]",
406+
cmd_value),
407+
SHELL_CMD(string, NULL,
408+
"<object type> <object instance> <property id>[array index] [string]",
409+
cmd_string),
410+
SHELL_CMD(delete, NULL, "<object type> <object instance> <property id>[array index]",
411+
cmd_delete),
412+
SHELL_SUBCMD_SET_END);
332413

333414
SHELL_SUBCMD_ADD((bacnet), settings, &sub_bacnet_settings_cmds, "BACnet settings commands", NULL, 1,
334415
0);

0 commit comments

Comments
 (0)