Open FFBoard
Open source force feedback firmware
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
41 reset_ffb();
42}
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}
62void SerialFFB::set_FFB(bool state){
63 this->effects_calc->setActive(state);
64}
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
124CommandStatus SerialFFB::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
127
128 switch(static_cast<SerialEffects_commands>(cmd.cmdId)){
131
133 if(cmd.type == CMDtype::get){
134 reset_ffb();
135 }else if(cmd.type == CMDtype::getat){
136 effects_calc->free_effect(cmd.adr);
137 }else
138 return CommandStatus::ERR;
139 break;
140
142 if(cmd.type == CMDtype::set){
143 replies.emplace_back(newEffect(cmd.val));
144 }else if(cmd.type == CMDtype::info){
145 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");
146 }else
147 return CommandStatus::ERR;
148 break;
149
151 if(cmd.type == CMDtype::setat){
152 setMagnitude(cmd.adr, cmd.val);
153 }else if(cmd.type == CMDtype::getat && cmd.adr < effects.size()){
154 replies.emplace_back(effects[cmd.adr].magnitude);
155 }else
156 return CommandStatus::ERR;
157 break;
158
160 if(cmd.adr < effects.size()){
161 if(cmd.type == CMDtype::setat){
162 setEffectState(cmd.adr,cmd.val);
163 }else if(cmd.type == CMDtype::getat){
164 replies.emplace_back(effects[cmd.adr].state);
165 }else{
166 return CommandStatus::ERR;
167 }
168 }else{
169 return CommandStatus::ERR;
170 }
171
172 break;
173
175 if(cmd.adr < effects.size())
176 return handleGetSet(cmd, replies, effects[cmd.adr].period);
177 else
178 return CommandStatus::ERR;
179 break;
180
182 if(cmd.adr < effects.size())
183 return handleGetSet(cmd, replies, effects[cmd.adr].duration);
184 else
185 return CommandStatus::ERR;
186 break;
187
189 if(cmd.adr < effects.size()){ // Set both condition offset and periodic offset
190 handleGetSet(cmd, replies, effects[cmd.adr].conditions[getCommandHandlerInstance()].cpOffset);
191 return handleGetSet(cmd, replies, effects[cmd.adr].offset);
192 }else
193 return CommandStatus::ERR;
194 break;
195
197 if(cmd.adr < effects.size())
198 return handleGetSet(cmd, replies, effects[cmd.adr].conditions[getCommandHandlerInstance()].deadBand);
199 else
200 return CommandStatus::ERR;
201 break;
202
204 if(cmd.adr < effects.size()){
205 if(cmd.type == CMDtype::getat){ // Must rescale between 0/1 float to uint16
206 replies.emplace_back(effects[cmd.adr].axisMagnitudes[getCommandHandlerInstance()] * 0xffff);
207 }else if(cmd.type == CMDtype::setat){
208 effects[cmd.adr].axisMagnitudes[getCommandHandlerInstance()] = (float)cmd.val / 0xffff;
209 }
210 }
211 else
212 return CommandStatus::ERR;
213 break;
214
216 if(cmd.adr < effects.size()){
217 handleGetSet(cmd, replies, effects[cmd.adr].conditions[getCommandHandlerInstance()].negativeSaturation);
218 return handleGetSet(cmd, replies, effects[cmd.adr].conditions[getCommandHandlerInstance()].positiveSaturation);
219 }else
220 return CommandStatus::ERR;
221 break;
223 if(cmd.adr < effects.size() && cmd.type == CMDtype::getat){
224 replies.emplace_back(effects[cmd.adr].type);
225 }else
226 return CommandStatus::ERR;
227 break;
228
230 if(cmd.adr < effects.size()){
231 handleGetSet(cmd, replies, effects[cmd.adr].conditions[getCommandHandlerInstance()].negativeCoefficient);
232 return handleGetSet(cmd, replies, effects[cmd.adr].conditions[getCommandHandlerInstance()].positiveCoefficient);
233 }else
234 return CommandStatus::ERR;
235 break;
236
237 default:
239 }
240
241 return status;
242}
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)
virtual void fxUpdateEvent()
virtual void cfUpdateEvent()
int32_t newEffect(uint8_t effectType)
Definition: SerialFFB.cpp:76
void setMagnitude(uint8_t idx, int16_t magnitude)
Definition: SerialFFB.cpp:95
static ClassIdentifier info
Definition: SerialFFB.h:42
virtual ~SerialFFB()
Definition: SerialFFB.cpp:40
std::array< FFB_Effect, EffectsCalculator::max_effects > & effects
Definition: SerialFFB.h:44
bool getFfbActive()
Definition: SerialFFB.cpp:45
void setEffectState(uint8_t id, bool state)
Definition: SerialFFB.cpp:114
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:46
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:43
void reset_ffb()
Definition: SerialFFB.cpp:52
CommandStatus command(const ParsedCommand &cmd, std::vector< CommandReply > &replies)
Definition: SerialFFB.cpp:124
const char * name
uint8_t type
Definition: ffb_defs.h:274
int16_t magnitude
Definition: ffb_defs.h:277
uint32_t cmdId