1+ /*
2+ This file is part of PICoBoot Utility.
3+
4+ Copyright (C) 2021 ReimuNotMoe <[email protected] > 5+
6+ This program is free software: you can redistribute it and/or modify
7+ it under the terms of the GNU Affero General Public License as
8+ published by the Free Software Foundation, either version 3 of the
9+ License, or (at your option) any later version.
10+
11+ This program is distributed in the hope that it will be useful,
12+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ GNU Affero General Public License for more details.
15+
16+ You should have received a copy of the GNU Affero General Public License
17+ along with this program. If not, see <https://www.gnu.org/licenses/>.
18+ */
19+
20+ #include " PICoBoot_Utility.hpp"
21+
22+ std::vector<std::string> env_list = {
23+ " watchdog_config" ,
24+ " watchdog_max_fails" ,
25+ " allow_read" ,
26+ " allow_write" ,
27+ " app_name" ,
28+ " app_version" ,
29+
30+ " reboot_count" ,
31+ " watchdog_failed_count" ,
32+ " boot_reason" ,
33+ " reboot_target" ,
34+ };
35+
36+ enum {
37+ EnvType_u8, EnvType_s8,
38+ EnvType_u16, EnvType_s16,
39+ EnvType_u32, EnvType_s32,
40+ EnvType_u64, EnvType_s64,
41+
42+ EnvType_str, EnvType_bin,
43+ };
44+ std::unordered_map<std::string, std::tuple<uint8_t , uint8_t , uint8_t , uint8_t >> env_table = {
45+ // Category, Type, Offset, Size
46+ {" watchdog_config" , {0 , EnvType_u8, 1 , 1 }},
47+ {" watchdog_max_fails" , {0 , EnvType_u8, 2 , 1 }},
48+ {" allow_read" , {0 , EnvType_u32, 4 , 4 }},
49+ {" allow_write" , {0 , EnvType_u32, 8 , 4 }},
50+ {" app_name" , {0 , EnvType_str, 12 , 16 }},
51+ {" app_version" , {0 , EnvType_str, 28 , 8 }},
52+
53+ {" reboot_count" , {1 , EnvType_u32, 0 , 4 }},
54+ {" watchdog_failed_count" , {1 , EnvType_u32, 4 , 4 }},
55+ {" boot_reason" , {1 , EnvType_u8, 8 , 1 }},
56+ {" reboot_target" , {1 , EnvType_u8, 9 , 1 }},
57+ };
58+
59+ static void print_val (uint8_t type, uint8_t *target, uint8_t len) {
60+ switch (type) {
61+ case EnvType_u8: {
62+ uint8_t val = *((uint8_t *) target);
63+ printf (" %" PRIu8 " (0x%02x)\n " , val, val);
64+ }
65+ break ;
66+ case EnvType_s8: {
67+ int8_t val = *((int8_t *) target);
68+ printf (" %" PRId8 " (0x%02x)\n " , val, val);
69+ }
70+ break ;
71+ case EnvType_u16: {
72+ uint16_t val = *((uint16_t *) target);
73+ printf (" %" PRIu16 " (0x%04x)\n " , val, val);
74+ }
75+ break ;
76+ case EnvType_s16: {
77+ int16_t val = *((int16_t *) target);
78+ printf (" %" PRId16 " (0x%04x)\n " , val, val);
79+ }
80+ break ;
81+ case EnvType_u32: {
82+ uint32_t val = *((uint32_t *) target);
83+ printf (" %" PRIu32 " (0x%08x)\n " , val, val);
84+ }
85+ break ;
86+ case EnvType_s32: {
87+ int32_t val = *((int32_t *) target);
88+ printf (" %" PRId32 " (0x%08x)\n " , val, val);
89+ }
90+ break ;
91+ case EnvType_u64: {
92+ uint64_t val = *((uint64_t *) target);
93+ printf (" %" PRIu64 " (0x%016lx)\n " , val, val);
94+ }
95+ break ;
96+ case EnvType_s64: {
97+ int64_t val = *((int64_t *) target);
98+ printf (" %" PRId64 " (0x%016lx)\n " , val, val);
99+ }
100+ break ;
101+ case EnvType_str: {
102+ printf (" %.*s (len = %u)\n " , len, target, len);
103+ }
104+ break ;
105+ case EnvType_bin: {
106+ for (size_t i = 0 ; i < len; i++) {
107+ printf (" %02x " , target[i]);
108+ }
109+ printf (" (len = %u)\n " , len);
110+ }
111+ break ;
112+
113+ }
114+ }
115+
116+ int write_env (Serial &tty, uint8_t cat, uint8_t type, uint8_t offset, uint8_t len, const std::string& user_input) {
117+ uint8_t buf[len];
118+ bool hex = (user_input.find (" 0x" ) == 0 );
119+ int base = hex ? 16 : 10 ;
120+
121+ switch (type) {
122+ case EnvType_u8:
123+ *((uint8_t *) buf) = strtoul (user_input.c_str (), nullptr , base);
124+ break ;
125+ case EnvType_s8:
126+ *((int8_t *) buf) = strtol (user_input.c_str (), nullptr , base);
127+ break ;
128+ case EnvType_u16:
129+ *((uint16_t *) buf) = strtoul (user_input.c_str (), nullptr , base);
130+ break ;
131+ case EnvType_s16:
132+ *((int16_t *) buf) = strtol (user_input.c_str (), nullptr , base);
133+ break ;
134+ case EnvType_u32:
135+ *((uint32_t *) buf) = strtoul (user_input.c_str (), nullptr , base);
136+ break ;
137+ case EnvType_s32:
138+ *((int32_t *) buf) = strtol (user_input.c_str (), nullptr , base);
139+ break ;
140+ case EnvType_u64:
141+ *((uint64_t *) buf) = strtoul (user_input.c_str (), nullptr , base);
142+ break ;
143+ case EnvType_s64:
144+ *((int64_t *) buf) = strtol (user_input.c_str (), nullptr , base);
145+ break ;
146+ case EnvType_str:
147+ strncpy (reinterpret_cast <char *>(buf), user_input.c_str (), len);
148+ break ;
149+ case EnvType_bin:
150+ puts (" Unsupported at this moment." );
151+ abort ();
152+ break ;
153+ }
154+
155+
156+ for (size_t i=0 ; i<len; i++) {
157+ uint8_t pkt[4 ] = {cat, static_cast <uint8_t >(offset+i), buf[i], 0 };
158+ pkt[3 ] = crc8 (pkt, 3 );
159+
160+ auto rcv = serial_chat (tty, FlasherCommand_EnvironmentWrite, pkt);
161+ uint8_t rc = *((uint8_t *)rcv.data ());
162+
163+ if (rc != FlasherResult_OK) {
164+ printf (" error: failed to write environment variable: %s\n " , FlasherResult_strerror (rc));
165+ return 2 ;
166+ }
167+ }
168+
169+ return 0 ;
170+ }
171+
172+ int Command_Env (const std::vector<std::string>& args) {
173+ if (args.size () < 2 ) {
174+ puts (" usage: env <show|get KEY|set KEY VALUE|save [static|runtime]>>" );
175+ return 2 ;
176+ }
177+
178+ if (global_device_path.empty ()) {
179+ auto paths = ScanDevice_GetValidDevices ();
180+ if (paths.size () > 1 ) {
181+ puts (" More than one devices connected. Please specify one using the `-d' option." );
182+ return 1 ;
183+ } else {
184+ global_device_path = paths[0 ];
185+ }
186+ }
187+
188+ Serial tty;
189+ tty.open (global_device_path);
190+
191+ #ifdef __CYGWIN__
192+ try {
193+ #endif
194+ tty.make_raw ();
195+ tty.speed () = 2000000 ;
196+ #ifdef __CYGWIN__
197+ } catch (...) {
198+
199+ }
200+ #endif
201+
202+ if (args[1 ] == " show" ) {
203+ uint8_t cat = 0 ;
204+ auto env_block0 = serial_chat (tty, FlasherCommand_EnvironmentRead, &cat);
205+ cat = 1 ;
206+ auto env_block1 = serial_chat (tty, FlasherCommand_EnvironmentRead, &cat);
207+
208+ for (auto &it : env_list) {
209+ auto &envdef = env_table[it];
210+ uint8_t *target;
211+
212+ const char *category;
213+
214+ if (std::get<0 >(envdef) == 0 ) {
215+ target = env_block0.data ();
216+ category = " static" ;
217+ } else {
218+ target = env_block1.data ();
219+ category = " runtime" ;
220+ }
221+
222+ printf (" %s.%s: " , category, it.c_str ());
223+
224+ print_val (std::get<1 >(envdef), target + std::get<2 >(envdef), std::get<3 >(envdef));
225+ }
226+ } else if (args[1 ] == " save" ) {
227+ uint8_t arg = 0x3 ;
228+
229+ if (args.size () > 2 ) {
230+ if (args[2 ] == " static" ) {
231+ arg = 0x1 ;
232+ } else if (args[2 ] == " runtime" ) {
233+ arg = 0x2 ;
234+ }
235+ }
236+
237+ auto rcv = serial_chat (tty, FlasherCommand_EnvironmentSave, &arg);
238+ uint8_t rc = *((uint8_t *)rcv.data ());
239+
240+ if (rc != FlasherResult_OK) {
241+ printf (" error: failed to save environment: %s\n " , FlasherResult_strerror (rc));
242+ }
243+ return 2 ;
244+ } else if (args[1 ] == " get" ) {
245+ if (args.size () != 3 ) {
246+ puts (" error: please specify a name" );
247+ return 2 ;
248+ }
249+
250+ auto it = env_table.find (args[2 ]);
251+
252+ if (it != env_table.end ()) {
253+ auto &envdef = it->second ;
254+ uint8_t *target;
255+
256+ uint8_t cat = 0 ;
257+ auto env_block0 = serial_chat (tty, FlasherCommand_EnvironmentRead, &cat);
258+ cat = 1 ;
259+ auto env_block1 = serial_chat (tty, FlasherCommand_EnvironmentRead, &cat);
260+
261+ if (std::get<0 >(envdef) == 0 ) {
262+ target = env_block0.data ();
263+ } else {
264+ target = env_block1.data ();
265+ }
266+
267+ print_val (std::get<1 >(envdef), target + std::get<2 >(envdef), std::get<3 >(envdef));
268+ } else {
269+ puts (" error: not a valid environment name (please don't write prefixes like `static.' or `runtime.' here)" );
270+ return 2 ;
271+ }
272+ } else if (args[1 ] == " set" ) {
273+ if (args.size () != 4 ) {
274+ puts (" error: please specify key and value" );
275+ return 2 ;
276+ }
277+
278+ auto it = env_table.find (args[2 ]);
279+
280+ if (it != env_table.end ()) {
281+ auto &envdef = it->second ;
282+ return write_env (tty, std::get<0 >(envdef), std::get<1 >(envdef), std::get<2 >(envdef), std::get<3 >(envdef), args[3 ]);
283+ } else {
284+ puts (" error: not a valid environment name (please don't write prefixes like `static.' or `runtime.' here)" );
285+ return 2 ;
286+ }
287+ }
288+
289+ return 0 ;
290+ }
0 commit comments