Open FFBoard
Open source force feedback firmware
Loading...
Searching...
No Matches
SystemCommands.cpp
Go to the documentation of this file.
1/*
2 * SystemCommands.cpp
3 *
4 * Created on: 30.11.2021
5 * Author: Yannick
6 */
7
8#include "SystemCommands.h"
9#include "PersistentStorage.h"
10#include "FFBoardMain.h"
11#include "voltagesense.h"
12#include <malloc.h>
13#include "constants.h"
14#include "task.h"
15#include "FreeRTOSConfig.h"
18//extern static const uint8_t SW_VERSION_INT[3];
19
20
21bool SystemCommands::debugMode = false;
24
26 .name = "System Commands" ,
27 .id = CLSID_SYSTEM,
28 .visibility = ClassVisibility::hidden
29 };
30
34
35SystemCommands::SystemCommands() : CommandHandler(CMDCLSTR_SYS, CMDCLSID_SYS) {
37 //CommandHandler::registerCommands();
39
40}
41
45
46
48 CommandHandler::registerCommand("help", FFBoardMain_commands::help, "Print system help",CMDFLAG_STR_ONLY);
49 CommandHandler::registerCommand("save", FFBoardMain_commands::save, "Write all settings to flash",CMDFLAG_GET);
50 CommandHandler::registerCommand("reboot", FFBoardMain_commands::reboot, "Reset chip",CMDFLAG_GET);
51 CommandHandler::registerCommand("dfu", FFBoardMain_commands::dfu, "reboot into DFU bootloader",CMDFLAG_GET);
52 CommandHandler::registerCommand("lsmain", FFBoardMain_commands::lsmain, "List available mainclasses",CMDFLAG_GET);
53 CommandHandler::registerCommand("lsactive", FFBoardMain_commands::lsactive, "List active classes (Fullname:clsname:inst:clsid:idx)",CMDFLAG_GET);
54 CommandHandler::registerCommand("vint", FFBoardMain_commands::vint, "Internal voltage(mV)",CMDFLAG_GET);
55 CommandHandler::registerCommand("vext", FFBoardMain_commands::vext, "External voltage(mV)",CMDFLAG_GET);
56 CommandHandler::registerCommand("main", FFBoardMain_commands::main, "Query or change mainclass",CMDFLAG_GET | CMDFLAG_SET);
57 CommandHandler::registerCommand("swver", FFBoardMain_commands::swver, "Firmware version",CMDFLAG_GET);
58 CommandHandler::registerCommand("hwtype", FFBoardMain_commands::hwtype, "Hardware type",CMDFLAG_GET);
59 CommandHandler::registerCommand("flashraw", FFBoardMain_commands::flashraw, "Write value to flash address",CMDFLAG_SETADR | CMDFLAG_GETADR);
60 CommandHandler::registerCommand("flashdump", FFBoardMain_commands::flashdump, "Read all flash variables (val:adr)",CMDFLAG_GET);
61 CommandHandler::registerCommand("errors", FFBoardMain_commands::errors, "Read error states",CMDFLAG_GET);
62 CommandHandler::registerCommand("errorsclr", FFBoardMain_commands::errorsclr, "Reset errors",CMDFLAG_GET);
63 CommandHandler::registerCommand("heapfree", FFBoardMain_commands::heapfree, "Memory info",CMDFLAG_GET);
64#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
65 CommandHandler::registerCommand("taskstats", FFBoardMain_commands::taskstats, "Task stats",CMDFLAG_GET);
66#endif
67 CommandHandler::registerCommand("format", FFBoardMain_commands::format, "set format=1 to erase all stored values",CMDFLAG_SET);
68 CommandHandler::registerCommand("debug", FFBoardMain_commands::debug, "Enable or disable debug commands",CMDFLAG_SET | CMDFLAG_GET);
69 CommandHandler::registerCommand("devid", FFBoardMain_commands::devid, "Get chip dev id and rev id",CMDFLAG_GET);
70 CommandHandler::registerCommand("name", CommandHandlerCommands::name, "name of class",CMDFLAG_GET|CMDFLAG_STR_ONLY);
71 CommandHandler::registerCommand("cmdinfo", CommandHandlerCommands::cmdinfo, "Flags of a command id (adr). -1 if cmd id invalid",CMDFLAG_GETADR);
72 CommandHandler::registerCommand("uid", FFBoardMain_commands::uid, "Get 96b chip uid. Adr0-2 sel blk",CMDFLAG_GET | CMDFLAG_GETADR | CMDFLAG_INFOSTRING);
73 CommandHandler::registerCommand("temp", FFBoardMain_commands::temp, "Chip temperature in C",CMDFLAG_GET);
74#if defined(OTPMEMORY)
75 CommandHandler::registerCommand("otp", FFBoardMain_commands::otp, "Access OTP memory",CMDFLAG_GETADR | CMDFLAG_SETADR | CMDFLAG_DEBUG);
76#endif
77#if defined(SIGNATURE)
78 CommandHandler::registerCommand("signature", FFBoardMain_commands::signature, "Chip signature in OTP. setadr to write data. set=1 to lock",CMDFLAG_GETADR | CMDFLAG_SETADR | CMDFLAG_GET | CMDFLAG_INFOSTRING);
79#endif
80#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
81 CommandHandler::registerCommand("tasklist", FFBoardMain_commands::tasklist, "Task list",CMDFLAG_GET);
82#endif
83}
84
85// Choose lower optimize level because the compiler likes to blow up this function
86__attribute__((optimize("-O1")))
87CommandStatus SystemCommands::internalCommand(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
89
90 if(flag != CommandStatus::NOT_FOUND){
91 return flag;
92 }else{
93 flag = CommandStatus::OK;
94 }
95
96 switch(static_cast<FFBoardMain_commands>(cmd.cmdId))
97 {
99 {// help
100 if(cmd.type == CMDtype::info){
101 replies.emplace_back(this->getCsvHelpstring());
102 }else{
103 std::string itfHelp = "";
104 if(cmd.originalInterface){
105 itfHelp = cmd.originalInterface->getHelpstring() + "\n";
106 }
107 std::string reply = itfHelp + "Available classes (use cls.0.help for more info):\n";
108 //std::string reply = "";
110 CmdHandlerInfo* info = handler->getCommandHandlerInfo();
111 reply += std::string(info->clsname) + "." + std::to_string(info->instance)+"\n";
112 }
113 reply += "\n"+this->getCommandsHelpstring();
114 replies.emplace_back(reply);
115 }
116
117 break;
118 }
119
122 handler->saveFlash();
123 }
124 break;
125
127 NVIC_SystemReset();
128 break;
129
131 RebootDFU();
132 break;
134 mainchooser.replyAvailableClasses(replies,mainclass->getSelectionID());
135 break;
136
138 {
139 replies.emplace_back(getIntV());
140 break;
141 }
142
144 return handleGetSet(cmd, replies, SystemCommands::debugMode);
145
147 {
148 replies.emplace_back(getExtV());
149 break;
150 }
151
153 {
154 if(cmd.type == CMDtype::get){
155 uint16_t buf=mainclass->getInfo().id;
156 Flash_Read(ADR_CURRENT_CONFIG, &buf);
157 replies.emplace_back(buf);
158 }else if(cmd.type == CMDtype::set){
159 if(mainchooser.isValidClassId(cmd.val)){
160 Flash_Write(ADR_CURRENT_CONFIG, (uint16_t)cmd.val);
161 if(cmd.val != mainclass->getInfo().id){
162 NVIC_SystemReset(); // Reboot
163 }
164 }
165 }
166 break;
167 }
169 {
170 replyErrors(replies);
171 break;
172 }
174 replyFlashDump(replies);
175 break;
176
178 {
179 if(cmd.type == CMDtype::setat){
180 Flash_Write(cmd.adr, cmd.val);
181
182 }else if(cmd.type == CMDtype::getat){
183 CommandReply reply;
185 uint16_t val;
186 if(Flash_Read(cmd.adr,&val)){
187 reply.val=val;
188 }
189 replies.push_back(reply);
190 }
191 break;
192 }
193
196 break;
197
199 {
200 CommandReply reply;
202
203 extern const uint8_t SW_VERSION_INT[3];
204 reply.reply += std::to_string(SW_VERSION_INT[0]) + "." + std::to_string(SW_VERSION_INT[1]) + "." + std::to_string(SW_VERSION_INT[2]);
205
206 reply.val = (SW_VERSION_INT[0]<<16) | (SW_VERSION_INT[1] << 8) | (SW_VERSION_INT[2]);
207 replies.push_back(reply);
208 break;
209 }
210
212 {
213 replies.emplace_back(HW_TYPE,HW_TYPE_INT);
214 //replies.emplace_back(HAL_GetDEVID());
215 break;
216 }
218 {
219 replies.emplace_back(HAL_GetDEVID(),HAL_GetREVID());
220 break;
221 }
222
223
225 {
226 CommandReply reply;
227 struct mallinfo info = mallinfo();
228 reply.adr = info.uordblks;
229 reply.val = info.uordblks;
230 reply.reply +="Usage: ";
231 reply.reply += std::to_string(info.uordblks);
232 reply.reply +=" Size: ";
233 reply.reply +=std::to_string(info.arena);
235 replies.push_back(reply);
236 break;
237 }
238
240 {
241 replies.emplace_back(xPortGetFreeHeapSize(),xPortGetMinimumEverFreeHeapSize());
242 break;
243 }
244#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
246 {
247 std::string repl;
248 repl.resize(uxTaskGetNumberOfTasks()*64,'\0');
249 vTaskGetRunTimeStats(repl.data());
250 repl.resize(repl.find_first_of('\0')); // Cut
251 replies.emplace_back("\n"+(repl));
252 break;
253 }
254#endif
255#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
257 {
258 std::string repl;
259 repl.resize(uxTaskGetNumberOfTasks()*64,'\0');
260 vTaskList(repl.data());
261 repl.resize(repl.find_first_of('\0')); // Cut
262 replies.emplace_back("\n"+(repl));
263 break;
264 }
265#endif
267 {
269
270 ClassIdentifier i = handler->getInfo();
271 CmdHandlerInfo* hi = handler->getCommandHandlerInfo();
272 CommandReply reply;
274 reply.adr = hi->instance;
275 reply.val = hi->clsTypeid;
276 reply.reply += std::string(i.name)+ ":" + hi->clsname + ":" + std::to_string(hi->instance) + ":" + std::to_string(i.id) + ":" + std::to_string(hi->commandHandlerID);
277 replies.push_back(reply);
278
279 }
280 break;
281 }
283 if(cmd.type == CMDtype::set && cmd.val==1){
284
285 if(Flash_Format()){
286 Flash_Write_Defaults(); // Restore default values if present
287 flag = CommandStatus::OK;
288 }else{
289 flag = CommandStatus::ERR;
290 }
291
292 }
293 break;
295 if(cmd.type == CMDtype::get){
296 replies.emplace_back((uint64_t)HAL_GetUIDw0() | (uint64_t)HAL_GetUIDw1() << 32,HAL_GetUIDw2());
297 }else if(cmd.type == CMDtype::getat){
298 if(cmd.adr == 0){
299 replies.emplace_back(HAL_GetUIDw0());
300 }else if(cmd.adr == 1){
301 replies.emplace_back(HAL_GetUIDw1());
302 }else if(cmd.adr == 2){
303 replies.emplace_back(HAL_GetUIDw2());
304 }
305 }else if(cmd.type == CMDtype::info){
306 char buf[32];
307 std::snprintf(buf,32,"0x%08lx%08lx%08lx",HAL_GetUIDw2(),HAL_GetUIDw1(),HAL_GetUIDw0()); // Print as hex string
308 replies.emplace_back(std::string(buf));
309 }
310 break;
312 {
313 replies.emplace_back(getChipTemp());
314 break;
315 }
316#if defined(OTPMEMORY)
318 if(cmd.type == CMDtype::setat){
319 bool success = OTP_Write(cmd.adr, cmd.val);
320 if(!success){
321 flag = CommandStatus::ERR;
322 }
323 }else if(cmd.type == CMDtype::getat){
324 CommandReply reply;
326 uint64_t val;
327 if(OTP_Read(cmd.adr,&val)){
328 reply.val=val;
329 }else{
330 flag = CommandStatus::ERR;
331 }
332 replies.push_back(reply);
333 }
334 break;
335#endif
336#if defined(SIGNATURE)
338#if defined(SIGNATURELEN) && defined(SIGBNATUREBASEADR)
339 if(cmd.type == CMDtype::info){
340 char buf[(SIGNATURELEN * 16) + 1];
341 uint64_t dat;
342 for(uint8_t i = 0;i<SIGNATURELEN;i++){
343 OTP_Read(SIGBNATUREBASEADR+i, &dat);
344 std::snprintf(buf+i*16,17,"%016llx",dat); // Print as hex string
345 }
346 replies.emplace_back(std::string(buf));
347 }else if(cmd.type == CMDtype::get){
348 for(uint8_t i = 0;i<SIGNATURELEN;i++){
349 uint64_t dat;
350 OTP_Read(SIGBNATUREBASEADR+i, &dat);
351 replies.emplace_back(dat,i);
352 }
353 }else if(cmd.type == CMDtype::getat){
354 if(cmd.adr >= SIGNATURELEN || cmd.adr < 0){
355 flag = CommandStatus::ERR;
356 }else{
357 uint64_t dat;
358 OTP_Read(SIGBNATUREBASEADR+cmd.adr, &dat);
359 replies.emplace_back(dat,cmd.adr);
360 }
361 }else if(cmd.type == CMDtype::setat){
362 bool success = OTP_Write(cmd.adr+SIGBNATUREBASEADR, cmd.val);
363 if(!success){
364 flag = CommandStatus::ERR;
365 }
366 }else{
367 flag = CommandStatus::ERR;
368 }
369#else
370 if(cmd.type == CMDtype::info){
371 replies.emplace_back("0");
372 }else if(cmd.type == CMDtype::get || cmd.type == CMDtype::getat){
373 replies.emplace_back(0);
374 }else{
375 flag = CommandStatus::ERR;
376 }
377#endif
378#endif
379 break;
380
381
382 default:
384 break;
385 }
386 return flag;
387}
388
389/*
390 * Prints a formatted flash dump to the reply string
391 */
392void SystemCommands::replyFlashDump(std::vector<CommandReply>& replies){
393 std::vector<std::tuple<uint16_t,uint16_t>> result;
394 Flash_Dump(&result,false);
395
396 for(auto entry : result){
397 CommandReply reply;
398 uint16_t adr;
399 uint16_t val;
400 std::tie(adr,val) = entry;
401 //reply.reply += std::to_string(adr) + ":" + std::to_string(val) + "\n";
402 reply.adr = adr;
403 reply.val = val;
405 replies.push_back(reply);
406 }
407}
408
409/*
410 * Prints a formatted list of error conditions
411 */
412void SystemCommands::replyErrors(std::vector<CommandReply>& replies){
413 std::span<Error> errors = ErrorHandler::getErrors();
414 if(errors.size() == 0){
415 CommandReply reply;
416 reply.reply += "None";
418 replies.push_back(reply);
419 return;
420 }
421
422 for(Error error : errors){
423 CommandReply reply;
424 reply.reply += error.toString() + "\n";
425 reply.val = (uint32_t)error.code;
427 replies.push_back(reply);
428 }
429
431}
CommandStatus
uint8_t adr
__attribute__((optimize("-O1"))) CommandStatus SystemCommands
FFBoardMain_commands
void registerCommand(const char *cmd, const ID cmdid, const char *help=nullptr, uint32_t flags=0)
virtual CommandStatus internalCommand(const ParsedCommand &cmd, std::vector< CommandReply > &replies)
CommandHandler(const char *clsname, uint16_t clsid, uint8_t instance=0)
static std::vector< CommandHandler * > & getCommandHandlers()
std::string reply
CommandReplyType type
static std::span< Error > getErrors()
static void clearTemp()
static void clearAll()
static std::vector< PersistentStorage * > & getFlashHandlers()
static SystemCommands * systemCommandsInstance
static ClassIdentifier info
virtual ~SystemCommands()
static bool errorPrintingEnabled
static bool debugMode
static void replyErrors(std::vector< CommandReply > &replies)
static void replyFlashDump(std::vector< CommandReply > &replies)
const ClassIdentifier getInfo()
Command handlers always have class infos. Works well with ChoosableClass.
static const uint8_t SW_VERSION_INT[3]
Definition constants.h:11
ClassChooser< FFBoardMain > mainchooser(class_registry)
bool Flash_Format()
void Flash_Dump(std::vector< std::tuple< uint16_t, uint16_t > > *result, bool includeAll=false)
bool Flash_Write(uint16_t adr, uint16_t dat)
bool OTP_Read(uint16_t adroffset, uint64_t *dat)
void Flash_Write_Defaults()
bool Flash_Read(uint16_t adr, uint16_t *buf, bool checkempty=true)
bool OTP_Write(uint16_t adroffset, uint64_t dat)
FFBoardMain * mainclass
const char * name
const char * clsname
uint16_t commandHandlerID
const uint16_t clsTypeid
int32_t getChipTemp()
int32_t getIntV()
int32_t getExtV()