Open FFBoard
Open source force feedback firmware
CANPort2B.cpp
Go to the documentation of this file.
1/*
2 * CANPort2B.cpp
3 *
4 * Created on: 21.09.2023
5 * Author: Yannick
6 */
7
8#include "CANPort2B.h"
9#if defined(CANTYPE_2B)
11 .name = "Can port",
12 .id = CLSID_CANPORT,
13 .visibility = ClassVisibility::visible};
14
15//CANPort::CANPort(const CANPortHardwareConfig<uint32_t>& presets,uint8_t instance) : presets(presets),CommandHandler("can", CLSID_CANPORT, instance){
16//
17//}
18
19CANPort_2B::CANPort_2B(CAN_HandleTypeDef &hcan,const CANPortHardwareConfig& presets,const OutputPin* silentPin,uint8_t instance) : CANPort(presets),CommandHandler("can", CLSID_CANPORT, instance), hcan(&hcan),silentPin(silentPin) {
20 //HAL_CAN_Start(this->hcan);
22#ifdef CAN_COMMANDS_DISABLED_IF_NOT_USED
23 this->setCommandsEnabled(false);
24#endif
26}
27//CANPort_2B::CANPort(CAN_HandleTypeDef &hcan,const OutputPin* silentPin) : CommandHandler("can", CLSID_CANPORT, 0), hcan(&hcan), silentPin(silentPin) {
28// //HAL_CAN_Start(this->hcan);
29// restoreFlash();
30// registerCommands();
31//}
32
35 registerCommand("speed", CanPort_commands::speed, "CAN speed preset (! for list)", CMDFLAG_GET|CMDFLAG_SET|CMDFLAG_INFOSTRING);
36 registerCommand("send", CanPort_commands::send, "Send CAN frame. Adr&Value required", CMDFLAG_SETADR);
37 registerCommand("len", CanPort_commands::len, "Set length of next frames", CMDFLAG_SET|CMDFLAG_GET);
38}
39
41 if(this->getCommandHandlerInfo()->instance != 0){
42 return; // Only first instance can save
43 }
44 uint16_t data = (this->speedPreset & 0b111); // set the baudrate in 0..2 bit
45 Flash_Write(ADR_CANCONF1, data);
46}
47
49 if(this->getCommandHandlerInfo()->instance != 0){
50 return; // Only first instance can save
51 }
52 uint16_t data;
53 if(Flash_Read(ADR_CANCONF1, &data)){
54 setSpeedPreset(data & 0b111);
55 }
56}
57
58
60 // removes all filters
61 for (uint8_t i = 0; i < canFilters.size(); i++){
62 canFilters[i].FilterActivation = false;
63 HAL_CAN_ConfigFilter(this->hcan, &canFilters[i]);
64 }
65 canFilters.clear();
66 HAL_CAN_Stop(this->hcan);
67 if(silentPin){
68 silentPin->set(); // set pin high to disable
69 }
70}
71
76//void CANPort_2B::takePort(){
77// if(portUsers++ == 0){
78// start();
79// }
80//}
81
86//void CANPort_2B::freePort(){
87// if(portUsers>0){
88// portUsers--;
89// }
90//
91// if(portUsers == 0){
92// stop();
93// }
94//}
95
100 setSilentMode(false);
101 active = true;
102#ifdef CAN_COMMANDS_DISABLED_IF_NOT_USED
103 this->setCommandsEnabled(true);
104#endif
105 //CAN_IT_RX_FIFO0_FULL | CAN_IT_RX_FIFO0_OVERRUN
106 HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_RX_FIFO1_MSG_PENDING | CAN_IT_RX_FIFO0_FULL | CAN_IT_RX_FIFO0_OVERRUN | CAN_IT_RX_FIFO1_FULL | CAN_IT_RX_FIFO1_OVERRUN | CAN_IT_ERROR | CAN_IT_BUSOFF | CAN_IT_TX_MAILBOX_EMPTY);
107 setSpeedPreset(this->speedPreset); // Set preset again for a safe state
108 return HAL_CAN_Start(this->hcan) == HAL_OK;
109}
110
115 setSilentMode(true);
116 active = false;
117#ifdef CAN_COMMANDS_DISABLED_IF_NOT_USED
118 this->setCommandsEnabled(false);
119#endif
120 return HAL_CAN_Stop(this->hcan) == HAL_OK;
121}
122
123
126}
127
129 return (speedPreset);
130}
131
132
136void CANPort_2B::setSpeedPreset(uint8_t preset){
137 if(preset > 5)
138 return;
139 speedPreset = preset;
140
141 configSem.Take();
142 HAL_CAN_Stop(this->hcan);
143 HAL_CAN_AbortTxRequest(hcan, txMailboxes);
144 this->hcan->Instance->BTR = presets.getPreset(preset).init;
145 HAL_CAN_ResetError(hcan);
146
147 HAL_CAN_Start(this->hcan);
148 configSem.Give();
149}
150
155void CANPort_2B::setSpeed(uint32_t speed){
156 uint8_t preset = speedToPreset(speed);
157 setSpeedPreset(preset);
158}
159
160
161
166 this->silent = silent;
167 if(silentPin){
169 }
170}
171
177 return this->sendMessage(&msg.header,msg.data,nullptr);
178}
179
181 HAL_CAN_AbortTxRequest(hcan, txMailboxes);
182}
183
187bool CANPort_2B::sendMessage(CAN_msg_header_tx *pHeader, uint8_t aData[],uint32_t *pTxMailbox){
188
189 header.DLC = pHeader->length;
190 header.IDE = pHeader->extId ? CAN_ID_EXT : CAN_ID_STD;
191 header.RTR = pHeader->rtr ? CAN_RTR_REMOTE : CAN_RTR_DATA;
192 header.StdId = pHeader->extId ? 0 : pHeader->id;
193 header.ExtId = pHeader->extId ? pHeader->id : 0;
194
195 if(this->silent)
196 setSilentMode(false);
197 uint32_t mailbox;
198 if(pTxMailbox == nullptr){
199 pTxMailbox = &mailbox;
200 }
201
202 if(!HAL_CAN_GetTxMailboxesFreeLevel(hcan) && HAL_GetTick() - lastSentTime > sendTimeout){
203 // Mailbox full and nothing has been sent successfully for some time. Abort previous requests if timeout reached
204 HAL_CAN_AbortTxRequest(hcan, txMailboxes);
205 }
206//
207 if(!HAL_CAN_GetTxMailboxesFreeLevel(hcan)){ // Only wait if no mailbox is free
208 isWaitingFlag = true;
210 isWaitingFlag = false;
211 return false;
212 }
213
214 }
215
216 //this->isTakenFlag = true;
217 if (HAL_CAN_AddTxMessage(this->hcan, &header, aData, pTxMailbox) != HAL_OK)
218 {
219 /* Transmission request Error */
220 if(isWaitingFlag)
222 return false;
223 }
224 txMailboxes |= *pTxMailbox;
225// if(HAL_CAN_GetTxMailboxesFreeLevel(hcan)) // Give back semaphore immediately if mailboxes are still free
226// giveSemaphore();
227 return true;
228}
229
230void CANPort_2B::canTxCpltCallback(CANPort *port,uint32_t mailbox){
231 if(port == this){
232 lastSentTime = HAL_GetTick();
233 txMailboxes &= ~mailbox;
234 if(isWaitingFlag)
236 }
237}
238
239void CANPort_2B::canTxAbortCallback(CANPort *port,uint32_t mailbox){
240 if(port == this){
241 txMailboxes &= ~mailbox;
242 if(isWaitingFlag)
244 }
245}
246
247void CANPort_2B::canErrorCallback(CANPort *port, uint32_t code){
248 if(
249 port == this &&
250 code & (HAL_CAN_ERROR_TX_ALST0 | HAL_CAN_ERROR_TX_ALST1 | HAL_CAN_ERROR_TX_ALST2 | HAL_CAN_ERROR_TX_TERR0 | HAL_CAN_ERROR_TX_TERR1 | HAL_CAN_ERROR_TX_TERR2)
251 ){
253 }
254}
255
256
263
264 CAN_FilterTypeDef sFilterConfig;
265 sFilterConfig.FilterActivation = filter.active;
266 sFilterConfig.FilterBank = 0; // Init new
267 sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
268 sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
269 sFilterConfig.FilterFIFOAssignment = filter.buffer == 0 ? CAN_RX_FIFO0 : CAN_RX_FIFO1;
270 sFilterConfig.FilterIdHigh = ((filter.filter_id << 5) | (filter.filter_id >> (32 - 5))) & 0xFFFF;
271 sFilterConfig.FilterIdLow = (filter.filter_id >> (11 - 3)) & 0xFFF8;
272 sFilterConfig.FilterMaskIdHigh = ((filter.filter_mask << 5) | (filter.filter_mask >> (32 - 5))) & 0xFFFF;
273 sFilterConfig.FilterMaskIdLow = (filter.filter_mask >> (11 - 3)) & 0xFFF8;
274
275
276 if(filter.extid){
277 sFilterConfig.FilterIdLow |= 0x04;
278 sFilterConfig.FilterMaskIdLow |= 0x4; // Add IDE bit
279 }
280
281 configSem.Take();
282 int32_t lowestId = 0;// sFilterConfig.FilterFIFOAssignment == CAN_RX_FIFO0 ? 0 : slaveFilterStart;
283 int32_t highestId = slaveFilterStart;// sFilterConfig.FilterFIFOAssignment == CAN_RX_FIFO0 ? slaveFilterStart : 29;
284 int32_t foundId = -1;
285
286 for(uint8_t id = lowestId; id < highestId ; id++ ){
287 bool foundExisting = false;
288 for(CAN_FilterTypeDef filter : canFilters){
289 if(id == filter.FilterBank
290// && filter.FilterIdHigh == sFilterConfig.FilterIdHigh && filter.FilterIdLow == sFilterConfig.FilterIdLow &&filter.FilterFIFOAssignment == sFilterConfig.FilterFIFOAssignment &&
291// && filter.FilterMaskIdHigh == sFilterConfig.FilterMaskIdHigh && filter.FilterMaskIdLow == sFilterConfig.FilterMaskIdLow
292// && filter.FilterMode == sFilterConfig.FilterMode && filter.FilterScale == sFilterConfig.FilterScale
293 )
294 {
295 foundExisting = true;
296 break;
297 }
298 }
299 foundId = id;
300 if(!foundExisting){
301 break;
302 }
303
304 }
305 if(foundId < highestId){
306 if(sFilterConfig.FilterBank == 0)
307 sFilterConfig.FilterBank = foundId;
308 if (HAL_CAN_ConfigFilter(this->hcan, &sFilterConfig) == HAL_OK){
309 canFilters.push_back(sFilterConfig);
310 }
311 }
312 configSem.Give();
313 return foundId;
314}
315
320void CANPort_2B::removeCanFilter(uint8_t filterId){
321 configSem.Take();
322 for (uint8_t i = 0; i < canFilters.size(); i++){
323 if(canFilters[i].FilterBank == filterId){
324 canFilters[i].FilterActivation = false;
325 HAL_CAN_ConfigFilter(this->hcan, &canFilters[i]);
326 canFilters.erase(canFilters.begin()+i);
327 break;
328 }
329 }
330 configSem.Give();
331}
332
333
334CommandStatus CANPort_2B::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
335
336 switch(static_cast<CanPort_commands>(cmd.cmdId)){
337
339 if(cmd.type == CMDtype::get){
340 replies.emplace_back(this->speedPreset);
341 }else if(cmd.type == CMDtype::set){
342 setSpeedPreset(cmd.val);
343 }else if(cmd.type == CMDtype::info){
344 for(uint8_t i = 0; i<presets.presets.size();i++){
345 replies.emplace_back(std::string(presets.presets[i].name) + ":" + std::to_string(i));
346 }
347 }
348 break;
349
351 {
352 if(cmd.type == CMDtype::setat){
353 if(!active){
354 start(); // If port is not used activate port at first use
355 }
356 CAN_tx_msg msg;
357 memcpy(msg.data,&cmd.val,8);
358 msg.header.id = cmd.adr;
359 msg.header.length = nextLen;
360 sendMessage(msg);
361 }else{
363 }
364 break;
365 }
367 handleGetSet(cmd, replies, nextLen);
368 nextLen = std::min<uint32_t>(nextLen,8);
369 break;
370 default:
372 }
373 return CommandStatus::OK;
374}
375#endif
CommandStatus
CAN_TxHeaderTypeDef header
Definition: CANPort2B.h:71
void registerCommands()
Definition: CANPort2B.cpp:33
static const uint32_t sendTimeout
Definition: CANPort2B.h:69
virtual ~CANPort_2B()
Definition: CANPort2B.cpp:59
bool sendMessage(CAN_tx_msg &msg)
Definition: CANPort2B.cpp:176
bool stop()
Definition: CANPort2B.cpp:114
bool start()
Definition: CANPort2B.cpp:99
uint32_t txMailboxes
Definition: CANPort2B.h:60
void canErrorCallback(CANPort *port, uint32_t code) override
Definition: CANPort2B.cpp:247
bool active
Definition: CANPort2B.h:65
const OutputPin * silentPin
Definition: CANPort2B.h:63
static const uint8_t slaveFilterStart
Definition: CANPort2B.h:39
CAN_HandleTypeDef * hcan
Definition: CANPort2B.h:58
void saveFlash()
Definition: CANPort2B.cpp:40
CommandStatus command(const ParsedCommand &cmd, std::vector< CommandReply > &replies)
Definition: CANPort2B.cpp:334
void restoreFlash()
Definition: CANPort2B.cpp:48
void setSpeedPreset(uint8_t preset)
Definition: CANPort2B.cpp:136
uint8_t nextLen
Definition: CANPort2B.h:72
std::vector< CAN_FilterTypeDef > canFilters
Definition: CANPort2B.h:59
int32_t addCanFilter(CAN_filter filter)
Definition: CANPort2B.cpp:262
void canTxAbortCallback(CANPort *port, uint32_t mailbox) override
Definition: CANPort2B.cpp:239
void setSilentMode(bool silent)
Definition: CANPort2B.cpp:165
uint8_t speedPreset
Definition: CANPort2B.h:57
static ClassIdentifier info
Definition: CANPort2B.h:51
uint32_t lastSentTime
Definition: CANPort2B.h:67
CanPort_commands
Definition: CANPort2B.h:16
uint32_t getSpeed()
Definition: CANPort2B.cpp:124
void setSpeed(uint32_t speed)
Definition: CANPort2B.cpp:155
uint8_t getSpeedPreset()
Definition: CANPort2B.cpp:128
bool silent
Definition: CANPort2B.h:64
void canTxCpltCallback(CANPort *port, uint32_t mailbox) override
Definition: CANPort2B.cpp:230
CANPort_2B(CAN_HandleTypeDef &hcan, const CANPortHardwareConfig &presets, const OutputPin *silentPin=nullptr, uint8_t instance=0)
Definition: CANPort2B.cpp:19
void removeCanFilter(uint8_t filterId)
Definition: CANPort2B.cpp:320
void abortTxRequests()
Definition: CANPort2B.cpp:180
constexpr PresetEntry getPreset(uint8_t idx) const
Definition: CAN.h:50
const std::span< const PresetEntry > presets
Definition: CAN.h:56
Definition: CAN.h:119
virtual void giveSemaphore()
Definition: CAN.h:173
virtual uint8_t speedToPreset(uint32_t speed)
Gets preset index for a speed.
Definition: CAN.h:197
cpp_freertos::BinarySemaphore configSem
Definition: CAN.h:202
virtual bool takeSemaphore(uint32_t delay=portMAX_DELAY)
Definition: CAN.h:183
const CANPortHardwareConfig & presets
CAN port presets for different speeds. Hardware dependent.
Definition: CAN.h:203
bool isWaitingFlag
Definition: CAN.h:204
virtual uint32_t presetToSpeed(uint8_t preset)
Gets speed for a preset index.
Definition: CAN.h:198
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)
virtual CmdHandlerInfo * getCommandHandlerInfo()
void write(bool state) const
Definition: GPIOPin.h:46
void set() const
Definition: GPIOPin.h:38
bool Take(TickType_t Timeout=portMAX_DELAY)
Definition: csemaphore.cpp:46
static struct @612 data
bool Flash_Write(uint16_t adr, uint16_t dat)
bool Flash_Read(uint16_t adr, uint16_t *buf, bool checkempty=true)
static void * memcpy(void *dst, const void *src, size_t n)
Definition: ringbuffer.c:8
bool extid
Definition: CAN.h:112
bool active
Definition: CAN.h:111
uint32_t buffer
Definition: CAN.h:110
uint32_t filter_mask
Definition: CAN.h:109
uint32_t filter_id
Definition: CAN.h:108
bool extId
Definition: CAN.h:62
bool rtr
Definition: CAN.h:63
uint32_t id
Definition: CAN.h:60
uint32_t length
Definition: CAN.h:61
Definition: CAN.h:89
CAN_msg_header_tx header
Definition: CAN.h:92
uint8_t data[CAN_MSGBUFSIZE]
Definition: CAN.h:90
const CAN_INITTYPE init
Definition: CAN.h:41
const char * name
uint32_t cmdId