Open FFBoard
Open source force feedback firmware
Loading...
Searching...
No Matches
SPIButtons.cpp
Go to the documentation of this file.
1/*
2 * ButtonSourceSPI.cpp
3 *
4 * Created on: 11.02.2020
5 * Author: Yannick
6 */
7
8#include <math.h>
9#include <tuple>
10
11#include "constants.h"
12#include <SPIButtons.h>
13#include "eeprom_addresses.h"
14
15static ButtonSourceConfig decodeIntToConf(uint16_t config, uint16_t config_int_2);
16static std::tuple<uint16_t, uint16_t> encodeConfToInt(ButtonSourceConfig* c);
17
18const std::vector<std::string> SPI_Buttons::mode_names = {"Thrustmaster/HEF4021BT","74xx165"};
19const std::vector<std::string> SPI_Buttons::speed_names = {"Fast","Medium","Slow"};
20
22 .name = "SPI Buttons 1" ,
23 .id=CLSID_BTN_SPI,
24 };
28
30 return (external_spi.hasFreePins());
31}
32
34 .name = "SPI Buttons 2" ,
35 .id=CLSID_BTN_SPI,
36 };
40
42 return false;//(external_spi.hasFreePins();
43}
44
45
46// TODO check if pin is free
48 : CommandHandler("spibtn",CLSID_BTN_SPI,0), SPIDevice(external_spi,external_spi.getFreeCsPins()[0]){
49
50 this->configuration_address = configuration_address;
51 this->configuration_address_2 = configuration_address_2;
53
54 this->spiConfig.peripheral.BaudRatePrescaler = speedPresets[this->conf.spi_speed];
55 this->spiConfig.peripheral.FirstBit = SPI_FIRSTBIT_LSB;
56 this->spiConfig.peripheral.CLKPhase = SPI_PHASE_1EDGE;
57 this->spiConfig.peripheral.CLKPolarity = SPI_POLARITY_LOW;
58
59 initSPI();
60
62 this->setCommandsEnabled(true);
63 ready = true;
64}
65
66
67
69 spiPort.takeSemaphore();
70 spiPort.configurePort(&this->spiConfig.peripheral);
71 spiPort.giveSemaphore();
72}
73
77
78
81 registerCommand("mode", SPIButtons_commands::mode, "SPI mode",CMDFLAG_INFOSTRING | CMDFLAG_GET | CMDFLAG_SET);
82 registerCommand("btncut", SPIButtons_commands::btncut, "Cut buttons right",CMDFLAG_GET | CMDFLAG_SET);
83 registerCommand("btnpol", SPIButtons_commands::btnpol, "Invert",CMDFLAG_GET | CMDFLAG_SET);
84 registerCommand("btnnum", SPIButtons_commands::btnnum, "Number of buttons",CMDFLAG_GET | CMDFLAG_SET);
85 registerCommand("cs", SPIButtons_commands::cs, "SPI CS pin",CMDFLAG_GET | CMDFLAG_SET);
86 registerCommand("spispeed", SPIButtons_commands::spispeed, "SPI speed preset",CMDFLAG_INFOSTRING | CMDFLAG_GET | CMDFLAG_SET);
87}
88
93 this->conf.mode = mode;
95}
96
98 config.numButtons = std::min<uint8_t>(this->maxButtons, config.numButtons);
99 this->conf = config;
100
101 spiPort.freeCsPin(this->spiConfig.cs);
102 OutputPin* newPin = spiPort.getCsPin(config.cs_num-1); // TODO update internal pin number if requested pin is blocked
103 if(newPin != nullptr){
104 this->spiConfig.cs = *newPin;
105
106 }
107 spiPort.reserveCsPin(this->spiConfig.cs);
108 // Setup presets
109 if(conf.mode == SPI_BtnMode::TM){
110 this->spiConfig.cspol = true;
111 this->conf.cutRight = true;
112 this->spiConfig.peripheral.CLKPolarity = SPI_POLARITY_LOW;
113 this->spiConfig.peripheral.CLKPhase = SPI_PHASE_1EDGE;
114
115 }else if(conf.mode == SPI_BtnMode::PISOSR){
116 this->spiConfig.cspol = false;
117 this->conf.cutRight = false;
118 this->spiConfig.peripheral.CLKPhase = SPI_PHASE_2EDGE;
119 this->spiConfig.peripheral.CLKPolarity = SPI_POLARITY_HIGH; // its actually shifting on the rising edge but 165 will have the first output set even before clocking. First clock cycle is actually second bit so we sample at the falling edge and skip the first bit with that.
120 }
121// spiPort.takeSemaphore();
122// spiPort.configurePort(&this->spiConfig.peripheral);
123// spiPort.giveSemaphore();
124 initSPI();
125 if(config.numButtons == 64){ // Special case
126 mask = 0xffffffffffffffff;
127 }else{
128 mask = (uint64_t)pow<uint64_t>(2,config.numButtons)-(uint64_t)1; // Must be done completely in 64 bit!
129 }
130 offset = 8 - (config.numButtons % 8);
131
132 // Thrustmaster uses extra bits for IDs
133 if(config.mode == SPI_BtnMode::TM){
134 bytes = 1+((config.numButtons+2)/8);
135 }else{
136 bytes = 1+((config.numButtons-1)/8);
137 }
138
139 this->btnnum = config.numButtons;
140}
141
145
146void SPI_Buttons::setSpiSpeed(uint8_t speedPreset){
147 speedPreset = clip<uint8_t,uint8_t>(speedPreset,0,this->speedPresets.size());
148 this->conf.spi_speed = speedPreset;
149 this->spiConfig.peripheral.BaudRatePrescaler = this->speedPresets[speedPreset];
150 initSPI();
151}
152
154 auto [configuration_int, cs_num_int] = encodeConfToInt(this->getConfig());
155
156 Flash_Write(configuration_address, configuration_int);
158}
159
161 uint16_t conf_int = Flash_ReadDefault(configuration_address, 0);
162 uint16_t cs_num_int = Flash_ReadDefault(configuration_address_2, 1);
163
164 setConfig(decodeIntToConf(conf_int, cs_num_int));
165}
166
167void SPI_Buttons::process(uint64_t* buf){
168 if(offset){
169 if(this->conf.cutRight){
170 *buf = *buf >> offset;
171 }else{
172 *buf = *buf & this->mask;
173 }
174 }
175 if(conf.invert)
176 *buf = (~*buf);
177 *buf = *buf & mask;
178}
179
180__attribute__((optimize("-Ofast")))
181uint8_t SPI_Buttons::readButtons(uint64_t* buf){
182 memcpy(buf,this->spi_buf,std::min<uint8_t>(this->bytes,8));
183 process(buf); // give back last buffer
184
185 if(spiPort.isTaken() || !ready)
186 return this->btnnum; // Don't wait.
187
188 // CS pin and semaphore managed by spi port
189 spiPort.receive_DMA(spi_buf, bytes, this);
190
191 return this->btnnum;
192}
193
194std::string SPI_Buttons::printModes(const std::vector<std::string>& names){
195 std::string reply;
196 for(uint8_t i = 0; i<names.size();i++){
197 reply+= names[i] + ":" + std::to_string(i)+"\n";
198 }
199 return reply;
200}
201
202CommandStatus SPI_Buttons::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
203
204 switch(static_cast<SPIButtons_commands>(cmd.cmdId)){
206 if(cmd.type == CMDtype::set){
207 ButtonSourceConfig* c = this->getConfig();
208 c->numButtons = cmd.val;
209 this->setConfig(*c);
210 }else if(cmd.type == CMDtype::get){
211 replies.emplace_back(this->getBtnNum());
212 }else{
213 return CommandStatus::ERR;
214 }
215 break;
217 if(cmd.type == CMDtype::set){
218 ButtonSourceConfig* c = this->getConfig();
219 c->invert = cmd.val != 0;
220 this->setConfig(*c);
221 }else if(cmd.type == CMDtype::get){
222 replies.emplace_back(this->getConfig()->invert ? 1 : 0);
223 }else{
224 return CommandStatus::ERR;
225 }
226 break;
228 if(cmd.type == CMDtype::set){
229 ButtonSourceConfig* c = this->getConfig();
230 c->cutRight = cmd.val != 0;
231 this->setConfig(*c);
232 }else if(cmd.type == CMDtype::get){
233 replies.emplace_back(this->getConfig()->cutRight ? 1 : 0);
234 }else{
235 return CommandStatus::ERR;
236 }
237 break;
239 if(cmd.type == CMDtype::set){
240 setMode((SPI_BtnMode)cmd.val);
241 }else if(cmd.type == CMDtype::get){
242 replies.emplace_back((uint8_t)this->conf.mode);
243 }else if(cmd.type == CMDtype::info){
244 replies.emplace_back(printModes(this->mode_names));
245 }else{
246 return CommandStatus::ERR;
247 }
248 break;
249
251 if(cmd.type == CMDtype::set){
252 setSpiSpeed(cmd.val);
253 }else if(cmd.type == CMDtype::get){
254 replies.emplace_back((uint8_t)this->conf.spi_speed);
255 }else if(cmd.type == CMDtype::info){
256 replies.emplace_back(printModes(this->speed_names));
257 }else{
258 return CommandStatus::ERR;
259 }
260 break;
261
263 if (handleGetSet(cmd, replies, this->conf.cs_num) == CommandStatus::OK ) {
264 setConfig(this->conf);
265 }
266 break;
267
268 default:
270 }
271
272 return CommandStatus::OK;
273}
274
275static ButtonSourceConfig decodeIntToConf(uint16_t config_int, uint16_t config_int_2){
277 c.numButtons = (config_int & 0x3F) + 1;
278 c.invert = (config_int >> 6) & 0x1;
279 c.cutRight = (config_int >> 7) & 0x1;
280 c.mode = SPI_BtnMode(config_int >> 8);
281 c.cs_num = (config_int_2 & 0x3);
282 c.spi_speed = (config_int_2 >> 3) & 0x3;
283 return c;
284}
285static std::tuple<uint16_t, uint16_t> encodeConfToInt(ButtonSourceConfig* c){
286 uint16_t val = (c->numButtons-1) & 0x3F; // 1-64
287 val |= c->invert << 6;
288 val |= c->cutRight << 7;
289 val |= (uint16_t)c->mode << 8;
290 uint16_t val2 = c->cs_num & 0x3;
291 val2 |= (c->spi_speed & 0x3) << 3;
292
293 return { val, val2 };
294}
295
CommandStatus
uint16_t val2
static ButtonSourceConfig decodeIntToConf(uint16_t config, uint16_t config_int_2)
static std::tuple< uint16_t, uint16_t > encodeConfToInt(ButtonSourceConfig *c)
__attribute__((optimize("-Ofast"))) uint8_t SPI_Buttons
SPI_BtnMode
Definition SPIButtons.h:22
virtual uint16_t getBtnNum()
void registerCommand(const char *cmd, const ID cmdid, const char *help=nullptr, uint32_t flags=0)
virtual void setCommandsEnabled(bool enable)
static CommandStatus handleGetSet(const ParsedCommand &cmd, std::vector< CommandReply > &replies, TVal &value)
CommandHandler(const char *clsname, uint16_t clsid, uint8_t instance=0)
const ClassIdentifier getInfo() override
static bool isCreatable()
static ClassIdentifier info
Definition SPIButtons.h:21
static ClassIdentifier info
Definition SPIButtons.h:33
static bool isCreatable()
const ClassIdentifier getInfo() override
virtual ~SPI_Buttons()
uint8_t bytes
Definition SPIButtons.h:75
CommandStatus command(const ParsedCommand &cmd, std::vector< CommandReply > &replies) override
void setSpiSpeed(uint8_t speedPreset)
static const std::vector< std::string > speed_names
Definition SPIButtons.h:19
void restoreFlash()
void setConfig(ButtonSourceConfig config)
ButtonSourceConfig conf
Definition SPIButtons.h:79
uint16_t configuration_address
Definition SPIButtons.h:69
virtual ButtonSourceConfig * getConfig()
SPI_Buttons(uint16_t configuration_address, uint16_t configuration_address_2)
static constexpr std::array< uint32_t, 3 > speedPresets
Definition SPIButtons.h:83
uint64_t mask
Definition SPIButtons.h:76
const uint8_t maxButtons
Definition SPIButtons.h:56
static const std::vector< std::string > mode_names
Definition SPIButtons.h:18
void saveFlash()
uint16_t configuration_address_2
Definition SPIButtons.h:70
void initSPI()
void setMode(SPI_BtnMode mode)
std::string printModes(const std::vector< std::string > &names)
uint8_t offset
Definition SPIButtons.h:77
void registerCommands()
void process(uint64_t *buf)
SPIPort & spiPort
Definition SPI.h:124
SPIDevice(SPIPort &port, OutputPin csPin)
Definition SPI.cpp:332
SPIConfig spiConfig
Definition SPI.h:125
SPIPort external_spi
T clip(T v, C l, C h)
Definition cppmain.h:58
TVal Flash_ReadDefault(uint16_t adr, TVal def)
bool Flash_Write(uint16_t adr, uint16_t dat)
static void * memcpy(void *dst, const void *src, size_t n)
Definition ringbuffer.c:8
SPI_BtnMode mode
Definition SPIButtons.h:29