Open FFBoard
Open source force feedback firmware
CommandInterface.cpp
Go to the documentation of this file.
1/*
2 * CommandInterface.cpp
3 *
4 * Created on: 17.11.2021
5 * Author: Yannick
6 */
7
8#include "CommandInterface.h"
9#include "CDCcomm.h"
10#include "global_callbacks.h"
11#include "CommandHandler.h"
12#include <stdlib.h>
13#include "critical.hpp"
14
15std::vector<CommandInterface*> CommandInterface::cmdInterfaces;
16
17
20}
21
24}
25
26
30void CommandInterface::broadcastCommandReplyAsync(const std::vector<CommandReply>& reply,CommandHandler* handler, uint32_t cmdId,CMDtype type){
31
32 const std::vector<CommandResult> results = {makeCommandReply(reply, handler, cmdId, type,nullptr)};
33
35 itf->sendReplies(results, nullptr);
36 }
37}
38
42void CommandInterface::sendReplyAsync(std::vector<CommandReply>& reply,CommandHandler* handler, uint32_t cmdId,CMDtype type){
43 std::vector<CommandResult> results = {makeCommandReply(reply, handler, cmdId, type,this)};
44 this->sendReplies(results, this);
45}
46
47CommandResult CommandInterface::makeCommandReply(const std::vector<CommandReply>& reply,CommandHandler* handler, uint32_t cmdId,CMDtype type,CommandInterface* originalInterface){
48 ParsedCommand fakeCmd;
49 fakeCmd.target = handler;
50 fakeCmd.cmdId = cmdId;
51 fakeCmd.instance = handler->getCommandHandlerInfo()->instance;
52 fakeCmd.type = type;
53 fakeCmd.originalInterface = originalInterface;
54
55
56 CommandResult fakeResult;
57 fakeResult.type = CommandStatus::BROADCAST;
58 fakeResult.handlerId = fakeCmd.target->getCommandHandlerID();
59 fakeResult.originalCommand = fakeCmd;
60 fakeResult.reply = reply;
61 fakeResult.commandHandler = fakeCmd.target;
62 return fakeResult;
63}
64
71 return parserReady;
72}
73
79 return true;
80}
81
86
87}
88
89
90/*
91 *
92 * **********************************************************
93 *
94 */
95
96bool StringCommandInterface::getNewCommands(std::vector<ParsedCommand>& commands){
97 parserReady = false;
98 return parser.parse(commands);
99}
100
101/*
102 * Adds a buffer to the parser
103 * if it returns true resume the thread
104 */
105bool StringCommandInterface::addBuf(char* Buf, uint32_t *Len){
106 bool res = this->parser.add(Buf, Len);
107 if(res){
108 parserReady = true; // Signals that we should execute commands in the thread
110 }
111 return res;
112}
113
115 return parser.bufferCapacity();
116}
117
118void StringCommandInterface::formatReply(std::string& reply,const std::vector<CommandResult>& results,const bool formatWriteAsRead){
119 //uint16_t lastId = 0xFFFF;
120 for(const CommandResult& result : results){ // All commands processed this batch
121 if(formatWriteAsRead && !(result.originalCommand.type == CMDtype::set || result.originalCommand.type == CMDtype::setat)){
122 return; // Ignore commands that should be formatted as read if they are not set commands
123 }
124
125 reply += '['; // Start marker
126 reply += StringCommandInterface::formatOriginalCommandFromResult(result.originalCommand,result.commandHandler, formatWriteAsRead);
127 reply += '|'; // Separator
128
129 if(formatWriteAsRead){
130 std::string tstr;
131 StringCommandInterface::generateReplyFromCmd(tstr,result.originalCommand);
132 reply += tstr;
133 }else{
134 if(result.type == CommandStatus::NOT_FOUND){
135 reply += "NOT_FOUND";
136 //ErrorHandler::addError(CommandInterface::cmdNotFoundError);
137 }else if(result.type == CommandStatus::OK || result.type == CommandStatus::BROADCAST){
138 if(result.reply.empty()){
139 reply += "OK";
140 }else{
141 uint16_t repliesRemaining = result.reply.size();
142 for(const CommandReply& cmdReply : result.reply){ // For all entries of this command. Normally just one
143 std::string tstr;
144 //TODO Long replies fail HERE while copying reply strings
146 reply += tstr;
147 if(--repliesRemaining > 0){
148 reply += "\n"; // Separate replies with newlines
149 }
150 }
151 }
152 }else if(result.type == CommandStatus::ERR){
153 reply += "ERR";
154 }else{
155 reply += "None";
156 }
157 }
158
159 reply += "]\n"; // end marker
160 }
161}
162
166std::string StringCommandInterface::formatOriginalCommandFromResult(const ParsedCommand& originalCommand,CommandHandler* commandHandler,const bool formatWriteAsRead){
167
168// ClassIdentifier info = commandHandler->getInfo();
169 std::string cmdstring = commandHandler->getCommandHandlerInfo()->clsname;
170 if(originalCommand.instance != 0xFF){
171 cmdstring += '.';
172 cmdstring += std::to_string(originalCommand.instance);
173 }
174 cmdstring += '.';
175
176
177 CmdHandlerCommanddef* cmdDef = commandHandler->getCommandFromId(originalCommand.cmdId); // CMD name
178 if(!cmdDef){
179 return ""; // can not find cmd. should never happen
180 }
181 cmdstring += std::string(cmdDef->cmd);
182 if(originalCommand.type == CMDtype::get || (formatWriteAsRead && originalCommand.type == CMDtype::set)){
183 cmdstring += '?';
184
185 }else if(originalCommand.type == CMDtype::getat || (formatWriteAsRead && originalCommand.type == CMDtype::setat)){ // cls.inst.cmd?
186 cmdstring += '?';
187 cmdstring += std::to_string(originalCommand.adr);
188
189 }else if(originalCommand.type == CMDtype::set){ // cls.inst.cmd?
190 cmdstring += '=';
191 cmdstring += std::to_string(originalCommand.val);
192
193 }else if(originalCommand.type == CMDtype::setat){ // cls.inst.cmd?x=y
194 cmdstring += '=';
195 cmdstring += std::to_string(originalCommand.val);
196 cmdstring += '?';
197 cmdstring += std::to_string(originalCommand.adr);
198
199 }else if(originalCommand.type == CMDtype::info){
200 cmdstring += '!';
201 }
202
203 return cmdstring;
204
205}
206
210void StringCommandInterface::generateReplyValueString(std::string& replyPart,const CommandReply& reply){
211 //std::string replyPart;
213 replyPart.assign(reply.reply);
214 }else if(reply.type == CommandReplyType::INT){
215 replyPart = std::to_string(reply.val);
216 }else if(reply.type == CommandReplyType::DOUBLEINTS){
217 replyPart = std::to_string(reply.val);
218 replyPart += ':';
219 replyPart += std::to_string(reply.adr);
220 }else if(reply.type == CommandReplyType::ACK){
221 replyPart = "OK";
222 }
223}
224
225void StringCommandInterface::generateReplyFromCmd(std::string& replyPart,const ParsedCommand& originalCommand){
226 if(originalCommand.type == CMDtype::set){
227 replyPart = std::to_string(originalCommand.val);
228 }else if(originalCommand.type == CMDtype::setat){
229 replyPart = std::to_string(originalCommand.val);
230 replyPart += ':';
231 replyPart += std::to_string(originalCommand.adr);
232 }
233}
234
235
236/*
237 *
238 * **********************************************************
239 *
240 */
241
242
245 this->Start();
246}
247
249
250}
251
252
254 while(true){
256
257 this->sendBuffer.clear();
258 if(this->sendBuffer.capacity() > 200){
259 this->sendBuffer.reserve(64);
260 }
262 resultsBuffer.clear();
263 bufferLength = 0;
264 if(!sendBuffer.empty())
266 }
267}
268
269void CDC_CommandInterface::sendReplies(const std::vector<CommandResult>& results,CommandInterface* originalInterface){
270 if(!tud_ready()){
271 return; //if not ready we will discard it anyways
272 }
273
274 if(HAL_GetTick() - lastSendTime > parserTimeout){
275 bufferLength = 0;
276 resultsBuffer.clear(); // Empty buffer because we were not able to reply in time to prevent the full buffer from blocking future commands
277 //CDCcomm::clearRemainingBuffer(0);
278 }
279
280 if( (!enableBroadcastFromOtherInterfaces && originalInterface != this) ){
281 return;
282 }
283 for(const CommandResult& r : results){
284 bufferLength += r.size();
285 }
286
287 resultsBuffer.insert(resultsBuffer.end(), results.begin(), results.end());
288 //resultsBuffer.shrink_to_fit();
289 nextFormat = originalInterface != this && originalInterface != nullptr;
290 lastSendTime = HAL_GetTick();
292 Notify(); // Resume
293 }
294
295}
296
298 if(resultsBuffer.empty())
299 return;
300 resultsBuffer.shrink_to_fit();
301 Notify();
302}
303
308 if(!tud_ready() || !tud_cdc_connected()){ // TODO check if cdc connected. if not connected be ready but ignore data.
309 return true;
310 }
311 if(HAL_GetTick() - lastSendTime > parserTimeout && CDCcomm::remainingData(0) == 0){
312 return true;
313 }
314 return CDCcomm::remainingData(0) == 0 && bufferLength < maxSendBuffer; //&& resultsBuffer.empty()
315}
316
317
318
319/*************************
320 *
321 * Uart command interface
322 * Takes bytes from a uart port
323 *
324 */
325
326extern UARTPort external_uart; // defined in cpp_target_config.cpp
327UART_CommandInterface::UART_CommandInterface(uint32_t baud) : UARTDevice(external_uart),Thread("UARTCMD", 150, 36),StringCommandInterface(512), baud(baud){ //
329 if(baud != 0){
330 uartconfig.BaudRate = this->baud;
332 }
334 uartport->registerInterrupt(); // enable port
335 this->Start();
336}
337
339
340}
341
346
348}
349
351 while(true){
352
354 while(uartport->isTaken()){
355 Delay(1);
356 }
357 this->sendBuffer.clear();
358 if(this->sendBuffer.capacity() > 100){
359 this->sendBuffer.reserve(64);
360 }
362 resultsBuffer.clear();
363 bufferLength = 0;
364 if(!sendBuffer.empty())
365 uartport->transmit_IT(sendBuffer.c_str(), sendBuffer.size());
366 }
367}
368
369
370void UART_CommandInterface::sendReplies(const std::vector<CommandResult>& results,CommandInterface* originalInterface){
371 if( (!enableBroadcastFromOtherInterfaces && originalInterface != this) ){
372 return;
373 }
374
375 for(const CommandResult& r : results){
376 bufferLength += r.size();
377 }
378
379 resultsBuffer.insert(resultsBuffer.end(), results.begin(), results.end());
380 //resultsBuffer.shrink_to_fit();
381 nextFormat = originalInterface != this && originalInterface != nullptr;
383 Notify(); // Resume
384 }
385}
386
391 uint32_t len = 1;
392 //BaseType_t savedInterruptStatus = cpp_freertos::CriticalSection::EnterFromISR();
395
396 //cpp_freertos::CriticalSection::ExitFromISR(savedInterruptStatus);
397}
398
400 if(resultsBuffer.empty())
401 return;
402 resultsBuffer.shrink_to_fit();
403 Notify();
404}
405
CMDtype
UARTPort external_uart
static TU_ATTR_ALWAYS_INLINE bool tud_cdc_connected(void)
Definition: cdc_device.h:127
std::vector< CommandResult > resultsBuffer
const uint32_t maxSendBuffer
void batchDone() override
bool readyToSend() override
const uint32_t parserTimeout
void sendReplies(const std::vector< CommandResult > &results, CommandInterface *originalInterface) override
static uint16_t cdcSend(std::string *reply, uint8_t itf)
Definition: CDCcomm.cpp:63
static uint32_t remainingData(uint8_t itf=0)
Definition: CDCcomm.cpp:44
int32_t bufferCapacity()
Definition: CmdParser.cpp:75
bool parse(std::vector< ParsedCommand > &commands)
Definition: CmdParser.cpp:85
void setClearBufferTimeout(uint32_t timeout)
Definition: CmdParser.cpp:71
bool add(char *Buf, uint32_t *Len)
Definition: CmdParser.cpp:37
virtual CmdHandlerCommanddef * getCommandFromId(const uint32_t id, uint32_t ignoredFlags=0)
virtual uint16_t getCommandHandlerID()
virtual CmdHandlerInfo * getCommandHandlerInfo()
virtual bool readyToSend()
virtual void sendReplyAsync(std::vector< CommandReply > &reply, CommandHandler *handler, uint32_t cmdId, CMDtype type)
static std::vector< CommandInterface * > cmdInterfaces
virtual bool hasNewCommands()
virtual void batchDone()
static void broadcastCommandReplyAsync(const std::vector< CommandReply > &reply, CommandHandler *handler, uint32_t cmdId, CMDtype type=CMDtype::get)
virtual ~CommandInterface()
static CommandResult makeCommandReply(const std::vector< CommandReply > &reply, CommandHandler *handler, uint32_t cmdId, CMDtype type=CMDtype::get, CommandInterface *originalInterface=nullptr)
virtual void sendReplies(const std::vector< CommandResult > &results, CommandInterface *originalInterface)=0
std::string reply
CommandReplyType type
bool addBuf(char *Buf, uint32_t *Len)
static std::string formatOriginalCommandFromResult(const ParsedCommand &originalCommand, CommandHandler *commandHandler, const bool formatWriteAsRead=false)
bool getNewCommands(std::vector< ParsedCommand > &commands) override
static void generateReplyValueString(std::string &replyPart, const CommandReply &reply)
static void generateReplyFromCmd(std::string &replyPart, const ParsedCommand &originalCommand)
static void formatReply(std::string &reply, const std::vector< CommandResult > &results, const bool formatWriteAsRead=false)
const uint32_t parserTimeout
void sendReplies(const std::vector< CommandResult > &results, CommandInterface *originalInterface) override
UART_CommandInterface(uint32_t baud=115200)
std::vector< CommandResult > resultsBuffer
const uint32_t maxSendBuffer
UART_InitTypeDef uartconfig
UARTPort * uartport
Definition: UART.h:85
Definition: UART.h:26
UART_InitTypeDef & getConfig()
Definition: UART.cpp:49
bool transmit_IT(const char *txbuf, uint16_t size)
Definition: UART.cpp:78
bool reconfigurePort(UART_InitTypeDef &config)
Definition: UART.cpp:35
bool registerInterrupt()
Definition: UART.cpp:56
bool isTaken()
Definition: UART.cpp:173
uint32_t WaitForNotification(TickType_t Timeout=portMAX_DELAY)
Definition: thread.hpp:246
void Delay(const TickType_t Delay)
Definition: thread.hpp:352
void addCallbackHandler(std::vector< C > &vec, C instance)
void removeCallbackHandler(std::vector< C > &vec, C instance)
const char * clsname
ParsedCommand originalCommand
CommandStatus type
CommandHandler * commandHandler
std::vector< CommandReply > reply
uint16_t handlerId
ID of the command handler responding to the command.
uint8_t instance
CommandHandler * target
uint32_t cmdId
CommandInterface * originalInterface
Command interface on which this command was received. nullptr indicates a broadcast.
static TU_ATTR_ALWAYS_INLINE bool tud_ready(void)
Definition: usbd.h:97