summaryrefslogtreecommitdiffstats
path: root/ard-parse-boards
blob: e2de71b23d4c5a39472faa4f1ae3953f04231ca9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
#! /usr/bin/perl

use strict;
use warnings;

use Getopt::Long;
use Pod::Usage;
use YAML;

my %Opt = 
  (
   boards_txt => '/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/boards.txt',
  );

GetOptions(\%Opt,
	   "boards_txt=s", # filename of the boards.txt file
	   "find!",        # search for data
	   "dump!",        # dump the whole database
	   "boards!",      # dump a list of boards
	   "help!",  
	   "info!",
	  );

if ($Opt{help} || $Opt{info})
  {
    usage();
  }

my $db = parse_boards($Opt{boards_txt});

if ($Opt{dump}) 
  { 
    dump_data("$Opt{boards_txt} contains:", $db);
  }
elsif ($Opt{find})
  {
    my @terms = @ARGV or usage();
    find_data($db, \@terms);
  }
elsif ($Opt{boards})
  {
    dump_boards($db);
  }
else
  {
    my $tag = shift @ARGV or usage();
    
    if (my $key = shift @ARGV)
      {
	die "$key isn't defined for the $tag board, "
	  unless $db->{$tag} && exists $db->{$tag}->{$key};

	print $db->{$tag}->{$key}, "\n";
      }
    else
      {
	die "The $tag board isn't defined, "
	  unless $db->{$tag};

	dump_data("The $tag board:", $db->{$tag});
      }
  }

## here endeth the main

sub usage 
  {
    pod2usage(-verbose => 2);
  }

# return HoH: {board}->{field} = value
sub parse_boards
  {
    my $filename = shift;

    my %b;

    open(my $fh, '<', $filename) 
      or die "Can't open $filename, ";

    while(<$fh>)
      {
	my ($board, $key, $value) = /^\s*(\S+?)\.(\S+?)\s*=\s*(.+?)\s*$/
	  or next;

	$b{$board}->{$key} = $value;
      }

    return \%b;
  }

# A rudimentary search engine
sub find_data
  {
    my ($db, $term_list) = @_;

    my @q = map { qr/$_/i } @$term_list;
    my $q = join(' && ', map { "/$_/i" } @$term_list);

    my %hit;
    foreach my $b (keys %$db)
      {
	foreach my $k (keys %{$db->{$b}})
	  {
	    my $v = $db->{$b}->{$k};
	    $hit{$b}->{$k} = $v if !grep { $v !~ /$_/i } @q;
	  }
      }

    dump_data("Matches for $q:", \%hit);
  }

# The list of boards...
sub dump_boards
  {
    my $db = shift or return;

    my %name;
    my $max_l = 0;
    foreach my $b (keys %$db)
      {
	$name{$b} = $db->{$b}->{name} || 'Anonymous';
	$max_l    = length($b) if $max_l < length($b);
      }

    my $fmt = sprintf("%%-%ds %%s\n", $max_l + 2);

    printf $fmt, "Tag", "Board Name";
    foreach my $b (sort keys %name)
      {
	printf $fmt, $b, $name{$b};
      }
  }


# dump arbitrary data with a title
sub dump_data
  {
    my ($title, $data) = @_;

    print "# $title\n", Dump($data);
  }

__END__

=head1 NAME
 
ard-parse-boards - Read data from the Arduino boards.txt file
  
=head1 USAGE
 
    Dump all the data in the file:
    $ ard-parse-boards --dump

    See which boards we know about:
    $ ard-parse-boards --boards

    Look for a particular board...
    $ ard-parse-boards --find uno

    ...multiple terms are implicitly ANDed:
    $ ard-parse-boards --find duemil 328

    Dump all the data for a particular board:
    $ ard-parse-boards atmega328

    Extract a particular field:
    $ ard-parse-boards atmega328 build.f_cpu
 
=head1 DESCRIPTION

The Arduino software package ships with a boards.txt file which tells
the Arduino IDE details about particular hardware. So when the user
says he's got a shiny new Arduino Uno, boards.txt knows that it has a
16MHz ATmega328 on it. It would be nice to access these data from the
command line too.

In normal operation you simply specify the tag given to the board in
the boards.txt file, and optionally a field name. This program then
extracts the data to STDOUT.

Most boards have names which are quite unwieldy, so we always refer to
a board by a tag, not its name. Strictly the tag is the bit before the
first dot in the boards.txt key. You can see a list of board tags and
names with the C<--boards> option.

=head1 OPTIONS

=over

=item --boards_txt=[file]

Specify the full path to the boards.txt file.

=back
 
The following options all disable the normal 'lookup' operation.

=over

=item --dump 

Dump the complete database in YAML format.

=item ---boards

Print a list of the tag and name of every board in the file.

=item --find [query] <query> ...

Find matching data. Strictly, return a list of values which match all
of the query terms, treating each term as a case-insensitive regexp.

For example:

=over

=item --find 328

List data containing 328 (anywhere in the value).

=item --find due

List data containing 'due' (e.g. duemilanove).

=item --find 328 due

List data containing both 328 and due.

=back

=back
 
=head1 BUGS AND LIMITATIONS

There are no known bugs in this application.

Please report problems to the author.

Patches are welcome.
 
=head1 AUTHOR

Martin Oldfield, ex-atelier@mjo.tc

Thanks to Mark Sproul who suggested doing something like this to me ages ago.
 
=head1 LICENCE AND COPYRIGHT
 
Copyright (c) 2011, Martin Oldfield. All rights reserved.
 
This file is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.