Open FFBoard
Open source force feedback firmware
Loading...
Searching...
No Matches
FFBHIDMain.cpp
Go to the documentation of this file.
1/*
2 * FFBWheel.cpp
3 *
4 * Created on: 31.01.2020
5 * Author: Yannick / Lidders
6 */
7
8#include <FFBHIDMain.h>
9#include "voltagesense.h"
10#include "hid_device.h"
11#include "tusb.h"
12#include "usb_hid_ffb_desc.h"
13
14#include "cmsis_os.h"
15extern osThreadId_t defaultTaskHandle;
16
17#ifdef TIM_FFB
18extern TIM_HandleTypeDef TIM_FFB;
19#endif
20
21#ifndef OVERRIDE_FFBRATES
23#endif
24
26
27
32 Thread("FFBMAIN", 256, 30),
33 SelectableInputs(ButtonSource::all_buttonsources,AnalogSource::all_analogsources),
35{
36 if(hidAxis32b){
37 reportHID = std::make_unique<HID_GamepadReport<int32_t>>();
38 }else{
39 reportHID = std::make_unique<HID_GamepadReport<int16_t>>();
40 }
41// reportHID((hidAxis32b ? HID_GamepadReport<int32_t>() : HID_GamepadReport<int16_t>())),
42// lastReportHID((hidAxis32b ? HID_GamepadReport<int32_t>() : HID_GamepadReport<int16_t>())),
43 restoreFlashDelayed(); // Load parameters
45
46}
47
53void FFBHIDMain::setFFBEffectsCalc(std::shared_ptr<EffectsControlItf> ffb,std::shared_ptr<EffectsCalculator> effects_calc){
54 this->ffb = ffb;
55 this->effects_calc = effects_calc;
56 axes_manager = std::make_unique<AxesManager>(&control,effects_calc);
57 axes_manager->setAxisCount(axisCount);
58 this->Start();
59}
60
61
65
70
71 Flash_Read(ADR_FFBWHEEL_BUTTONCONF, &this->btnsources);
73
74 Flash_Read(ADR_FFBWHEEL_ANALOGCONF, &this->ainsources);
76
77 uint16_t conf1 = 0;
78 if(Flash_Read(ADR_FFBWHEEL_CONF1,&conf1)){
79 uint8_t rateidx = conf1 & 0x3;
80 setReportRate(rateidx);
81 }else{
82 setReportRate(0); // default
83 }
84
85}
86
90
91 Flash_Write(ADR_FFBWHEEL_BUTTONCONF,this->btnsources);
92 Flash_Write(ADR_FFBWHEEL_ANALOGCONF,this->ainsources);
93
94 uint8_t conf1 = 0;
95 conf1 |= usb_report_rate_idx & 0x7;
96 Flash_Write(ADR_FFBWHEEL_CONF1,conf1);
97}
98
99
100
102#ifdef E_STOP_Pin
103 bool estopState = HAL_GPIO_ReadPin(E_STOP_GPIO_Port, E_STOP_Pin) == GPIO_PIN_RESET;
104 if(estopState){ // Estop pressed at startup
105 emergencyStop(!estopState);
106// control.emergency = true; // Immediately enter emergency state but without notifying other classes yet
107 lastEstop = HAL_GetTick();
108 }
109#endif
110#ifdef TIM_FFB
111 HAL_TIM_Base_Start_IT(&TIM_FFB); // Start generating updates
112#endif
113 while(true){
114#ifndef TIM_FFB
116 Delay(1);
117 }
119#else
121#endif
123 }
124}
125
130 if(control.request_update_disabled) {
131 //logSerial("request update disabled");
132 control.update_disabled = true;
133 control.request_update_disabled = false;
134
135 }
136 if(control.update_disabled){
137 //logSerial("Update disabled");
138 return;
139 }
140
141 if(control.resetEncoder){
142 control.resetEncoder = false;
143 axes_manager->resetPosZero();
144 }
145
146 //debugpin.set();
147 axes_manager->update();
148
150 report_rate_cnt = 0;
151 this->send_report();
152 }
153 if(!control.emergency){
154 axes_manager->updateTorque();
155
156 }else{
157 pulseClipLed();
158 }
159 //debugpin.reset();
160}
161
162
164 return this->ffb->getRate();
165}
166
168 return this->ffb->getFfbActive();
169}
170
175 // Check if HID command interface wants to send something and allow that if we did not skip too many reports
176 if(!tud_hid_n_ready(0) || ((reportSendCounter++ < usb_report_rate*2) && this->hidCommands->waitingToSend())){
177 return;
178 }
179 //Try semaphore
180// if(!sourcesSem.Take(10)){
181// return;
182// }
183
184 // Read buttons
185 uint64_t b = 0;
187 reportHID->setButtons(b);
188
189 // Encoder
190 //axes_manager->addAxesToReport(analogAxesReport, &count);
191
192 std::vector<int32_t>* axes = axes_manager->getAxisValues();
193 uint8_t count = 0;
194 for(auto val : *axes){
195 if(!hidAxis32b){
196 val = val >> 16; // Scale to 16b
197 }else{
198 val = val >> (32-HIDAXISRES_32B_BITS); // Scale if less than 32b
199 }
200 //setHidReportAxis(&reportHID,count++,val);
201 reportHID->setHidReportAxis(count++, val);
202 }
203
204 // Fill remaining values with analog inputs
206 for(int32_t val : *axes){
207 if(count >= analogAxisCount)
208 break;
209 if((count < MAX_AXIS) && hidAxis32b)
210 val = val << (HIDAXISRES_32B_BITS-16); // Shift up 16 bit to fill 32b value. Primary axis is 32b
211 reportHID->setHidReportAxis(count++, val);
212 }
213
214// sourcesSem.Give();
215 // Fill rest
216 for(;count<analogAxisCount; count++){
217 //setHidReportAxis(&reportHID,count,0);
218 reportHID->setHidReportAxis(count, 0);
219 }
220
221
222 /*
223 * Only send a new report if actually changed since last time or timeout and hid is ready
224 */
225 if( (reportSendCounter > 100/usb_report_rate || reportHID->changed()) )
226 {
227 tud_hid_report(0, reportHID->getBuffer(), reportHID->getLength());
228 reportHID->swap(); // Report has changed and was sent. Swap buffers.
230 }
231
232}
233
238 return ffbrates.basefreq/((uint32_t)ffbrates.dividers[usb_report_rate_idx].basediv);
239}
240
244void FFBHIDMain::setReportRate(uint8_t rateidx){
245 uint32_t usbrate_base = TUD_OPT_HIGH_SPEED ? 8000 : 1000;
246 if(tud_connected()){ // Get either actual rate or max supported rate if not connected
247 usbrate_base = tud_speed_get() == TUSB_SPEED_HIGH ? 8000 : 1000; // Only FS and HS supported
248 }
249
250 rateidx = clip<uint8_t,uint8_t>(rateidx, 0,ffbrates.dividers.size());
251 usb_report_rate_idx = rateidx;
252
253
254 // Either limit using rate counter or HW timer if present.
255#ifdef TIM_FFB
256 TIM_FFB.Instance->ARR = ((1000000*(uint32_t)ffbrates.dividers[rateidx].basediv)/ffbrates.basefreq); // Assumes 1µs timer steps
257#else
258 ffb_rate_divider = ffbrates.dividers[rateidx].basediv;
259#endif
260 usb_report_rate = ffbrates.dividers[rateidx].hiddiv*HID_BINTERVAL;
261 // Divide report rate down if above actual usb rate
262 while(((ffbrates.basefreq / (uint32_t)ffbrates.dividers[rateidx].basediv) / usb_report_rate) > usbrate_base){
264 }
265
266 // Pass updated rate to other classes to update filters
267 float newRate = getCurFFBFreq();
268 if(ffb)
269 ffb->updateSamplerate(newRate);
270 if(axes_manager)
271 axes_manager->updateSamplerate(newRate);
272}
273
278 std::string s = "";
279 uint32_t usbrate_base = TUD_OPT_HIGH_SPEED ? 8000 : 1000;
280 if(tud_connected()){ // Get either actual rate or max supported rate if not connected
281 usbrate_base = tud_speed_get() == TUSB_SPEED_HIGH ? 8000 : 1000; // Only FS and HS supported
282 }
283 for(uint8_t i = 0 ; i < ffbrates.dividers.size();i++){
284 uint32_t updatefreq = ffbrates.basefreq/((uint32_t)ffbrates.dividers[i].basediv);
285 uint32_t hidrate = (HID_BINTERVAL*ffbrates.dividers[i].hiddiv);
286 while((updatefreq/hidrate) > usbrate_base){ // Fall back if usb rate is still higher than supported
287 hidrate++;
288 }
289 uint32_t hidfreq = updatefreq/hidrate;
290 s += "FFB "+std::to_string(updatefreq) + "Hz\nUSB " + std::to_string(hidfreq) + "Hz:"+std::to_string(i);
291 if(i < ffbrates.dividers.size()-1)
292 s += ",";
293 }
294 return s;
295}
296
298 control.emergency = !reset;
299 axes_manager->emergencyStop(reset);
300}
301
302
308 if(control.usb_disabled)
309 return;
310 control.usb_disabled = true;
311 ffb->stop_FFB();
312 ffb->reset_ffb(); // Delete all effects
313 axes_manager->usbSuspend();
314}
315
320#ifdef E_STOP_Pin
321 if(control.emergency && HAL_GPIO_ReadPin(E_STOP_GPIO_Port, E_STOP_Pin) != GPIO_PIN_RESET){ // Reconnected after emergency stop
322 control.emergency = false;
323 }
324#endif
326 control.usb_disabled = false;
327 axes_manager->usbResume();
328}
329
330
331// External interrupt pins
332void FFBHIDMain::exti(uint16_t GPIO_Pin){
333 if(GPIO_Pin == BUTTON_A_Pin){
334 // Button down?
335 if(HAL_GPIO_ReadPin(BUTTON_A_GPIO_Port, BUTTON_A_Pin)){
336 this->control.resetEncoder = true;
337 }
338 }
339#ifdef E_STOP_Pin
340 if(GPIO_Pin == E_STOP_Pin){ // Emergency stop. low active
341// if(HAL_GPIO_ReadPin(E_STOP_GPIO_Port, E_STOP_Pin) == GPIO_PIN_RESET){
342 bool estopPinState = HAL_GPIO_ReadPin(E_STOP_GPIO_Port, E_STOP_Pin) == GPIO_PIN_RESET;
343 if(HAL_GetTick()-lastEstop > 1000 && estopPinState != this->control.emergency){ // Long debounce
344 lastEstop = HAL_GetTick();
345 if(estopPinState){
346 emergencyStop(false);
347 }else if(allowEstopReset){
348 emergencyStop(true);
349 }
350
351 }
352// }
353 }
354#endif
355}
356
357/*
358 * Error handling
359 */
360void FFBHIDMain::errorCallback(const Error &error, bool cleared){
361 if(error.type == ErrorType::critical){
362 if(!cleared){
363 this->emergencyStop(true);
364 }
365 }
366 if(error.code == ErrorCode::emergencyStop){
367 this->emergencyStop(cleared); // Clear Estop
368 }
369 if(!cleared){
370 pulseErrLed();
371 }
372}
373
374#ifdef TIM_FFB
375void FFBHIDMain::timerElapsed(TIM_HandleTypeDef* htim){
376 if(htim == &TIM_FFB){
378 }
379}
380#endif
381
TIM_HandleTypeDef TIM_FFB
osThreadId_t defaultTaskHandle
ErrorCode code
ErrorType type
std::shared_ptr< EffectsControlItf > ffb
Definition FFBHIDMain.h:88
uint8_t ffb_rate_counter
Definition FFBHIDMain.h:107
uint32_t getRate()
void setReportRate(uint8_t rateidx)
void usbResume()
void usbSuspend()
std::string usb_report_rates_names()
void exti(uint16_t GPIO_Pin)
uint8_t ffb_rate_divider
Definition FFBHIDMain.h:106
volatile Control_t control
Definition FFBHIDMain.h:93
uint8_t usb_report_rate
Definition FFBHIDMain.h:103
void restoreFlash()
const bool hidAxis32b
Definition FFBHIDMain.h:129
uint8_t axisCount
Definition FFBHIDMain.h:90
static const FFB_update_rates ffbrates
Definition FFBHIDMain.h:127
void saveFlash()
volatile uint32_t lastEstop
Definition FFBHIDMain.h:151
uint8_t usb_report_rate_idx
Definition FFBHIDMain.h:104
std::unique_ptr< AxesManager > axes_manager
Definition FFBHIDMain.h:135
const bool allowEstopReset
Definition FFBHIDMain.h:95
void setFFBEffectsCalc(std::shared_ptr< EffectsControlItf > ffb, std::shared_ptr< EffectsCalculator > effects_calc)
void timerElapsed(TIM_HandleTypeDef *htim)
bool getFfbActive()
FFBHIDMain(uint8_t axisCount, bool hidAxis32b=false)
const uint8_t analogAxisCount
Definition FFBHIDMain.h:145
virtual ~FFBHIDMain()
void send_report()
std::shared_ptr< EffectsCalculator > effects_calc
Definition FFBHIDMain.h:89
uint8_t report_rate_cnt
Definition FFBHIDMain.h:133
std::unique_ptr< HID_GamepadReport_base > reportHID
Definition FFBHIDMain.h:141
void updateControl()
void errorCallback(const Error &error, bool cleared)
float getCurFFBFreq()
void emergencyStop(bool reset)
std::unique_ptr< HID_CommandInterface > hidCommands
Definition FFBHIDMain.h:147
uint8_t reportSendCounter
Definition FFBHIDMain.h:143
virtual void setAinTypes(uint16_t aintypes)
virtual void setBtnTypes(uint16_t btntypes)
virtual std::vector< int32_t > * getAnalogValues()
SelectableInputs(const ClassChooser< ButtonSource > &btn_chooser, const ClassChooser< AnalogSource > &analog_chooser)
virtual void clearBtnTypes()
virtual uint8_t getButtonValues(uint64_t &values)
uint32_t WaitForNotification(TickType_t Timeout=portMAX_DELAY)
Definition thread.hpp:246
void Delay(const TickType_t Delay)
Definition thread.hpp:352
Thread(const std::string Name, uint16_t StackDepth, UBaseType_t Priority)
Definition cthread.cpp:56
T clip(T v, C l, C h)
Definition cppmain.h:58
bool Flash_Write(uint16_t adr, uint16_t dat)
bool Flash_Read(uint16_t adr, uint16_t *buf, bool checkempty=true)
bool tud_hid_n_ready(uint8_t instance)
Definition hid_device.c:104
static TU_ATTR_ALWAYS_INLINE bool tud_hid_report(uint8_t report_id, void const *report, uint16_t len)
Definition hid_device.h:97
void pulseClipLed()
void pulseErrLed()
@ TUSB_SPEED_HIGH
Definition tusb_types.h:52
tusb_speed_t tud_speed_get(void)
Definition usbd.c:407
bool tud_connected(void)
Definition usbd.c:411