Open FFBoard
Open source force feedback firmware
Loading...
Searching...
No Matches
SerialFFB.cpp
Go to the documentation of this file.
1/*
2 * SerialFFB.cpp
3 *
4 * Created on: 30.11.2022
5 * Author: Yannick
6 */
7
8#include "SerialFFB.h"
9
11 .name = "Effects manager" ,
12 .id = CLSID_EFFECTSMGR,
13 .visibility = ClassVisibility::visible
14};
16 return info;
17}
18
22SerialFFB::SerialFFB(std::shared_ptr<EffectsCalculator> ec,uint8_t instance) : CommandHandler("fxm", CLSID_EFFECTSMGR,instance), effects_calc(ec), effects(ec->effects) {
23
25 registerCommand("ffbstate", SerialEffects_commands::ffbstate, "FFB active", CMDFLAG_GET | CMDFLAG_SET);
26 registerCommand("type", SerialEffects_commands::fxtype, "Effect type", CMDFLAG_GETADR);
27 registerCommand("reset", SerialEffects_commands::ffbreset, "Reset all effects or effect adr", CMDFLAG_GET | CMDFLAG_GETADR);
28 registerCommand("new", SerialEffects_commands::newEffect, "Create new effect of type val. Returns index or -1 on err", CMDFLAG_SET | CMDFLAG_INFOSTRING);
29 registerCommand("mag", SerialEffects_commands::fxmagnitude, "16b magnitude of non cond. effect adr", CMDFLAG_SETADR | CMDFLAG_GETADR);
30 registerCommand("state", SerialEffects_commands::fxstate, "Enable/Disable effect adr", CMDFLAG_SETADR | CMDFLAG_GETADR);
31 registerCommand("period", SerialEffects_commands::fxperiod, "Period of effect adr", CMDFLAG_SETADR | CMDFLAG_GETADR);
32 registerCommand("duration", SerialEffects_commands::fxduration, "Duration of effect adr", CMDFLAG_SETADR | CMDFLAG_GETADR);
33 registerCommand("offset", SerialEffects_commands::fxoffset, "Offset of cond. effect adr", CMDFLAG_SETADR | CMDFLAG_GETADR);
34 registerCommand("deadzone", SerialEffects_commands::fxdeadzone, "Deadzone of cond. effect adr", CMDFLAG_SETADR | CMDFLAG_GETADR);
35 registerCommand("sat", SerialEffects_commands::fxsat, "Saturation of cond. effect adr", CMDFLAG_SETADR | CMDFLAG_GETADR);
36 registerCommand("coeff", SerialEffects_commands::fxcoeff, "Coefficient of cond. effect adr", CMDFLAG_SETADR | CMDFLAG_GETADR);
37 registerCommand("axisgain", SerialEffects_commands::fxaxisgain, "Gain for this axis (instance) 16b", CMDFLAG_SETADR | CMDFLAG_GETADR);
38}
39
43
44
46 return this->effects_calc->isActive();
47}
48
53 for(uint8_t i=0;i<effects.size();i++){
54 effects_calc->free_effect(i);
55 }
56 set_FFB(false);
57 set_gain(255);
58}
59
63 this->effects_calc->setActive(state);
64}
65
68void SerialFFB::set_gain(uint8_t gain){
69 effects_calc->setGain(gain); // Global gain
70}
71
76int32_t SerialFFB::newEffect(uint8_t effectType){
77 int32_t idx = this->effects_calc->find_free_effect(effectType);
78 if(idx >= 0){
79 // Allocate effect
80 effects[idx].type = effectType;
81 effects[idx].duration = FFB_EFFECT_DURATION_INFINITE;
82 effects[idx].axisMagnitudes[std::min(this->getCommandHandlerInstance(),(uint8_t)MAX_AXIS)] = 1;
83 effects[idx].useSingleCondition = false;
84 for(auto &cond : effects[idx].conditions){ // Set default conditions
85 cond = defaultCond;
86 }
87 this->effects_calc->logEffectType(effectType,false);
88 }
89 return idx;
90}
91
95void SerialFFB::setMagnitude(uint8_t idx,int16_t magnitude){
96 if(idx > effects.size()){
97 return;
98 }
99 FFB_Effect* effect = &effects[idx];
100 effect->magnitude = magnitude;
101
102 if(effect->type == FFB_EFFECT_CONSTANT){
104 }
105
106 // Compatibility for conditional effects... Recommended to use the set coefficient functions instead.
107 effects[idx].conditions[getCommandHandlerInstance()].negativeCoefficient;
108 effects[idx].conditions[getCommandHandlerInstance()].positiveCoefficient;
109}
110
114void SerialFFB::setEffectState(uint8_t id, bool state){
115 if(id >= effects.size()){
116 return;
117 }
118 if(state){
119 effects[id].startTime = HAL_GetTick() + effects[id].startDelay;
120 }
121 effects[id].state = state ? 1 : 0;
122}
123
124void SerialFFB::updateSamplerate(float newSamplerate){
125 effects_calc->updateSamplerate(newSamplerate);
126}
127
128CommandStatus SerialFFB::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
131
132 switch(static_cast<SerialEffects_commands>(cmd.cmdId)){
135
137 if(cmd.type == CMDtype::get){
138 reset_ffb();
139 }else if(cmd.type == CMDtype::getat){
140 effects_calc->free_effect(cmd.adr);
141 }else
142 return CommandStatus::ERR;
143 break;
144
146 if(cmd.type == CMDtype::set){
147 replies.emplace_back(newEffect(cmd.val));
148 }else if(cmd.type == CMDtype::info){
149 replies.emplace_back("Constant=1,Ramp=2,Square=3,Sine=4,Triangle=5,Sawtooth Up=6,Sawtooth Down=7,Spring=8,Damper=9,Inertia=10,Friction=11");
150 }else
151 return CommandStatus::ERR;
152 break;
153
155 if(cmd.type == CMDtype::setat){
156 setMagnitude(cmd.adr, cmd.val);
157 }else if(cmd.type == CMDtype::getat && cmd.adr < effects.size()){
158 replies.emplace_back(effects[cmd.adr].magnitude);
159 }else
160 return CommandStatus::ERR;
161 break;
162
164 if(cmd.adr < effects.size()){
165 if(cmd.type == CMDtype::setat){
166 setEffectState(cmd.adr,cmd.val);
167 }else if(cmd.type == CMDtype::getat){
168 replies.emplace_back(effects[cmd.adr].state);
169 }else{
170 return CommandStatus::ERR;
171 }
172 }else{
173 return CommandStatus::ERR;
174 }
175
176 break;
177
179 if(cmd.adr < effects.size())
180 return handleGetSet(cmd, replies, effects[cmd.adr].period);
181 else
182 return CommandStatus::ERR;
183 break;
184
186 if(cmd.adr < effects.size())
187 return handleGetSet(cmd, replies, effects[cmd.adr].duration);
188 else
189 return CommandStatus::ERR;
190 break;
191
193 if(cmd.adr < effects.size()){ // Set both condition offset and periodic offset
194 handleGetSet(cmd, replies, effects[cmd.adr].conditions[getCommandHandlerInstance()].cpOffset);
195 return handleGetSet(cmd, replies, effects[cmd.adr].offset);
196 }else
197 return CommandStatus::ERR;
198 break;
199
201 if(cmd.adr < effects.size())
202 return handleGetSet(cmd, replies, effects[cmd.adr].conditions[getCommandHandlerInstance()].deadBand);
203 else
204 return CommandStatus::ERR;
205 break;
206
208 if(cmd.adr < effects.size()){
209 if(cmd.type == CMDtype::getat){ // Must rescale between 0/1 float to uint16
210 replies.emplace_back(effects[cmd.adr].axisMagnitudes[getCommandHandlerInstance()] * 0xffff);
211 }else if(cmd.type == CMDtype::setat){
212 effects[cmd.adr].axisMagnitudes[getCommandHandlerInstance()] = (float)cmd.val / 0xffff;
213 }
214 }
215 else
216 return CommandStatus::ERR;
217 break;
218
220 if(cmd.adr < effects.size()){
221 handleGetSet(cmd, replies, effects[cmd.adr].conditions[getCommandHandlerInstance()].negativeSaturation);
222 return handleGetSet(cmd, replies, effects[cmd.adr].conditions[getCommandHandlerInstance()].positiveSaturation);
223 }else
224 return CommandStatus::ERR;
225 break;
227 if(cmd.adr < effects.size() && cmd.type == CMDtype::getat){
228 replies.emplace_back(effects[cmd.adr].type);
229 }else
230 return CommandStatus::ERR;
231 break;
232
234 if(cmd.adr < effects.size()){
235 handleGetSet(cmd, replies, effects[cmd.adr].conditions[getCommandHandlerInstance()].negativeCoefficient);
236 return handleGetSet(cmd, replies, effects[cmd.adr].conditions[getCommandHandlerInstance()].positiveCoefficient);
237 }else
238 return CommandStatus::ERR;
239 break;
240
241 default:
243 }
244
245 return status;
246}
CommandStatus
static CommandStatus handleGetFuncSetFunc(const ParsedCommand &cmd, std::vector< CommandReply > &replies, TVal(cls1::*getfunc)(), void(cls2::*setfunc)(TVal), cls *obj)
virtual uint8_t getCommandHandlerInstance()
void registerCommand(const char *cmd, const ID cmdid, const char *help=nullptr, uint32_t flags=0)
static CommandStatus handleGetSet(const ParsedCommand &cmd, std::vector< CommandReply > &replies, TVal &value)
CommandHandler(const char *clsname, uint16_t clsid, uint8_t instance=0)
virtual void fxUpdateEvent()
virtual void cfUpdateEvent()
void setMagnitude(uint8_t idx, int16_t magnitude)
Definition SerialFFB.cpp:95
static ClassIdentifier info
Definition SerialFFB.h:10
virtual ~SerialFFB()
Definition SerialFFB.cpp:40
std::array< FFB_Effect, EffectsCalculator::max_effects > & effects
Definition SerialFFB.h:45
void updateSamplerate(float newSamplerate)
bool getFfbActive()
Definition SerialFFB.cpp:45
void setEffectState(uint8_t id, bool state)
SerialFFB(std::shared_ptr< EffectsCalculator > ec, uint8_t instance=0)
Definition SerialFFB.cpp:22
void set_gain(uint8_t gain)
Definition SerialFFB.cpp:68
SerialEffects_commands
Definition SerialFFB.h:19
static constexpr FFB_Effect_Condition defaultCond
Definition SerialFFB.h:47
void set_FFB(bool state)
Definition SerialFFB.cpp:62
const ClassIdentifier getInfo()
Command handlers always have class infos. Works well with ChoosableClass.
Definition SerialFFB.cpp:15
std::shared_ptr< EffectsCalculator > effects_calc
Definition SerialFFB.h:44
void reset_ffb()
Definition SerialFFB.cpp:52
CommandStatus command(const ParsedCommand &cmd, std::vector< CommandReply > &replies)
uint8_t type
Definition ffb_defs.h:315
int16_t magnitude
Definition ffb_defs.h:318