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
55 this->setCommandsEnabled(true);
56 ready = true;
57}
58
59
60
62 spiPort.takeSemaphore();
63 spiPort.configurePort(&this->spiConfig.peripheral);
64 spiPort.giveSemaphore();
65}
66
70
71
74 registerCommand("mode", SPIButtons_commands::mode, "SPI mode",CMDFLAG_INFOSTRING | CMDFLAG_GET | CMDFLAG_SET);
75 registerCommand("btncut", SPIButtons_commands::btncut, "Cut buttons right",CMDFLAG_GET | CMDFLAG_SET);
76 registerCommand("btnpol", SPIButtons_commands::btnpol, "Invert",CMDFLAG_GET | CMDFLAG_SET);
77 registerCommand("btnnum", SPIButtons_commands::btnnum, "Number of buttons",CMDFLAG_GET | CMDFLAG_SET);
78 registerCommand("cs", SPIButtons_commands::cs, "SPI CS pin",CMDFLAG_GET | CMDFLAG_SET);
79 registerCommand("spispeed", SPIButtons_commands::spispeed, "SPI speed preset",CMDFLAG_INFOSTRING | CMDFLAG_GET | CMDFLAG_SET);
80}
81
86 this->conf.mode = mode;
88}
89
91 config.numButtons = std::min<uint8_t>(this->maxButtons, config.numButtons);
92 this->conf = config;
93
94 spiPort.freeCsPin(this->spiConfig.cs);
95 OutputPin* newPin = spiPort.getCsPin(config.cs_num-1); // TODO update internal pin number if requested pin is blocked
96 if(newPin != nullptr){
97 this->spiConfig.cs = *newPin;
98
99 }
100 spiPort.reserveCsPin(this->spiConfig.cs);
101 // Setup presets
102 if(conf.mode == SPI_BtnMode::TM){
103 this->spiConfig.cspol = true;
104 this->conf.cutRight = true;
105 this->spiConfig.peripheral.FirstBit = SPI_FIRSTBIT_LSB;
106 this->spiConfig.peripheral.CLKPhase = SPI_PHASE_1EDGE;
107 this->spiConfig.peripheral.CLKPolarity = SPI_POLARITY_LOW;
108 }else if(conf.mode == SPI_BtnMode::PISOSR){
109 this->spiConfig.cspol = false;
110 this->conf.cutRight = false;
111 this->spiConfig.peripheral.FirstBit = SPI_FIRSTBIT_LSB;
112 this->spiConfig.peripheral.CLKPhase = SPI_PHASE_2EDGE;
113 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.
114 }
115 this->spiConfig.peripheral.BaudRatePrescaler = speedPresets[this->conf.spi_speed];
116 initSPI();
117 if(config.numButtons == 64){ // Special case
118 mask = 0xffffffffffffffff;
119 }else{
120 mask = (uint64_t)pow<uint64_t>(2,config.numButtons)-(uint64_t)1; // Must be done completely in 64 bit!
121 }
122 offset = 8 - (config.numButtons % 8);
123
124 // Thrustmaster uses extra bits for IDs
125 if(config.mode == SPI_BtnMode::TM){
126 bytes = 1+((config.numButtons+2)/8);
127 }else{
128 bytes = 1+((config.numButtons-1)/8);
129 }
130
131 this->btnnum = config.numButtons;
132}
133
137
138void SPI_Buttons::setSpiSpeed(uint8_t speedPreset){
139 speedPreset = clip<uint8_t,uint8_t>(speedPreset,0,this->speedPresets.size());
140 this->conf.spi_speed = speedPreset;
141 this->spiConfig.peripheral.BaudRatePrescaler = this->speedPresets[speedPreset];
142 initSPI();
143}
144
146 auto [configuration_int, cs_num_int] = encodeConfToInt(this->getConfig());
147
148 Flash_Write(configuration_address, configuration_int);
150}
151
153 uint16_t conf_int = Flash_ReadDefault(configuration_address, 0);
154 uint16_t cs_num_int = Flash_ReadDefault(configuration_address_2, 1);
155
156 setConfig(decodeIntToConf(conf_int, cs_num_int));
157}
158
159void SPI_Buttons::process(uint64_t* buf){
160 if(offset){
161 if(this->conf.cutRight){
162 *buf = *buf >> offset;
163 }else{
164 *buf = *buf & this->mask;
165 }
166 }
167 if(conf.invert)
168 *buf = (~*buf);
169 *buf = *buf & mask;
170}
171
172__attribute__((optimize("-Ofast")))
173uint8_t SPI_Buttons::readButtons(uint64_t* buf){
174 memcpy(buf,this->spi_buf,std::min<uint8_t>(this->bytes,8));
175 process(buf); // give back last buffer
176
177 if(spiPort.isTaken() || !ready)
178 return this->btnnum; // Don't wait.
179
180 // CS pin and semaphore managed by spi port
181 spiPort.receive_DMA(spi_buf, bytes, this);
182
183 return this->btnnum;
184}
185
186std::string SPI_Buttons::printModes(const std::vector<std::string>& names){
187 std::string reply;
188 for(uint8_t i = 0; i<names.size();i++){
189 reply+= names[i] + ":" + std::to_string(i)+"\n";
190 }
191 return reply;
192}
193
194CommandStatus SPI_Buttons::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
195
196 switch(static_cast<SPIButtons_commands>(cmd.cmdId)){
198 if(cmd.type == CMDtype::set){
199 ButtonSourceConfig* c = this->getConfig();
200 c->numButtons = cmd.val;
201 this->setConfig(*c);
202 }else if(cmd.type == CMDtype::get){
203 replies.emplace_back(this->getBtnNum());
204 }else{
205 return CommandStatus::ERR;
206 }
207 break;
209 if(cmd.type == CMDtype::set){
210 ButtonSourceConfig* c = this->getConfig();
211 c->invert = cmd.val != 0;
212 this->setConfig(*c);
213 }else if(cmd.type == CMDtype::get){
214 replies.emplace_back(this->getConfig()->invert ? 1 : 0);
215 }else{
216 return CommandStatus::ERR;
217 }
218 break;
220 if(cmd.type == CMDtype::set){
221 ButtonSourceConfig* c = this->getConfig();
222 c->cutRight = cmd.val != 0;
223 this->setConfig(*c);
224 }else if(cmd.type == CMDtype::get){
225 replies.emplace_back(this->getConfig()->cutRight ? 1 : 0);
226 }else{
227 return CommandStatus::ERR;
228 }
229 break;
231 if(cmd.type == CMDtype::set){
232 setMode((SPI_BtnMode)cmd.val);
233 }else if(cmd.type == CMDtype::get){
234 replies.emplace_back((uint8_t)this->conf.mode);
235 }else if(cmd.type == CMDtype::info){
236 replies.emplace_back(printModes(this->mode_names));
237 }else{
238 return CommandStatus::ERR;
239 }
240 break;
241
243 if(cmd.type == CMDtype::set){
244 setSpiSpeed(cmd.val);
245 }else if(cmd.type == CMDtype::get){
246 replies.emplace_back((uint8_t)this->conf.spi_speed);
247 }else if(cmd.type == CMDtype::info){
248 replies.emplace_back(printModes(this->speed_names));
249 }else{
250 return CommandStatus::ERR;
251 }
252 break;
253
255 if (handleGetSet(cmd, replies, this->conf.cs_num) == CommandStatus::OK ) {
256 setConfig(this->conf);
257 }
258 break;
259
260 default:
262 }
263
264 return CommandStatus::OK;
265}
266
267static ButtonSourceConfig decodeIntToConf(uint16_t config_int, uint16_t config_int_2){
269 c.numButtons = (config_int & 0x3F) + 1;
270 c.invert = (config_int >> 6) & 0x1;
271 c.cutRight = (config_int >> 7) & 0x1;
272 c.mode = SPI_BtnMode(config_int >> 8);
273 c.cs_num = (config_int_2 & 0x3);
274 c.spi_speed = (config_int_2 >> 3) & 0x3;
275 return c;
276}
277static std::tuple<uint16_t, uint16_t> encodeConfToInt(ButtonSourceConfig* c){
278 uint16_t val = (c->numButtons-1) & 0x3F; // 1-64
279 val |= c->invert << 6;
280 val |= c->cutRight << 7;
281 val |= (uint16_t)c->mode << 8;
282 uint16_t val2 = c->cs_num & 0x3;
283 val2 |= (c->spi_speed & 0x3) << 3;
284
285 return { val, val2 };
286}
287
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:125
SPIDevice(SPIPort &port, OutputPin csPin)
Definition SPI.cpp:333
SPIConfig spiConfig
Definition SPI.h:126
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