Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_module_lcd.c
1 #include <stm32l0xx.h>
2 #include <bc_module_lcd.h>
3 #include <bc_tca9534a.h>
4 #include <bc_scheduler.h>
5 #include <bc_ls013b7dh03.h>
6 
7 enum
8 {
9  _BC_MODULE_LCD_BACKLIGHT_PIN = BC_TCA9534A_PIN_P0,
10  _BC_MODULE_LCD_BUTTON1_PIN = BC_TCA9534A_PIN_P1,
11  _BC_MODULE_LCD_DISP_ON_PIN = BC_TCA9534A_PIN_P2,
12  _BC_MODULE_LCD_BUTTON2_PIN = BC_TCA9534A_PIN_P3,
13  _BC_MODULE_LCD_LED_GREEN_PIN = BC_TCA9534A_PIN_P4,
14  _BC_MODULE_LCD_LED_RED_PIN = BC_TCA9534A_PIN_P5,
15  _BC_MODULE_LCD_LED_BLUE_PIN = BC_TCA9534A_PIN_P6,
16  _BC_MODULE_LCD_LED_DISP_CS_PIN = BC_TCA9534A_PIN_P7
17 };
18 
19 #define _BC_MODULE_LCD_INITIALIZED ((1 << _BC_MODULE_LCD_BACKLIGHT_PIN) | (1 << _BC_MODULE_LCD_LED_DISP_CS_PIN) | (1 << _BC_MODULE_LCD_DISP_ON_PIN) | (1 << _BC_MODULE_LCD_LED_GREEN_PIN) | (1 << _BC_MODULE_LCD_LED_RED_PIN) | (1 << _BC_MODULE_LCD_LED_BLUE_PIN))
20 
21 typedef struct bc_module_lcd_t
22 {
23  void (*event_handler)(bc_module_lcd_event_t, void *);
24  void *event_param;
25  bool is_tca9534a_initialized;
26  bc_tca9534a_t tca9534a;
27  bc_ls013b7dh03_t ls013b7dh03;
28  bc_gfx_t gfx;
29 
30  bc_button_t button_left;
31  bc_button_t button_right;
32 
34 
35 bc_module_lcd_t _bc_module_lcd;
36 
37 static bc_tca9534a_pin_t _bc_module_lcd_led_pin_lut[3] =
38 {
39  [BC_MODULE_LCD_LED_RED] = BC_TCA9534A_PIN_P5,
40  [BC_MODULE_LCD_LED_GREEN] = BC_TCA9534A_PIN_P4,
41  [BC_MODULE_LCD_LED_BLUE] = BC_TCA9534A_PIN_P6
42 };
43 
44 static bc_tca9534a_pin_t _bc_module_lcd_button_pin_lut[2] =
45 {
46  [BC_MODULE_LCD_BUTTON_LEFT] = BC_TCA9534A_PIN_P3,
47  [BC_MODULE_LCD_BUTTON_RIGHT] = BC_TCA9534A_PIN_P1
48 };
49 
50 static bool _bc_module_lcd_tca9534a_init(void);
51 
52 static bool _bc_module_lcd_cs_pin_set(bool state);
53 
54 static void _bc_module_lcd_led_init(bc_led_t *self);
55 
56 static void _bc_module_lcd_led_on(bc_led_t *self);
57 
58 static void _bc_module_lcd_led_off(bc_led_t *self);
59 
60 static void _bc_module_lcd_button_init(bc_button_t *self);
61 
62 static int _bc_module_lcd_button_get_input(bc_button_t *self);
63 
65 {
66  _bc_module_lcd_tca9534a_init();
67 
68  bc_ls013b7dh03_init(&_bc_module_lcd.ls013b7dh03, _bc_module_lcd_cs_pin_set);
69 
70  bc_gfx_init(&_bc_module_lcd.gfx, &_bc_module_lcd.ls013b7dh03, bc_ls013b7dh03_get_driver());
71 
72  bc_gfx_clear(&_bc_module_lcd.gfx);
73 }
74 
76 {
77  return &_bc_module_lcd.gfx;
78 }
79 
80 bool bc_module_lcd_on(void)
81 {
82  return bc_tca9534a_write_pin(&_bc_module_lcd.tca9534a, _BC_MODULE_LCD_DISP_ON_PIN, 1);
83 }
84 
86 {
87  return bc_tca9534a_write_pin(&_bc_module_lcd.tca9534a, _BC_MODULE_LCD_DISP_ON_PIN, 0);
88 }
89 
91 {
92  return _bc_module_lcd_tca9534a_init() && bc_gfx_display_is_ready(&_bc_module_lcd.gfx);
93 }
94 
96 {
97  bc_gfx_clear(&_bc_module_lcd.gfx);
98 }
99 
100 void bc_module_lcd_draw_pixel(int x, int y, bool value)
101 {
102  bc_gfx_draw_pixel(&_bc_module_lcd.gfx, x, y, value);
103 }
104 
105 int bc_module_lcd_draw_char(int left, int top, uint8_t ch, bool color)
106 {
107  return bc_gfx_draw_char(&_bc_module_lcd.gfx, left, top, ch, color);
108 }
109 
110 int bc_module_lcd_draw_string(int left, int top, char *str, bool color)
111 {
112  return bc_gfx_draw_string(&_bc_module_lcd.gfx, left, top, str, color);
113 }
114 
115 
116 void bc_module_lcd_draw(const uint8_t *frame, uint8_t width, uint8_t height) // In pixels
117 {
118  (void)frame;
119  (void)width;
120  (void)height;
121 }
122 
123 void bc_module_lcd_printf(uint8_t line, /*uint8_t size, font, */const uint8_t *string/*, ...*/)
124 {
125  (void) line;
126  (void) string;
127 }
128 
129 void bc_module_lcd_draw_line(int x0, int y0, int x1, int y1, bool color)
130 {
131  bc_gfx_draw_line(&_bc_module_lcd.gfx, x0, y0, x1, y1, color);
132 }
133 
134 void bc_module_lcd_draw_rectangle(int x0, int y0, int x1, int y1, bool color)
135 {
136  bc_gfx_draw_rectangle(&_bc_module_lcd.gfx, x0, y0, x1, y1, color);
137 }
138 
139 void bc_module_lcd_draw_circle(int x0, int y0, int radius, bool color)
140 {
141  bc_gfx_draw_circle(&_bc_module_lcd.gfx, x0, y0, radius, color);
142 }
143 
144 void bc_module_lcd_draw_image(int left, int top, const bc_image_t *img)
145 {
146  uint8_t line;
147  uint8_t row;
148  uint8_t bytes_per_row = img->width / 8;
149 
150  if(img->width % 8 != 0)
151  {
152  bytes_per_row++;
153  }
154 
155  bc_tick_t start = bc_tick_get();
156 
157  for (row = 0; row < img->height; row++) {
158  for (line = 0; line < img->width; line++) {
159  uint32_t byte_offset = line / 8 + row * bytes_per_row;
160  uint32_t bit = line % 8;
161  bc_gfx_draw_pixel(&_bc_module_lcd.gfx, line + left, row + top, (img->data[byte_offset]) & (1 << bit));
162  }
163  }
164  volatile bc_tick_t duration = bc_tick_get() - start;
165  (void)duration;
166 
167 }
168 
170 {
171  return bc_gfx_update(&_bc_module_lcd.gfx);
172 }
173 
175 {
176  bc_gfx_set_font(&_bc_module_lcd.gfx, font);
177 }
178 
179 static void _bc_module_lcd_button_event_handler(bc_button_t *self, bc_button_event_t event, void *event_param)
180 {
181  (void) event_param;
182 
183  if (self == &_bc_module_lcd.button_left)
184  {
185  if (event == BC_BUTTON_EVENT_PRESS)
186  {
187  _bc_module_lcd.event_handler(BC_MODULE_LCD_EVENT_LEFT_PRESS, _bc_module_lcd.event_param);
188  }
189  if (event == BC_BUTTON_EVENT_RELEASE)
190  {
191  _bc_module_lcd.event_handler(BC_MODULE_LCD_EVENT_LEFT_RELEASE, _bc_module_lcd.event_param);
192  }
193  if (event == BC_BUTTON_EVENT_CLICK)
194  {
195  _bc_module_lcd.event_handler(BC_MODULE_LCD_EVENT_LEFT_CLICK, _bc_module_lcd.event_param);
196  }
197  if (event == BC_BUTTON_EVENT_HOLD)
198  {
199  if (_bc_module_lcd.button_right._state)
200  {
201  _bc_module_lcd.event_handler(BC_MODULE_LCD_EVENT_BOTH_HOLD, _bc_module_lcd.event_param);
202  // Force _hold_signalized to true, so the hold event of the second button won't trigger which would cause event duplication
203  _bc_module_lcd.button_right._hold_signalized = true;
204  }
205  else
206  {
207  _bc_module_lcd.event_handler(BC_MODULE_LCD_EVENT_LEFT_HOLD, _bc_module_lcd.event_param);
208  }
209  }
210  }
211 
212  if (self == &_bc_module_lcd.button_right)
213  {
214  if (event == BC_BUTTON_EVENT_PRESS)
215  {
216  _bc_module_lcd.event_handler(BC_MODULE_LCD_EVENT_RIGHT_PRESS, _bc_module_lcd.event_param);
217  }
218  if (event == BC_BUTTON_EVENT_RELEASE)
219  {
220  _bc_module_lcd.event_handler(BC_MODULE_LCD_EVENT_RIGHT_RELEASE, _bc_module_lcd.event_param);
221  }
222  if (event == BC_BUTTON_EVENT_CLICK)
223  {
224  _bc_module_lcd.event_handler(BC_MODULE_LCD_EVENT_RIGHT_CLICK, _bc_module_lcd.event_param);
225  }
226  if (event == BC_BUTTON_EVENT_HOLD)
227  {
228  if (_bc_module_lcd.button_left._state)
229  {
230  _bc_module_lcd.event_handler(BC_MODULE_LCD_EVENT_BOTH_HOLD, _bc_module_lcd.event_param);
231  // Force _hold_signalized to true, so the hold event of the second button won't trigger which would cause event duplication
232  _bc_module_lcd.button_left._hold_signalized = true;
233  }
234  else
235  {
236  _bc_module_lcd.event_handler(BC_MODULE_LCD_EVENT_RIGHT_HOLD, _bc_module_lcd.event_param);
237  }
238  }
239  }
240 }
241 
242 void bc_module_lcd_set_event_handler(void (*event_handler)(bc_module_lcd_event_t, void *), void *event_param)
243 {
244  _bc_module_lcd.event_handler = event_handler;
245  _bc_module_lcd.event_param = event_param;
246 
247  const bc_button_driver_t* lcdButtonDriver = bc_module_lcd_get_button_driver();
248 
249  bc_button_init_virtual(&_bc_module_lcd.button_left, 0, lcdButtonDriver, 0);
250  bc_button_init_virtual(&_bc_module_lcd.button_right, 1, lcdButtonDriver, 0);
251 
252  bc_button_set_event_handler(&_bc_module_lcd.button_left, _bc_module_lcd_button_event_handler, (int*)0);
253  bc_button_set_event_handler(&_bc_module_lcd.button_right, _bc_module_lcd_button_event_handler, (int*)1);
254 }
255 
257 {
258  bc_button_set_hold_time(&_bc_module_lcd.button_left, hold_time);
259  bc_button_set_hold_time(&_bc_module_lcd.button_right, hold_time);
260 }
261 
263 {
264  bc_button_set_scan_interval(&_bc_module_lcd.button_left, scan_interval);
265  bc_button_set_scan_interval(&_bc_module_lcd.button_right, scan_interval);
266 }
267 
269 {
270  bc_button_set_debounce_time(&_bc_module_lcd.button_left, debounce_time);
271  bc_button_set_debounce_time(&_bc_module_lcd.button_right, debounce_time);
272 }
273 
275 {
276  bc_button_set_click_timeout(&_bc_module_lcd.button_left, click_timeout);
277  bc_button_set_click_timeout(&_bc_module_lcd.button_right, click_timeout);
278 }
279 
281 {
282  bc_gfx_set_rotation(&_bc_module_lcd.gfx, rotation);
283 }
284 
286 {
287  return bc_gfx_get_rotation(&_bc_module_lcd.gfx);
288 }
289 
291 {
292  static const bc_led_driver_t bc_module_lcd_led_driver =
293  {
294  .init = _bc_module_lcd_led_init,
295  .on = _bc_module_lcd_led_on,
296  .off = _bc_module_lcd_led_off,
297  };
298 
299  return &bc_module_lcd_led_driver;
300 }
301 
303 {
304  static const bc_button_driver_t bc_module_lcd_button_driver =
305  {
306  .init = _bc_module_lcd_button_init,
307  .get_input = _bc_module_lcd_button_get_input,
308  };
309 
310  return &bc_module_lcd_button_driver;
311 }
312 
313 static bool _bc_module_lcd_tca9534a_init(void)
314 {
315  if (!_bc_module_lcd.is_tca9534a_initialized)
316  {
317  if (!bc_tca9534a_init(&_bc_module_lcd.tca9534a, BC_I2C_I2C0, 0x3c))
318  {
319  return false;
320  }
321 
322  if (!bc_tca9534a_write_port(&_bc_module_lcd.tca9534a, _BC_MODULE_LCD_INITIALIZED))
323  {
324  return false;
325  }
326 
327  if (!bc_tca9534a_set_port_direction(&_bc_module_lcd.tca9534a, (1 << _BC_MODULE_LCD_BUTTON1_PIN) | (1 << _BC_MODULE_LCD_BUTTON2_PIN)))
328  {
329  return false;
330  }
331 
332  _bc_module_lcd.is_tca9534a_initialized = true;
333  }
334 
335  return true;
336 }
337 
338 static bool _bc_module_lcd_cs_pin_set(bool state)
339 {
340  if (!_bc_module_lcd_tca9534a_init())
341  {
342  return false;
343  }
344 
345  if (!bc_tca9534a_write_pin(&_bc_module_lcd.tca9534a, _BC_MODULE_LCD_LED_DISP_CS_PIN, state))
346  {
347  _bc_module_lcd.is_tca9534a_initialized = false;
348 
349  return false;
350  }
351 
352  return true;
353 }
354 
355 static void _bc_module_lcd_led_init(bc_led_t *self)
356 {
357  (void) self;
358 
359  _bc_module_lcd_tca9534a_init();
360 }
361 
362 static void _bc_module_lcd_led_on(bc_led_t *self)
363 {
364  if (!bc_tca9534a_write_pin(&_bc_module_lcd.tca9534a, _bc_module_lcd_led_pin_lut[self->_channel.virtual], self->_idle_state ? 0 : 1))
365  {
366  _bc_module_lcd.is_tca9534a_initialized = false;
367  }
368 }
369 
370 static void _bc_module_lcd_led_off(bc_led_t *self)
371 {
372  if (!bc_tca9534a_write_pin(&_bc_module_lcd.tca9534a, _bc_module_lcd_led_pin_lut[self->_channel.virtual], self->_idle_state ? 1 : 0))
373  {
374  _bc_module_lcd.is_tca9534a_initialized = false;
375  }
376 }
377 
378 static void _bc_module_lcd_button_init(bc_button_t *self)
379 {
380  (void) self;
381 
382  _bc_module_lcd_tca9534a_init();
383 
386 }
387 
388 static int _bc_module_lcd_button_get_input(bc_button_t *self)
389 {
391  {
392  return 0;
393  }
394 
395  int state;
396 
397  if (!bc_tca9534a_read_pin(&_bc_module_lcd.tca9534a, _bc_module_lcd_button_pin_lut[self->_channel.virtual], &state))
398  {
399  _bc_module_lcd.is_tca9534a_initialized = false;
400  return 0;
401  }
402 
403  return state;
404 }
uint64_t bc_tick_t
Timestamp data type.
Definition: bc_tick.h:16
void bc_button_set_hold_time(bc_button_t *self, bc_tick_t hold_time)
Set hold time (interval after which hold event is recognized when button is steadily pressed) ...
Definition: bc_button.c:98
int bc_gfx_draw_char(bc_gfx_t *self, int left, int top, uint8_t ch, uint32_t color)
Display draw char.
Definition: bc_gfx.c:86
bool bc_module_lcd_is_ready(void)
Check if lcd is ready for commands.
Definition: bc_module_lcd.c:90
Button driver interface.
Definition: bc_button.h:36
void bc_gfx_clear(bc_gfx_t *self)
Clear.
Definition: bc_gfx.c:22
void bc_gfx_init(bc_gfx_t *self, void *display, const bc_gfx_driver_t *driver)
Initialize button.
Definition: bc_gfx.c:3
bool bc_module_lcd_on(void)
Lcd on.
Definition: bc_module_lcd.c:80
void bc_gfx_draw_pixel(bc_gfx_t *self, int x, int y, uint32_t color)
Draw pixel.
Definition: bc_gfx.c:42
bc_module_lcd_rotation_t bc_module_lcd_get_rotation(void)
Lcd get rotation.
LED driver interface.
Definition: bc_led.h:56
bool bc_tca9534a_set_port_direction(bc_tca9534a_t *self, uint8_t direction)
Set direction of all pins.
Definition: bc_tca9534a.c:87
Event button released.
Definition: bc_button.h:20
void bc_module_lcd_draw_circle(int x0, int y0, int radius, bool color)
Lcd draw circle.
bool bc_tca9534a_write_pin(bc_tca9534a_t *self, bc_tca9534a_pin_t pin, int state)
Write pin state.
Definition: bc_tca9534a.c:61
bool bc_module_lcd_update(void)
Lcd update, send data.
bc_module_lcd_event_t
Callback events.
Definition: bc_module_lcd.h:17
I2C channel I2C0.
Definition: bc_i2c.h:18
const bc_gfx_driver_t * bc_ls013b7dh03_get_driver(void)
Get Lcd driver.
Pin state.
Definition: bc_tca9534a.h:42
void bc_module_lcd_clear(void)
Lcd clear.
Definition: bc_module_lcd.c:95
Event button pressed.
Definition: bc_button.h:17
int bc_module_lcd_draw_string(int left, int top, char *str, bool color)
Lcd draw string.
bool bc_tca9534a_write_port(bc_tca9534a_t *self, uint8_t state)
Write state to all pins.
Definition: bc_tca9534a.c:35
void bc_gfx_set_rotation(bc_gfx_t *self, bc_gfx_rotation_t rotation)
Set rotation.
Definition: bc_gfx.c:32
void(* init)(bc_button_t *self)
Callback for initialization.
Definition: bc_button.h:39
LCD green LED channel.
Definition: bc_module_lcd.h:60
struct bc_led_t bc_led_t
LED instance.
Definition: bc_led.h:52
void bc_module_lcd_set_rotation(bc_module_lcd_rotation_t rotation)
Lcd set rotation.
void bc_module_lcd_draw_rectangle(int x0, int y0, int x1, int y1, bool color)
Lcd draw rectangle.
void bc_gpio_set_mode(bc_gpio_channel_t channel, bc_gpio_mode_t mode)
Set mode of operation for GPIO channel.
Definition: bc_gpio.c:340
bc_module_lcd_rotation_t
Rotation.
Definition: bc_module_lcd.h:36
void bc_module_lcd_set_font(const bc_font_t *font)
Lcd set font.
bc_tick_t bc_tick_get(void)
Get absolute timestamp since start of program.
Definition: bc_tick.c:7
LCD blue LED channel.
Definition: bc_module_lcd.h:63
void bc_module_lcd_draw_line(int x0, int y0, int x1, int y1, bool color)
Lcd draw line.
bool bc_tca9534a_read_pin(bc_tca9534a_t *self, bc_tca9534a_pin_t pin, int *state)
Read pin state.
Definition: bc_tca9534a.c:47
void bc_module_lcd_draw_image(int left, int top, const bc_image_t *img)
Lcd draw image.
void bc_gfx_draw_rectangle(bc_gfx_t *self, int x0, int y0, int x1, int y1, uint32_t color)
Display draw rectangle.
Definition: bc_gfx.c:278
LCD left button channel.
Definition: bc_module_lcd.h:72
void bc_module_lcd_set_button_scan_interval(bc_tick_t scan_interval)
Set scan interval (period of button input sampling)
int bc_gpio_get_input(bc_gpio_channel_t channel)
Get input state for GPIO channel.
Definition: bc_gpio.c:436
LCD right button channel.
Definition: bc_module_lcd.h:75
void bc_module_lcd_set_event_handler(void(*event_handler)(bc_module_lcd_event_t, void *), void *event_param)
Lcd set event handler for buttons.
GPIO channel operates as input.
Definition: bc_gpio.h:99
bc_button_event_t
Callback events.
Definition: bc_button.h:14
int bc_gfx_draw_string(bc_gfx_t *self, int left, int top, char *str, uint32_t color)
Display draw string.
Definition: bc_gfx.c:152
void bc_gfx_draw_circle(bc_gfx_t *self, int x0, int y0, int radius, uint32_t color)
Lcd draw circle, using Midpoint circle algorithm.
Definition: bc_gfx.c:313
bool bc_tca9534a_init(bc_tca9534a_t *self, bc_i2c_channel_t i2c_channel, uint8_t i2c_address)
Initialize TCA9534A.
Definition: bc_tca9534a.c:8
GPIO channel BUTTON.
Definition: bc_gpio.h:72
void bc_module_lcd_set_button_click_timeout(bc_tick_t click_timeout)
Set click timeout (maximum interval within which button has to be released to recognize click event) ...
bool bc_gfx_display_is_ready(bc_gfx_t *self)
Check if display driver is ready for commands.
Definition: bc_gfx.c:12
Event button hold (pressed for longer time)
Definition: bc_button.h:26
void(* init)(bc_led_t *self)
Callback for initialization.
Definition: bc_led.h:59
bc_gfx_t * bc_module_lcd_get_gfx()
Get gfx instance.
Definition: bc_module_lcd.c:75
const bc_button_driver_t * bc_module_lcd_get_button_driver(void)
Lcd get button driver.
bool bc_module_lcd_off(void)
Lcd off.
Definition: bc_module_lcd.c:85
void bc_module_lcd_draw_pixel(int x, int y, bool value)
Lcd draw pixel.
void bc_module_lcd_init()
Initialize lcd.
Definition: bc_module_lcd.c:64
void bc_button_set_scan_interval(bc_button_t *self, bc_tick_t scan_interval)
Set scan interval (period of button input sampling)
Definition: bc_button.c:83
void bc_button_init_virtual(bc_button_t *self, int channel, const bc_button_driver_t *driver, int idle_state)
Initialize virtual button.
Definition: bc_button.c:43
bc_tca9534a_pin_t
Individual pin names.
Definition: bc_tca9534a.h:16
void bc_module_lcd_set_button_hold_time(bc_tick_t hold_time)
Set hold time (interval after which hold event is recognized when button is steadily pressed) ...
bool bc_gfx_update(bc_gfx_t *self)
Display update, send data.
Definition: bc_gfx.c:476
const bc_led_driver_t * bc_module_lcd_get_led_driver(void)
Lcd get led driver.
int bc_module_lcd_draw_char(int left, int top, uint8_t ch, bool color)
Lcd draw char.
Instance.
Definition: bc_gfx.h:80
void bc_module_lcd_set_button_debounce_time(bc_tick_t debounce_time)
Set debounce time (minimum sampling interval during which input cannot change to toggle its state) ...
Event button clicked (pressed and released within certain time)
Definition: bc_button.h:23
bc_gfx_rotation_t bc_gfx_get_rotation(bc_gfx_t *self)
Get rotation.
Definition: bc_gfx.c:37
void bc_button_set_event_handler(bc_button_t *self, void(*event_handler)(bc_button_t *, bc_button_event_t, void *), void *event_param)
Set callback function.
Definition: bc_button.c:66
void bc_gfx_set_font(bc_gfx_t *self, const bc_font_t *font)
Set font.
Definition: bc_gfx.c:27
void bc_gfx_draw_line(bc_gfx_t *self, int x0, int y0, int x1, int y1, uint32_t color)
Display draw line.
Definition: bc_gfx.c:188
void bc_ls013b7dh03_init(bc_ls013b7dh03_t *self, bool(*pin_cs_set)(bool state))
Initialize lcd driver.
void bc_button_set_debounce_time(bc_button_t *self, bc_tick_t debounce_time)
Set debounce time (minimum sampling interval during which input cannot change to toggle its state) ...
Definition: bc_button.c:88
struct bc_button_t bc_button_t
Button instance.
Definition: bc_button.h:32
LCD red LED channel.
Definition: bc_module_lcd.h:57
void bc_button_set_click_timeout(bc_button_t *self, bc_tick_t click_timeout)
Set click timeout (maximum interval within which button has to be released to recognize click event) ...
Definition: bc_button.c:93
void bc_gpio_init(bc_gpio_channel_t channel)
Initialize GPIO channel.
Definition: bc_gpio.c:301