Open FFBoard
Open source force feedback firmware
HidCommandInterface.cpp
Go to the documentation of this file.
1/*
2 * HidCommandInterface.cpp
3 *
4 * Created on: 10.12.2021
5 * Author: Yannick
6 */
7
8
10#include "CommandHandler.h"
11#include "critical.hpp"
12
13/***********************
14 * HID Command Interface
15 *
16 * ******************
17 */
18//cpp_freertos::BinarySemaphore HID_CommandInterface::threadSem = cpp_freertos::BinarySemaphore();
19
20
23 globalInterface = this;
24 this->Start();
25}
26
28 globalInterface = nullptr;
29}
30
31bool HID_CommandInterface::getNewCommands(std::vector<ParsedCommand>& commands){
32 commands = std::move(this->commands);
33 this->commands.clear();
34 parserReady = false;
35 return !commands.empty();
36}
37
38// TODO maybe simplify and get rid of thread again if reliable
40 while(true){
41 this->WaitForNotification();
42 for(HID_CMD_Data_t& rep : outBuffer){
43 while(!tud_hid_n_ready(0)){
44 Delay(1);
45 }
46 this->sendHidCmd(&rep);
47 }
48 outBuffer.clear();
49 if(outBuffer.capacity() > 20){
50 outBuffer.shrink_to_fit();
51 }
52 }
53}
54
59 return !this->outBuffer.empty();
60}
61
63 return this->outBuffer.size() < maxQueuedReplies;
64}
65
66void HID_CommandInterface::sendReplies(const std::vector<CommandResult>& results,CommandInterface* originalInterface){
67
68 for(const CommandResult& result : results){
69 const std::vector<CommandReply>& replies = result.reply;
70 if(result.type == CommandStatus::NO_REPLY) // Normally not possible at this point.
71 continue;
72
73 if( (originalInterface != this && enableBroadcastFromOtherInterfaces) || ( result.type == CommandStatus::OK && replies.empty() ) || (result.type == CommandStatus::ERR && replies.empty()) ){ // Request was sent by a different interface
74 if(this->outBuffer.size() > maxQueuedRepliesBroadcast){
75 continue; // for now we just throw away broadcasts if the buffer contains too many pending replies.
76 }
77
78 CommandReply reply; // Fake reply
79
80 // return original command as get value if it was a set command
81 if(result.originalCommand.type == CMDtype::set ){
83 reply.val = result.originalCommand.val;
84 }else if(result.originalCommand.type == CMDtype::setat){
86 reply.val = result.originalCommand.val;
87 reply.adr = result.originalCommand.adr;
88 }else if( (result.originalCommand.type == CMDtype::getat || result.originalCommand.type == CMDtype::get) && replies.empty()){
89 // Send an ACK if there is no actual reply
91 reply.adr = result.originalCommand.adr;
92 }else if(result.type == CommandStatus::ERR){
94 }else{
95 continue;
96 }
97 this->queueReplyValues(reply,result.originalCommand);
98
99 }
100
101
102 for(const CommandReply reply : replies){
103 if(reply.type == CommandReplyType::STRING){
104 continue; // Ignore string only replies
105 }
106
107 this->queueReplyValues(reply,result.originalCommand);
108 }
109 }
110 if(!this->outBuffer.empty())
111 this->Notify();
112}
113
114
116 HID_CMD_Data_t hidReply;
118 hidReply.addr = reply.adr;
119 hidReply.clsid = info->clsTypeid;
120 hidReply.cmd = command.cmdId;
121 hidReply.data = reply.val;
122 hidReply.instance = info->instance;
123
124 switch(reply.type){
126 // Echo
127 hidReply.type = HidCmdType::ACK;
128 break;
131 // Return 2 ints
132 hidReply.type = HidCmdType::requestAddr;
133 break;
136 // Return 1 int
137 hidReply.type = HidCmdType::request;
138 break;
140 hidReply.type = HidCmdType::err;
141 break;
144 default:
145 // Ignore
146 return;
147
148 }
149 this->outBuffer.push_back(hidReply);
150}
151
152void HID_CommandInterface::transferComplete(uint8_t itf, uint8_t const* report, uint8_t len){
153
154}
155
156
157
159 ParsedCommand cmd;
160 cmd.cmdId = data->cmd;
161 cmd.instance = data->instance;
162 cmd.val = data->data;
163 cmd.adr = data->addr;
164
165 // Translate type
166 if(data->type == HidCmdType::write){
167 cmd.type = CMDtype::set;
168 }else if(data->type == HidCmdType::request){
169 cmd.type = CMDtype::get;
170 }else if(data->type == HidCmdType::info){
171 cmd.type = CMDtype::info;
172 }else if(data->type == HidCmdType::writeAddr){
173 cmd.type = CMDtype::setat;
174 }else if(data->type == HidCmdType::requestAddr){
175 cmd.type = CMDtype::getat;
176 }
177
178
179
180 if(data->instance != 0xff){
181 cmd.target = CommandHandler::getHandlerFromId(data->clsid,data->instance);
182 if(cmd.target == nullptr || !(cmd.target->isValidCommandId(cmd.cmdId, CMDFLAG_STR_ONLY))){
184 //sendHidCmd(data); // Send back error
185 this->outBuffer.push_back(*data);
186 this->Notify();
187 return;
188 }
189 if(cmd.target->isValidCommandId(cmd.cmdId, CMDFLAG_STR_ONLY))
190 commands.push_back(cmd);
191 }else{
192 std::vector<CommandHandler*> handlers = CommandHandler::getHandlersFromId(data->clsid);
193 for(CommandHandler* handler : handlers){
194 ParsedCommand newCmd = cmd;
195 newCmd.target = handler;
196 if(newCmd.target == nullptr || !(cmd.target->isValidCommandId(cmd.cmdId, CMDFLAG_STR_ONLY))){
198 //sendHidCmd(data); // Send back error
199 this->outBuffer.push_back(*data);
200 this->Notify();
201 return;
202 }
203 commands.push_back(newCmd);
204 }
205 }
206
207 if(!commands.empty()){
208 parserReady = true; // Signals that we should execute commands in the thread
210 }
211}
212
213/*
214 * Send a custom transfer with the vendor defined IN report
215 */
217 bool res = false;
218 res = tud_hid_n_report(0,0, reinterpret_cast<uint8_t*>(data), sizeof(HID_CMD_Data_t)); // sizeof(HID_CMD_Data_t)
219
220
221 return res; // fail
222}
virtual CmdHandlerInfo * getCommandHandlerInfo()
static CommandHandler * getHandlerFromId(const uint16_t id, const uint8_t instance=0xFF)
static std::vector< CommandHandler * > getHandlersFromId(const uint16_t id)
virtual bool isValidCommandId(uint32_t cmdid, uint32_t ignoredFlags=0, uint32_t requiredFlag=0)
CommandReplyType type
void queueReplyValues(const CommandReply &reply, const ParsedCommand &command)
const uint32_t maxQueuedRepliesBroadcast
void transferComplete(uint8_t itf, uint8_t const *report, uint8_t len)
std::vector< ParsedCommand > commands
void sendReplies(const std::vector< CommandResult > &results, CommandInterface *originalInterface)
std::vector< HID_CMD_Data_t > outBuffer
const uint32_t maxQueuedReplies
bool sendHidCmd(HID_CMD_Data_t *data)
void hidCmdCallback(HID_CMD_Data_t *data)
static HID_CommandInterface * globalInterface
bool getNewCommands(std::vector< ParsedCommand > &commands)
uint32_t WaitForNotification(TickType_t Timeout=portMAX_DELAY)
Definition: thread.hpp:246
void Delay(const TickType_t Delay)
Definition: thread.hpp:352
static struct @612 data
bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, uint16_t len)
Definition: hid_device.c:110
bool tud_hid_n_ready(uint8_t instance)
Definition: hid_device.c:104
uint8_t instance
CommandHandler * target
uint32_t cmdId