-
Notifications
You must be signed in to change notification settings - Fork 42
/
main.c
264 lines (219 loc) · 7.6 KB
/
main.c
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
/*
* Either COMPILE_RIGHT or COMPILE_LEFT has to be defined from the make call to allow proper functionality
*/
#include "redox-w.h"
#include "nrf_drv_config.h"
#include "nrf_gzll.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "nrf_drv_clock.h"
#include "nrf_drv_rtc.h"
#include "nrf51_bitfields.h"
#include "nrf51.h"
/*****************************************************************************/
/** Configuration */
/*****************************************************************************/
const nrf_drv_rtc_t rtc = NRF_DRV_RTC_INSTANCE(1); /**< Declaring an instance of nrf_drv_rtc for RTC1. */
// Data and acknowledgement payloads
static uint8_t ack_payload[NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH]; ///< Placeholder for received ACK payloads from Host.
// Debounce time (dependent on tick frequency)
#define DEBOUNCE 5
// Mark as inactive after a number of ticks:
#define INACTIVITY_THRESHOLD 500 // 0.5sec
#ifdef COMPILE_LEFT
static uint8_t channel_table[3]={4, 42, 77};
#endif
#ifdef COMPILE_RIGHT
static uint8_t channel_table[3]={25, 63, 33};
#endif
// Setup switch pins with pullups
static void gpio_config(void)
{
nrf_gpio_cfg_sense_input(R01, NRF_GPIO_PIN_PULLDOWN, NRF_GPIO_PIN_SENSE_HIGH);
nrf_gpio_cfg_sense_input(R02, NRF_GPIO_PIN_PULLDOWN, NRF_GPIO_PIN_SENSE_HIGH);
nrf_gpio_cfg_sense_input(R03, NRF_GPIO_PIN_PULLDOWN, NRF_GPIO_PIN_SENSE_HIGH);
nrf_gpio_cfg_sense_input(R04, NRF_GPIO_PIN_PULLDOWN, NRF_GPIO_PIN_SENSE_HIGH);
nrf_gpio_cfg_sense_input(R05, NRF_GPIO_PIN_PULLDOWN, NRF_GPIO_PIN_SENSE_HIGH);
nrf_gpio_cfg_output(C01);
nrf_gpio_cfg_output(C02);
nrf_gpio_cfg_output(C03);
nrf_gpio_cfg_output(C04);
nrf_gpio_cfg_output(C05);
nrf_gpio_cfg_output(C06);
nrf_gpio_cfg_output(C07);
nrf_gpio_pin_clear(C01);
nrf_gpio_pin_clear(C02);
nrf_gpio_pin_clear(C03);
nrf_gpio_pin_clear(C04);
nrf_gpio_pin_clear(C05);
nrf_gpio_pin_clear(C06);
nrf_gpio_pin_clear(C07);
}
// Return the key states
static void read_keys(uint8_t *row_stat)
{
unsigned short c;
uint32_t input = 0;
static const uint32_t COL_PINS[] = { C01, C02, C03, C04, C05, C06, C07 };
// scan matrix by columns
for (c = 0; c < COLUMNS; ++c) {
// Force the compiler to add one cycle gap between activating
// the column pin and reading the input to allow some time for
// it to be come stable. Note that compile optimizations are
// not allowed for next three statements. Setting the pin
// write a location which is marked as volatile
// (NRF_GPIO->OUTSET) and reading the input is also a memory
// access to a location which is marked as volatile too
// (NRF_GPIO->IN).
nrf_gpio_pin_set(COL_PINS[c]);
asm volatile("nop");
input = NRF_GPIO->IN;
row_stat[0] = (row_stat[0] << 1) | ((input >> R01) & 1);
row_stat[1] = (row_stat[1] << 1) | ((input >> R02) & 1);
row_stat[2] = (row_stat[2] << 1) | ((input >> R03) & 1);
row_stat[3] = (row_stat[3] << 1) | ((input >> R04) & 1);
row_stat[4] = (row_stat[4] << 1) | ((input >> R05) & 1);
nrf_gpio_pin_clear(COL_PINS[c]);
}
}
static bool compare_keys(const uint8_t* first, const uint8_t* second,
uint32_t size)
{
for(int i=0; i < size; i++)
{
if (first[i] != second[i])
{
return false;
}
}
return true;
}
static bool empty_keys(const uint8_t* keys_buffer)
{
for(int i=0; i < ROWS; i++)
{
if (keys_buffer[i])
{
return false;
}
}
return true;
}
static void handle_inactivity(const uint8_t *keys_buffer)
{
static uint32_t inactivity_ticks = 0;
// looking for 500 ticks of no keys pressed, to go back to deep sleep
if (empty_keys(keys_buffer)) {
inactivity_ticks++;
if (inactivity_ticks > INACTIVITY_THRESHOLD) {
nrf_drv_rtc_disable(&rtc);
nrf_gpio_pin_set(C01);
nrf_gpio_pin_set(C02);
nrf_gpio_pin_set(C03);
nrf_gpio_pin_set(C04);
nrf_gpio_pin_set(C05);
nrf_gpio_pin_set(C06);
nrf_gpio_pin_set(C07);
inactivity_ticks = 0;
NRF_POWER->SYSTEMOFF = 1;
}
} else {
inactivity_ticks = 0;
}
}
static void handle_send(const uint8_t* keys_buffer)
{
static uint8_t keys_snapshot[ROWS] = {0};
static uint32_t debounce_ticks = 0;
const bool no_change = compare_keys(keys_buffer, keys_snapshot, ROWS);
if (no_change) {
debounce_ticks++;
// debouncing - send only if the keys state has been stable
// for DEBOUNCE ticks
if (debounce_ticks == DEBOUNCE) {
// Assemble packet and send to receiver
nrf_gzll_add_packet_to_tx_fifo(PIPE_NUMBER, keys_snapshot, ROWS);
debounce_ticks = 0;
}
} else {
// change detected, start over
debounce_ticks = 0;
for (int k = 0; k < ROWS; k++) {
keys_snapshot[k] = keys_buffer[k];
}
}
}
// 1000Hz debounce sampling
static void tick(nrf_drv_rtc_int_type_t int_type)
{
uint8_t keys_buffer[ROWS] = {0, 0, 0, 0, 0};
read_keys(keys_buffer);
handle_inactivity(keys_buffer);
handle_send(keys_buffer);
}
// Low frequency clock configuration
static void lfclk_config(void)
{
nrf_drv_clock_init();
nrf_drv_clock_lfclk_request(NULL);
}
// RTC peripheral configuration
static void rtc_config(void)
{
//Initialize RTC instance
nrf_drv_rtc_init(&rtc, NULL, tick);
//Enable tick event & interrupt
nrf_drv_rtc_tick_enable(&rtc, true);
//Power on RTC instance
nrf_drv_rtc_enable(&rtc);
}
int main()
{
// Initialize Gazell
nrf_gzll_init(NRF_GZLL_MODE_DEVICE);
// Attempt sending every packet up to 100 times
nrf_gzll_set_max_tx_attempts(100);
nrf_gzll_set_timeslots_per_channel(4);
nrf_gzll_set_channel_table(channel_table,3);
nrf_gzll_set_datarate(NRF_GZLL_DATARATE_1MBIT);
nrf_gzll_set_timeslot_period(900);
// Addressing
nrf_gzll_set_base_address_0(0x01020304);
nrf_gzll_set_base_address_1(0x05060708);
// Enable Gazell to start sending over the air
nrf_gzll_enable();
// Configure 32kHz xtal oscillator
lfclk_config();
// Configure RTC peripherals with ticks
rtc_config();
// Configure all keys as inputs with pullups
gpio_config();
// Main loop, constantly sleep, waiting for RTC and gpio IRQs
while(1)
{
__SEV();
__WFE();
__WFE();
}
}
/*****************************************************************************/
/** Gazell callback function definitions */
/*****************************************************************************/
void nrf_gzll_device_tx_success(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info)
{
uint32_t ack_payload_length = NRF_GZLL_CONST_MAX_PAYLOAD_LENGTH;
if (tx_info.payload_received_in_ack)
{
// Pop packet and write first byte of the payload to the GPIO port.
nrf_gzll_fetch_packet_from_rx_fifo(pipe, ack_payload, &ack_payload_length);
}
}
// no action is taken when a packet fails to send, this might need to change
void nrf_gzll_device_tx_failed(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info)
{
}
// Callbacks not needed
void nrf_gzll_host_rx_data_ready(uint32_t pipe, nrf_gzll_host_rx_info_t rx_info)
{}
void nrf_gzll_disabled()
{}