Open FFBoard
Open source force feedback firmware
Loading...
Searching...
No Matches
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#include <algorithm>
16
17//std::vector<CommandHandler*> CommandHandler::cmdHandlers;
18//std::set<uint16_t> CommandHandler::cmdHandlerIDs;
19//std::vector<uint16_t> CommandHandler::cmdHandlerIDs;
20//cpp_freertos::MutexStandard CommandHandler::cmdHandlerListMutex;
21bool CommandHandler::logEnabled = true; // If logs are sent by default
22
26CommandHandler::CommandHandler(const char* clsname,uint16_t clsid,uint8_t instance) : cmdHandlerInfo({clsname,clsid,instance,0}) {
27 addCommandHandler();
28}
29
30
32 // Remove from global list when deleted
34}
35
41 std::string helpstring = "\n";
42 helpstring.reserve(this->registeredCommands.size() * 40); // Helpstrings are large. reserve a big buffer to save on reallocations
44 if(info.name == nullptr || cmdHandlerInfo.clsname == nullptr){
45 return "";
46 }
47 helpstring.append(info.name);
48 helpstring.push_back('(');
49 helpstring.append(cmdHandlerInfo.clsname);
50 helpstring.push_back('.');
51 helpstring.append(std::to_string(cmdHandlerInfo.instance)).append("):\n");
52
53 std::string handlerHelp = getHelpstring();
54
55 if(!handlerHelp.empty()){
56 helpstring.append(handlerHelp).append("\n");
57 }
58
59 if(registeredCommands.empty()){
60 helpstring += "No commands.";
61 }else{
62 helpstring += "cmd\tflags\tdescription\n\n";
64 if(cmd.helpstring != nullptr && cmd.cmd != nullptr){
65 helpstring += std::string(cmd.cmd);
66 helpstring += "\t(";
67
68 if(cmd.flags & CMDFLAG_GET){
69 helpstring+= " R";
70 }
71 if(cmd.flags & CMDFLAG_SET){
72 helpstring+= " W";
73 }
74 if(cmd.flags & CMDFLAG_SETADR){
75 helpstring+= " WA";
76 }
77 if(cmd.flags & CMDFLAG_GETADR){
78 helpstring+= " RA";
79 }
80 if(cmd.flags & CMDFLAG_INFOSTRING){
81 helpstring+= " I";
82 }
83 if(cmd.flags & CMDFLAG_STR_ONLY){
84 helpstring+= " STR";
85 }
86 if(cmd.flags & CMDFLAG_DEBUG){
87 helpstring+= " DBG";
88 }
89 helpstring.append(" )\t").append(std::string(cmd.helpstring)).append("\n");
90 }
91
92 }
93 }
94
95 return helpstring;
96}
97
103 std::string helpstring = "\nPrefix,Class ID, Class description\n";
104 helpstring.reserve(this->registeredCommands.size() * 40); // Helpstrings are large. reserve a big buffer to save on reallocations
105 ClassIdentifier info = this->getInfo();
106 if(info.name == nullptr || cmdHandlerInfo.clsname == nullptr){
107 return "";
108 }
109
110 helpstring.append(cmdHandlerInfo.clsname);
111 helpstring += '.';
112 helpstring += std::to_string(cmdHandlerInfo.instance);
113 helpstring += ',';
114 char clshex[7];
115 std::snprintf(clshex,7,"0x%X",cmdHandlerInfo.clsTypeid);
116 helpstring += std::string(clshex);
117 helpstring += ',';
118
119 helpstring.append(info.name);
120
121 std::string handlerHelp = getHelpstring();
122
123 if(!handlerHelp.empty()){
124 helpstring.append(": ").append(handlerHelp).append("\n");
125 }else{
126 helpstring += "\n";
127 }
128
129 if(registeredCommands.empty()){
130 helpstring += "No commands.";
131 }else{
132 helpstring += "Command name,CMD ID, Description, Flags\n";
134 if(cmd.helpstring != nullptr && cmd.cmd != nullptr){
135 char cmdhex[11];
136 std::snprintf(cmdhex,11,"0x%lX",cmd.cmdId);
137 helpstring.append(cmd.cmd);
138 helpstring += ',';
139 helpstring += std::string(cmdhex);
140 helpstring += ',';
141 helpstring.append(cmd.helpstring);
142 helpstring += ',';
143 if(cmd.flags & CMDFLAG_GET){
144 helpstring+= " R";
145 }
146 if(cmd.flags & CMDFLAG_SET){
147 helpstring+= " W";
148 }
149 if(cmd.flags & CMDFLAG_SETADR){
150 helpstring+= " WA";
151 }
152 if(cmd.flags & CMDFLAG_GETADR){
153 helpstring+= " RA";
154 }
155 if(cmd.flags & CMDFLAG_INFOSTRING){
156 helpstring+= " I";
157 }
158 if(cmd.flags & CMDFLAG_STR_ONLY){
159 helpstring+= " (STR)";
160 }
161 if(cmd.flags & CMDFLAG_DEBUG){
162 helpstring+= " (DEBUG)";
163 }
164 helpstring += "\n";
165 }
166 }
167 }
168
169 return helpstring;
170}
171
176 registerCommand("id", CommandHandlerCommands::id, "ID of class",CMDFLAG_GET);
177 registerCommand("name", CommandHandlerCommands::name, "name of class",CMDFLAG_GET|CMDFLAG_STR_ONLY);
178 registerCommand("help", CommandHandlerCommands::help, "Prints help for commands",CMDFLAG_GET | CMDFLAG_STR_ONLY | CMDFLAG_INFOSTRING);
179 registerCommand("cmduid", CommandHandlerCommands::cmdhandleruid, "Command handler index",CMDFLAG_GET);
180 registerCommand("instance", CommandHandlerCommands::instance, "Command handler instance number",CMDFLAG_GET);
181 registerCommand("cmdinfo", CommandHandlerCommands::cmdinfo, "Flags of a command id (adr). -1 if cmd id invalid",CMDFLAG_GETADR);
182 //registerCommand("selId", CommandHandlerCommands::selectionid, "Selection id used to create this class",CMDFLAG_GET);
183}
184
189CmdHandlerCommanddef* CommandHandler::getCommandFromName(const std::string& cmd,uint32_t ignoredFlags){
191 if(cmdItem.cmd == cmd && !(cmdItem.flags & ignoredFlags) && (SystemCommands::debugMode || !(cmdItem.flags & CMDFLAG_DEBUG))){
192 return &cmdItem;
193 }
194 }
195 return nullptr;
196}
197
202CmdHandlerCommanddef* CommandHandler::getCommandFromId(const uint32_t id,uint32_t ignoredFlags){
204 if(cmdItem.cmdId == id && !(cmdItem.flags & ignoredFlags) && (SystemCommands::debugMode || !(cmdItem.flags & CMDFLAG_DEBUG))){
205 return &cmdItem;
206 }
207 }
208 return nullptr;
209}
210
216 this->cmdHandlerInfo.instance = instance;
217}
218
222CommandStatus CommandHandler::internalCommand(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
224 switch(static_cast<CommandHandlerCommands>(cmd.cmdId)){
225
227 replies.emplace_back(this->getInfo().id);
228 break;
229
231 replies.emplace_back(this->getInfo().name);
232 break;
233
235 if(cmd.type == CMDtype::info){
236 replies.emplace_back(this->getCsvHelpstring());
237 }else{
238 replies.emplace_back(this->getCommandsHelpstring());
239 }
240 break;
241
243 replies.emplace_back(this->getCommandHandlerID());
244 break;
245
247 replies.emplace_back(this->getCommandHandlerInfo()->instance);
248 break;
249
251 {
252 CmdHandlerCommanddef* command_p = this->getCommandFromId(cmd.adr);
253 replies.emplace_back(command_p ? command_p->flags : (int64_t)-1); // Replies with the commands flags if command is valid else with -1
254 }
255 break;
256
257// case CommandHandlerCommands::selectionid:
258// replies.emplace_back(this->getSelectionID());
259// break;
260
261 default:
263 break;
264 }
265 return result;
266}
267
268
270 return this->commandsEnabled;
271}
273 this->commandsEnabled = enable;
274}
275
279
284 logEnabled = enable;
285}
286
292
294 CmdHandlerInfo* cmdhandlerinfo = cls->getCommandHandlerInfo();
295 if(strcmp(cmdhandlerinfo->clsname , name) == 0){
296 return cmdhandlerinfo->clsTypeid;
297 }
298 }
299 return 0;
300}
301
305const char* CommandHandler::getClassNameFromId(const uint32_t id){
306
308 CmdHandlerInfo* cmdhandlerinfo = cls->getCommandHandlerInfo();
309 if(cmdhandlerinfo->clsTypeid == id){
310 return cmdhandlerinfo->clsname;
311 }
312 }
313 return nullptr;
314}
315
321 if(cls->getCommandHandlerID() == cmdhandlerID){
322 return cls;
323 }
324 }
325 return nullptr;
326}
327
332
334 CmdHandlerInfo* cmdhandlerinfo = cls->getCommandHandlerInfo();
335 if(cmdhandlerinfo->clsTypeid == id && (cmdhandlerinfo->instance == instance || instance == 0xFF)){
336 return cls;
337 }
338 }
339 return nullptr;
340}
341
346
348 CmdHandlerInfo* cmdhandlerinfo = cls->getCommandHandlerInfo();
349 if(strcmp(cmdhandlerinfo->clsname, name) == 0 && (cmdhandlerinfo->instance == instance || instance == 0xFF)){
350 return cls;
351 }
352 }
353 return nullptr;
354}
355
359std::vector<CommandHandler*> CommandHandler::getHandlersFromClassName(const char* name){
360 std::vector<CommandHandler*> reply;
362 CmdHandlerInfo* cmdhandlerinfo = cls->getCommandHandlerInfo();
363 if(strcmp(cmdhandlerinfo->clsname, name) == 0){
364 reply.push_back(cls);
365 }
366 }
367 return reply;
368}
369
372std::vector<CommandHandler*> CommandHandler::getHandlersFromId(const uint16_t id){
373 std::vector<CommandHandler*> reply;
375 CmdHandlerInfo* cmdhandlerinfo = cls->getCommandHandlerInfo();
376 if(id == cmdhandlerinfo->clsTypeid){
377 reply.push_back(cls);
378 }
379 }
380 return reply;
381}
382
387 return std::find(getCommandHandlers().begin(), getCommandHandlers().end(), handler) != getCommandHandlers().end();
388}
389
393bool CommandHandler::isValidCommandId(uint32_t cmdid,uint32_t ignoredFlags,uint32_t requiredFlags){
395 if(cmd.cmdId == cmdid && !(cmd.flags & ignoredFlags) && ((cmd.flags & requiredFlags) == requiredFlags) && (SystemCommands::debugMode || !(cmd.flags & CMDFLAG_DEBUG))){
396 return true;
397 }
398 }
399 return false;
400}
401
402
403
411CommandStatus CommandHandler::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
413
414 return reply;
415}
416
424 std::vector<CommandReply> replies = {reply};
425 CommandInterface::broadcastCommandReplyAsync(replies, this, cmdId, type);
426}
427
436 if(interface == nullptr){
437 broadcastCommandReply(reply, cmdId, type);
438 return;
439 }
440
441 std::vector<CommandReply> replies = {reply};
442 interface->sendReplyAsync(replies, this, cmdId, type);
443}
444
445
449void CommandHandler::logSerial(std::string string){
450 if( !logEnabled) // !tud_ready() ||
451 return;
452 std::string reply = "[>!" + string + "\n]";
453 CDCcomm::cdcSend(&reply, 0);
454
455}
456
460void CommandHandler::logSerialDebug(std::string string)
461{
463 logSerial(string);
464 }
465}
466
471 return "";
472}
473
480
487
492 //cmdHandlerListMutex.Lock();
493// while(this->cmdHandlerInfo.commandHandlerID != 0xffff){
494// auto res = CommandHandler::cmdHandlerIDs.insert(cmdHandlerIDs.end(),this->cmdHandlerInfo.commandHandlerID);
495// if(res.second){ // Element was inserted
496// break;
497// }
498// this->cmdHandlerInfo.commandHandlerID++; // Try next id
499// }
501 std::vector<uint16_t>&cmdHandlerIDs = getCommandHandlerIds();
502 while(this->cmdHandlerInfo.commandHandlerID++ != 0xffff){
503 if(std::find(cmdHandlerIDs.begin(),cmdHandlerIDs.end(), cmdHandlerInfo.commandHandlerID) == cmdHandlerIDs.end()){
504 cmdHandlerIDs.push_back(this->cmdHandlerInfo.commandHandlerID);
505 pulseSysLed();
506 break;
507 }
508 }
509
510
511
512 //cmdHandlerListMutex.Unlock();
513}
514
519 //cmdHandlerListMutex.Lock();
520 //cmdHandlerIDs.erase(this->cmdHandlerInfo.commandHandlerID); // removes id from list of reserved ids
521 std::vector<uint16_t>&cmdHandlerIDs = getCommandHandlerIds();
522 cmdHandlerIDs.erase(std::find(cmdHandlerIDs.begin(),cmdHandlerIDs.end(), cmdHandlerInfo.commandHandlerID)); // removes id from list of reserved ids
524 //cmdHandlerListMutex.Unlock();
525}
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()
const char * name
const char * clsname
const uint16_t clsTypeid