1 /*
2  * Copyright (c) 2021 Titouan Christophe
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "display_7seg.h"
8 
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/sys/printk.h>
12 
13 const uint8_t DISPLAY_OFF[4] = { CHAR_OFF, CHAR_OFF, CHAR_OFF, CHAR_OFF };
14 const uint8_t TEXT_Err[4] = { CHAR_E, CHAR_r, CHAR_r, CHAR_OFF };
15 
16 static bool initialized;
17 static const struct device *const expander1 =
18 				DEVICE_DT_GET(DT_NODELABEL(expander1_x_nucleo_53l0a1));
19 static const struct device *const expander2 =
20 				DEVICE_DT_GET(DT_NODELABEL(expander2_x_nucleo_53l0a1));
21 static const uint8_t digits[16] = {
22 	CHAR_0,
23 	CHAR_1,
24 	CHAR_2,
25 	CHAR_3,
26 	CHAR_4,
27 	CHAR_5,
28 	CHAR_6,
29 	CHAR_7,
30 	CHAR_8,
31 	CHAR_9,
32 	CHAR_A,
33 	CHAR_b,
34 	CHAR_C,
35 	CHAR_d,
36 	CHAR_E,
37 	CHAR_F,
38 };
39 
40 static const int max_positive_for_base[17] = {
41 	0,
42 	1,
43 	16,
44 	81,
45 	256,
46 	625,
47 	1296,
48 	2401,
49 	4096,
50 	6561,
51 	10000,
52 	14641,
53 	20736,
54 	28561,
55 	38416,
56 	50625,
57 	65536,
58 };
59 
60 static const int max_negative_for_base[17] = {
61 	-0,
62 	-1,
63 	-8,
64 	-27,
65 	-64,
66 	-125,
67 	-216,
68 	-343,
69 	-512,
70 	-729,
71 	-1000,
72 	-1331,
73 	-1728,
74 	-2197,
75 	-2744,
76 	-3375,
77 	-4096,
78 };
79 
init_display(void)80 static int init_display(void)
81 {
82 	int ret;
83 
84 	for (int i = 0; i < 14; i++) {
85 		ret = gpio_pin_configure(expander1, i, GPIO_OUTPUT | GPIO_OUTPUT_INIT_HIGH);
86 		if (ret) {
87 			printk("Error in configure pin %d on expander1: %d", i, ret);
88 			return ret;
89 		}
90 		ret = gpio_pin_configure(expander2, i, GPIO_OUTPUT | GPIO_OUTPUT_INIT_HIGH);
91 		if (ret) {
92 			printk("Error in configure pin %d on expander2: %d", i, ret);
93 			return ret;
94 		}
95 	}
96 
97 	initialized = true;
98 	return 0;
99 }
100 
101 
display_chars(const uint8_t chars[4])102 int display_chars(const uint8_t chars[4])
103 {
104 	int r;
105 	uint16_t port1, port2;
106 
107 	if (!initialized) {
108 		r = init_display();
109 		if (r) {
110 			return r;
111 		}
112 	}
113 
114 	port1 = ((chars[3] & 0x7f) << 7) | (chars[2] & 0x7f);
115 	port2 = ((chars[1] & 0x7f) << 7) | (chars[0] & 0x7f);
116 
117 	/* Common anode: invert the output (LOW = led on) */
118 	r = gpio_port_set_masked(expander1, 0x3fff, port1 ^ 0x3fff);
119 	if (r) {
120 		return r;
121 	}
122 	return gpio_port_set_masked(expander2, 0x3fff, port2 ^ 0x3fff);
123 }
124 
display_number(int num,unsigned int base)125 int display_number(int num, unsigned int base)
126 {
127 	int d, i, neg = 0;
128 	uint8_t representation[4] = { CHAR_E, CHAR_r, CHAR_r, CHAR_OFF };
129 
130 	/* Unsupported base */
131 	if (base > 16) {
132 		return -EINVAL;
133 	}
134 
135 	/* Number too large to be displayed */
136 	if (num <= max_negative_for_base[base] || num >= max_positive_for_base[base]) {
137 		return -EINVAL;
138 	}
139 
140 	if (num < 0) {
141 		num = -num;
142 		representation[0] = CHAR_DASH;
143 		neg = 1;
144 	}
145 
146 	for (i = 3; i >= neg; i--) {
147 		if (num > 0 || i == 3) {
148 			d = num % base;
149 			representation[i] = digits[d];
150 			num /= base;
151 		} else {
152 			representation[i] = CHAR_OFF;
153 		}
154 	}
155 	return display_chars(representation);
156 }
157