This repository was archived by the owner on Jul 16, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathcan_knob.hpp
More file actions
183 lines (165 loc) · 6.42 KB
/
Copy pathcan_knob.hpp
File metadata and controls
183 lines (165 loc) · 6.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include <Arduino.h>
#include <U8g2lib.h>
#include <STM32FreeRTOS.h>
#include <math.h>
using namespace std;
// Reading from the keyboard
extern volatile uint8_t keyArray[7];
extern SemaphoreHandle_t keyArrayMutex;
extern volatile bool isReceiverBoard;
extern volatile uint8_t boardIndex;
extern QueueHandle_t msgOutQ;
/// Takes in as argument:
/// - int index: Index of the knob on the physical board (used to identify the knob in CAN messages)
/// - int row: The row index of the knob in the key matrix
/// - int firstColumn: The index of the first column of the 2 that are read from the key matrix
/// - int lowerLimit: The lower bound that the value of the rotation of the knob can have
/// - int upperLimit: The upper bound that the value of the rotation of the knob can have
/// - bool loops: If true, the value of the rotation of the knob will wrap-around to the lower bound when it exceeds the upper bound (and vice-versa)
class CAN_Knob {
private:
int index;
int upperLimit;
int lowerLimit;
bool loops;
int row;
int firstColumn;
int prevState;
int rotation;
int decodeRotationStateChange(uint8_t prevState, uint8_t currentState) volatile {
int rotationChange = 0;
if(prevState == 0b00){
// Regular state changes
if (currentState == 0b01) {
rotationChange = -1;
} else if (currentState == 0b10) {
rotationChange = +1;
}
// Skip state changes
else if (currentState == 0b11) {
rotationChange = -2;
}
} else if (prevState == 0b01) {
// Regular state changes
if(currentState == 0b00){
rotationChange = +1;
} else if (currentState == 0b11) {
rotationChange = -1;
}
// Skip state changes
else if (currentState == 0b10) {
rotationChange = -2;
}
} else if (prevState == 0b10) {
// Regular state changes
if(currentState == 0b00){
rotationChange = -1;
} else if (currentState == 0b11) {
rotationChange = +1;
}
// Skip state changes
else if (currentState == 0b01) {
rotationChange = -2;
}
} else if (prevState == 0b11) {
// Regular state changes
if (currentState == 0b01) {
rotationChange = +1;
} else if (currentState == 0b10) {
rotationChange = -1;
}
// Skip state changes
else if (currentState == 0b00) {
rotationChange = -2;
}
}
return rotationChange;
}
public:
CAN_Knob(int _index, int _row, int _firstColumn, int _lowerLimit, int _upperLimit, bool _loops) {
index = _index;
lowerLimit = _lowerLimit;
upperLimit = _upperLimit;
loops = _loops;
row = _row;
firstColumn = _firstColumn;
prevState = 0b11;
rotation = floor((_lowerLimit + _upperLimit) / 2);
}
/// Send the current rotation of the Knob as a CAN Message
void sendRotationCANMsg() volatile {
uint8_t TX_Message[8] = {0};
TX_Message[0] = 'K';
TX_Message[1] = boardIndex;
TX_Message[2] = index;
TX_Message[3] = rotation;
xQueueSend(msgOutQ, TX_Message, portMAX_DELAY);
}
/// Analyse the output of the keymatrix read and compute the rotation of the knob
void updateCurrentRotation() volatile {
if(isReceiverBoard) {
// Define local variables
uint8_t currentRotationState = 0b00;
int localRotation = rotation;
// Get the row of keyArray where the data about the knob state is
uint8_t keyArrayR;
xSemaphoreTake(keyArrayMutex, portMAX_DELAY);
memcpy(&keyArrayR, (void*) &keyArray[row], sizeof(keyArray[row]));
xSemaphoreGive(keyArrayMutex);
// Iterate through the last 2 bits of the row's value to get the currentRotationState
// Stored as {A,B}, so reverse from lab notes
int keyArrayValue0 = ((keyArrayR >> firstColumn) & 0x01) ? 0b1 : 0b0;
int keyArrayValue1 = ((keyArrayR >> (firstColumn + 1)) & 0x01) ? 0b1 : 0b0;
currentRotationState = (keyArrayValue0 << 1) + keyArrayValue1;
// If there has been a change of state
if(currentRotationState != prevState) {
// Compute the new rotation based on previous rotation + rotation change
localRotation = localRotation + decodeRotationStateChange(prevState, currentRotationState);
// If the 'loops' boolean is set to true, wrap-around
if(loops){
if(localRotation < lowerLimit) {
localRotation = upperLimit;
} else if(localRotation > upperLimit){
localRotation = lowerLimit;
}
// If not, block at the limit
} else {
if(localRotation < lowerLimit) {
localRotation = lowerLimit;
} else if(localRotation > upperLimit){
localRotation = upperLimit;
}
}
// Set the new rotation value using atomic store
__atomic_store_n(&rotation, localRotation, __ATOMIC_RELAXED);
sendRotationCANMsg();
}
// Store the current rotation state for next iteration
prevState = currentRotationState;
}
}
/// Manually set the rotation value of a CAN_KNOB
void setRotation(int value) volatile {
int localRotation = value;
// If the 'loops' boolean is set to true, wrap-around
if(loops){
if(localRotation < lowerLimit) {
localRotation = upperLimit - (lowerLimit - localRotation - 1);
} else if(localRotation > upperLimit){
localRotation = lowerLimit - (upperLimit - localRotation - 1);
}
// If not, block at the limit
} else {
if(localRotation < lowerLimit) {
localRotation = lowerLimit;
} else if(localRotation > upperLimit){
localRotation = upperLimit;
}
}
__atomic_store_n(&rotation, localRotation, __ATOMIC_RELAXED);
}
/// Returns the current rotation value of the knob
int getRotation() volatile {
return rotation;
}
};