1 /* microbit.c - BBC micro:bit specific hooks */
2
3 /*
4 * Copyright (c) 2017 Intel Corporation
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <soc.h>
10 #include <zephyr/sys/printk.h>
11 #include <ctype.h>
12 #include <zephyr/drivers/gpio.h>
13 #include <zephyr/drivers/pwm.h>
14
15 #include <zephyr/display/mb_display.h>
16
17 #include <zephyr/bluetooth/mesh.h>
18
19 #include "board.h"
20
21 #define SCROLL_SPEED 300
22
23 #define BUZZER_PWM_CHANNEL 0
24 #define BEEP_DURATION K_MSEC(60)
25
26 #define SEQ_PER_BIT 976
27 #define SEQ_PAGE (NRF_FICR->CODEPAGESIZE * (NRF_FICR->CODESIZE - 1))
28 #define SEQ_MAX (NRF_FICR->CODEPAGESIZE * 8 * SEQ_PER_BIT)
29
30 static const struct gpio_dt_spec button_a =
31 GPIO_DT_SPEC_GET(DT_NODELABEL(buttona), gpios);
32 static const struct gpio_dt_spec button_b =
33 GPIO_DT_SPEC_GET(DT_NODELABEL(buttonb), gpios);
34 static const struct device *const nvm =
35 DEVICE_DT_GET(DT_CHOSEN(zephyr_flash_controller));
36 static const struct device *const pwm =
37 DEVICE_DT_GET_ANY(nordic_nrf_sw_pwm);
38
39 static struct k_work button_work;
40
button_send_pressed(struct k_work * work)41 static void button_send_pressed(struct k_work *work)
42 {
43 printk("button_send_pressed()\n");
44 board_button_1_pressed();
45 }
46
button_pressed(const struct device * dev,struct gpio_callback * cb,uint32_t pins)47 static void button_pressed(const struct device *dev, struct gpio_callback *cb,
48 uint32_t pins)
49 {
50 struct mb_display *disp = mb_display_get();
51
52 if (pins & BIT(button_a.pin)) {
53 k_work_submit(&button_work);
54 } else {
55 uint16_t target = board_set_target();
56
57 if (target > 0x0009) {
58 mb_display_print(disp, MB_DISPLAY_MODE_SINGLE,
59 2 * MSEC_PER_SEC, "A");
60 } else {
61 mb_display_print(disp, MB_DISPLAY_MODE_SINGLE,
62 2 * MSEC_PER_SEC, "%X", (target & 0xf));
63 }
64 }
65 }
66
67 static const struct {
68 char note;
69 uint32_t period;
70 uint32_t sharp;
71 } period_map[] = {
72 { 'C', 3822, 3608 },
73 { 'D', 3405, 3214 },
74 { 'E', 3034, 3034 },
75 { 'F', 2863, 2703 },
76 { 'G', 2551, 2407 },
77 { 'A', 2273, 2145 },
78 { 'B', 2025, 2025 },
79 };
80
get_period(char note,bool sharp)81 static uint32_t get_period(char note, bool sharp)
82 {
83 int i;
84
85 if (note == ' ') {
86 return 0;
87 }
88
89 for (i = 0; i < ARRAY_SIZE(period_map); i++) {
90 if (period_map[i].note != note) {
91 continue;
92 }
93
94 if (sharp) {
95 return period_map[i].sharp;
96 } else {
97 return period_map[i].period;
98 }
99 }
100
101 return 1500;
102 }
103
board_play_tune(const char * str)104 void board_play_tune(const char *str)
105 {
106 while (*str) {
107 uint32_t period, duration = 0U;
108
109 while (*str && isdigit((unsigned char)*str) == 0) {
110 str++;
111 }
112
113 while (isdigit((unsigned char)*str) != 0) {
114 duration *= 10U;
115 duration += *str - '0';
116 str++;
117 }
118
119 if (!*str) {
120 break;
121 }
122
123 if (str[1] == '#') {
124 period = get_period(*str, true);
125 str += 2;
126 } else {
127 period = get_period(*str, false);
128 str++;
129 }
130
131 if (period) {
132 pwm_set(pwm, BUZZER_PWM_CHANNEL, PWM_USEC(period),
133 PWM_USEC(period) / 2U, 0);
134 }
135
136 k_sleep(K_MSEC(duration));
137
138 /* Disable the PWM */
139 pwm_set(pwm, BUZZER_PWM_CHANNEL, 0, 0, 0);
140 }
141 }
142
board_heartbeat(uint8_t hops,uint16_t feat)143 void board_heartbeat(uint8_t hops, uint16_t feat)
144 {
145 struct mb_display *disp = mb_display_get();
146 const struct mb_image hops_img[] = {
147 MB_IMAGE({ 1, 1, 1, 1, 1 },
148 { 1, 1, 1, 1, 1 },
149 { 1, 1, 1, 1, 1 },
150 { 1, 1, 1, 1, 1 },
151 { 1, 1, 1, 1, 1 }),
152 MB_IMAGE({ 1, 1, 1, 1, 1 },
153 { 1, 1, 1, 1, 1 },
154 { 1, 1, 0, 1, 1 },
155 { 1, 1, 1, 1, 1 },
156 { 1, 1, 1, 1, 1 }),
157 MB_IMAGE({ 1, 1, 1, 1, 1 },
158 { 1, 0, 0, 0, 1 },
159 { 1, 0, 0, 0, 1 },
160 { 1, 0, 0, 0, 1 },
161 { 1, 1, 1, 1, 1 }),
162 MB_IMAGE({ 1, 1, 1, 1, 1 },
163 { 1, 0, 0, 0, 1 },
164 { 1, 0, 0, 0, 1 },
165 { 1, 0, 0, 0, 1 },
166 { 1, 1, 1, 1, 1 }),
167 MB_IMAGE({ 1, 0, 1, 0, 1 },
168 { 0, 0, 0, 0, 0 },
169 { 1, 0, 0, 0, 1 },
170 { 0, 0, 0, 0, 0 },
171 { 1, 0, 1, 0, 1 })
172 };
173
174 printk("%u hops\n", hops);
175
176 if (hops) {
177 hops = MIN(hops, ARRAY_SIZE(hops_img));
178 mb_display_image(disp, MB_DISPLAY_MODE_SINGLE, 2 * MSEC_PER_SEC,
179 &hops_img[hops - 1], 1);
180 }
181 }
182
board_other_dev_pressed(uint16_t addr)183 void board_other_dev_pressed(uint16_t addr)
184 {
185 struct mb_display *disp = mb_display_get();
186
187 printk("board_other_dev_pressed(0x%04x)\n", addr);
188
189 mb_display_print(disp, MB_DISPLAY_MODE_SINGLE, 2 * MSEC_PER_SEC, "%X",
190 (addr & 0xf));
191 }
192
board_attention(bool attention)193 void board_attention(bool attention)
194 {
195 struct mb_display *disp = mb_display_get();
196 static const struct mb_image attn_img[] = {
197 MB_IMAGE({ 0, 0, 0, 0, 0 },
198 { 0, 0, 0, 0, 0 },
199 { 0, 0, 1, 0, 0 },
200 { 0, 0, 0, 0, 0 },
201 { 0, 0, 0, 0, 0 }),
202 MB_IMAGE({ 0, 0, 0, 0, 0 },
203 { 0, 1, 1, 1, 0 },
204 { 0, 1, 1, 1, 0 },
205 { 0, 1, 1, 1, 0 },
206 { 0, 0, 0, 0, 0 }),
207 MB_IMAGE({ 1, 1, 1, 1, 1 },
208 { 1, 1, 1, 1, 1 },
209 { 1, 1, 0, 1, 1 },
210 { 1, 1, 1, 1, 1 },
211 { 1, 1, 1, 1, 1 }),
212 MB_IMAGE({ 1, 1, 1, 1, 1 },
213 { 1, 0, 0, 0, 1 },
214 { 1, 0, 0, 0, 1 },
215 { 1, 0, 0, 0, 1 },
216 { 1, 1, 1, 1, 1 }),
217 };
218
219 if (attention) {
220 mb_display_image(disp,
221 MB_DISPLAY_MODE_DEFAULT | MB_DISPLAY_FLAG_LOOP,
222 150, attn_img, ARRAY_SIZE(attn_img));
223 } else {
224 mb_display_stop(disp);
225 }
226 }
227
configure_button(const struct gpio_dt_spec * button)228 static int configure_button(const struct gpio_dt_spec *button)
229 {
230 int err;
231
232 err = gpio_pin_configure_dt(button, GPIO_INPUT);
233 if (err) {
234 return err;
235 }
236 return gpio_pin_interrupt_configure_dt(button, GPIO_INT_EDGE_TO_ACTIVE);
237 }
238
configure_buttons(void)239 static int configure_buttons(void)
240 {
241 static struct gpio_callback button_cb;
242 int err;
243
244 k_work_init(&button_work, button_send_pressed);
245
246 err = configure_button(&button_a);
247 if (err) {
248 return err;
249 }
250
251 err = configure_button(&button_b);
252 if (err) {
253 return err;
254 }
255
256 if (button_a.port != button_b.port) {
257 /* These should be the same device on this board. */
258 return -EINVAL;
259 }
260
261 gpio_init_callback(&button_cb, button_pressed,
262 BIT(button_a.pin) | BIT(button_b.pin));
263 return gpio_add_callback(button_a.port, &button_cb);
264 }
265
board_init(uint16_t * addr)266 int board_init(uint16_t *addr)
267 {
268 struct mb_display *disp = mb_display_get();
269
270 if (!(device_is_ready(nvm) && device_is_ready(pwm) &&
271 gpio_is_ready_dt(&button_a) &&
272 gpio_is_ready_dt(&button_b))) {
273 printk("One or more devices are not ready\n");
274 return -ENODEV;
275 }
276
277 *addr = NRF_UICR->CUSTOMER[0];
278 if (!*addr || *addr == 0xffff) {
279 #if defined(NODE_ADDR)
280 *addr = NODE_ADDR;
281 #else
282 *addr = 0x0b0c;
283 #endif
284 }
285
286 mb_display_print(disp, MB_DISPLAY_MODE_DEFAULT, SCROLL_SPEED,
287 "0x%04x", *addr);
288
289 return configure_buttons();
290 }
291