• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lexus2k / lcdgfx / 17492045111

05 Sep 2025 11:35AM UTC coverage: 36.084%. Remained the same
17492045111

push

github

lexus2k
Updated platform.cpp for linux to support kernel 6

188 of 521 relevant lines covered (36.08%)

84.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

7.02
/src/lcd_hal/linux/platform.cpp
1
/*
2
    MIT License
3

4
    Copyright (c) 2018-2020, Alexey Dynda
5

6
    Permission is hereby granted, free of charge, to any person obtaining a copy
7
    of this software and associated documentation files (the "Software"), to deal
8
    in the Software without restriction, including without limitation the rights
9
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
    copies of the Software, and to permit persons to whom the Software is
11
    furnished to do so, subject to the following conditions:
12

13
    The above copyright notice and this permission notice shall be included in all
14
    copies or substantial portions of the Software.
15

16
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
    SOFTWARE.
23
*/
24

25
#if ( defined(__linux__) || defined(__APPLE__) ) && !defined(ARDUINO)
26

27
#include "../io.h"
28

29
#include <sys/stat.h>
30
#include <sys/types.h>
31
#include <errno.h>
32
#include <fcntl.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <unistd.h>
36

37
#include <sys/ioctl.h>
38
#if defined(__linux__)
39
#include <linux/i2c-dev.h>
40
#include <linux/spi/spidev.h>
41
#endif
42

43
#if __has_include(<gpiod.h>)
44
#define LCDGFX_USE_LIBGPIOD 1
45
#include <gpiod.h>
46
#else
47
#define LCDGFX_USE_LIBGPIOD 0
48
#endif
49

50
//#include <cstdlib>
51

52
#include <map>
53

54
#if defined(CONFIG_LINUX_SPI_AVAILABLE) && defined(CONFIG_LINUX_SPI_ENABLE) && !defined(SDL_EMULATION)
55
#define LINUX_SPI_AVAILABLE
56
#endif
57

58

59
#define MAX_GPIO_COUNT 256
60

61
#ifdef IN
62
#undef IN
63
#endif
64
#define IN 0
65

66
#ifdef OUT
67
#undef OUT
68
#endif
69
#define OUT 1
70

71

72
#if LCDGFX_USE_LIBGPIOD
73
// libgpiod context
74
static struct gpiod_chip *lcdgfx_gpiod_chip = NULL;
75
static int lcdgfx_gpiod_init_chip(void) {
76
    if (!lcdgfx_gpiod_chip) {
77
        lcdgfx_gpiod_chip = gpiod_chip_open_by_number(0); // default to gpiochip0
78
        if (!lcdgfx_gpiod_chip) {
79
            fprintf(stderr, "Failed to open gpiochip0 via libgpiod!\n");
80
            return -1;
81
        }
82
    }
83
    return 0;
84
}
85
#endif
86

87
int gpio_export(int pin)
×
88
{
89
#if LCDGFX_USE_LIBGPIOD
90
    // No export needed for libgpiod
91
    return lcdgfx_gpiod_init_chip();
92
#else
93
    char buffer[4];
×
94
    ssize_t bytes_written;
×
95
    int fd;
×
96
    char path[64];
×
97

98
    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d", pin);
×
99

100
    if ( access(path, F_OK) == 0 )
×
101
    {
102
        return 0;
103
    }
104

105
    fd = open("/sys/class/gpio/export", O_WRONLY);
×
106
    if ( -1 == fd )
×
107
    {
108
        fprintf(stderr, "Failed to allocate gpio pin[%d]: %s%s!\n", pin, strerror(errno),
×
109
                getuid() == 0 ? "" : ", need to be root");
×
110
        return (-1);
×
111
    }
112

113
    bytes_written = snprintf(buffer, sizeof(buffer), "%d", pin);
×
114
    if ( write(fd, buffer, bytes_written) < 0 )
×
115
    {
116
        fprintf(stderr, "Failed to allocate gpio pin[%d]: %s%s!\n", pin, strerror(errno),
×
117
                getuid() == 0 ? "" : ", need to be root");
×
118
        close(fd);
×
119
        return -1;
×
120
    }
121
    close(fd);
×
122
    return (0);
123
#endif
124
}
125

126
int gpio_unexport(int pin)
×
127
{
128
#if LCDGFX_USE_LIBGPIOD
129
    // No unexport needed for libgpiod
130
    return 0;
131
#else
132
    char buffer[4];
×
133
    ssize_t bytes_written;
×
134
    int fd;
×
135

136
    fd = open("/sys/class/gpio/unexport", O_WRONLY);
×
137
    if ( -1 == fd )
×
138
    {
139
        fprintf(stderr, "Failed to free gpio pin resources!\n");
×
140
        return (-1);
×
141
    }
142

143
    bytes_written = snprintf(buffer, sizeof(buffer), "%d", pin);
×
144
    if ( write(fd, buffer, bytes_written) < 0 )
×
145
    {
146
        fprintf(stderr, "Failed to free gpio pin resources!\n");
×
147
    }
148
    close(fd);
×
149
    return (0);
150
#endif
151
}
152

153
int gpio_direction(int pin, int dir)
×
154
{
155
#if LCDGFX_USE_LIBGPIOD
156
    if (lcdgfx_gpiod_init_chip() < 0) return -1;
157
    struct gpiod_line *line = gpiod_chip_get_line(lcdgfx_gpiod_chip, pin);
158
    if (!line) {
159
        fprintf(stderr, "libgpiod: Failed to get line for pin %d\n", pin);
160
        return -1;
161
    }
162
    int ret = 0;
163
    if (dir == OUT) {
164
        ret = gpiod_line_request_output(line, "lcdgfx", 0);
165
    } else {
166
        ret = gpiod_line_request_input(line, "lcdgfx");
167
    }
168
    if (ret < 0) {
169
        fprintf(stderr, "libgpiod: Failed to set direction for pin %d\n", pin);
170
        return -1;
171
    }
172
    return 0;
173
#else
174
    static const char s_directions_str[] = "in\0out";
×
175

176
    char path[64];
×
177
    int fd;
×
178

179
    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", pin);
×
180
    fd = open(path, O_WRONLY);
×
181
    if ( -1 == fd )
×
182
    {
183
        fprintf(stderr, "Failed to set gpio pin direction1[%d]: %s!\n", pin, strerror(errno));
×
184
        return (-1);
×
185
    }
186

187
    if ( -1 == write(fd, &s_directions_str[IN == dir ? 0 : 3], IN == dir ? 2 : 3) )
×
188
    {
189
        fprintf(stderr, "Failed to set gpio pin direction2[%d]: %s!\n", pin, strerror(errno));
×
190
        return (-1);
×
191
    }
192

193
    close(fd);
×
194
    return (0);
195
#endif
196
}
197

198
int gpio_read(int pin)
×
199
{
200
#if LCDGFX_USE_LIBGPIOD
201
    if (lcdgfx_gpiod_init_chip() < 0) return -1;
202
    struct gpiod_line *line = gpiod_chip_get_line(lcdgfx_gpiod_chip, pin);
203
    if (!line) {
204
        fprintf(stderr, "libgpiod: Failed to get line for pin %d\n", pin);
205
        return -1;
206
    }
207
    int ret = gpiod_line_request_input(line, "lcdgfx");
208
    if (ret < 0) {
209
        fprintf(stderr, "libgpiod: Failed to request input for pin %d\n", pin);
210
        return -1;
211
    }
212
    int value = gpiod_line_get_value(line);
213
    gpiod_line_release(line);
214
    return value;
215
#else
216
    char path[32];
×
217
    char value_str[3];
×
218
    int fd;
×
219

220
    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);
×
221
    fd = open(path, O_RDONLY);
×
222
    if ( -1 == fd )
×
223
    {
224
        fprintf(stderr, "Failed to read gpio pin value!\n");
×
225
        return (-1);
×
226
    }
227

228
    if ( -1 == read(fd, value_str, 3) )
×
229
    {
230
        fprintf(stderr, "Failed to read gpio pin value!\n");
×
231
        return (-1);
×
232
    }
233

234
    close(fd);
×
235

236
    return (atoi(value_str));
×
237
#endif
238
}
239

240
int gpio_write(int pin, int value)
×
241
{
242
#if LCDGFX_USE_LIBGPIOD
243
    if (lcdgfx_gpiod_init_chip() < 0) return -1;
244
    struct gpiod_line *line = gpiod_chip_get_line(lcdgfx_gpiod_chip, pin);
245
    if (!line) {
246
        fprintf(stderr, "libgpiod: Failed to get line for pin %d\n", pin);
247
        return -1;
248
    }
249
    int ret = gpiod_line_request_output(line, "lcdgfx", value);
250
    if (ret < 0) {
251
        fprintf(stderr, "libgpiod: Failed to request output for pin %d\n", pin);
252
        return -1;
253
    }
254
    ret = gpiod_line_set_value(line, value);
255
    gpiod_line_release(line);
256
    return ret;
257
#else
258
    static const char s_values_str[] = "01";
×
259

260
    char path[64];
×
261
    int fd;
×
262

263
    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);
×
264
    fd = open(path, O_WRONLY);
×
265
    if ( -1 == fd )
×
266
    {
267
        fprintf(stderr, "Failed to set gpio pin value[%d]: %s%s!\n", pin, strerror(errno),
×
268
                getuid() == 0 ? "" : ", need to be root");
×
269
        return (-1);
×
270
    }
271

272
    if ( 1 != write(fd, &s_values_str[LOW == value ? 0 : 1], 1) )
×
273
    {
274
        fprintf(stderr, "Failed to set gpio pin value[%d]: %s%s!\n", pin, strerror(errno),
×
275
                getuid() == 0 ? "" : ", need to be root");
×
276
        return (-1);
×
277
    }
278

279
    close(fd);
×
280
    return (0);
281
#endif
282
}
283

284
#if defined(__KERNEL__) // ============== KERNEL
285

286
int lcd_gpioRead(int pin)
287
{
288
    // TODO: Not implemented
289
    return LCD_LOW;
290
}
291

292
void lcd_gpioWrite(int pin, int level)
293
{
294
    // TODO: Not implemented
295
}
296

297
void lcd_delay(unsigned long ms)
298
{
299
    // TODO: Not implemented
300
}
301

302
void lcd_delayUs(unsigned long us)
303
{
304
    // TODO: Not implemented
305
}
306

307
int lcd_adcRead(int pin)
308
{
309
    // TODO: Not implemented
310
    return 0;
311
}
312

313
uint32_t lcd_millis(void)
314
{
315
    // TODO: Not implemented
316
    return 0;
317
}
318

319
uint32_t lcd_micros(void)
320
{
321
    // TODO: Not implemented
322
    return 0;
323
}
324

325
void lcd_gpioMode(int pin, int mode)
326
{
327
    // TODO: Not implemented
328
}
329

330
#elif !defined(SDL_EMULATION)
331

332
#ifdef LINUX_SPI_AVAILABLE
333
typedef struct
334
{
335
    void (*on_pin_change)(void *);
336
    void *arg;
337
} SPinEvent;
338
#endif
339

340
static uint8_t s_exported_pin[MAX_GPIO_COUNT] = {0};
341
static uint8_t s_pin_mode[MAX_GPIO_COUNT] = {0};
342
#ifdef LINUX_SPI_AVAILABLE
343
std::map<int, SPinEvent> s_events;
344
#endif
345

346
void lcd_gpioMode(int pin, int mode)
347
{
348
    if ( !s_exported_pin[pin] )
349
    {
350
        if ( gpio_export(pin) < 0 )
351
        {
352
            return;
353
        }
354
        s_exported_pin[pin] = 1;
355
    }
356
    if ( mode == LCD_GPIO_OUTPUT )
357
    {
358
        gpio_direction(pin, OUT);
359
        s_pin_mode[pin] = 1;
360
    }
361
    if ( mode == LCD_GPIO_INPUT )
362
    {
363
        gpio_direction(pin, IN);
364
        s_pin_mode[pin] = 0;
365
    }
366
}
367

368
void lcd_gpioWrite(int pin, int level)
369
{
370
#ifdef LINUX_SPI_AVAILABLE
371
    if ( s_events.find(pin) != s_events.end() )
372
    {
373
        s_events[pin].on_pin_change(s_events[pin].arg);
374
    }
375
#endif
376

377
    if ( !s_exported_pin[pin] )
378
    {
379
        if ( gpio_export(pin) < 0 )
380
        {
381
            return;
382
        }
383
        s_exported_pin[pin] = 1;
384
    }
385
    if ( !s_pin_mode[pin] )
386
    {
387
        pinMode(pin, OUTPUT);
388
    }
389
    gpio_write(pin, level);
390
}
391

392
void lcd_registerGpioEvent(int pin, void (*on_pin_change)(void *), void *arg)
393
{
394
#ifdef LINUX_SPI_AVAILABLE
395
    s_events[pin].arg = arg;
396
    s_events[pin].on_pin_change = on_pin_change;
397
#endif
398
}
399

400
void lcd_unregisterGpioEvent(int pin)
401
{
402
    s_events.erase(pin);
403
}
404

405
int lcd_gpioRead(int pin)
406
{
407
    return gpio_read(pin) ? LCD_HIGH : LCD_LOW;
408
}
409

410
int lcd_adcRead(int pin)
411
{
412
    // NOT IMPLEMENTED
413
    return 0;
414
}
415

416
void lcd_delay(unsigned long ms)
417
{
418
    usleep(ms * 1000);
419
}
420

421
void lcd_delayUs(unsigned long us)
422
{
423
    usleep(us);
424
}
425

426
uint32_t lcd_millis(void)
427
{
428
    struct timespec ts;
429
    clock_gettime(CLOCK_MONOTONIC, &ts);
430
    return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
431
}
432

433
uint32_t lcd_micros(void)
434
{
435
    struct timespec ts;
436
    clock_gettime(CLOCK_MONOTONIC, &ts);
437
    return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
438
}
439

440
int lcd_gfx_min(int a, int b)
441
{
442
    return a < b ? a : b;
443
}
444
int lcd_gfx_max(int a, int b)
445
{
446
    return a > b ? a : b;
447
}
448

449
#else // SDL_EMULATION
450

451
int lcd_gpioRead(int pin)
×
452
{
453
    return sdl_read_digital(pin);
×
454
}
455

456
int lcd_adcRead(int pin)
×
457
{
458
    return sdl_read_analog(pin);
×
459
}
460

461
void lcd_gpioWrite(int pin, int level)
123✔
462
{
463
    sdl_write_digital(pin, level);
123✔
464
}
123✔
465

466
void lcd_gpioMode(int pin, int mode)
×
467
{
468
    // TODO: Not implemented
469
}
×
470

471
void lcd_delay(unsigned long ms)
2✔
472
{
473
    usleep(ms * 1000);
2✔
474
}
2✔
475

476
void lcd_delayUs(unsigned long us)
×
477
{
478
    usleep(us);
×
479
}
×
480

481
uint32_t lcd_millis(void)
×
482
{
483
    struct timespec ts;
×
484
    clock_gettime(CLOCK_MONOTONIC, &ts);
×
485
    return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
×
486
}
487

488
uint32_t lcd_micros(void)
×
489
{
490
    struct timespec ts;
×
491
    clock_gettime(CLOCK_MONOTONIC, &ts);
×
492
    return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
×
493
};
494

495
int lcd_gfx_min(int a, int b)
×
496
{
497
    return a < b ? a : b;
×
498
}
499
int lcd_gfx_max(int a, int b)
×
500
{
501
    return a > b ? a : b;
×
502
}
503

504
#endif // SDL_EMULATION
505

506
void lcd_randomSeed(int seed)
×
507
{
508
    // TODO: Not implemented
509
}
×
510

511
void lcd_attachInterrupt(int pin, void (*interrupt)(void), int level)
×
512
{
513
    // TODO: Not implemented
514
}
×
515

516
uint8_t lcd_pgmReadByte(const void *ptr)
3,013✔
517
{
518
    return *reinterpret_cast<const uint8_t *>(ptr);
3,013✔
519
}
520

521
uint16_t lcd_eepromReadWord(const void *ptr)
×
522
{
523
    // TODO: Not implemented
524
    return 0;
×
525
}
526

527
void lcd_eepromWriteWord(const void *ptr, uint16_t val)
×
528
{
529
    // TODO: Not implemented
530
}
×
531

532
int lcd_random(int v)
×
533
{
534
    return rand() % v;
×
535
}
536

537
int lcd_random(int min, int max)
×
538
{
539
    return rand() % (max - min + 1) + min;
×
540
}
541

542
#endif // __linux__
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc