File Coverage

lib/Device/Chip/SSD1306.xs
Criterion Covered Total %
statement 74 79 93.6
branch 46 74 62.1
condition n/a
subroutine n/a
pod n/a
total 120 153 78.4


line stmt bran cond sub pod time code
1             /* You may distribute under the terms of either the GNU General Public License
2             * or the Artistic License (the same terms as Perl itself)
3             *
4             * (C) Paul Evans, 2026 -- leonerd@leonerd.org.uk
5             */
6             #define PERL_NO_GET_CONTEXT
7              
8             #include "EXTERN.h"
9             #include "perl.h"
10             #include "XSUB.h"
11              
12             struct SSD1306FrameBuffer
13             {
14             U8 rows, columns; /* size */
15             U8 dirty_pages; /* bitmask */
16             U8 dirty_xlo, dirty_xhi;
17              
18             /* Data is stored in pages. Each page has all the columns of a set of 8
19             * contigouous rows. All data is concatenated in one big byte buffer
20             */
21             U8 *pixels;
22             };
23              
24             MODULE = Device::Chip::SSD1306 PACKAGE = Device::Chip::SSD1306
25              
26             void
27             _framebuffer_new(SV *fbsv, U8 rows, U8 columns)
28             CODE:
29             struct SSD1306FrameBuffer *fb;
30 1           Newx(fb, 1, struct SSD1306FrameBuffer);
31              
32 1           fb->rows = rows;
33 1           fb->columns = columns;
34              
35 1           U8 pages = (rows + 7) / 8;
36 1           Newx(fb->pixels, pages * columns, char);
37             Zero(fb->pixels, pages * columns, char);
38              
39 1           fb->dirty_pages = 0;
40 1           fb->dirty_xlo = columns;
41 1           fb->dirty_xhi = 0xFF;
42              
43 1           sv_setuv(fbsv, PTR2UV(fb));
44              
45             void
46             _framebuffer_free(SV *fbsv)
47             CODE:
48 1           struct SSD1306FrameBuffer *fb = INT2PTR(struct SSD1306FrameBuffer *, SvUV(fbsv));
49              
50 1           Safefree(fb->pixels);
51 1           Safefree(fb);
52              
53             void
54             _framebuffer_cleaned(SV *fbsv)
55             CODE:
56 4           struct SSD1306FrameBuffer *fb = INT2PTR(struct SSD1306FrameBuffer *, SvUV(fbsv));
57              
58 4           fb->dirty_pages = 0;
59 4           fb->dirty_xlo = fb->columns;
60 4           fb->dirty_xhi = 0xFF;
61              
62             SV *
63             _framebuffer_pagedata(SV *fbsv, U8 page, U8 xlo, U8 xhi)
64             CODE:
65 24           struct SSD1306FrameBuffer *fb = INT2PTR(struct SSD1306FrameBuffer *, SvUV(fbsv));
66              
67 24 50         if(xlo >= fb->columns || xhi >= fb->columns)
    50          
68 0           XSRETURN_UNDEF;
69              
70 24 50         if(xlo >= xhi)
71 0           RETVAL = newSVpvs("");
72             else
73 24           RETVAL = newSVpvn(&fb->pixels[page*fb->columns + xlo], xhi - xlo + 1);
74             OUTPUT:
75             RETVAL
76              
77             void
78             _framebuffer_dirty_xlohi(SV *fbsv)
79             PPCODE:
80 4           struct SSD1306FrameBuffer *fb = INT2PTR(struct SSD1306FrameBuffer *, SvUV(fbsv));
81              
82 4 50         EXTEND(SP, 2);
83 4           mPUSHi(fb->dirty_xlo);
84 4           mPUSHi(fb->dirty_xhi);
85 4           XSRETURN(2);
86              
87             bool
88             _framebuffer_is_dirty_page(SV *fbsv, U8 page)
89             CODE:
90 32           struct SSD1306FrameBuffer *fb = INT2PTR(struct SSD1306FrameBuffer *, SvUV(fbsv));
91 32 100         RETVAL = (fb->dirty_pages & (1 << page));
92             OUTPUT:
93             RETVAL
94              
95             void
96             _framebuffer_clear(SV *fbsv)
97             CODE:
98 2           struct SSD1306FrameBuffer *fb = INT2PTR(struct SSD1306FrameBuffer *, SvUV(fbsv));
99              
100 2           U8 pages = (fb->rows + 7) / 8;
101 2           Zero(fb->pixels, pages * fb->columns, char);
102              
103 2           fb->dirty_pages = (1 << fb->rows/8) - 1;
104 2           fb->dirty_xlo = 0;
105 2           fb->dirty_xhi = fb->columns - 1;
106              
107             void
108             _framebuffer_draw_pixel(SV *fbsv, U8 x, U8 y, U8 val)
109             CODE:
110 185           struct SSD1306FrameBuffer *fb = INT2PTR(struct SSD1306FrameBuffer *, SvUV(fbsv));
111              
112 185 50         if(x >= fb->columns || y >= fb->rows)
    50          
113             return;
114              
115 185           U8 page = (y / 8); y %= 8;
116 185 100         if(val)
117 101           fb->pixels[page*fb->columns + x] |= (1 << y);
118             else
119 84           fb->pixels[page*fb->columns + x] &= ~(1 << y);
120              
121 185           fb->dirty_pages |= (1 << page);
122 185 100         if(fb->dirty_xlo > x) fb->dirty_xlo = x;
123 185 50         if(fb->dirty_xhi == 0xFF || fb->dirty_xhi < x) fb->dirty_xhi = x;
    100          
124              
125             void
126             _framebuffer_draw_hline(SV *fbsv, U8 x1, U8 x2, U8 y, U8 val)
127             CODE:
128 1           struct SSD1306FrameBuffer *fb = INT2PTR(struct SSD1306FrameBuffer *, SvUV(fbsv));
129              
130 1 50         if(x1 >= fb->columns || y >= fb->rows)
    50          
131             return;
132              
133 1           U8 page = (y / 8); y %= 8;
134 33 100         for(U8 x = x1; x <= x2; x++) {
135 32 50         if(x >= fb->columns)
136             break;
137              
138 32 50         if(val)
139 32           fb->pixels[page*fb->columns + x] |= (1 << y);
140             else
141 0           fb->pixels[page*fb->columns + x] &= ~(1 << y);
142             }
143              
144 1           fb->dirty_pages |= (1 << page);
145 1 50         if(fb->dirty_xlo > x1) fb->dirty_xlo = x1;
146 1 50         if(fb->dirty_xhi == 0xFF || fb->dirty_xhi < x2) fb->dirty_xhi = x2;
    0          
147              
148             void
149             _framebuffer_draw_vline(SV *fbsv, U8 x, U8 y1, U8 y2, U8 val)
150             CODE:
151 2           struct SSD1306FrameBuffer *fb = INT2PTR(struct SSD1306FrameBuffer *, SvUV(fbsv));
152              
153 2 50         if(x >= fb->columns || y1 >= fb->rows)
    50          
154             return;
155              
156 66 100         for(U8 y = y1; y <= y2; y++) {
157 64 50         if(y >= fb->rows)
158             break;
159              
160 64           U8 page = (y / 8);
161              
162 64 50         if(val)
163 64           fb->pixels[page*fb->columns + x] |= (1 << (y%8));
164             else
165 0           fb->pixels[page*fb->columns + x] &= ~(1 << (y%8));
166              
167 64           fb->dirty_pages |= (1 << page);
168             }
169              
170 2 100         if(fb->dirty_xlo > x) fb->dirty_xlo = x;
171 2 100         if(fb->dirty_xhi == 0xFF || fb->dirty_xhi < x) fb->dirty_xhi = x;
    50          
172              
173             void
174             _framebuffer_draw_rect(SV *fbsv, U8 x1, U8 y1, U8 x2, U8 y2, U8 val)
175             CODE:
176 1           struct SSD1306FrameBuffer *fb = INT2PTR(struct SSD1306FrameBuffer *, SvUV(fbsv));
177              
178 1 50         if(x1 >= fb->columns || y1 >= fb->rows)
    50          
179             return;
180              
181 7 100         for(U8 y = y1; y <= y2; y++) {
182 6 50         if(y >= fb->rows)
183             break;
184              
185 6           U8 page = (y / 8);
186              
187 36 100         for(U8 x = x1; x <= x2; x++) {
188 30 50         if(x >= fb->columns)
189             break;
190              
191 30 50         if(val)
192 30           fb->pixels[page*fb->columns + x] |= (1 << (y%8));
193             else
194 0           fb->pixels[page*fb->columns + x] &= ~(1 << (y%8));
195             }
196              
197 6           fb->dirty_pages |= (1 << page);
198             }
199              
200 1 50         if(fb->dirty_xlo > x1) fb->dirty_xlo = x1;
201 1 50         if(fb->dirty_xhi == 0xFF || fb->dirty_xhi < x2) fb->dirty_xhi = x2;
    50