1111#include <zephyr/shell/shell.h>
1212#include <bacnet_settings/bacnet_storage.h>
1313#include <bacnet/bactext.h>
14+ #include <bacnet/proplist.h>
1415#include <bacnet/wp.h>
1516
1617static const char Storage_Base_Name [] = CONFIG_BACNET_STORAGE_BASE_NAME ;
@@ -29,6 +30,7 @@ static int cmd_key(BACNET_STORAGE_KEY *key, const struct shell *sh, size_t argc,
2930 uint32_t property_id = 77 ;
3031 uint32_t array_index = BACNET_STORAGE_ARRAY_INDEX_NONE ;
3132 long value = 0 ;
33+ unsigned long unsigned_value = 0 ;
3234 int found_index = 0 ;
3335
3436 if (argc < 3 ) {
@@ -46,12 +48,31 @@ static int cmd_key(BACNET_STORAGE_KEY *key, const struct shell *sh, size_t argc,
4648 return - EINVAL ;
4749 }
4850 object_type = (uint16_t )value ;
49- value = strtoul (argv [2 ], NULL , 0 );
50- if (value > 4194303 ) {
51+ if (!bacnet_storage_strtoul (argv [2 ], & unsigned_value )) {
52+ shell_error (sh , "Invalid object-instance: %s." , argv [2 ]);
53+ return - EINVAL ;
54+ }
55+ if (unsigned_value > 4194303 ) {
5156 shell_error (sh , "Invalid object-instance: %s. Must be 0-4194303." , argv [2 ]);
5257 return - EINVAL ;
5358 }
54- object_instance = (uint32_t )value ;
59+ 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 );
65+ return - EINVAL ;
66+ }
67+ if (unsigned_value > UINT32_MAX ) {
68+ shell_error (sh , "Invalid array-index: \"%s\". Must be 0-4294967295." ,
69+ at_ptr );
70+ return - EINVAL ;
71+ }
72+ array_index = (uint32_t )unsigned_value ;
73+ /* null terminate the string at the @ symbol */
74+ * at_ptr = 0 ;
75+ }
5576 if (bactext_property_strtol (argv [3 ], & found_index )) {
5677 value = found_index ;
5778 } else {
@@ -69,6 +90,111 @@ static int cmd_key(BACNET_STORAGE_KEY *key, const struct shell *sh, size_t argc,
6990 return 0 ;
7091}
7192
93+ /**
94+ * @brief Get or set a string using BACnet storage subsystem
95+ * @param sh Shell
96+ * @param argc Number of arguments
97+ * @param argv Argument list
98+ * @return 0 on success, negative on failure
99+ */
100+ static int cmd_value (const struct shell * sh , size_t argc , char * * argv )
101+ {
102+ char key_name [BACNET_STORAGE_KEY_SIZE_MAX + 1 ] = {0 };
103+ uint8_t data [BACNET_STORAGE_VALUE_SIZE_MAX + 1 ] = {0 };
104+ BACNET_STORAGE_KEY key = {0 };
105+ int rc ;
106+ unsigned enumerated_value = 0 ;
107+ bool status = false;
108+ bool null_value = false;
109+ BACNET_APPLICATION_DATA_VALUE value = {0 };
110+ BACNET_OBJECT_PROPERTY_VALUE object_value = {0 };
111+ char value_name [80 ] = {0 };
112+ char * value_string = NULL ;
113+ uint8_t value_tag ;
114+ int len ;
115+
116+ rc = cmd_key (& key , sh , argc , argv );
117+ if (rc < 0 ) {
118+ return rc ;
119+ }
120+ /* convert the key to a string for the shell to print */
121+ (void )bacnet_storage_key_encode (key_name , sizeof (key_name ), & key );
122+ if (argc > 4 ) {
123+ 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+ }
130+ /* 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 ) {
138+ status = bactext_object_property_strtoul (
139+ (BACNET_OBJECT_TYPE )key .object_type ,
140+ (BACNET_PROPERTY_ID )key .property_id , value_string ,
141+ & enumerated_value );
142+ if (status ) {
143+ value .tag = BACNET_APPLICATION_TAG_ENUMERATED ;
144+ value .type .Enumerated = (uint32_t )enumerated_value ;
145+ }
146+ } else {
147+ status = bacapp_parse_application_data (value_tag , value_string ,
148+ & value );
149+ }
150+ }
151+ if (status ) {
152+ shell_print (sh , "Parsed %s = %s as tag=%u" , key_name , value_string ,
153+ value .tag );
154+ len = bacapp_encode_application_data (NULL , & value );
155+ if (len <= 0 ) {
156+ return false;
157+ } else if (len > sizeof (data )) {
158+ return false;
159+ }
160+ len = bacapp_encode_application_data (data , & value );
161+ rc = bacnet_storage_set (& key , data , len );
162+ if (rc == 0 ) {
163+ shell_print (sh , "Set %s = %s" , key_name , value_string );
164+ } else {
165+ shell_error (sh , "Unable to set %s = %s" , key_name , value_string );
166+ return - EINVAL ;
167+ }
168+ } else {
169+ shell_error (sh , "Unable to parse value for %s = %s" , key_name ,
170+ value_string );
171+ return - EINVAL ;
172+ }
173+ } 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+ }
179+ /* convert to printable value */
180+ len = bacapp_decode_known_array_property (data , rc , & value , key .object_type ,
181+ key .property_id , key .array_index );
182+ if (len < 0 ) {
183+ shell_error (sh , "Unable to decode value for %s" , key_name );
184+ return - EINVAL ;
185+ }
186+ object_value .object_type = key .object_type ;
187+ object_value .object_instance = key .object_instance ;
188+ object_value .object_property = key .property_id ;
189+ object_value .array_index = key .array_index ;
190+ object_value .value = & value ;
191+ bacapp_snprintf_value (value_name , sizeof (value_name ), & object_value );
192+ shell_print (sh , "Get %s = %s" , key_name , value_name );
193+ }
194+
195+ return 0 ;
196+ }
197+
72198/**
73199 * @brief Get or set a string using BACnet storage subsystem
74200 * @param sh Shell
@@ -200,6 +326,7 @@ static int cmd_list(const struct shell *sh, size_t argc, char **argv)
200326
201327SHELL_STATIC_SUBCMD_SET_CREATE (
202328 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 ),
203330 SHELL_CMD (string , NULL , "get or set BACnet storage string" , cmd_string ),
204331 SHELL_CMD (delete , NULL , "delete BACnet storage string" , cmd_delete ), SHELL_SUBCMD_SET_END );
205332
0 commit comments