Implement ard-parse-boards with shell scripting instead of Perl.

Working towards dropping the dependency on Perl (which very few Windows users
have), this commit implements the required functionality from ard-parse-boards
in a few shell commands from within the Makefile.

Fix #100
This commit is contained in:
Christopher Peplin 2013-07-02 17:57:57 -04:00 committed by Sudar
parent df88db2cfb
commit 87e29ea806
3 changed files with 19 additions and 294 deletions

View file

@ -14,6 +14,7 @@ The following is the rough list of changes that went into different versions. I
- Move binary sketch size verification logic inside makefile. Fix issue #54
- Remove dependency on wait-connection-leonardo shell script. Fix issue #95
- Add support for the Digilent chipKIT platform. (https://github.com/peplin)
- Implement ard-parse-boards with shell scripting instead of Perl (https://github.com/peplin)
### 0.12.0 (2013-06-20)
- Fix "generated_assembly" target, which got broken earlier. Fix issue #76 (https://github.com/matthijskooijman)

View file

@ -29,7 +29,7 @@
#
# We need to worry about three different sorts of file:
#
# 1. Things which are included in this distribution e.g. ard-parse-boards
# 1. Things which are included in this distribution e.g. ard-reset-arduino
# => ARDMK_DIR
#
# 2. Things which are always in the Arduino distribution e.g.
@ -100,7 +100,7 @@
# ARDUINO_PORT - The port where the Arduino can be found (only needed
# when uploading)
#
# BOARD_TAG - The ard-parse-boards tag for the board e.g. uno or mega
# BOARD_TAG - The tag for the board e.g. uno or mega
# 'make show_boards' shows a list
#
# If you have your additional libraries relative to your source, rather
@ -507,78 +507,71 @@ else
endif
ifndef PARSE_BOARD
PARSE_BOARD = $(ARDMK_PATH)/ard-parse-boards
endif
ifndef PARSE_BOARD_OPTS
PARSE_BOARD_OPTS = --boards_txt=$(BOARDS_TXT)
# result = $(call READ_BOARD_TXT, 'boardname', 'parameter')
PARSE_BOARD = $(shell grep $(1).$(2) $(BOARDS_TXT) | cut -d = -f 2 )
endif
# If NO_CORE is set, then we don't have to parse boards.txt file
# But the user might have to define MCU, F_CPU etc
ifeq ($(strip $(NO_CORE)),)
ifndef PARSE_BOARD_CMD
PARSE_BOARD_CMD = $(PARSE_BOARD) $(PARSE_BOARD_OPTS)
endif
# Which variant ? This affects the include path
ifndef VARIANT
VARIANT = $(shell $(PARSE_BOARD_CMD) $(BOARD_TAG) build.variant)
VARIANT = $(call PARSE_BOARD,$(BOARD_TAG),build.variant)
endif
# processor stuff
ifndef MCU
MCU = $(shell $(PARSE_BOARD_CMD) $(BOARD_TAG) build.mcu)
MCU = $(call PARSE_BOARD,$(BOARD_TAG),build.mcu)
endif
ifndef F_CPU
F_CPU = $(shell $(PARSE_BOARD_CMD) $(BOARD_TAG) build.f_cpu)
F_CPU = $(call PARSE_BOARD,$(BOARD_TAG),build.f_cpu)
endif
ifeq ($(VARIANT),leonardo)
# USB IDs for the Leonardo
ifndef USB_VID
USB_VID = $(shell $(PARSE_BOARD_CMD) $(BOARD_TAG) build.vid 2>/dev/null)
USB_VID = $(call PARSE_BOARD,$(BOARD_TAG),build.vid)
endif
ifndef USB_PID
USB_PID = $(shell $(PARSE_BOARD_CMD) $(BOARD_TAG) build.pid 2>/dev/null)
USB_PID = $(call PARSE_BOARD,$(BOARD_TAG),build.pid)
endif
endif
# normal programming info
ifndef AVRDUDE_ARD_PROGRAMMER
AVRDUDE_ARD_PROGRAMMER = $(shell $(PARSE_BOARD_CMD) $(BOARD_TAG) upload.protocol)
AVRDUDE_ARD_PROGRAMMER = $(call PARSE_BOARD,$(BOARD_TAG),upload.protocol)
endif
ifndef AVRDUDE_ARD_BAUDRATE
AVRDUDE_ARD_BAUDRATE = $(shell $(PARSE_BOARD_CMD) $(BOARD_TAG) upload.speed)
AVRDUDE_ARD_BAUDRATE = $(call PARSE_BOARD,$(BOARD_TAG),upload.speed)
endif
# fuses if you're using e.g. ISP
ifndef ISP_LOCK_FUSE_PRE
ISP_LOCK_FUSE_PRE = $(shell $(PARSE_BOARD_CMD) $(BOARD_TAG) bootloader.unlock_bits)
ISP_LOCK_FUSE_PRE = $(call PARSE_BOARD,$(BOARD_TAG),bootloader.unlock_bits)
endif
ifndef ISP_HIGH_FUSE
ISP_HIGH_FUSE = $(shell $(PARSE_BOARD_CMD) $(BOARD_TAG) bootloader.high_fuses)
ISP_HIGH_FUSE = $(call PARSE_BOARD,$(BOARD_TAG),bootloader.high_fuses)
endif
ifndef ISP_LOW_FUSE
ISP_LOW_FUSE = $(shell $(PARSE_BOARD_CMD) $(BOARD_TAG) bootloader.low_fuses)
ISP_LOW_FUSE = $(call PARSE_BOARD,$(BOARD_TAG),bootloader.low_fuses)
endif
ifndef ISP_EXT_FUSE
ISP_EXT_FUSE = $(shell $(PARSE_BOARD_CMD) $(BOARD_TAG) bootloader.extended_fuses)
ISP_EXT_FUSE = $(call PARSE_BOARD,$(BOARD_TAG),bootloader.extended_fuses)
endif
ifndef ISP_LOCK_FUSE_POST
ISP_LOCK_FUSE_POST = $(shell $(PARSE_BOARD_CMD) $(BOARD_TAG) bootloader.lock_bits)
ISP_LOCK_FUSE_POST = $(call PARSE_BOARD,$(BOARD_TAG),bootloader.lock_bits)
endif
ifndef HEX_MAXIMUM_SIZE
HEX_MAXIMUM_SIZE = $(shell $(PARSE_BOARD_CMD) $(BOARD_TAG) upload.maximum_size)
HEX_MAXIMUM_SIZE = $(call PARSE_BOARD,$(BOARD_TAG),upload.maximum_size)
endif
endif
@ -1076,7 +1069,7 @@ size: $(TARGET_HEX)
$(call avr_size,$(TARGET_ELF),$(TARGET_HEX))
show_boards:
$(PARSE_BOARD_CMD) --boards
@cat $(BOARDS_TXT) | grep -E "^[[:alnum:]]" | cut -d . -f 1 | uniq
monitor:
$(MONITOR_CMD) $(call get_arduino_port) $(MONITOR_BAUDRATE)

View file

@ -1,269 +0,0 @@
#! /usr/bin/env perl
use strict;
use warnings;
use Getopt::Long;
use Pod::Usage;
use YAML;
# TODO: If you writing an installation script or a package for the makefile,
# then you might want to replace the below path based on the environment.
# More discussion at https://github.com/sudar/Arduino-Makefile/issues/50
my %Opt =
(
boards_txt => '/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/boards.txt',
);
# if the ARDUINO_DIR is defined, then use it
if (defined $ENV{'ARDUINO_DIR'}) {
$Opt{boards_txt} = "$ENV{'ARDUINO_DIR'}/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.