23779f9aeb7f6cd3a87a11420306b6c0be42f06e
[linux-gpio-pinout] / gpio.pl
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4 use autodie;
5 use Data::Dump qw(dump);
6 use Getopt::Long;
7
8 my $opt_svg = $ENV{SVG} || 0;
9 my $opt_alt = $ENV{ALT} || 0;
10 my $opt_invert = $ENV{INVERT} = 0;
11 my $opt_vertical = $ENV{VERTICAL} = 0;
12 my $opt_kernel = $ENV{kernel} = 1;
13 GetOptions(
14         'svg!' => \$opt_svg,
15         'alt!' => \$opt_alt,
16         'invert!' => \$opt_invert,
17         'vertical!' => \$opt_vertical,
18         'kernel!' => \$opt_kernel,
19 );
20
21 # svg font hints
22 my $font_w = 1.67; # < 2.54, font is not perfect square
23 my $font_b = 2.10; # font baseline position
24
25 sub slurp {
26         open(my $fh, '<', shift);
27         local $/ = undef;
28         <$fh>;
29 }
30
31 my $pins;
32
33 my $model = slurp('/proc/device-tree/model');
34 $model =~ s/\x00$//; # strip kernel NULL
35 warn "# model [$model]";
36
37 my @lines;
38 my $line_i = 0;
39
40 my $include = 0;
41 while(<DATA>) {
42         chomp;
43         if ( m/^#\s(.+)/ ) {
44                 warn "MODEL [$1] == [$model] ?\n";
45                 if ( $model =~ m/$1/ ) {
46                         $include = 1;
47                 } else {
48                         $include = 0;
49                 }
50         } elsif ( m/^#\s+/ ) {
51                 $include = 1;
52         } elsif ( $include ) {
53                 push @{ $pins->{$1} }, $line_i while ( m/\t(\w+\d+)/g );
54
55                 push @lines, $_;
56
57                 $line_i++;
58         } else {
59                 warn "IGNORE: [$_]\n";
60         }
61 }
62
63 die "add pin definition for # $model" unless $pins;
64
65 warn "# pins ",dump($pins);
66
67 my $pin_function;
68
69 open(my $fh, '<', '/sys/kernel/debug/pinctrl/pinctrl-handles');
70 while(<$fh>) {
71         chomp;
72         if ( m/group: (\w+\d+)\s.+function: (\S+)/ ) {
73                 my ($pin, $function) = ($1,$2);
74                 $pin_function->{$pin} = $function;
75
76                 next unless $opt_kernel;
77
78                 if ( $pins->{$pin} ) {
79                         foreach my $line ( @{$pins->{$pin}} ) {
80 warn "XXX $pin $line";
81                                 my $t = $lines[$line];
82                                 if ( $opt_svg ) {
83                                         $t =~ s/$pin/[$function]/;
84                                 } else {
85                                         $t =~ s/$pin/$pin [$function]/ || die "can't find $pin in [$t]";
86                                 }
87                                 $lines[$line] = $t;
88                                 warn "# $line: $lines[$line]\n";
89                         }
90                 } else {
91                         warn "IGNORED: pin $pin function $function\n";
92                 }
93         }
94 }
95
96 warn "# pin_function = ",dump($pin_function);
97
98 my @max_len = ( 0,0,0,0 );
99 my @line_parts;
100 foreach my $line (@lines) {
101         if ( $line =~ m/^#/ ) {
102                 push @line_parts, [ $line ] unless $opt_svg;
103                 next;
104         }
105         $line =~ s/(\[uart\d)(\]\s[^\t]*(rx|tx))/$1 $3$2/gi;
106         $line =~ s/(\[i2c\d)(\]\s[^\t]*(sck|sda))/$1 $3$2/gi;
107         $line =~ s/(\[spi\d)(\]\s[^\t]*(miso|mosi|clk|cs))/$1 $3$2/gi;
108         $line =~ s/\s*\([^\)]+\)//g if ! $opt_alt;
109
110         my @v = split(/\s*\t+\s*/,$line,4);
111         push @line_parts, [ @v ];
112         foreach my $i ( 0 .. 3 ) {
113                 next unless exists $v[$i];
114                 next if $v[$i] =~ m/^#/; # don't calculate comments into max length
115                 my $l = length($v[$i]);
116                 $max_len[$i] = $l if $l > $max_len[$i];
117         }
118 }
119
120 warn "# max_len = ",dump( \@max_len );
121 warn "# line_parts = ",dump( \@line_parts );
122
123 #print "$_\n" foreach @lines;
124
125 my $fmt = "%$max_len[0]s %-$max_len[1]s %$max_len[2]s %-$max_len[3]s\n";
126
127 my $x = 30.00; # mm
128 my $y = 30.00; # mm
129
130 if ( $opt_svg ) {
131         print qq{<?xml version="1.0" encoding="UTF-8" standalone="no"?>
132 <svg
133    xmlns:dc="http://purl.org/dc/elements/1.1/"
134    xmlns:cc="http://creativecommons.org/ns#"
135    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
136    xmlns:svg="http://www.w3.org/2000/svg"
137    xmlns="http://www.w3.org/2000/svg"
138    xmlns:xlink="http://www.w3.org/1999/xlink"
139    id="svg8"
140    version="1.1"
141    viewBox="0 0 210 297"
142    height="297mm"
143    width="210mm">
144
145
146 <g id="layer1">
147
148         }; # svg, insert rest of rect
149
150         print qq{<rect x="0" y="0" width="210" height="297" style="fill:#000000" id="high-contrast"/>} if $opt_invert;
151 }
152
153 my @later;
154
155 my $cols = {    # foreground background
156         txt  => [ '#000000', '#ffffff' ],
157         pins => [ '#ffffff', '#ff00ff' ],
158         vcc  => [ '#ff0000', '#ffff00' ],
159         gnd  => [ '#000000', '#00ffff' ],
160         i2c  => [ '#008800', '#ffcccc' ],
161         uart => [ '#000088', '#ccffcc' ],
162         spi  => [ '#880000', '#ccccff' ],
163 };
164
165 sub swap_cols {
166         my $swap = shift;
167         die "$swap not found in ",dump($cols) unless $cols->{$swap};
168         my ( $c1, $c2 ) = @{ $cols->{$swap} };
169         $cols->{$swap} = [ $c2, $c1 ];
170 }
171
172 swap_cols 'txt' if $opt_invert;
173         
174
175 sub svg_style {
176         my ($name,$x,$y,$col) = @_;
177         $y -= $font_b; # shift box overlay to right vertical position based on font baseline
178
179         sub rect {
180                 my ($x,$y,$col,$fill) = @_;
181                 print qq{<rect x="$x" y="$y" height="2.54" width="}, $max_len[$col] * $font_w, qq{" style="opacity:1;fill:$fill;stroke:#ffffff;stroke-width:0.10" />\n};
182
183         }
184
185         if ( $name =~ m/^(\d+)$/ ) { # pins
186                 my $pin = $1;
187                 my ( $fg, $bg ) = @{ $cols->{pins} };
188                 if ( $pin == 1 ) {
189                         my $w  = $max_len[$col]*$font_w - 0.1;
190                         my $cx = $x + $w;
191                         my $cy = $y + 2.54;
192                         #print qq{<polygon points="$x,$y $cx,$y $x,$cy $x,$y" stroke="$fg" stroke-width="0.25" fill="$bg" />};
193                         #print qq{<polygon points="$x,$cy $cx,$cy $cx,$y $x,$cy" stroke="$bg" stroke-width="0.25" fill="$fg" />};
194                         print qq{<rect x="$x" y="$y" width="$w" height="2.54" stroke="$fg" stroke-width="0.3" fill="$bg" />};
195                         my ( $fg, $bg ) = @{ $cols->{txt} };
196                         print qq{<rect x="$x" y="$y" width="$w" height="2.54" rx="1" ry="1" stroke="$fg" stroke-width="0.3" fill="$bg" />};
197                 } else {
198                         rect $x,$y,$col,$fg;
199                 }
200                 return qq{ style="fill:$bg"};
201         }
202
203         if ( $name =~ m/(VCC|3V3|3.3V)/i ) {
204                 my ($fg,$bg) = @{ $cols->{vcc} };
205                 rect $x,$y,$col,$bg;
206                 return qq{ style="fill:$fg"};
207         } elsif ( $name =~ m/(G(ND|Round)|VSS)/i ) {
208                 my ($fg,$bg) = @{ $cols->{gnd} };
209                 rect $x,$y,$col,$bg;
210                 return qq{ style="fill:$fg"};
211         } elsif ( $name =~ m/\[(\w+)\d/ ) { # kernel
212                 my $dev = $1;
213                 if ( my ($fg,$bg) = @{ $cols->{$dev} } ) {
214                         rect $x,$y,$col,$bg;
215                         return qq{ style="fill:$fg"};
216                 }
217         } else {
218                 my ( $fg, $bg ) = @{ $cols->{txt} };
219                 rect $x,$y,$col,$bg;
220                 #return qq{ style="fill:$fg"};
221                 return '';
222         }
223 }
224
225 my $alt_col = 0;
226
227 my @cols_order = ( 0,1,2,3 );
228 my @cols_align = ( '','-','','-' ); # sprintf prefix
229
230 @cols_order = ( 0,1,3,2 ); # pins outside on the right
231 @cols_align = ( '','-','-','' );
232
233
234 # cut marks
235 my ($fg,$bg) = @{ $cols->{txt} };
236 my $line_fmt = qq{<line x1="%s" y1="%s" x2="%s" y2="%s" style="stroke:$fg;stroke-width:0.10;fill:$bg" />\n};
237
238 my @cut_marks;
239 sub cut_mark {
240         my ($x,$y) = @_;
241         return unless $opt_svg;
242         push @cut_marks, sprintf($line_fmt, $x-5, $y-$font_b,   $x+5, $y-$font_b);
243         push @cut_marks, sprintf($line_fmt, $x,   $y-$font_b-5, $x,   $y-$font_b+5);
244 }
245 cut_mark $x, $y;
246 my $max_x = $x;
247 $max_x += $max_len[$_] * $font_w foreach ( 0 .. 3 );
248 cut_mark $max_x, $y;
249
250 my $last_cut_mark = 0;
251
252 foreach my $i ( 0 .. $#line_parts ) {
253         $i = $#line_parts - $i if $opt_vertical;
254         my $line = $line_parts[$i];
255
256         if ( $opt_svg ) {
257
258                 if ( ! exists $line->[0] ) {
259                         # before first empty line
260                         if ( $last_cut_mark == 0 ) {
261                                 cut_mark $x, $y;
262                                 cut_mark $max_x, $y;
263                                 $last_cut_mark = 1;
264                                 $y += 15; # make spacing between pinouts
265                         }
266                 } elsif ( $last_cut_mark ) {
267                         # first full line
268                         cut_mark $x, $y;
269                         cut_mark $max_x, $y;
270                         $last_cut_mark = 0;
271                 } else {
272                         #warn "CUTMARK no magic";
273                 }
274
275                 my ($fg,$bg) = @{ $cols->{txt} };
276                 my $tspan = qq{<tspan x="$x" y="$y" style="line-height:2.54;fill-opacity:1;fill:$fg;stroke:none;">\n};
277
278                 my $x_pos = $x;
279                 foreach my $i ( @cols_order ) {
280                         next unless $line->[$i];
281                         my $text_anchor = 'middle';
282                         my $x2 = $x_pos + ( $max_len[$i] * $font_w ) / 2;
283                         $tspan .= qq{<tspan x="$x2" text-anchor="$text_anchor"}.svg_style($line->[$i],$x_pos,$y,$i).sprintf( '>%' . $cols_align[$i] . $max_len[$i] . 's</tspan>', $line->[$i]);
284                         $x_pos += $max_len[$i] * $font_w;
285                 }
286
287                 $tspan .= qq{</tspan>\n};
288                 push @later,sprintf $tspan, @$line;
289                 $y += 2.54;
290
291                 # swap pin colors for line stripes
292                 swap_cols $_ foreach qw( pins txt );
293
294         } else {
295
296                 if ( $#$line == 0 ) {
297                         print $line->[0], "\n";
298                 } else {
299                         push @$line, '' while ($#$line < 3); # fill-in single row header
300                         printf $fmt, @$line;
301                 }
302
303         }
304 }
305
306 if ( $opt_svg ) {
307         print qq{
308     <text
309        id="text4506"
310        y="$x"
311        x="$y"
312        style="font-size:2.34px;line-height:2.54px;font-family:'Andale Mono';fill-opacity:1;stroke:none;stroke-opacity:1"
313        xml:space="preserve">
314
315         }; #svg
316
317         print @later, qq{</text>\n}, @cut_marks, qq{</g>\n</svg>};
318
319 }
320
321 __DATA__
322 # Cubietech Cubieboard2
323 ## U14 (Next to SATA connector)
324 ###     SPI0
325 48      PI13 (SPI0-MISO/UART6-RX/EINT25)        47      PI11 (SPI0-CLK/UART5-RX/EINT23)
326 46      PI12 (SPI0-MOSI/UART6-TX/EINT24)        45      PI10 (SPI0-CS/UART5-TX/EINT22)
327 ###     LCD
328 44      3.3V (nc in 2012-08-08)                 43      VCC-5V
329 42      Ground                                  41      SPDIF
330 40      PB10 (LCD0-SCK/LCD-PIO1)                39      PB11 (LCD0-SDA/LCD-PIO2)
331 38      Ground                                  37      PH7 (LCD0-BL-EN/LCD-PIO0/UART5-RX/EINT7)
332 36      XN_TP (TP-X2)                           35      YN_TP (TP-Y2)
333 34      XP_TP (TP-X1)                           33      YP_TP (TP-Y1)
334 32      PD25 (LCDDE)                            31      PB2 (PWM0)
335 30      PD26 (LCDHSYNC/VGA-HSYNC)               29      PD24 (LCDCLK)
336 28      PD23 (LCDD23)                           27      PD27 (LCDVSYNC/VGA-VSYNC)
337 26      PD21 (LCDD21)                           25      PD22 (LCDD22)
338 24      PD19 (LCDD19/LVDS1N3)                   23      PD20 (LCDD20)
339 22      PD17 (LCDD17/LVDS1NC)                   21      PD18 (LCDD18/LVDS1P3)
340 20      Ground                                  19      PD16 (LCDD16/LVDS1PC)
341 18      PD14 (LCDD14/LVDS1P2)                   17      PD15 (LCDD15/LVDS1N2)
342 16      PD12 (LCDD12/LVDS1P1)                   15      PD13 (LCDD13/LVDS1N1)
343 14      PD10 (LCDD10/LVDS1P0)                   13      PD11 (LCDD11/LVDS1N0)
344 12      PD8 (LCDD8/LVDS0P3)                     11      PD9 (LCDD9/LVDS0N3)
345 10      PD7 (LCDD7/LVDS0NC)                     9       Ground
346 8       PD5 (LCDD5/LVDS0N2)                     7       PD6 (LCDD6/LVDS0PC)
347 6       PD3 (LCDD3/LVDS0N1)                     5       PD4 (LCDD4/LNVS0P2)
348 4       PD1 (LCDD1/LVDS0N0)                     3       PD2 (LCDD2/LVDS0P1)
349 2       Ground                                  1       PD0 (LCDD0/LVDSP0)
350
351 # Cubietech Cubieboard2
352 ## U15 (Between Ethernet port and USB ports)
353 ### CSI1/TS
354 1       VCC-5V                                  2       PH15 (CSI1-PWR/EINT15)
355 3       CSI1-IO-2V8                             4       PH14 (CSI1-RST#/EINT14)
356 5       PG0 (CSI1-PCLK/SDC1-CMD)                6       PB18 (TWI1-SCK)
357 7       PB19 (TWI1-SDA)                         8       PG3 (CSI1-VSYNC/SDC1-D1)
358 9       PG2 (CSI1-HSYNC/SDC1-D0)                10      PG1 (CSI1-MCLK/SDC1-CLK)
359 11      PG4 (CSI1-D0/SDC1-D2)                   12      PG5 (CSI1-D1/SDC1-D3)
360 13      PG6 (CSI1-D2/UART3-TX)                  14      PG7 (CSI1-D3/UART3-RX)
361 15      PG8 (CSI1-D4/UART3-RTS)                 16      PG9 (CSI1-D5/UART3-CTS)
362 17      PG10 (CSI1-D6/UART4-TX)                 18      PG11 (CSI1-D7/UART4-RX)
363 19      Ground                                  20      Ground
364 ###     Analog SDIO3
365 21      FMINL                                   22      PI4 (SDC3-CMD)
366 23      FMINR                                   24      PI5 (SDC3-CLK)
367 25      Ground                                  26      PI6 (SDC3-D0)
368 27      VGA-R                                   28      PI7 (SDC3-D1)
369 29      VGA-G                                   30      PI8 (SDC3-D2)
370 31      VGA-B                                   32      PI9 (SDC3-D3)
371 ###     CSI0/TS
372 33      LCD1-VSYNC                              34      PE4 (CSI0-D0)
373 35      LCD1-HSYNC                              36      PE5 (CSI0-D1)
374 37      Ground                                  38      PE6 (CSI0-D2)
375 39      AVCC                                    40      PE7 (CSI0-D3)
376 41      LRADC0                                  42      PE8 (CSI0-D4)
377 43      CVBS                                    44      PE9 (CSI0-D5)
378 45      HPL                                     46      PE10 (CSI0-D6)
379 47      HPR                                     48      PE11 (CSI0-D7)
380
381 ## DEBUG serial (middle of board)
382 4       PB22 (UART0-TX)
383 3       PB23 (UART0-RX)
384 2       VCC-3V3
385 1       GND
386
387
388 # Lamobo R1
389 ## CON3 rpi DIP26-254
390 1       3.3v                    2       5v     
391 3       PB20 SDA.1              4       5V     
392 5       PB21 SCL.1              6       0v     
393 7       PI3 PWM1                8       PH0 UART3_TX
394 9       0v                      10      PH1 UART3_RX
395 11      PI19 UART2_RX           12      PH2
396 13      PI18 UART2_TX           14      0v     
397 15      PI17 UART2_CTS          16      PH21 CAN_RX 
398 17      3.3v                    18      PH20 CAN_TX 
399 19      PI12 SPI0_MOSI          20      0v     
400 21      PI13 SPI0_MISO          22      PI16 UART2_RTS   
401 23      PI11 SPI0_SCLK          24      PI10 SPI0_CS0    
402 25      0v                      26      PI14 SPI0_CS1
403
404 ## J13 DIP2-254
405 2       PB22 UART0_TX
406 1       PB23 UART0_RX
407
408 ## J12 DIP8-254
409 8       GND                     7       GND
410 6       PI20 UART7_TX           5       PH3
411 4       PI21 UART7_RX           3       PH5
412 2       3V3                     1       SATA-5V
413
414 # Raspberry Pi 3 Model B Rev 1.2
415 1       3.3v                    2       5v
416 3       gpio2 (SDA.1)           4       5v
417 5       gpio3 (SCL.1)           6       0v
418 7       gpio4 (GPIO. 7)         8       gpio14  (TxD)
419 9       0v                      10      gpio15  (RxD)
420 11      gpio17 (GPIO. 0)        12      gpio18  (GPIO. 1)
421 13      gpio27 (GPIO. 2)        14      0v
422 15      gpio22 (GPIO. 3)        16      gpio23  (GPIO. 4)
423 17      3.3v                    18      gpio24  (GPIO. 5)
424 19      gpio10 (MOSI)           20      0v
425 21      gpio9 (MISO)            22      gpio25  (GPIO. 6) 
426 23      gpio11 (SCLK)           24      gpio8   (CE0)
427 25      0v                      26      gpio7   (CE1)
428 27      gpio0 (SDA.0)           28      gpio1   (SCL.0)
429 29      gpio5 (GPIO.21)         30      0v
430 31      gpio6 (GPIO.22)         32      gpio12  (GPIO.26)
431 33      gpio13 (GPIO.23)        34      0v
432 35      gpio19 (GPIO.24)        36      gpio16  (GPIO.27)
433 37      gpio26 (GPIO.25)        38      gpio20  (GPIO.28)
434 39      0v                      40      gpio21  (GPIO.29)