Open FFBoard
Open source force feedback firmware
AnalogAxisProcessing.cpp
Go to the documentation of this file.
1/*
2 * AnalogAxisProcessing.cpp
3 *
4 * Created on: Jun 29, 2022
5 * Author: Yannick
6 */
7
9#include "CommandHandler.h"
10
20AnalogAxisProcessing::AnalogAxisProcessing(const uint32_t axisAmount,AnalogSource* analogSource,CommandHandler* cmdHandler,bool allowFilters,bool allowAutoscale,bool allowRawValues,bool allowManualScale) : axisAmount(axisAmount),analogSource(analogSource), modes({allowFilters,allowAutoscale,allowRawValues,allowManualScale}){
21
22 if(allowAutoscale || allowManualScale){
23 minMaxVals.resize(axisAmount); // We need min/max pairs if autoscaling or manual scaling is allowed
24 }
25
26 if(allowFilters){
27 filters = std::vector<Biquad>(axisAmount); // Allocate filter
28 // Activate command
29 if(cmdHandler)
30 cmdHandler->registerCommand("filter", AnalogAxisProcessing_commands::filter, "Enable lowpass filters",CMDFLAG_GET|CMDFLAG_SET);
31
32 }else{
33 conf.filtersEnabled = false;
34 }
35
36
37 if(allowAutoscale){
38 if(cmdHandler)
39 cmdHandler->registerCommand("autocal", AnalogAxisProcessing_commands::autoscale, "Autoranging",CMDFLAG_GET|CMDFLAG_SET);
40 }else{
41 conf.autorange = false;
42 }
43
44 if(analogSource)
45 cmdHandler->registerCommand("values", AnalogAxisProcessing_commands::values, "Analog output values",CMDFLAG_GET);
46
47 if(allowRawValues)
48 cmdHandler->registerCommand("rawval", AnalogAxisProcessing_commands::rawvalues, "All raw values",CMDFLAG_GET);
49
50 if(allowManualScale && cmdHandler){
51 cmdHandler->registerCommand("min", AnalogAxisProcessing_commands::min, "Min value limit (adr=chan)",CMDFLAG_GETADR|CMDFLAG_SETADR);
52 cmdHandler->registerCommand("max", AnalogAxisProcessing_commands::max, "Max value limit (adr=chan)",CMDFLAG_GETADR|CMDFLAG_SETADR);
53 conf.raw = false;
54 }
55 setupFilters(); // Initialize filters
56}
57
59
60}
61
63
64}
65
66
68 for(Biquad& filter : filters){
69 filter.setBiquad(BiquadType::lowpass, filterF, filterQ, 0.0);
70 }
71 filterSamples = 0;
72}
73
78 return this->conf;
79}
80
85 this->conf = conf;
86}
87
88void AnalogAxisProcessing::processAxes(std::vector<int32_t>& buf){
90 this->rawValues = buf;
91 }
92
93 for(uint32_t i = 0 ; i < std::min<uint32_t>(this->axisAmount , buf.size()) ; i++){
94 // Modify values in vector directly
95 int32_t val = buf[i];
96 // Apply filter
97 if(conf.filtersEnabled && i < filters.size()){
98 val = filters[i].process(val);
101 }
102 }
103
104
105 // Only process if minMaxVals are available
106 if(i < minMaxVals.size()){
107
108 // If filter and autoranging enabled wait for enough samples to update min/max
110 minMaxVals[i].max = std::max(minMaxVals[i].max,val);
111 minMaxVals[i].min = std::min(minMaxVals[i].min,val);
112 }
113
114 int32_t range = (minMaxVals[i].max - minMaxVals[i].min);
115 if(range > 1 && range <= 0xffff && !conf.raw){
116 float scaler = ((float)0xffff / (float)range)*(autorangeScale);
117 val *= scaler;
118 val = val - ((scaler*(float)minMaxVals[i].min) + 0x7fff);
119 }
120 }
121 val = clip(val,-0x7fff,0x7fff); // Clip if slightly out of range because of inaccuracy
122 buf[i] = val; // Store in buffer
123 }
124
125}
126
127
131CommandStatus AnalogAxisProcessing::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
132 switch(static_cast<AnalogAxisProcessing_commands>(cmd.cmdId))
133 {
135 if(cmd.type == CMDtype::get){
136 std::vector<int32_t>* axes = this->analogSource->getAxes();
137
138 for(int32_t val : *axes){
139 replies.emplace_back(val);
140 }
141
142 }else{
143 return CommandStatus::ERR;
144 }
145 break;
146
148 if(cmd.type == CMDtype::get){
149 for(int32_t val : this->rawValues){
150 replies.emplace_back(val);
151 }
152
153 }else{
154 return CommandStatus::ERR;
155 }
156 break;
157
159 if( (cmd.type == CMDtype::set && cmd.val != 0) || !modes.allowManualScale){
160 // Reset autorange
161 for(uint8_t i = 0 ; i<minMaxVals.size() ; i++){
162 minMaxVals[i] = MinMaxPair(); // Reset minmax
163 }
164 }
165 return CommandHandler::handleGetSet(cmd, replies, this->conf.autorange);
166
168 if(cmd.type == CMDtype::set)
169 setupFilters(); // Reset filters
170 return CommandHandler::handleGetSet(cmd, replies, this->conf.filtersEnabled);
171
173 // Valid if address is in pin range and value is 16b int
174 if(cmd.adr >= 0 && cmd.adr <= axisAmount && cmd.val >= -0x7fff && cmd.val <= 0x7fff){
175 if(cmd.type == CMDtype::getat){
176 replies.emplace_back(minMaxVals[cmd.adr].max);
177 break;
178 }else if(cmd.type == CMDtype::setat){
179 minMaxVals[cmd.adr].max = cmd.val;
180 break;
181 }
182 }
183 return CommandStatus::ERR; // Invalid
184
186 // Valid if address is in pin range and value is 16b int
187 if(cmd.adr >= 0 && cmd.adr <= axisAmount && cmd.val >= -0x7fff && cmd.val <= 0x7fff){
188 if(cmd.type == CMDtype::getat){
189 replies.emplace_back(minMaxVals[cmd.adr].min);
190 break;
191 }else if(cmd.type == CMDtype::setat){
192 minMaxVals[cmd.adr].min = cmd.val;
193 break;
194 }
195 }
196 return CommandStatus::ERR; // Invalid
197
198 default:
200 }
201 return CommandStatus::OK;
202}
203
204
205
211 aconf.autorange = (val) & 0x1;
212 aconf.filtersEnabled = (val >> 1) & 0x1;
213 return aconf;
214}
215
220 uint16_t val = 0;
221 val |= (conf.autorange & 0x1);
222 val |= (conf.filtersEnabled & 0x1) << 1;
223 return val;
224}
225
226
227
void registerCommands(CommandHandler *cmdhandler)
CommandStatus
AnalogProcessingConfig conf
std::vector< int32_t > rawValues
std::vector< MinMaxPair > minMaxVals
const uint32_t waitFilterSamples
AnalogAxisProcessing(const uint32_t axisAmount, AnalogSource *analogSource, CommandHandler *cmdHandler=nullptr, bool allowFilters=true, bool allowAutoscale=true, bool allowRawValues=false, bool allowManualScale=false)
void processAxes(std::vector< int32_t > &buf)
static AnalogProcessingConfig decodeAnalogProcessingConfFromInt(uint16_t val)
AnalogProcessingConfig & getAnalogProcessingConfig()
CommandStatus command(const ParsedCommand &cmd, std::vector< CommandReply > &replies)
static uint16_t encodeAnalogProcessingConfToInt(AnalogProcessingConfig &conf)
std::vector< Biquad > filters
const struct AnalogAxisProcessing::AnalogProcessingMode modes
void setAnalogProcessingConfig(AnalogProcessingConfig conf)
virtual std::vector< int32_t > * getAxes()
Definition: Filters.h:31
static CommandStatus handleGetSet(const ParsedCommand &cmd, std::vector< CommandReply > &replies, TVal &value)
T clip(T v, C l, C h)
Definition: cppmain.h:58
uint32_t cmdId