Open FFBoard
Open source force feedback firmware
CommandHandler.cpp
Go to the documentation of this file.
1/*
2 * CommandHandler.cpp
3 *
4 * Created on: 03.04.2020
5 * Author: Yannick
6 */
7
8#include "CommandHandler.h"
9#include "global_callbacks.h"
10#include "FFBoardMain.h"
11#include "cdc_device.h"
12#include "CDCcomm.h"
13//#include <set>
14#include "ChoosableClass.h"
15
16//std::vector<CommandHandler*> CommandHandler::cmdHandlers;
17//std::set<uint16_t> CommandHandler::cmdHandlerIDs;
18//std::vector<uint16_t> CommandHandler::cmdHandlerIDs;
19//cpp_freertos::MutexStandard CommandHandler::cmdHandlerListMutex;
20bool CommandHandler::logEnabled = true; // If logs are sent by default
21
25CommandHandler::CommandHandler(const char* clsname,uint16_t clsid,uint8_t instance) : cmdHandlerInfo({clsname,clsid,instance,0}) {
26 addCommandHandler();
27}
28
29
31 // Remove from global list when deleted
33}
34
40 std::string helpstring = "\n";
41 helpstring.reserve(this->registeredCommands.size() * 40); // Helpstrings are large. reserve a big buffer to save on reallocations
43 if(info.name == nullptr || cmdHandlerInfo.clsname == nullptr){
44 return "";
45 }
46 helpstring.append(info.name);
47 helpstring.push_back('(');
48 helpstring.append(cmdHandlerInfo.clsname);
49 helpstring.push_back('.');
50 helpstring.append(std::to_string(cmdHandlerInfo.instance)).append("):\n");
51
52 std::string handlerHelp = getHelpstring();
53
54 if(!handlerHelp.empty()){
55 helpstring.append(handlerHelp).append("\n");
56 }
57
58 if(registeredCommands.empty()){
59 helpstring += "No commands.";
60 }else{
61 helpstring += "cmd\tflags\tdescription\n\n";
63 if(cmd.helpstring != nullptr && cmd.cmd != nullptr){
64 helpstring += std::string(cmd.cmd);
65 helpstring += "\t(";
66
67 if(cmd.flags & CMDFLAG_GET){
68 helpstring+= " R";
69 }
70 if(cmd.flags & CMDFLAG_SET){
71 helpstring+= " W";
72 }
73 if(cmd.flags & CMDFLAG_SETADR){
74 helpstring+= " WA";
75 }
76 if(cmd.flags & CMDFLAG_GETADR){
77 helpstring+= " RA";
78 }
79 if(cmd.flags & CMDFLAG_INFOSTRING){
80 helpstring+= " I";
81 }
82 if(cmd.flags & CMDFLAG_STR_ONLY){
83 helpstring+= " STR";
84 }
85 if(cmd.flags & CMDFLAG_DEBUG){
86 helpstring+= " DBG";
87 }
88 helpstring.append(" )\t").append(std::string(cmd.helpstring)).append("\n");
89 }
90
91 }
92 }
93
94 return helpstring;
95}
96
102 std::string helpstring = "\nPrefix,Class ID, Class description\n";
103 helpstring.reserve(this->registeredCommands.size() * 40); // Helpstrings are large. reserve a big buffer to save on reallocations
104 ClassIdentifier info = this->getInfo();
105 if(info.name == nullptr || cmdHandlerInfo.clsname == nullptr){
106 return "";
107 }
108
109 helpstring.append(cmdHandlerInfo.clsname);
110 helpstring += '.';
111 helpstring += std::to_string(cmdHandlerInfo.instance);
112 helpstring += ',';
113 char clshex[7];
114 std::snprintf(clshex,7,"0x%X",cmdHandlerInfo.clsTypeid);
115 helpstring += std::string(clshex);
116 helpstring += ',';
117
118 helpstring.append(info.name);
119
120 std::string handlerHelp = getHelpstring();
121
122 if(!handlerHelp.empty()){
123 helpstring.append(": ").append(handlerHelp).append("\n");
124 }else{
125 helpstring += "\n";
126 }
127
128 if(registeredCommands.empty()){
129 helpstring += "No commands.";
130 }else{
131 helpstring += "Command name,CMD ID, Description, Flags\n";
133 if(cmd.helpstring != nullptr && cmd.cmd != nullptr){
134 char cmdhex[11];
135 std::snprintf(cmdhex,11,"0x%lX",cmd.cmdId);
136 helpstring.append(cmd.cmd);
137 helpstring += ',';
138 helpstring += std::string(cmdhex);
139 helpstring += ',';
140 helpstring.append(cmd.helpstring);
141 helpstring += ',';
142 if(cmd.flags & CMDFLAG_GET){
143 helpstring+= " R";
144 }
145 if(cmd.flags & CMDFLAG_SET){
146 helpstring+= " W";
147 }
148 if(cmd.flags & CMDFLAG_SETADR){
149 helpstring+= " WA";
150 }
151 if(cmd.flags & CMDFLAG_GETADR){
152 helpstring+= " RA";
153 }
154 if(cmd.flags & CMDFLAG_INFOSTRING){
155 helpstring+= " I";
156 }
157 if(cmd.flags & CMDFLAG_STR_ONLY){
158 helpstring+= " (STR)";
159 }
160 if(cmd.flags & CMDFLAG_DEBUG){
161 helpstring+= " (DEBUG)";
162 }
163 helpstring += "\n";
164 }
165 }
166 }
167
168 return helpstring;
169}
170
175 registerCommand("id", CommandHandlerCommands::id, "ID of class",CMDFLAG_GET);
176 registerCommand("name", CommandHandlerCommands::name, "name of class",CMDFLAG_GET|CMDFLAG_STR_ONLY);
177 registerCommand("help", CommandHandlerCommands::help, "Prints help for commands",CMDFLAG_GET | CMDFLAG_STR_ONLY | CMDFLAG_INFOSTRING);
178 registerCommand("cmduid", CommandHandlerCommands::cmdhandleruid, "Command handler index",CMDFLAG_GET);
179 registerCommand("instance", CommandHandlerCommands::instance, "Command handler instance number",CMDFLAG_GET);
180 registerCommand("cmdinfo", CommandHandlerCommands::cmdinfo, "Flags of a command id (adr). -1 if cmd id invalid",CMDFLAG_GETADR);
181 //registerCommand("selId", CommandHandlerCommands::selectionid, "Selection id used to create this class",CMDFLAG_GET);
182}
183
188CmdHandlerCommanddef* CommandHandler::getCommandFromName(const std::string& cmd,uint32_t ignoredFlags){
190 if(cmdItem.cmd == cmd && !(cmdItem.flags & ignoredFlags) && (SystemCommands::debugMode || !(cmdItem.flags & CMDFLAG_DEBUG))){
191 return &cmdItem;
192 }
193 }
194 return nullptr;
195}
196
201CmdHandlerCommanddef* CommandHandler::getCommandFromId(const uint32_t id,uint32_t ignoredFlags){
203 if(cmdItem.cmdId == id && !(cmdItem.flags & ignoredFlags) && (SystemCommands::debugMode || !(cmdItem.flags & CMDFLAG_DEBUG))){
204 return &cmdItem;
205 }
206 }
207 return nullptr;
208}
209
214void CommandHandler::setInstance(uint8_t instance){
216}
217
221CommandStatus CommandHandler::internalCommand(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
223 switch(static_cast<CommandHandlerCommands>(cmd.cmdId)){
224
226 replies.emplace_back(this->getInfo().id);
227 break;
228
230 replies.emplace_back(this->getInfo().name);
231 break;
232
234 if(cmd.type == CMDtype::info){
235 replies.emplace_back(this->getCsvHelpstring());
236 }else{
237 replies.emplace_back(this->getCommandsHelpstring());
238 }
239 break;
240
242 replies.emplace_back(this->getCommandHandlerID());
243 break;
244
246 replies.emplace_back(this->getCommandHandlerInfo()->instance);
247 break;
248
250 {
251 CmdHandlerCommanddef* command_p = this->getCommandFromId(cmd.adr);
252 replies.emplace_back(command_p ? command_p->flags : (int64_t)-1); // Replies with the commands flags if command is valid else with -1
253 }
254 break;
255
256// case CommandHandlerCommands::selectionid:
257// replies.emplace_back(this->getSelectionID());
258// break;
259
260 default:
262 break;
263 }
264 return result;
265}
266
267
269 return this->commandsEnabled;
270}
272 this->commandsEnabled = enable;
273}
274
276 return logEnabled;
277}
278
283 logEnabled = enable;
284}
285
290uint32_t CommandHandler::getClassIdFromName(const char* name){
291
293 CmdHandlerInfo* cmdhandlerinfo = cls->getCommandHandlerInfo();
294 if(strcmp(cmdhandlerinfo->clsname , name) == 0){
295 return cmdhandlerinfo->clsTypeid;
296 }
297 }
298 return 0;
299}
300
304const char* CommandHandler::getClassNameFromId(const uint32_t id){
305
307 CmdHandlerInfo* cmdhandlerinfo = cls->getCommandHandlerInfo();
308 if(cmdhandlerinfo->clsTypeid == id){
309 return cmdhandlerinfo->clsname;
310 }
311 }
312 return nullptr;
313}
314
320 if(cls->getCommandHandlerID() == cmdhandlerID){
321 return cls;
322 }
323 }
324 return nullptr;
325}
326
330CommandHandler* CommandHandler::getHandlerFromId(const uint16_t id,const uint8_t instance){
331
333 CmdHandlerInfo* cmdhandlerinfo = cls->getCommandHandlerInfo();
334 if(cmdhandlerinfo->clsTypeid == id && (cmdhandlerinfo->instance == instance || instance == 0xFF)){
335 return cls;
336 }
337 }
338 return nullptr;
339}
340
344CommandHandler* CommandHandler::getHandlerFromClassName(const char* name,const uint8_t instance){
345
347 CmdHandlerInfo* cmdhandlerinfo = cls->getCommandHandlerInfo();
348 if(strcmp(cmdhandlerinfo->clsname, name) == 0 && (cmdhandlerinfo->instance == instance || instance == 0xFF)){
349 return cls;
350 }
351 }
352 return nullptr;
353}
354
358std::vector<CommandHandler*> CommandHandler::getHandlersFromClassName(const char* name){
359 std::vector<CommandHandler*> reply;
361 CmdHandlerInfo* cmdhandlerinfo = cls->getCommandHandlerInfo();
362 if(strcmp(cmdhandlerinfo->clsname, name) == 0){
363 reply.push_back(cls);
364 }
365 }
366 return reply;
367}
371std::vector<CommandHandler*> CommandHandler::getHandlersFromId(const uint16_t id){
372 std::vector<CommandHandler*> reply;
374 CmdHandlerInfo* cmdhandlerinfo = cls->getCommandHandlerInfo();
375 if(id == cmdhandlerinfo->clsTypeid){
376 reply.push_back(cls);
377 }
378 }
379 return reply;
380}
381
386 return std::find(getCommandHandlers().begin(), getCommandHandlers().end(), handler) != getCommandHandlers().end();
387}
388
392bool CommandHandler::isValidCommandId(uint32_t cmdid,uint32_t ignoredFlags,uint32_t requiredFlags){
394 if(cmd.cmdId == cmdid && !(cmd.flags & ignoredFlags) && ((cmd.flags & requiredFlags) == requiredFlags) && (SystemCommands::debugMode || !(cmd.flags & CMDFLAG_DEBUG))){
395 return true;
396 }
397 }
398 return false;
399}
400
401
402
410CommandStatus CommandHandler::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
412
413 return reply;
414}
415
423 std::vector<CommandReply> replies = {reply};
424 CommandInterface::broadcastCommandReplyAsync(replies, this, cmdId, type);
425}
426
435 if(interface == nullptr){
436 broadcastCommandReply(reply, cmdId, type);
437 return;
438 }
439
440 std::vector<CommandReply> replies = {reply};
441 interface->sendReplyAsync(replies, this, cmdId, type);
442}
443
444
448void CommandHandler::logSerial(std::string string){
449 if( !logEnabled) // !tud_ready() ||
450 return;
451 std::string reply = "[>!" + string + "\n]";
452 CDCcomm::cdcSend(&reply, 0);
453
454}
455
459void CommandHandler::logSerialDebug(std::string string)
460{
462 logSerial(string);
463 }
464}
465
470 return "";
471}
472
477 return &cmdHandlerInfo;
478}
479
485}
486
491 //cmdHandlerListMutex.Lock();
492// while(this->cmdHandlerInfo.commandHandlerID != 0xffff){
493// auto res = CommandHandler::cmdHandlerIDs.insert(cmdHandlerIDs.end(),this->cmdHandlerInfo.commandHandlerID);
494// if(res.second){ // Element was inserted
495// break;
496// }
497// this->cmdHandlerInfo.commandHandlerID++; // Try next id
498// }
500 std::vector<uint16_t>&cmdHandlerIDs = getCommandHandlerIds();
501 while(this->cmdHandlerInfo.commandHandlerID++ != 0xffff){
502 if(std::find(cmdHandlerIDs.begin(),cmdHandlerIDs.end(), cmdHandlerInfo.commandHandlerID) == cmdHandlerIDs.end()){
503 cmdHandlerIDs.push_back(this->cmdHandlerInfo.commandHandlerID);
504 pulseSysLed();
505 break;
506 }
507 }
508
509
510
511 //cmdHandlerListMutex.Unlock();
512}
513
518 //cmdHandlerListMutex.Lock();
519 //cmdHandlerIDs.erase(this->cmdHandlerInfo.commandHandlerID); // removes id from list of reserved ids
520 std::vector<uint16_t>&cmdHandlerIDs = getCommandHandlerIds();
521 cmdHandlerIDs.erase(std::find(cmdHandlerIDs.begin(),cmdHandlerIDs.end(), cmdHandlerInfo.commandHandlerID)); // removes id from list of reserved ids
523 //cmdHandlerListMutex.Unlock();
524}
CommandHandlerCommands
CMDtype
CommandStatus
static uint16_t cdcSend(std::string *reply, uint8_t itf)
Definition: CDCcomm.cpp:63
const uint32_t flags
virtual std::string getHelpstring()
static bool logsEnabled()
static std::vector< CommandHandler * > getHandlersFromClassName(const char *name)
static std::vector< uint16_t > & getCommandHandlerIds()
virtual uint8_t getCommandHandlerInstance()
void registerCommand(const char *cmd, const ID cmdid, const char *help=nullptr, uint32_t flags=0)
static void logSerial(std::string string)
Send a log formatted sequence.
virtual void addCommandHandler()
std::vector< CmdHandlerCommanddef > registeredCommands
virtual CmdHandlerCommanddef * getCommandFromId(const uint32_t id, uint32_t ignoredFlags=0)
virtual void setCommandsEnabled(bool enable)
static void setLogsEnabled(bool enabled)
static const char * getClassNameFromId(const uint32_t id)
static bool isInHandlerList(CommandHandler *handler)
virtual bool hasCommands()
virtual uint16_t getCommandHandlerID()
virtual CommandStatus internalCommand(const ParsedCommand &cmd, std::vector< CommandReply > &replies)
void setInstance(uint8_t instance)
virtual const ClassIdentifier getInfo()=0
Command handlers always have class infos. Works well with ChoosableClass.
static CommandHandler * getHandlerFromClassName(const char *name, const uint8_t instance=0xFF)
CmdHandlerInfo cmdHandlerInfo
virtual ~CommandHandler()
static void logSerialDebug(std::string string)
Send a log formatted sequence if debug is on.
virtual CommandStatus command(const ParsedCommand &cmd, std::vector< CommandReply > &replies)
static bool logEnabled
static CommandHandler * getHandlerFromHandlerId(const uint16_t cmdhandlerID)
void sendCommandReplyAsync(CommandReply reply, uint32_t cmdId, CMDtype type, CommandInterface *interface=nullptr)
virtual CmdHandlerCommanddef * getCommandFromName(const std::string &cmd, uint32_t ignoredFlags=0)
virtual std::string getCommandsHelpstring()
void broadcastCommandReply(CommandReply reply, uint32_t cmdId, CMDtype type)
virtual CmdHandlerInfo * getCommandHandlerInfo()
virtual void removeCommandHandler()
static CommandHandler * getHandlerFromId(const uint16_t id, const uint8_t instance=0xFF)
static std::vector< CommandHandler * > getHandlersFromId(const uint16_t id)
static uint32_t getClassIdFromName(const char *name)
CommandHandler(const char *clsname, uint16_t clsid, uint8_t instance=0)
static std::vector< CommandHandler * > & getCommandHandlers()
virtual bool isValidCommandId(uint32_t cmdid, uint32_t ignoredFlags=0, uint32_t requiredFlag=0)
virtual std::string getCsvHelpstring()
virtual void sendReplyAsync(std::vector< CommandReply > &reply, CommandHandler *handler, uint32_t cmdId, CMDtype type)
static void broadcastCommandReplyAsync(const std::vector< CommandReply > &reply, CommandHandler *handler, uint32_t cmdId, CMDtype type=CMDtype::get)
static bool debugMode
void addCallbackHandler(std::vector< C > &vec, C instance)
void removeCallbackHandler(std::vector< C > &vec, C instance)
void pulseSysLed()
Definition: ledEffects.cpp:39
const char * name
const char * clsname
uint16_t commandHandlerID
const uint16_t clsTypeid
uint32_t cmdId