Initial commit.

pull/1/head
Christopher Young 2015-08-07 13:37:02 -04:00
rodzic a203e84c97
commit 61e9bb56ea
49 zmienionych plików z 7781 dodań i 0 usunięć

3
dump978/.gitignore vendored 100644
Wyświetl plik

@ -0,0 +1,3 @@
*~
*.o
dump978

340
dump978/LICENSE 100644
Wyświetl plik

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 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. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

33
dump978/Makefile 100644
Wyświetl plik

@ -0,0 +1,33 @@
CFLAGS+=-O2 -g -Wall -Werror -Ifec
LDFLAGS=
LIBS=-lm
CC=gcc
all: dump978 uat2json uat2text uat2esnt extract_nexrad
%.o: %.c *.h
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
dump978: dump978.o fec.o fec/decode_rs_char.o fec/init_rs_char.o
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS)
uat2json: uat2json.o uat_decode.o reader.o
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS)
uat2text: uat2text.o uat_decode.o reader.o
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS)
uat2esnt: uat2esnt.o uat_decode.o reader.o
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS)
extract_nexrad: extract_nexrad.o uat_decode.o reader.o
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS)
fec_tests: fec_tests.o fec.o fec/decode_rs_char.o fec/init_rs_char.o
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS)
test: fec_tests
./fec_tests
clean:
rm -f *~ *.o fec/*.o dump978 uat2json uat2text uat2esnt fec_tests

124
dump978/README.md 100644
Wyświetl plik

@ -0,0 +1,124 @@
# dump978
Experimental demodulator/decoder for 978MHz UAT signals.
## A note about future development
I'm in Europe which doesn't use UAT, so there won't be much spontaneous
development going on now that the demodulator is at a basic "it works" stage.
I'm happy to look at signal or message captures and help with further
development, but it really needs to be driven by whoever is actually using the
code to receive UAT!
## Demodulator
dump978 is the demodulator. It expects 8-bit I/Q samples on stdin at
2.083334MHz, for example:
````
$ rtl_sdr -f 978000000 -s 2083334 -g 48 - | ./dump978
````
It outputs one one line per demodulated message, in the form:
````
+012345678..; this is an uplink message
-012345678..; this is a downlink message
````
For parsers: ignore everything between the first semicolon and newline that
you don't understand, it will be used for metadata later. See reader.[ch] for
a reference implementation.
## Decoder
To decode messages into a readable form use uat2text:
````
$ rtl_sdr -f 978000000 -s 2083334 -g 48 - | ./dump978 | ./uat2text
````
## Sample data
Around 1100 sample messages are in the file sample-data.txt.gz. They are the
output of the demodulator from various RF captures I have on hand. This file
can be fed to uat2text etc:
$ zcat sample-data.txt.gz | ./uat2text
When testing, this is much easier on your CPU (and disk space!) than starting
from the raw RF captures.
## Filtering for just uplink or downlink messages
As the uplink and downlink messages start with different characters, you can
filter for just one type of message very easily with grep:
````
# Uplink messages only:
$ zcat sample-data.txt.gz | grep "^+" | ./uat2text
# Downlink messages only:
$ zcat sample-data.txt.gz | grep "^-" | ./uat2text
````
## Map generation via uat2json
uat2json writes aircraft.json files in the format expected by dump1090's
map html/javascript.
To set up a live map feed:
1) Get a copy of dump1090, we're going to reuse its mapping html/javascript:
````
$ git clone https://github.com/mutability/dump1090 dump1090-copy
````
2) Put the html/javascript somewhere your webserver can reach:
````
$ mkdir /var/www/dump978map
$ cp -a dump1090-copy/public_html/* /var/www/dump978map/
````
3) Create an empty "data" subdirectory
````
$ mkdir /var/www/dump978map/data
````
4) Feed uat2json from dump978:
````
$ rtl_sdr -f 978000000 -s 2083334 -g 48 - | \
./dump978 | \
./uat2json /var/www/dump978map/data
````
5) Go look at http://localhost/dump978map/
## uat2esnt: convert UAT ADS-B messages to Mode S ADS-B messages.
Warning: This one is particularly experimental.
uat2esnt accepts 978MHz UAT downlink messages on stdin and
generates 1090MHz Extended Squitter messages on stdout.
The generated messages mostly use DF18 with CF=6, which is
for rebroadcasts of ADS-B messages (ADS-R).
The output format is the "AVR" text format; this can be
fed to dump1090 on port 30001 by default. Other ADS-B tools
may accept it too - e.g. VRS seems to accept most of it (though
it ignores DF18 CF=5 messages which are generated for
non-ICAO-address callsign/squawk information.
You'll want a pipeline like this:
````
$ rtl_sdr -f 978000000 -s 2083334 -g 48 - | \
./dump978 | \
./uat2esnt | \
nc -q1 localhost 30001
````

429
dump978/dump978.c 100644
Wyświetl plik

@ -0,0 +1,429 @@
//
// Copyright 2015, Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file 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. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include "uat.h"
#include "fec.h"
static void make_atan2_table();
static void read_from_stdin();
static int process_buffer(uint16_t *phi, int len, uint64_t offset);
static int demod_adsb_frame(uint16_t *phi, uint8_t *to, int *rs_errors);
static int demod_uplink_frame(uint16_t *phi, uint8_t *to, int *rs_errors);
static void demod_frame(uint16_t *phi, uint8_t *frame, int bytes, int16_t center_dphi);
static void handle_adsb_frame(uint64_t timestamp, uint8_t *frame, int rs);
static void handle_uplink_frame(uint64_t timestamp, uint8_t *frame, int rs);
#define SYNC_BITS (36)
#define ADSB_SYNC_WORD 0xEACDDA4E2UL
#define UPLINK_SYNC_WORD 0x153225B1DUL
// relying on signed overflow is theoretically bad. Let's do it properly.
#ifdef USE_SIGNED_OVERFLOW
#define phi_difference(from,to) ((int16_t)((to) - (from)))
#else
inline int16_t phi_difference(uint16_t from, uint16_t to)
{
int32_t difference = to - from; // lies in the range -65535 .. +65535
if (difference >= 32768) // +32768..+65535
return difference - 65536; // -> -32768..-1: always in range
else if (difference < -32768) // -65535..-32769
return difference + 65536; // -> +1..32767: always in range
else
return difference;
}
#endif
int main(int argc, char **argv)
{
make_atan2_table();
init_fec();
read_from_stdin();
return 0;
}
static void dump_raw_message(char updown, uint8_t *data, int len, int rs_errors)
{
int i;
fprintf(stdout, "%c", updown);
for (i = 0; i < len; ++i) {
fprintf(stdout, "%02x", data[i]);
}
if (rs_errors)
fprintf(stdout, ";rs=%d", rs_errors);
fprintf(stdout, ";\n");
}
static void handle_adsb_frame(uint64_t timestamp, uint8_t *frame, int rs)
{
dump_raw_message('-', frame, (frame[0]>>3) == 0 ? SHORT_FRAME_DATA_BYTES : LONG_FRAME_DATA_BYTES, rs);
fflush(stdout);
}
static void handle_uplink_frame(uint64_t timestamp, uint8_t *frame, int rs)
{
dump_raw_message('+', frame, UPLINK_FRAME_DATA_BYTES, rs);
fflush(stdout);
}
uint16_t iqphase[65536]; // contains value [0..65536) -> [0, 2*pi)
void make_atan2_table()
{
unsigned i,q;
union {
uint8_t iq[2];
uint16_t iq16;
} u;
for (i = 0; i < 256; ++i) {
for (q = 0; q < 256; ++q) {
double d_i = (i - 127.5);
double d_q = (q - 127.5);
double ang = atan2(d_q, d_i) + M_PI; // atan2 returns [-pi..pi], normalize to [0..2*pi]
double scaled_ang = round(32768 * ang / M_PI);
u.iq[0] = i;
u.iq[1] = q;
iqphase[u.iq16] = (scaled_ang < 0 ? 0 : scaled_ang > 65535 ? 65535 : (uint16_t)scaled_ang);
}
}
}
static void convert_to_phi(uint16_t *buffer, int n)
{
int i;
for (i = 0; i < n; ++i)
buffer[i] = iqphase[buffer[i]];
}
void read_from_stdin()
{
char buffer[65536*2];
int n;
int used = 0;
uint64_t offset = 0;
while ( (n = read(0, buffer+used, sizeof(buffer)-used)) > 0 ) {
int processed;
convert_to_phi((uint16_t*) (buffer+(used&~1)), ((used&1)+n)/2);
used += n;
processed = process_buffer((uint16_t*) buffer, used/2, offset);
used -= processed * 2;
offset += processed;
if (used > 0) {
memmove(buffer, buffer+processed*2, used);
}
}
}
// Return 1 if word is "equal enough" to expected
static inline int sync_word_fuzzy_compare(uint64_t word, uint64_t expected)
{
uint64_t diff;
if (word == expected)
return 1;
diff = word ^ expected; // guaranteed nonzero
// This is a bit-twiddling popcount
// hack, tweaked as we only care about
// "<N" or ">=N" set bits for fixed N -
// so we can bail out early after seeing N
// set bits.
//
// It relies on starting with a nonzero value
// with zero or more trailing clear bits
// after the last set bit:
//
// 010101010101010000
// ^
// Subtracting one, will flip the
// bits starting at the last set bit:
//
// 010101010101001111
// ^
// then we can use that as a bitwise-and
// mask to clear the lowest set bit:
//
// 010101010101000000
// ^
// And repeat until the value is zero
// or we have seen too many set bits.
// >= 1 bit
diff &= (diff-1); // clear lowest set bit
if (!diff)
return 1; // 1 bit error
// >= 2 bits
diff &= (diff-1); // clear lowest set bit
if (!diff)
return 1; // 2 bits error
// >= 3 bits
diff &= (diff-1); // clear lowest set bit
if (!diff)
return 1; // 3 bits error
// >= 4 bits
diff &= (diff-1); // clear lowest set bit
if (!diff)
return 1; // 4 bits error
// > 4 bits in error, give up
return 0;
}
#define MAX_SYNC_ERRORS 4
// check that there is a valid sync word starting at 'phi'
// that matches the sync word 'pattern'. Place the dphi
// threshold to use for bit slicing in '*center'. Return 1
// if the sync word is OK, 0 on failure
int check_sync_word(uint16_t *phi, uint64_t pattern, int16_t *center)
{
int i;
int32_t dphi_zero_total = 0;
int zero_bits = 0;
int32_t dphi_one_total = 0;
int one_bits = 0;
int error_bits;
// find mean dphi for zero and one bits;
// take the mean of the two as our central value
for (i = 0; i < SYNC_BITS; ++i) {
int16_t dphi = phi_difference(phi[i*2], phi[i*2+1]);
if (pattern & (1UL << (35-i))) {
++one_bits;
dphi_one_total += dphi;
} else {
++zero_bits;
dphi_zero_total += dphi;
}
}
dphi_zero_total /= zero_bits;
dphi_one_total /= one_bits;
*center = (dphi_one_total + dphi_zero_total) / 2;
// recheck sync word using our center value
error_bits = 0;
for (i = 0; i < SYNC_BITS; ++i) {
int16_t dphi = phi_difference(phi[i*2], phi[i*2+1]);
if (pattern & (1UL << (35-i))) {
if (dphi < *center)
++error_bits;
} else {
if (dphi >= *center)
++error_bits;
}
}
//fprintf(stdout, "check_sync_word: center=%.0fkHz, errors=%d\n", *center * 2083334.0 / 65536 / 1000, error_bits);
return (error_bits <= MAX_SYNC_ERRORS);
}
#define SYNC_MASK ((((uint64_t)1)<<SYNC_BITS)-1)
int process_buffer(uint16_t *phi, int len, uint64_t offset)
{
uint64_t sync0 = 0, sync1 = 0;
int lenbits;
int bit;
uint8_t demod_buf_a[UPLINK_FRAME_BYTES];
uint8_t demod_buf_b[UPLINK_FRAME_BYTES];
// We expect samples at twice the UAT bitrate.
// We look at phase difference between pairs of adjacent samples, i.e.
// sample 1 - sample 0 -> sync0
// sample 2 - sample 1 -> sync1
// sample 3 - sample 2 -> sync0
// sample 4 - sample 3 -> sync1
// ...
//
// We accumulate bits into two buffers, sync0 and sync1.
// Then we compare those buffers to the expected 36-bit sync word that
// should be at the start of each UAT frame. When (if) we find it,
// that tells us which sample to start decoding from.
// Stop when we run out of remaining samples for a max-sized frame.
// Arrange for our caller to pass the trailing data back to us next time;
// ensure we don't consume any partial sync word we might be part-way
// through. This means we don't need to maintain state between calls.
lenbits = len/2 - (SYNC_BITS + UPLINK_FRAME_BITS);
for (bit = 0; bit < lenbits; ++bit) {
int16_t dphi0 = phi_difference(phi[bit*2], phi[bit*2+1]);
int16_t dphi1 = phi_difference(phi[bit*2+1], phi[bit*2+2]);
sync0 = ((sync0 << 1) | (dphi0 > 0 ? 1 : 0)) & SYNC_MASK;
sync1 = ((sync1 << 1) | (dphi1 > 0 ? 1 : 0)) & SYNC_MASK;
if (bit < SYNC_BITS)
continue; // haven't fully populated sync0/1 yet
// see if we have (the start of) a valid sync word
// It would be nice to look at popcount(expected ^ sync)
// so we can tolerate some errors, but that turns out
// to be very expensive to do on every sample
// when we find a match, try to demodulate both with that match
// and with the next position, and pick the one with fewer
// errors.
// check for downlink frames:
if (sync_word_fuzzy_compare(sync0, ADSB_SYNC_WORD) || sync_word_fuzzy_compare(sync1, ADSB_SYNC_WORD)) {
int startbit = (bit-SYNC_BITS+1);
int shift = (sync_word_fuzzy_compare(sync0, ADSB_SYNC_WORD) ? 0 : 1);
int index = startbit*2+shift;
int skip_0, skip_1;
int rs_0 = -1, rs_1 = -1;
skip_0 = demod_adsb_frame(phi+index, demod_buf_a, &rs_0);
skip_1 = demod_adsb_frame(phi+index+1, demod_buf_b, &rs_1);
if (skip_0 && rs_0 <= rs_1) {
handle_adsb_frame(offset+index, demod_buf_a, rs_0);
bit = startbit + skip_0;
continue;
} else if (skip_1 && rs_1 <= rs_0) {
handle_adsb_frame(offset+index+1, demod_buf_b, rs_1);
bit = startbit + skip_1;
continue;
} else {
// demod failed
}
}
// check for uplink frames:
else if (sync_word_fuzzy_compare(sync0, UPLINK_SYNC_WORD) || sync_word_fuzzy_compare(sync1, UPLINK_SYNC_WORD)) {
int startbit = (bit-SYNC_BITS+1);
int shift = (sync_word_fuzzy_compare(sync0, UPLINK_SYNC_WORD) ? 0 : 1);
int index = startbit*2+shift;
int skip_0, skip_1;
int rs_0 = -1, rs_1 = -1;
skip_0 = demod_uplink_frame(phi+index, demod_buf_a, &rs_0);
skip_1 = demod_uplink_frame(phi+index+1, demod_buf_b, &rs_1);
if (skip_0 && rs_0 <= rs_1) {
handle_uplink_frame(offset+index, demod_buf_a, rs_0);
bit = startbit + skip_0;
continue;
} else if (skip_1 && rs_1 <= rs_0) {
handle_uplink_frame(offset+index+1, demod_buf_b, rs_1);
bit = startbit + skip_1;
continue;
} else {
// demod failed
}
}
}
return (bit - SYNC_BITS)*2;
}
// demodulate 'bytes' bytes from samples at 'phi' into 'frame',
// using 'center_dphi' as the bit slicing threshold
static void demod_frame(uint16_t *phi, uint8_t *frame, int bytes, int16_t center_dphi)
{
while (--bytes >= 0) {
uint8_t b = 0;
if (phi_difference(phi[0], phi[1]) > center_dphi) b |= 0x80;
if (phi_difference(phi[2], phi[3]) > center_dphi) b |= 0x40;
if (phi_difference(phi[4], phi[5]) > center_dphi) b |= 0x20;
if (phi_difference(phi[6], phi[7]) > center_dphi) b |= 0x10;
if (phi_difference(phi[8], phi[9]) > center_dphi) b |= 0x08;
if (phi_difference(phi[10], phi[11]) > center_dphi) b |= 0x04;
if (phi_difference(phi[12], phi[13]) > center_dphi) b |= 0x02;
if (phi_difference(phi[14], phi[15]) > center_dphi) b |= 0x01;
*frame++ = b;
phi += 16;
}
}
// Demodulate an ADSB (Long UAT or Basic UAT) downlink frame
// with the first sync bit in 'phi', storing the frame into 'to'
// of length up to LONG_FRAME_BYTES. Set '*rs_errors' to the
// number of corrected errors, or 9999 if demodulation failed.
// Return 0 if demodulation failed, or the number of bits (not
// samples) consumed if demodulation was OK.
static int demod_adsb_frame(uint16_t *phi, uint8_t *to, int *rs_errors)
{
int16_t center_dphi;
int frametype;
if (!check_sync_word(phi, ADSB_SYNC_WORD, &center_dphi)) {
*rs_errors = 9999;
return 0;
}
demod_frame(phi + SYNC_BITS*2, to, LONG_FRAME_BYTES, center_dphi);
frametype = correct_adsb_frame(to, rs_errors);
if (frametype == 1)
return (SYNC_BITS + SHORT_FRAME_BITS);
else if (frametype == 2)
return (SYNC_BITS + LONG_FRAME_BITS);
else
return 0;
}
// Demodulate an uplink frame
// with the first sync bit in 'phi', storing the frame into 'to'
// of length up to UPLINK_FRAME_BYTES. Set '*rs_errors' to the
// number of corrected errors, or 9999 if demodulation failed.
// Return 0 if demodulation failed, or the number of bits (not
// samples) consumed if demodulation was OK.
static int demod_uplink_frame(uint16_t *phi, uint8_t *to, int *rs_errors)
{
int16_t center_dphi;
uint8_t interleaved[UPLINK_FRAME_BYTES];
if (!check_sync_word(phi, UPLINK_SYNC_WORD, &center_dphi)) {
*rs_errors = 9999;
return 0;
}
demod_frame(phi + SYNC_BITS*2, interleaved, UPLINK_FRAME_BYTES, center_dphi);
// deinterleave and correct
if (correct_uplink_frame(interleaved, to, rs_errors) == 1)
return (UPLINK_FRAME_BITS+SYNC_BITS);
else
return 0;
}

Wyświetl plik

@ -0,0 +1,315 @@
//
// Copyright 2015, Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file 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. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdio.h>
#include <math.h>
#include "uat.h"
#include "uat_decode.h"
#include "reader.h"
#define BLOCK_WIDTH (48.0/60.0)
#define WIDE_BLOCK_WIDTH (96.0/60.0)
#define BLOCK_HEIGHT (4.0/60.0)
#define BLOCK_THRESHOLD 405000
#define BLOCKS_PER_RING 450
//
// This reads demodulated uplink messages and extracts NEXRAD global block representation formats - type 63 and 64
//
// The output format is a series of lines, one line per decoded block.
// Each line is space-separated and is formatted as:
//
// NEXRAD <type> <hour>:<minute> <scale> <north> <west> <height> <width> <data>
//
// where:
// <type> is Regional (for type 63) or CONUS (for type 64)
// <hour>:<minute> is the time from the PDU header - all blocks from one composite radar image will have the same time
// <scale> is the scale value of this block - 0 (high res), 1 (med res), or 2 (low res)
// <north> is the north edge of the block, in _integer arcminutes_. Divide by 60 to get degrees.
// <west> is the west edge of the block, in _positive integer arcminutes_. Divide by 60 to get degrees; subtract 360 if you want the conventional -180..+180 range.
// <height> is the height of the block, in integer arcminutes of latitude
// <width> is the width of the block, in integer arcminutes of longitude
//
// Each block contains 128 evenly spaced bins, in a grid of 32 (longitude) x 4 (latitude), working west-to-east then north-to-south.
// i.e. each bin represents a pixel that covers <width>/32 arcminutes of longitude by <height>/4 arcminutes of latitude.
//
// <data> is a string of 128 digits (no spaces); each character represents the intensity of one bin, in the order above.
//
// Given:
// bn - block number
// ns - north/south flag
// sf - scale factor
//
// compute the northwest corner of the referenced block and place it in (*latN, *lonW)
// and place the total height and width of the block in (*latSize, *lonSize)
void block_location(int bn, int ns, int sf, double *latN, double *lonW, double *latSize, double *lonSize)
{
// With SF=0:
// blocks are (48 arcminutes longitude) x (4 arcminute latitude) between 0 and 60 degrees latitude
// (450 blocks for each ring of latitude)
// blocks are (96 arcminutes longitude) x (4 arcminute latitude) between 60 and 90 degrees latitude
// (225 blocks for each ring of latitude) - but the block numbering continues to use
// a 48-arcminute spacing, so only even numbered blocks are meaningful.
// block zero is immediately northeast of (0,0), then blocks are numbered east-to-west, south-to-north.
//
// Southern hemisphere numbering is mirrored around the equator, and indicated by the "ns" flag.
// ^N
// | 405446 | 405448 | 405000 | 405002 |
// --------------------------------------------------------- 60 00' 00" N
// |404996|404997|404998|404999|404550|404551|404552|404553|
// --------------------------------------------------------- 59 56' 00" N
// ...
// | 896 | 897 | 898 | 899 | 450 | 451 | 452 | 453 |
// --------------------------------------------------------- 00 04' 00" N
// | 446 | 447 | 447 | 449 | 0 | 1 | 2 | 3 |
//W<------------------------------------------------------->E equator
// | 446* | 447* | 447* | 449* | 0* | 1* | 2* | 3* |
// --------------------------------------------------------- 00 04' 00" S
// | 896* | 897* | 898* | 899* | 450* | 451* | 452* | 453* |
// 2d24'W 1d36'W 0d48'W V 0d48'E 1d36'E 2d24'E
// (* = ns_flag set)
// Each block is subdivided into 32 (longitude) x 4 (latitude) bins.
// The bins are numbered starting at the northwest corner of the block,
// west-to-east then north-to-south.
// block 0:
//
// ------------------------------------ <- 0d04m00s N
// | 0 1 2 3 ... 28 29 30 31| <- each bin is 1 arcminute tall
// | 32 33 34 35 ... 60 61 62 63|
// | 64 65 66 67 ... 92 93 94 95|
// | 96 97 98 99 ... 124 125 126 127|
// ------------------------------------ <- 0N - equator
// ^ ^ each bin is ^
// 0E 1.5 arcminute wide 0d48m00s E
// With SF=1, an identical block numbering is used to locate the northwest corner of the block,
// but then each bin is 5x larger in both axes i.e. 240 x 20 or 480 x 20 arcminutes.
// this means that the block data will actually overlap 24 other block positions.
// With SF=2, it works like SF=1 but with a scale factor of 9x.
double raw_lat, raw_lon;
double scale;
if (sf == 1)
scale = 5.0;
else if (sf == 2)
scale = 9.0;
else
scale = 1.0;
if (bn >= BLOCK_THRESHOLD) {
// 60-90 degrees - even-numbered blocks only
bn = bn & ~1;
}
raw_lat = BLOCK_HEIGHT * trunc(bn / BLOCKS_PER_RING);
raw_lon = (bn % BLOCKS_PER_RING) * BLOCK_WIDTH;
*lonSize = (bn >= BLOCK_THRESHOLD ? WIDE_BLOCK_WIDTH : BLOCK_WIDTH) * scale;
*latSize = BLOCK_HEIGHT * scale;
// raw_lat/raw_lon points to the southwest corner in the northern hemisphere version
*lonW = raw_lon;
if (ns) {
// southern hemisphere, mirror along the equator
*latN = 0 - raw_lat;
} else {
// adjust to the northwest corner
*latN = raw_lat + BLOCK_HEIGHT;
}
}
void decode_nexrad(struct fisb_apdu *fisb)
{
// Header:
//
// byte/bit 7 6 5 4 3 2 1 0
// 0 |RLE|NS | Scale | MSB Block # |
// 1 | Block # |
// 2 | Block # LSB |
int rle_flag = (fisb->data[0] & 0x80) != 0;
int ns_flag = (fisb->data[0] & 0x40) != 0;
int block_num = ((fisb->data[0] & 0x0f) << 16) | (fisb->data[1] << 8) | (fisb->data[2]);
int scale_factor = (fisb->data[0] & 0x30) >> 4;
// now decode the bins
if (rle_flag) {
// One bin, 128 values, RLE-encoded
int i;
double latN = 0, lonW = 0, latSize = 0, lonSize = 0;
block_location(block_num, ns_flag, scale_factor, &latN, &lonW, &latSize, &lonSize);
fprintf(stdout, "NEXRAD %s %02d:%02d %d %.0f %.0f %.0f %.0f ",
fisb->product_id == 63 ? "Regional" : "CONUS",
fisb->hours,
fisb->minutes,
scale_factor,
latN * 60,
lonW * 60,
latSize * 60,
lonSize * 60);
// each byte following the header is:
// 7 6 5 4 3 2 1 0
// | runlength - 1 | intensity |
for (i = 3; i < fisb->length; ++i) {
int intensity = fisb->data[i] & 7;
int runlength = (fisb->data[i] >> 3) + 1;
while (runlength-- > 0)
fprintf(stdout, "%d", intensity);
}
fprintf(stdout, "\n");
} else {
int L = fisb->data[3] & 15;
int i;
int row_start, row_offset, row_size;
//
// Empty block representation, representing one
// or more blocks that are completely empty of
// data.
//
// 7 6 5 4 3 2 1 0
// 3 |b+4 |b+3 |b+2 |b+1 | length (L) |
// 4 |b+12|b+11|b+10|b+9 |b+8 |b+7 |b+6 |b+5 |
// ...
// 3+L |b+8L-3 ... b+8L+4|
// The block number from the header is always
// empty.
//
// If the bit for b+x is empty, then the block
// X to the right of the block from the header is
// empty. Note that the block is _always on the
// same row_ even if the offset would make the
// block cross the 0E meridian, so it is not simply
// a case of adding to the block number.
// find the lowest-numbered block of this row
if (block_num >= 405000) {
row_start = block_num - ((block_num - 405000) % 225);
row_size = 225;
} else {
row_start = block_num - (block_num % 450);
row_size = 450;
}
// find the offset of the first block in this row handled
// by this message
row_offset = block_num - row_start;
for (i = 0; i < L; ++i) {
int bb;
int j;
if (i == 0)
bb = (fisb->data[3] & 0xF0) | 0x08; // synthesize a first byte in the same format as all the other bytes
else
bb = (fisb->data[i+3]);
for (j = 0; j < 8; ++j) {
if (bb & (1 << j)) {
// find the relevant block for this bit, limited
// to the same row as the original block.
int row_x = (row_offset + 8*i + j - 3) % row_size;
int bn = row_start + row_x;
double latN = 0, lonW = 0, latSize = 0, lonSize = 0;
int k;
block_location(bn, ns_flag, scale_factor, &latN, &lonW, &latSize, &lonSize);
fprintf(stdout, "NEXRAD %s %02d:%02d %d %.0f %.0f %.0f %.0f ",
fisb->product_id == 63 ? "Regional" : "CONUS",
fisb->hours,
fisb->minutes,
scale_factor,
latN * 60,
lonW * 60,
latSize * 60,
lonSize * 60);
// seems to work best if we assume that
// CONUS empty blocks = intensity 1 (valid data, but no precipitation)
// regional empty blocks = intensity 0 (valid data <5dBz)
for (k = 0; k < 128; ++k)
fprintf(stdout, "%d", (fisb->product_id == 63 ? 0 : 1));
fprintf(stdout, "\n");
}
}
}
}
}
void handle_frame(frame_type_t type, uint8_t *frame, int len, void *extra)
{
if (type == UAT_UPLINK) {
struct uat_uplink_mdb mdb;
int i;
uat_decode_uplink_mdb(frame, &mdb);
if (!mdb.app_data_valid)
return;
for (i = 0; i < mdb.num_info_frames; ++i) {
struct fisb_apdu *fisb;
if (!mdb.info_frames[i].is_fisb)
continue;
fisb = &mdb.info_frames[i].fisb;
if (fisb->product_id != 63 && fisb->product_id != 64)
continue;
decode_nexrad(fisb);
}
}
fflush(stdout);
}
int main(int argc, char **argv)
{
struct dump978_reader *reader;
int framecount;
reader = dump978_reader_new(0,0);
if (!reader) {
perror("dump978_reader_new");
return 1;
}
while ((framecount = dump978_read_frames(reader, handle_frame, NULL)) > 0)
;
if (framecount < 0) {
perror("dump978_read_frames");
return 1;
}
return 0;
}

93
dump978/fec.c 100644
Wyświetl plik

@ -0,0 +1,93 @@
//
// Copyright 2015, Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file 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. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include "uat.h"
#include "fec/rs.h"
static void *rs_uplink;
static void *rs_adsb_short;
static void *rs_adsb_long;
#define UPLINK_POLY 0x187
#define ADSB_POLY 0x187
void init_fec(void)
{
rs_adsb_short = init_rs_char(8, /* gfpoly */ ADSB_POLY, /* fcr */ 120, /* prim */ 1, /* nroots */ 12, /* pad */ 225);
rs_adsb_long = init_rs_char(8, /* gfpoly */ ADSB_POLY, /* fcr */ 120, /* prim */ 1, /* nroots */ 14, /* pad */ 207);
rs_uplink = init_rs_char(8, /* gfpoly */ UPLINK_POLY, /* fcr */ 120, /* prim */ 1, /* nroots */ 20, /* pad */ 163);
}
int correct_adsb_frame(uint8_t *to, int *rs_errors)
{
// Try decoding as a Long UAT.
// We rely on decode_rs_char not modifying the data if there were
// uncorrectable errors.
int n_corrected = decode_rs_char(rs_adsb_long, to, NULL, 0);
if (n_corrected >= 0 && n_corrected <= 7 && (to[0]>>3) != 0) {
// Valid long frame.
*rs_errors = n_corrected;
return 2;
}
// Retry as Basic UAT
n_corrected = decode_rs_char(rs_adsb_short, to, NULL, 0);
if (n_corrected >= 0 && n_corrected <= 6 && (to[0]>>3) == 0) {
// Valid short frame
*rs_errors = n_corrected;
return 1;
}
// Failed.
*rs_errors = 9999;
return -1;
}
int correct_uplink_frame(uint8_t *from, uint8_t *to, int *rs_errors)
{
int block;
int total_corrected = 0;
for (block = 0; block < UPLINK_FRAME_BLOCKS; ++block) {
int i, n_corrected;
uint8_t *blockdata = &to[block * UPLINK_BLOCK_DATA_BYTES];
for (i = 0; i < UPLINK_BLOCK_BYTES; ++i)
blockdata[i] = from[i * UPLINK_FRAME_BLOCKS + block];
// error-correct in place
n_corrected = decode_rs_char(rs_uplink, blockdata, NULL, 0);
if (n_corrected < 0 || n_corrected > 10) {
// Failed
*rs_errors = 9999;
return -1;
}
total_corrected += n_corrected;
// next block (if there is one) will overwrite the ECC bytes.
}
*rs_errors = total_corrected;
return 1;
}

44
dump978/fec.h 100644
Wyświetl plik

@ -0,0 +1,44 @@
//
// Copyright 2015, Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file 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. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef DUMP978_FEC_H
#define DUMP978_FEC_H
/* Initialize. Must be called once before correct_* */
void init_fec(void);
/* Correct a downlink frame.
*
* 'to' should contain LONG_FRAME_BYTES of data.
* Errors are corrected in-place within 'to'.
* Returns -1 on uncorrectable errors, 1 for a valid basic frame, 2 for a valid long frame.
* Sets *rs_errors to the number of corrected errors, or 9999 if uncorrectable.
*/
int correct_adsb_frame(uint8_t *to, int *rs_errors);
/* Deinterleave and correct an uplink frame.
*
* 'from' should point to UPLINK_FRAME_BYTES of interleaved input data
* 'to' should point to UPLINK_FRAME_BYTES of space for output data
* (only the first UPLINK_FRAME_DATA_BYTES will contain useful data)
* Blocks are deinterleaved and corrected, and written to 'to'.
* Returns -1 on uncorrectable errors, 1 for a valid uplink frame.
* Sets *rs_errors to the number of corrected errors, or 9999 if uncorrectable.
*/
int correct_uplink_frame(uint8_t *from, uint8_t *to, int *rs_errors);
#endif

Wyświetl plik

@ -0,0 +1,8 @@
This directory contains just the Reed-Solomon decoder parts
of the fec-3.0.1 library by Phil Karn.
The full version of the library may be found at
http://www.ka9q.net/code/fec/
See README.fec for the original library README and license
information.

Wyświetl plik

@ -0,0 +1,120 @@
COPYRIGHT
This package is copyright 2006 by Phil Karn, KA9Q. It may be used
under the terms of the GNU Lesser General Public License (LGPL). See
the file "lesser.txt" in this package for license details.
INTRODUCTION
This package provides a set of functions that implement several
popular forward error correction (FEC) algorithms and several low-level routines
useful in modems implemented with digital signal processing (DSP).
The following routines are provided:
1. Viterbi decoders for the following convolutional codes:
r=1/2 k=7 ("Voyager" code, now a widely used industry standard)
r=1/2 k=9 (Used on the IS-95 CDMA forward link)
r=1/6 k=15 ("Cassini" code, used by several NASA/JPL deep space missions)
2. Reed-Solomon encoders and decoders for any user-specified code.
3. Optimized encoder and decoder for the CCSDS-standard (255,223)
Reed-Solomon code, with and without the CCSDS-standard "dual basis"
symbol representation.
4. Compute dot product between a 16-bit buffer and a set of 16-bit
coefficients. This is the basic DSP primitive for digital filtering
and correlation.
4. Compute sum of squares of a buffer of 16-bit signed integers. This is
useful in DSP for finding the total energy in a signal.
5. Find peak value in a buffer of 16-bit signed integers, useful for
scaling a signal to prevent overflow.
SIMD SUPPORT
This package automatically makes use of various SIMD (Single
Instruction stream, Multiple Data stream) instruction sets, when
available: MMX, SSE and SSE2 on the IA-32 (Intel) architecture, and
Altivec on the PowerPC G4 and G5 used by Power Macintoshes.
"Altivec" is a Motorola trademark; Apple calls it "Velocity Engine",
and IBM calls it "VMX". Altivec is roughly comparable to SSE2 on the
IA-32.
Many of the SIMD versions run more than an order of
magnitude faster than their portable C versions. The available SIMD
instruction sets, if any, are determined at run time and the proper
version of each routine is automatically selected. If no SIMD
instructions are available, the portable C version is invoked by
default. On targets other than IA-32 and PPC, only the portable C
version is built.
The SIMD-assisted versions generally produce the same results as the C
versions, with a few minor exceptions. The Viterbi decoders in C have
a very slightly greater Eb/No performance due to their use of 32-bit
path metrics. On the other hand, the SIMD versions use the
"saturating" arithmetic available in these instructions to avoid the
integer wraparounds that can occur in C when argument ranges are not
properly constrained. This applies primarily to the "dotprod" (dot
product) function.
The MMX (MultiMedia eXtensions) instruction set was introduced on
later Pentium CPUs; it is also implemented on the Pentium II and most
AMD CPUs starting with the K6. SSE (SIMD Streaming Extensions) was
introduced in the Pentium III; AMD calls it "3D Now! Professional".
Intel introduced SSE2 on the Pentium 4, and it has been picked up by
later AMD CPUs. SSE support implies MMX support, while SSE2 support
implies both SSE and MMX support.
The latest IA-32 SIMD instruction set, SSE3 (also known as "Prescott
New Instructions") was introduced in early 2004 with the latest
("Prescott") revision of the Pentium 4. Relatively little was
introduced with SSE3, and this library currently makes no use of it.
See the various manual pages for details on how to use the library
routines.
Copyright 2006, Phil Karn, KA9Q
karn@ka9q.net
http://www.ka9q.net/
This software may be used under the terms of the GNU Lesser General
Public License (LGPL); see the file lesser.txt for details.
Revision history:
Version 1.0 released 29 May 2001
Version 2.0 released 3 Dec 2001:
Restructured to add support for shared libraries.
Version 2.0.1 released 8 Dec 2001:
Includes autoconf/configure script
Version 2.0.2 released 4 Feb 2002:
Add SIMD version override options
Test for lack of SSE2 mnemonic support in 'as'
Build only selected version
Version 2.0.3 released 6 Feb 2002:
Fix to parityb function in parity.h
feclib version 1.0 released November 2003
Merged SIMD-Viterbi, RS and DSP libraries
Changed SIMD Viterbi decoder to detect SSE2/SSE/MMX at runtime rather than build time
feclib version 2.0 (unreleased) Mar 2004
General speedups and cleanups
Switch from 4 to 8-bit input symbols on all Viterbi decoders
Support for Altivec on PowerPC
Support for k=15 r=1/6 Cassini/Mars Pathfinder/Mars Exploration Rover/STEREO code
Changed license to GNU Lesser General Public License (LGPL)
feclib version 2.1 June 5 2006
Added error checking, fixed alignment bug in SSE2 versions of Viterbi decoders causing segfaults
feclib version 2.1.1 June 6 2006
Fix test/benchmark time measurement on Linux

24
dump978/fec/char.h 100644
Wyświetl plik

@ -0,0 +1,24 @@
/* Stuff specific to the 8-bit symbol version of the general purpose RS codecs
*
* Copyright 2003, Phil Karn, KA9Q
* May be used under the terms of the GNU Lesser General Public License (LGPL)
*/
typedef unsigned char data_t;
#define MODNN(x) modnn(rs,x)
#define MM (rs->mm)
#define NN (rs->nn)
#define ALPHA_TO (rs->alpha_to)
#define INDEX_OF (rs->index_of)
#define GENPOLY (rs->genpoly)
#define NROOTS (rs->nroots)
#define FCR (rs->fcr)
#define PRIM (rs->prim)
#define IPRIM (rs->iprim)
#define PAD (rs->pad)
#define A0 (NN)

Wyświetl plik

@ -0,0 +1,298 @@
/* The guts of the Reed-Solomon decoder, meant to be #included
* into a function body with the following typedefs, macros and variables supplied
* according to the code parameters:
* data_t - a typedef for the data symbol
* data_t data[] - array of NN data and parity symbols to be corrected in place
* retval - an integer lvalue into which the decoder's return code is written
* NROOTS - the number of roots in the RS code generator polynomial,
* which is the same as the number of parity symbols in a block.
Integer variable or literal.
* NN - the total number of symbols in a RS block. Integer variable or literal.
* PAD - the number of pad symbols in a block. Integer variable or literal.
* ALPHA_TO - The address of an array of NN elements to convert Galois field
* elements in index (log) form to polynomial form. Read only.
* INDEX_OF - The address of an array of NN elements to convert Galois field
* elements in polynomial form to index (log) form. Read only.
* MODNN - a function to reduce its argument modulo NN. May be inline or a macro.
* FCR - An integer literal or variable specifying the first consecutive root of the
* Reed-Solomon generator polynomial. Integer variable or literal.
* PRIM - The primitive root of the generator poly. Integer variable or literal.
* DEBUG - If set to 1 or more, do various internal consistency checking. Leave this
* undefined for production code
* The memset(), memmove(), and memcpy() functions are used. The appropriate header
* file declaring these functions (usually <string.h>) must be included by the calling
* program.
*/
#if !defined(NROOTS)
#error "NROOTS not defined"
#endif
#if !defined(NN)
#error "NN not defined"
#endif
#if !defined(PAD)
#error "PAD not defined"
#endif
#if !defined(ALPHA_TO)
#error "ALPHA_TO not defined"
#endif
#if !defined(INDEX_OF)
#error "INDEX_OF not defined"
#endif
#if !defined(MODNN)
#error "MODNN not defined"
#endif
#if !defined(FCR)
#error "FCR not defined"
#endif
#if !defined(PRIM)
#error "PRIM not defined"
#endif
#if !defined(NULL)
#define NULL ((void *)0)
#endif
#undef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#undef A0
#define A0 (NN)
{
int deg_lambda, el, deg_omega;
int i, j, r,k;
data_t u,q,tmp,num1,num2,den,discr_r;
data_t lambda[NROOTS+1], s[NROOTS]; /* Err+Eras Locator poly
* and syndrome poly */
data_t b[NROOTS+1], t[NROOTS+1], omega[NROOTS+1];
data_t root[NROOTS], reg[NROOTS+1], loc[NROOTS];
int syn_error, count;
/* form the syndromes; i.e., evaluate data(x) at roots of g(x) */
for(i=0;i<NROOTS;i++)
s[i] = data[0];
for(j=1;j<NN-PAD;j++){
for(i=0;i<NROOTS;i++){
if(s[i] == 0){
s[i] = data[j];
} else {
s[i] = data[j] ^ ALPHA_TO[MODNN(INDEX_OF[s[i]] + (FCR+i)*PRIM)];
}
}
}
/* Convert syndromes to index form, checking for nonzero condition */
syn_error = 0;
for(i=0;i<NROOTS;i++){
syn_error |= s[i];
s[i] = INDEX_OF[s[i]];
}
if (!syn_error) {
/* if syndrome is zero, data[] is a codeword and there are no
* errors to correct. So return data[] unmodified
*/
count = 0;
goto finish;
}
memset(&lambda[1],0,NROOTS*sizeof(lambda[0]));
lambda[0] = 1;
if (no_eras > 0) {
/* Init lambda to be the erasure locator polynomial */
lambda[1] = ALPHA_TO[MODNN(PRIM*(NN-1-eras_pos[0]))];
for (i = 1; i < no_eras; i++) {
u = MODNN(PRIM*(NN-1-eras_pos[i]));
for (j = i+1; j > 0; j--) {
tmp = INDEX_OF[lambda[j - 1]];
if(tmp != A0)
lambda[j] ^= ALPHA_TO[MODNN(u + tmp)];
}
}
#if DEBUG >= 1
/* Test code that verifies the erasure locator polynomial just constructed
Needed only for decoder debugging. */
/* find roots of the erasure location polynomial */
for(i=1;i<=no_eras;i++)
reg[i] = INDEX_OF[lambda[i]];
count = 0;
for (i = 1,k=IPRIM-1; i <= NN; i++,k = MODNN(k+IPRIM)) {
q = 1;
for (j = 1; j <= no_eras; j++)
if (reg[j] != A0) {
reg[j] = MODNN(reg[j] + j);
q ^= ALPHA_TO[reg[j]];
}
if (q != 0)
continue;
/* store root and error location number indices */
root[count] = i;
loc[count] = k;
count++;
}
if (count != no_eras) {
printf("count = %d no_eras = %d\n lambda(x) is WRONG\n",count,no_eras);
count = -1;
goto finish;
}
#if DEBUG >= 2
printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
for (i = 0; i < count; i++)
printf("%d ", loc[i]);
printf("\n");
#endif
#endif
}
for(i=0;i<NROOTS+1;i++)
b[i] = INDEX_OF[lambda[i]];
/*
* Begin Berlekamp-Massey algorithm to determine error+erasure
* locator polynomial
*/
r = no_eras;
el = no_eras;
while (++r <= NROOTS) { /* r is the step number */
/* Compute discrepancy at the r-th step in poly-form */
discr_r = 0;
for (i = 0; i < r; i++){
if ((lambda[i] != 0) && (s[r-i-1] != A0)) {
discr_r ^= ALPHA_TO[MODNN(INDEX_OF[lambda[i]] + s[r-i-1])];
}
}
discr_r = INDEX_OF[discr_r]; /* Index form */
if (discr_r == A0) {
/* 2 lines below: B(x) <-- x*B(x) */
memmove(&b[1],b,NROOTS*sizeof(b[0]));
b[0] = A0;
} else {
/* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
t[0] = lambda[0];
for (i = 0 ; i < NROOTS; i++) {
if(b[i] != A0)
t[i+1] = lambda[i+1] ^ ALPHA_TO[MODNN(discr_r + b[i])];
else
t[i+1] = lambda[i+1];
}
if (2 * el <= r + no_eras - 1) {
el = r + no_eras - el;
/*
* 2 lines below: B(x) <-- inv(discr_r) *
* lambda(x)
*/
for (i = 0; i <= NROOTS; i++)
b[i] = (lambda[i] == 0) ? A0 : MODNN(INDEX_OF[lambda[i]] - discr_r + NN);
} else {
/* 2 lines below: B(x) <-- x*B(x) */
memmove(&b[1],b,NROOTS*sizeof(b[0]));
b[0] = A0;
}
memcpy(lambda,t,(NROOTS+1)*sizeof(t[0]));
}
}
/* Convert lambda to index form and compute deg(lambda(x)) */
deg_lambda = 0;
for(i=0;i<NROOTS+1;i++){
lambda[i] = INDEX_OF[lambda[i]];
if(lambda[i] != A0)
deg_lambda = i;
}
/* Find roots of the error+erasure locator polynomial by Chien search */
memcpy(&reg[1],&lambda[1],NROOTS*sizeof(reg[0]));
count = 0; /* Number of roots of lambda(x) */
for (i = 1,k=IPRIM-1; i <= NN; i++,k = MODNN(k+IPRIM)) {
q = 1; /* lambda[0] is always 0 */
for (j = deg_lambda; j > 0; j--){
if (reg[j] != A0) {
reg[j] = MODNN(reg[j] + j);
q ^= ALPHA_TO[reg[j]];
}
}
if (q != 0)
continue; /* Not a root */
/* store root (index-form) and error location number */
#if DEBUG>=2
printf("count %d root %d loc %d\n",count,i,k);
#endif
root[count] = i;
loc[count] = k;
/* If we've already found max possible roots,
* abort the search to save time
*/
if(++count == deg_lambda)
break;
}
if (deg_lambda != count) {
/*
* deg(lambda) unequal to number of roots => uncorrectable
* error detected
*/
count = -1;
goto finish;
}
/*
* Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
* x**NROOTS). in index form. Also find deg(omega).
*/
deg_omega = deg_lambda-1;
for (i = 0; i <= deg_omega;i++){
tmp = 0;
for(j=i;j >= 0; j--){
if ((s[i - j] != A0) && (lambda[j] != A0))
tmp ^= ALPHA_TO[MODNN(s[i - j] + lambda[j])];
}
omega[i] = INDEX_OF[tmp];
}
/*
* Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
* inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form
*/
for (j = count-1; j >=0; j--) {
num1 = 0;
for (i = deg_omega; i >= 0; i--) {
if (omega[i] != A0)
num1 ^= ALPHA_TO[MODNN(omega[i] + i * root[j])];
}
num2 = ALPHA_TO[MODNN(root[j] * (FCR - 1) + NN)];
den = 0;
/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
for (i = MIN(deg_lambda,NROOTS-1) & ~1; i >= 0; i -=2) {
if(lambda[i+1] != A0)
den ^= ALPHA_TO[MODNN(lambda[i+1] + i * root[j])];
}
#if DEBUG >= 1
if (den == 0) {
printf("\n ERROR: denominator = 0\n");
count = -1;
goto finish;
}
#endif
/* Apply error to data */
if (num1 != 0 && loc[j] >= PAD) {
data[loc[j]-PAD] ^= ALPHA_TO[MODNN(INDEX_OF[num1] + INDEX_OF[num2] + NN - INDEX_OF[den])];
}
}
finish:
if(eras_pos != NULL){
for(i=0;i<count;i++)
eras_pos[i] = loc[i];
}
retval = count;
}

Wyświetl plik

@ -0,0 +1,22 @@
/* General purpose Reed-Solomon decoder for 8-bit symbols or less
* Copyright 2003 Phil Karn, KA9Q
* May be used under the terms of the GNU Lesser General Public License (LGPL)
*/
#ifdef DEBUG
#include <stdio.h>
#endif
#include <string.h>
#include "char.h"
#include "rs-common.h"
int decode_rs_char(void *p, data_t *data, int *eras_pos, int no_eras){
int retval;
struct rs *rs = (struct rs *)p;
#include "decode_rs.h"
return retval;
}

Wyświetl plik

@ -0,0 +1,106 @@
/* Common code for intializing a Reed-Solomon control block (char or int symbols)
* Copyright 2004 Phil Karn, KA9Q
* May be used under the terms of the GNU Lesser General Public License (LGPL)
*/
#undef NULL
#define NULL ((void *)0)
{
int i, j, sr,root,iprim;
rs = NULL;
/* Check parameter ranges */
if(symsize < 0 || symsize > 8*sizeof(data_t)){
goto done;
}
if(fcr < 0 || fcr >= (1<<symsize))
goto done;
if(prim <= 0 || prim >= (1<<symsize))
goto done;
if(nroots < 0 || nroots >= (1<<symsize))
goto done; /* Can't have more roots than symbol values! */
if(pad < 0 || pad >= ((1<<symsize) -1 - nroots))
goto done; /* Too much padding */
rs = (struct rs *)calloc(1,sizeof(struct rs));
if(rs == NULL)
goto done;
rs->mm = symsize;
rs->nn = (1<<symsize)-1;
rs->pad = pad;
rs->alpha_to = (data_t *)malloc(sizeof(data_t)*(rs->nn+1));
if(rs->alpha_to == NULL){
free(rs);
rs = NULL;
goto done;
}
rs->index_of = (data_t *)malloc(sizeof(data_t)*(rs->nn+1));
if(rs->index_of == NULL){
free(rs->alpha_to);
free(rs);
rs = NULL;
goto done;
}
/* Generate Galois field lookup tables */
rs->index_of[0] = A0; /* log(zero) = -inf */
rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */
sr = 1;
for(i=0;i<rs->nn;i++){
rs->index_of[sr] = i;
rs->alpha_to[i] = sr;
sr <<= 1;
if(sr & (1<<symsize))
sr ^= gfpoly;
sr &= rs->nn;
}
if(sr != 1){
/* field generator polynomial is not primitive! */
free(rs->alpha_to);
free(rs->index_of);
free(rs);
rs = NULL;
goto done;
}
/* Form RS code generator polynomial from its roots */
rs->genpoly = (data_t *)malloc(sizeof(data_t)*(nroots+1));
if(rs->genpoly == NULL){
free(rs->alpha_to);
free(rs->index_of);
free(rs);
rs = NULL;
goto done;
}
rs->fcr = fcr;
rs->prim = prim;
rs->nroots = nroots;
/* Find prim-th root of 1, used in decoding */
for(iprim=1;(iprim % prim) != 0;iprim += rs->nn)
;
rs->iprim = iprim / prim;
rs->genpoly[0] = 1;
for (i = 0,root=fcr*prim; i < nroots; i++,root += prim) {
rs->genpoly[i+1] = 1;
/* Multiply rs->genpoly[] by @**(root + x) */
for (j = i; j > 0; j--){
if (rs->genpoly[j] != 0)
rs->genpoly[j] = rs->genpoly[j-1] ^ rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[j]] + root)];
else
rs->genpoly[j] = rs->genpoly[j-1];
}
/* rs->genpoly[0] can never be zero */
rs->genpoly[0] = rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[0]] + root)];
}
/* convert rs->genpoly[] to index form for quicker encoding */
for (i = 0; i <= nroots; i++)
rs->genpoly[i] = rs->index_of[rs->genpoly[i]];
done:;
}

Wyświetl plik

@ -0,0 +1,35 @@
/* Initialize a RS codec
*
* Copyright 2002 Phil Karn, KA9Q
* May be used under the terms of the GNU Lesser General Public License (LGPL)
*/
#include <stdlib.h>
#include "char.h"
#include "rs-common.h"
void free_rs_char(void *p){
struct rs *rs = (struct rs *)p;
free(rs->alpha_to);
free(rs->index_of);
free(rs->genpoly);
free(rs);
}
/* Initialize a Reed-Solomon codec
* symsize = symbol size, bits
* gfpoly = Field generator polynomial coefficients
* fcr = first root of RS code generator polynomial, index form
* prim = primitive element to generate polynomial roots
* nroots = RS code generator polynomial degree (number of roots)
* pad = padding bytes at front of shortened block
*/
void *init_rs_char(int symsize,int gfpoly,int fcr,int prim,
int nroots,int pad){
struct rs *rs;
#include "init_rs.h"
return rs;
}

Wyświetl plik

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library 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 library 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. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

Wyświetl plik

@ -0,0 +1,26 @@
/* Stuff common to all the general-purpose Reed-Solomon codecs
* Copyright 2004 Phil Karn, KA9Q
* May be used under the terms of the GNU Lesser General Public License (LGPL)
*/
/* Reed-Solomon codec control block */
struct rs {
int mm; /* Bits per symbol */
int nn; /* Symbols per block (= (1<<mm)-1) */
data_t *alpha_to; /* log lookup table */
data_t *index_of; /* Antilog lookup table */
data_t *genpoly; /* Generator polynomial */
int nroots; /* Number of generator roots = number of parity symbols */
int fcr; /* First consecutive root, index form */
int prim; /* Primitive element, index form */
int iprim; /* prim-th root of 1, index form */
int pad; /* Padding bytes in shortened block */
};
static inline int modnn(struct rs *rs,int x){
while (x >= rs->nn) {
x -= rs->nn;
x = (x >> rs->mm) + (x & rs->nn);
}
return x;
}

17
dump978/fec/rs.h 100644
Wyświetl plik

@ -0,0 +1,17 @@
/* User include file for libfec
* Copyright 2004, Phil Karn, KA9Q
* May be used under the terms of the GNU Lesser General Public License (LGPL)
*/
#ifndef _FEC_RS_H_
#define _FEC_RS_H_
/* General purpose RS codec, 8-bit symbols */
int decode_rs_char(void *rs,unsigned char *data,int *eras_pos,
int no_eras);
void *init_rs_char(int symsize,int gfpoly,
int fcr,int prim,int nroots,
int pad);
void free_rs_char(void *rs);
#endif

217
dump978/fec_tests.c 100644
Wyświetl plik

@ -0,0 +1,217 @@
//
// Copyright 2015, Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file 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. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include "uat.h"
#include "fec.h"
// Test data from DO-282B:
// Table 2-104 "ADS-B Message Reception - Set 1"
// Table 2-105 "ADS-B Message Reception - Set 2"
struct {
const char *testname;
const char *input;
int frametype;
const char *expected;
} downlink_tests[] = {
// Table 2-104
{ "2-104 #1", "FF8196782DD44238C1453855F89980C7524F5970940ED83AD89CE7A9BEF8761BBCD9FCC817D82E2D1ACF90CA78DA3C49", 1, "007E6987D2D74238C1453855F89980C7524F" },
{ "2-104 #2", "007E6987D328BDC73EBA3955F89980C7524F5970940ED83AD89CE7A9BEF8BB7B190B2EA0EACC7237B7B01B036E07EE04", -1, NULL },
{ "2-104 #3", "007E6987D2D74238C146C7AA07667FC7524F5970940ED83AD89CE7A9BEF8DBE78F0C386EB860D64E9BA9E06B95BEB66A", 1, "007E6987D2D74238C1453855F89980C7524F" },
{ "2-104 #4", "007E6987D2D74238C1453855F8998738ADB0A60F940ED83AD89CE7A9BEF8171F980B40C8B76AC0791254EE04AA73A982", 1, "007E6987D2D74238C1453855F89980C7524F" },
{ "2-104 #5", "007E6987D2D74238C1453855F89980C7524F597F6BF127C5E79CE7A9BEF8B22C710A46621200763F2DF70CBCBFCA1721", 1, "007E6987D2D74238C1453855F89980C7524F" },
{ "2-104 #6", "5A8CAA4ABC7AEE2AD0929EB80DA044D556B452A7A73A5716CD1DB40964F5BA105D9DAAD75342196DEBB63CC972994DEA", 2, "A57355B54385ED2AD0929EB80DA044D556B452A7A73A5716CD1DB40964F5BA105D9D" },
{ "2-104 #7", "A57355B5438412D52F6D61470CA044D556B452A7A73A5716CD1DB40964F5BA105D9DAAD75342196DEBB63CC972994DEA", -1, NULL },
{ "2-104 #8", "A57355B54385ED2AD0929EBBF25FBB2AA94B52A7A73A5716CD1DB40964F5BA105D9DAAD75342196DEBB63CC972994DEA", 2, "A57355B54385ED2AD0929EB80DA044D556B452A7A73A5716CD1DB40964F5BA105D9D" },
{ "2-104 #9", "A57355B54385ED2AD0929EB80DA044D556B3AD5858C5A869CD1DB40964F5BA105D9DAAD75342196DEBB63CC972994DEA", 2, "A57355B54385ED2AD0929EB80DA044D556B452A7A73A5716CD1DB40964F5BA105D9D" },
{ "2-104 #10", "A57355B54385ED2AD0929EB80DA044D556B452A7A73A571932E24BF69BCABA105D9DAAD75342196DEBB63CC972994DEA", 2, "A57355B54385ED2AD0929EB80DA044D556B452A7A73A5716CD1DB40964F5BA105D9D" },
{ "2-104 #11", "A57355B54385ED2AD0929EB80DA044D556B452A7A73A5716CD1DB40964EA45EFA26255C85342196DEBB63CC972994DEA", 2, "A57355B54385ED2AD0929EB80DA044D556B452A7A73A5716CD1DB40964F5BA105D9D" },
{ "2-104 #12", "A57355B54385ED2AD0929EB80DA044D556B452A7A73A5716CD1DB40964F5BA105D9DAAE8ACBDE69214B93CC972994DEA", 2, "A57355B54385ED2AD0929EB80DA044D556B452A7A73A5716CD1DB40964F5BA105D9D" },
{ "2-104 #13", "FFD7E73F83C10D2BF6B961410BEE0C2FD5A4C934E4972E7D17C8495075B2F64260211F48524C5A5590A16E3EAF4068AB", 1, "002818C07CC20D2BF6B961410BEE0C2FD5A4" },
{ "2-104 #14", "002818C07D3DF2D4094660410BEE0C2FD5A4C934E4972E7D17C8495075B26DD7F172B5B56FF8F49067515A8A55D64D5E", -1, NULL },
{ "2-104 #15", "002818C07CC20D2BF6BA9EBEF411F32FD5A4C934E4972E7D17C8495075B2C06F20916457C90BC47D261C8DEFE3ED74C5", 1, "002818C07CC20D2BF6B961410BEE0C2FD5A4" },
{ "2-104 #16", "002818C07CC20D2BF6B961410BEE0BD02A5B364BE4972E7D17C8495075B233CE68A8ABDCF663EAF24B3B2B1369D92C8D", 1, "002818C07CC20D2BF6B961410BEE0C2FD5A4" },
{ "2-104 #17", "002818C07CC20D2BF6B961410BEE0C2FD5A4C93B1B68D18228C8495075B215B194556A7E44E71C724666C96E55DEE72E", 1, "002818C07CC20D2BF6B961410BEE0C2FD5A4" },
{ "2-104 #18", "FF6BD35D16B72B5A4521DB1F0697464369387A5F2C8C9E435F936F4912E17BD726E20847E1E69847CE7504CFE31ACE30", 1, "00942CA2E9B42B5A4521DB1F069746436938" },
{ "2-104 #19", "00942CA2E84BD4A5BADEDA1F0697464369387A5F2C8C9E435F936F4912E1875A6F0477167558D0E3FCE8FC17F176AED4", -1, NULL },
{ "2-104 #20", "00942CA2E9B42B5A452224E0F968B94369387A5F2C8C9E435F936F4912E13773225FF83FE1D774B684BC1B474D55879A", 1, "00942CA2E9B42B5A4521DB1F069746436938" },
{ "2-104 #21", "00942CA2E9B42B5A4521DB1F069741BC96C785202C8C9E435F936F4912E189CFFBB621E21E555CCC06495B619BDA4ABC", 1, "00942CA2E9B42B5A4521DB1F069746436938" },
{ "2-104 #22", "00942CA2E9B42B5A4521DB1F0697464369387A50D37361BC60936F4912E1263E0AD23CEC55487CDF1D60B972DE252D81", 1, "00942CA2E9B42B5A4521DB1F069746436938" },
{ "2-104 #23", "29E66548CD3A0A4527AB422D6A14598C515810717B02C9C79B79F029CEEE6B4DD1E8F1F77F4CAB43AD74CBB01ECD155C", 2, "D6199AB732C5094527AB422D6A14598C515810717B02C9C79B79F029CEEE6B4DD1E8" },
{ "2-104 #24", "D6199AB732C4F6BAD854BDD26B14598C515810717B02C9C79B79F029CEEE6B4DD1E8F1F77F4CAB43AD74CBB01ECD155C", -1, NULL },
{ "2-104 #25", "D6199AB732C5094527AB422E95EBA673AEA710717B02C9C79B79F029CEEE6B4DD1E8F1F77F4CAB43AD74CBB01ECD155C", 2, "D6199AB732C5094527AB422D6A14598C515810717B02C9C79B79F029CEEE6B4DD1E8" },
{ "2-104 #26", "D6199AB732C5094527AB422D6A14598C515FEF8E84FD36B89B79F029CEEE6B4DD1E8F1F77F4CAB43AD74CBB01ECD155C", 2, "D6199AB732C5094527AB422D6A14598C515810717B02C9C79B79F029CEEE6B4DD1E8" },
{ "2-104 #27", "D6199AB732C5094527AB422D6A14598C515810717B02C9C864860FD631D16B4DD1E8F1F77F4CAB43AD74CBB01ECD155C", 2, "D6199AB732C5094527AB422D6A14598C515810717B02C9C79B79F029CEEE6B4DD1E8" },
{ "2-104 #28", "287F318C2A9FFF7F0784CA4036E252DEB0226A9F9E183CBB933FA68DBF5E1F018F635195DE87894F16BDA55E42A64137", -1, "D780CE73D59CFF7F0784CA4036E252DEB022" }, // basic/long mismatch
{ "2-104 #29", "D780CE73D4630080F87BCB4036E252DEB0226A9F9E183CBB933FA68DBF5E161C9333D935A0C83220FC2799D84A139CAB", -1, NULL },
{ "2-104 #30", "157A70631C57176BA3073708854B66FF4083C2AF2D96F628422CDA1A522295B85ED8C94A0DB164A4BEF4B3A402210E02", -1, NULL },
{ "2-104 #31", "773448BE613236BD3F0C53F45DCA5CC6F0B2C0A92F6B6DF3072E0BEFFC8ADAA641EE602AC8B2DDE9A4429FAAB9AFD694", 2, "88CBB7419ECD35BD3F0C53F45DCA5CC6F0B2C0A92F6B6DF3072E0BEFFC8ADAA641EE" },
{ "2-104 #32", "88CBB7419ECCCA42C0F3AC0B5CCA5CC6F0B2C0A92F6B6DF3072E0BEFFC8ADAA641EE602AC8B2DDE9A4429FAAB9AFD694", -1, NULL },
{ "2-104 #33", "88CBB7419ECD35BD3F0C53F7A235A3390F4DC0A92F6B6DF3072E0BEFFC8ADAA641EE602AC8B2DDE9A4429FAAB9AFD694", 2, "88CBB7419ECD35BD3F0C53F45DCA5CC6F0B2C0A92F6B6DF3072E0BEFFC8ADAA641EE" },
{ "2-104 #34", "88CBB7419ECD35BD3F0C53F45DCA5CC6F0B2C0A92F6B6DF3072E0BEFFC8ADAA641EE6015374D22165B4D9FAAB9AFD694", 2, "88CBB7419ECD35BD3F0C53F45DCA5CC6F0B2C0A92F6B6DF3072E0BEFFC8ADAA641EE" },
{ "2-104 #35", "EE62BBECF66420F249ECF8FBC08F8FB3092B6EB4C61D6C264DB6F333BEA5570E0407693351FA9161858E6460DE629EFE", 2, "119D4413099B23F249ECF8FBC08F8FB3092B6EB4C61D6C264DB6F333BEA5570E0407" },
{ "2-104 #36", "119D4413099ADC0DB6130704C18F8FB3092B6EB4C61D6C264DB6F333BEA5570E0407693351FA9161858E6460DE629EFE", -1, NULL },
{ "2-104 #37", "119D4413099B23F249ECF8F83F70704CF6D46EB4C61D6C264DB6F333BEA5570E0407693351FA9161858E6460DE629EFE", 2, "119D4413099B23F249ECF8FBC08F8FB3092B6EB4C61D6C264DB6F333BEA5570E0407" },
{ "2-104 #38", "119D4413099B23F249ECF8FBC08F8FB3092C914B39E293594DB6F333BEA5570E0407693351FA9161858E6460DE629EFE", 2, "119D4413099B23F249ECF8FBC08F8FB3092B6EB4C61D6C264DB6F333BEA5570E0407" },
{ "2-104 #39", "DF784C02075C59B503CFF562E1A553E2B54F40092EF8C22D0BFC643D3C5290867B135A1DB2EEC69474D7F594AC5738D8", -1, "20884C02075C59B503CF0A92E1A553E2B54F" }, // basic/long mismatch
{ "2-104 #40", "5A8355B54385ED2AD0929EB80DA044D556B452A758CA5716CD1DB40964F5BA10A26DAAD75342196DEBB63CC972994DEA", 2, "A57355B54385ED2AD0929EB80DA044D556B452A7A73A5716CD1DB40964F5BA105D9D" },
{ "2-104 #41", "D616654732C5094527AB422D65EBA98C515810717B02C9C794860029CEEE6B4DD1E8F1F77F4CAB43AD74CBB01ECD155C", -1, NULL },
{ "2-104 #42", "AC8857D3318447091F3244DB71A661C7CFC7C4D859F34BD305CED0F22A0FDBE78F0C386EB860D64E9BA9E06B95BEB66A", -1, NULL },
{ "2-104 #43", "F8A60931105731F486BCE2B75D2EBAB00C4FBFEC1C827BEBDDF3BABC5DFC90867BECAA1DB2EEC69474D7F594AC5738D8", 1, "07560931105731F486BCE2B75D2EBA4FFC4F" },
{ "2-104 #44", "87AAEE174F86F7D6F81A6A5DFFE44BBE819127C89004918D683D2DD3608523EFAC727A23A788A711FCA51139D874D5C8", 2, "87AAEE174F86F7D6F8E5955DFFE44BBE816ED8C89004918D683DD22C608523EFAC72" },
{ "2-104 #45", "46D9B1EE2CE9216C8027CE5AE861E20BB742FF717C21B944DED0B164595D7181B14C131EA2DCCDD5B86D46824464BE9A", 2, "46D9B1EE2C16DE6C8027CE5AE89E1D0BB742FF717C21B9BB21D0B164595D7181B14C" },
{ "2-104 #46", "007F9667D2D74238C1453855076980C7524F5970940ED83AD89CE856BEF890867B135A1DB2EEC69474D7F594AC5738D8", -1, NULL },
// Table 2-105
{ "2-105 #1", "007E6987D2D74238C1453855F89980C7524F5970940ED83AD89CE7A9BEF890867B135A1DB2EEC69474D7F594AC5738D8", 1, "007E6987D2D74238C1453855F89980C7524F" },
{ "2-105 #2", "A57355B54385ED2AD0929EB80DA044D556B452A7A73A5716CD1DB4096465BA105D9DAAD75342196DEBB63CC972994DEA", 2, "A57355B54385ED2AD0929EB80DA044D556B452A7A73A5716CD1DB40964F5BA105D9D" },
{ "2-105 #3", "002818C07CC20D2BF6B961410BEE0C2FD5B9C934E4972EED17C8495075B290867B135A1DB2EEC69474D7F594AC5738D8", 1, "002818C07CC20D2BF6B961410BEE0C2FD5A4" },
{ "2-105 #4", "00942CA2E9B42B5A4521DB1F0697FE4369257A5F2C8C9ED35F936F4912E190867B135A1DB2EEC69474D7F594AC5738D8", 1, "00942CA2E9B42B5A4521DB1F069746436938" },
{ "2-105 #5", "8B199AB732C509459FAB422D6A14598C515810717B02C9DA9B79F029CE7E6B4DD1E8F1F77F4CAB43AD74CBB01ECD155C", 2, "D6199AB732C5094527AB422D6A14598C515810717B02C9C79B79F029CEEE6B4DD1E8" },
{ "2-105 #6", "00879223318447F6E03244DB2CA6D93830DADB42E877E27CF095B704326590867B135A1DB2EEC69474D7F594AC5738D8", 1, "0087A823318447F6E03244DB71A6613830C7" },
{ "2-105 #7", "DAAAD4174F86F7D640E5955DFFE44BBE816ED86290049190683DD22C601523EFAC727A23A788A711FCA51139D874D5C8", 2, "87AAEE174F86F7D6F8E5955DFFE44BBE816ED8C89004918D683DD22C608523EFAC72" },
{ "2-105 #8", "1BD98BEE5D16DE6C3827CE5AE89E1D0BB742FFDB7C21B9A621D0B16459CD7181B14C131EA2DCCDD5B86D46824464BE9A", 2, "46D9B1EE2C16DE6C8027CE5AE89E1D0BB742FF717C21B9BB21D0B164595D7181B14C" },
{ "2-105 #9", "D780F473A49C677F0784CA406BE2EADEB03F6A9F9E183C2B9395A68DBF5E90867B135A1DB2EEC69474D7F594AC5738D8", -1, NULL },
{ "2-105 #10", "487A4A636D56E894E4F8C8F7844B66FF4083C2052D96F635DA2CDA1A52B295B85ED8C94A0DE064A4BEF4B3A402210E02", -1, NULL },
{ "2-105 #11", "88CBB7419ECD35BD3F0C53F45DCA5CC6F0B2C0A92F6B6DF3072E0BEFFC8ADAA641EE602AC8B2DDE9A4429FAAB9AFD694", 2, "88CBB7419ECD35BD3F0C53F45DCA5CC6F0B2C0A92F6B6DF3072E0BEFFC8ADAA641EE" },
{ "2-105 #12", "3DC87150293C43E1218BBBB462F06CE1ABE77693C3C24648277112B17B0EC4E774EED67F4A5C486E47E688B2FFA81FAD", 2, "60C84B50293C43E1998BBBB462F06CE1ABE77693C3C24655277112B17B9EC4E774EE" },
{ "2-105 #13", "E4C735D67923E302D648F20F35C66F7027697BF77AE4F6759F5106D592E19E48996C4008A98EC6178BB74D5E05380D73", 2, "B9C70FD67923E3026E48F20F35C66F7027697B5D7AE4F6689F5106D592719E48996C" },
{ "2-105 #14", "53A810655AA6E68A2585D51E07F01003A662B66F98020986F472BD563FD6D8CE9D354AB7E56F1871EF087F2C2DC5810F", -1, NULL },
{ "2-105 #15", "294B0831CCD9B59FB2DB2078C6A796AC873977A0061D2AA5FC057583D39AA1429DFBAC89A4F1A9D94D17D93FB5A982BA", 2, "294B0831CCD9B59FB2DB2078C6A796AC873977A0061D2AB8FC057583D30AA1429DFB" },
{ "2-105 #16", "A30D2EF671D7A56136FCAAEEFA838793C58706661638720E3E2539F280FD5B1CEC3255DB60BA866B7CD2E927188DAC0A", 2, "A30D2EF671D7A5618EFCAAEEFA838793C5870666163872133E2539F2806D5B1CEC32" },
{ "2-105 #17", "1E9297DE55DDFDBC646A63E90E96784012A92DCE42660EC20BC9EC886EE60DC70D7E9B3FA52D17E62E90F4C69EDA07F6", 2, "4392ADDE55DDFDBCDC6A63E90E96784012A92DCE42660EDF0BC9EC886E760DC70D7E" },
{ "2-105 #18", "FE767C70F15A99EE3FC77178FB1EED52BBBDBEFAB8C0F0EC0C1FB1350D363A24A24DEA5F5E955696C56858C093594BF1", 2, "A3764670805A99EE87C77178FB1EED52BBBDBE50B8C0F0F10C1FB1350DA63A24A24D" },
{ "2-105 #19", "62A76B1293A13428872CF1A006431013E1E25D045594026AB07440F966277040AF3B9FD2701B68113F6BCABB38B1AB7C", -1, NULL },
{ "2-105 #20", "00CB83BC39C90101CD97F84751E2D679CD3ADE7EE8D98C8824BE9F7565B690867B135A1DB2EEC69474D7F594AC5738D8", -1, NULL },
{ "2-105 #21", "BEF0F217696E4652DE8CB92BEC089CFA688E91363C4C627EEDC50B2B3621CD80A407357B9646CF133CDE92807BDE083A", 2, "BEF0F217696E4652DE8CB92BEC089CFA688E91363C4C627EEDC50B2B36B1CD80A407" },
{ "2-105 #22", "25F2846879F474085AD651F61011A07E55B92EF8412B72ED889CCBABD43BE51C2CECE97C250E4F5FAB16CEDAFA5CE238", 2, "25F2846879F474085AD651F61011A07E55B92EF8412B72F0889CCBABD4ABE51C2CEC" },
{ "2-105 #23", "FE8BBEFA469671700F1B9BCE491CE2E7C61DCB02668054401B2D129FBBA808A0C4F18A2B7847A35F56BFE897BFF31E71", 2, "A38B84FA46967170B71B9BCE491CE2E7C61DCBA86680545D1B2D129FBB3808A0C4F1" },
{ "2-105 #24", "B026C4F405E0F6DAF7EEA90134AD7F4C79CC105115F779A696B6FF79665B7D30DA7B0E12E49705C2EFBF64726AF41A65", 2, "ED26FEF474E0F6DA4FEEA90134AD7F4C79CC10FB15F779BB96B6FF7966CB7D30DA7B" },
{ "2-105 #25", "B2F0B85427A6B9B30ADE959C9A3597E429B4C7DB15DDD9C8E9DC9CADC4FBBDB6B7BD2446C0391DA4ACB7D62FF4DE4448", -1, NULL },
{ "2-105 #26", "6B9AC92CCE70667C6FD5D4B316DA46E4B5322A4B4151F651DEDBE85633E19768DE42F879B6BCB73C308D85D5E6EC2834", -1, NULL },
{ "2-105 #27", "07560931105731F486BCE2B75D2EBA4FFC4FBFEC1C827BEBDDF3BABC5DFC90867B135A1DB2EEC69474D7F594AC5738D8", 1, "07560931105731F486BCE2B75D2EBA4FFC4F" },
{ "2-105 #28", "8D264F73C42014181D475A812755061B88B784F2D7E57866DAF007EA4A420D7B5829E103C0E3DF069015893738D26FC1", 2, "8D264F73C42014181D475A812755061B88B784F2D7E57866DAF007EA4AD20D7B5829" },
{ "2-105 #29", "0511EE3AFD5356739D80545F1D978A8E75FFBA8D349CFBD3C19D1852B06690867B135A1DB2EEC69474D7F594AC5738D8", 1, "0511EE3AFD5356739D80545F1D978A8E75E2" },
{ "2-105 #30", "077B559BEFA8DA4D43A0ED6253FA096926C1EBE0899BC38D3A8415367D64756997DB0F53F54227A14229F3654F5FB489", 2, "5A7B6F9BEFA8DA4DFBA0ED6253FA096926C1EBE0899BC3903A8415367DF4756997DB" },
{ "2-105 #31", "14A61CC7D8766A511C98CAF387403156AFB78E35C0840FB82D6A1C4A9EEB8D3493E567AFA9EDDF7B6713935817587985", 2, "49A626C7D8766A51A498CAF387403156AFB78E9FC0840FA52D6A1C4A9E7B8D3493E5" },
{ "2-105 #32", "94032D84D22B86C1E1E2A18859083B9737E7F48C1F477D2951D333795CB75CA801BEFFF271349F7665D670AD62AF2FF3", 2, "C9031784A32B86C159E2A18859083B9737E7F4261F477D3451D333795C275CA801BE" },
{ "2-105 #33", "105B5212705BBE0DE89A8033898EFBA25AA41F9D4880BA066C874BD4AA7B90867B135A1DB2EEC69474D7F594AC5738D8", -1, NULL },
{ "2-105 #34", "0C646844862595EAA54DAD2F2DA5D1481D0DE3828C22F4E2A4D9D15D795D570AE9320018B985B188C1192A60300F0A37", 2, "0C646844862595EAA54DAD2F2DA5D1481D0DE3828C22F4E2A4D9D15D795D570AE932" },
{ "2-105 #35", "71219DC30B25D77EB24D25A1E38811FDEB9C303F0329C26F0DA358E86C327A3EAEBE2D88F3C31EC323F20D43109D7BFF", 2, "71219DC30B25D77EB24D25A1E38811FDEB9C303F0329C2720DA358E86CA27A3EAEBE" },
{ "2-105 #36", "20884C02075C59B503CF0A92E1A5EBE2B55240092EF8C22D0BFC643D3C5290867B135A1DB2EEC69474D7F594AC5738D8", -1, "20884C02075C59B503CF0A92E1A553E2B54F" }, // basic/long mismatch
{ "2-105 #37", "041FAD506C2ACF832E6E709A64393C100253641E26C3D92D0F2AA4C38AF490867B135A1DB2EEC69474D7F594AC5738D8", 1, "041F97506C2ACF832E6E709A39398410024E" },
{ "2-105 #38", "00117E82A1E6F9F487423BD32B0765CFC70A65332A820C1B34702487811990867B135A1DB2EEC69474D7F594AC5738D8", -1, NULL },
{ "2-105 #39", "7C69D795C15C7E322415505445A1588476473FF6928382FD43173F9B56A96BACBBF0B5C3868CAEB2856C8AD0E4F31A95", 2, "7C69D795C15C7E322415505445A1588476473FF6928382E043173F9B56396BACBBF0" },
{ "2-105 #40", "E4D3C31F1B25232D4E43F6C3F8368596C5346C919C0960B2EE40492BEEDA77934474F26191E4D8048AB87CA49EE0BE29", 2, "B9D3F91F1B25232DF643F6C3F8368596C5346C3B9C0960AFEE40492BEE4A77934474" },
{ "2-105 #41", "FE69CC228E786E996CCC8318C9C90F25C6B68F566C74316CB5FDAFCA226E7A19EA66AD963A6327B8A2F49291C22A656C", 2, "A369F622FF786E99D4CC8318C9C90F25C6B68FFC6C743171B5FDAFCA22FE7A19EA66" },
{ "2-105 #42", "008B74BC393401BE9D6A11D93C62435F127541E5D17C2397CCFF49EE043890867B135A1DB2EEC69474D7F594AC5738D8", -1, NULL },
{ "2-105 #43", "00FAE34A81BF609DACB0388BDC818EAAD028684EF3F7A68A856C9BD8CA0F90867B135A1DB2EEC69474D7F594AC5738D8", -1, NULL },
{ "2-105 #44", "0004E865A9FCC6E11D03557BAC9C64852F69D3174482AD9106856918E6D790867B135A1DB2EEC69474D7F594AC5738D8", 1, "0004E865A9FCC6E11D03557BAC9C64852F69" },
{ "2-105 #45", "B509125D72B9D0CDC67016287921F01E0DD52193C1BD8B50DD2A6BBECDEF7A50DDDC73D996CFD227032EB4A1EC746E4C", 2, "B509125D72B9D0CDC67016287921F01E0DD52193C1BD8B50DD2A6BBECD7F7A50DDDC" },
{ "2-105 #46", "E5A6D7BE57EBB83BFA867DA7B6978BB7161F778B63B098D72EE880885E48E6F3240528F8F1230C5537F5EA030243537A", 2, "E5A6D7BE57EBB83BFA867DA7B6978BB7161F778B63B098CA2EE880885ED8E6F32405" },
{ "2-105 #47", "00E7B451B11DAE9750011F73723404D39A5DE2647484ABC7890F0800969890867B135A1DB2EEC69474D7F594AC5738D8", 1, "00E7B451B11DAE9750011F737234BCD39A40" },
{ "2-105 #48", "FD24A99E20ECC8E347D4D46D141FCCC52A6AC35E5CE4B69338BE22E0ECB72F702E49D0EF7142D6675A4E79E2590865AF", 2, "A024939E20ECC8E3FFD4D46D141FCCC52A6AC35E5CE4B68E38BE22E0EC272F702E49" },
{ "2-105 #49", "1F83699AD2D74238C1453855F89980C7524F5C70390ED83AD89CE7A947F8BA105D9D83DADD3FC8DC9842693A4E9D7E63", 1, "007E6987D2D74238C1453855F89980C7524F" },
{ "2-105 #50", "20884C02075C59B503CFC353E1A553E2B54F4009EAF8C20E0BFC64C93C52D0AA219E83E952864A5EE34E5C06B43ED570", -1, "20884C02075C59B503CF0A92E1A553E2B54F" }, // basic/long mismatch
{ "2-105 #51", "1F83699AD2D74238C1453855F89980C7524F5C70390ED83AD89CE7A9BEF8BA105D9D83DADD3FC8DC9842693A4E9D7E63", 2, "097E6987D2D74238C1453855F89980C7524F5970940ED83AD89CE7A9BEF8BA105D9D" },
{ "2-105 #52", "20884C02075C59B503CFC392E1A553E2B54F4009EAF8C20E0BFC64C93C52D0AA219E83E952864A5EE34E5C06B43ED58B", 2, "20884C02075C59B503CF0A92E1A553E2B54F40092EF8C2BD0BFC643D3C52D6AA219E" },
{ NULL, NULL, -1, NULL }
};
static int hexbyte(const char *buf)
{
int i;
char c;
c = buf[0];
if (c >= '0' && c <= '9')
i = (c - '0');
else if (c >= 'a' && c <= 'f')
i = (c - 'a' + 10);
else if (c >= 'A' && c <= 'F')
i = (c - 'A' + 10);
else
return -1;
i <<= 4;
c = buf[1];
if (c >= '0' && c <= '9')
return i | (c - '0');
else if (c >= 'a' && c <= 'f')
return i | (c - 'a' + 10);
else if (c >= 'A' && c <= 'F')
return i | (c - 'A' + 10);
else
return -1;
}
static void hex_to_bytes(const char *s, uint8_t *to)
{
for (; *s; s += 2)
*to++ = (uint8_t) hexbyte(s);
}
int main(int argc, char **argv)
{
int i;
uint8_t input[LONG_FRAME_BYTES];
uint8_t expected[LONG_FRAME_DATA_BYTES];
int all_ok = 1;
init_fec();
for (i = 0; downlink_tests[i].testname; ++i) {
int rs_errors;
int frametype;
int ok = 1;
fprintf(stderr, "%s: ", downlink_tests[i].testname);
hex_to_bytes(downlink_tests[i].input, input);
frametype = correct_adsb_frame(input, &rs_errors);
if (frametype != downlink_tests[i].frametype) {
fprintf(stderr, "FAIL: expected frametype %d, got frametype %d\n", downlink_tests[i].frametype, frametype);
ok = 0;
} else if (downlink_tests[i].expected) {
hex_to_bytes(downlink_tests[i].expected, expected);
if (memcmp(expected, input, (frametype == 2) ? LONG_FRAME_DATA_BYTES : SHORT_FRAME_DATA_BYTES) != 0) {
fprintf(stderr, "FAIL: wrong corrected output\n");
ok = 0;
}
}
if (ok)
fprintf(stderr, "PASS\n");
else
all_ok = 0;
}
return all_ok ? 0 : 1;
}

Wyświetl plik

@ -0,0 +1,146 @@
#!/usr/bin/env python2
#
# This takes the output of extract_nexrad and generates images.
# It isn't very smart at the moment and won't draw anything
# until all input has been consumed, so it's not very useful
# for realtime continuous generation of maps.
#
import sys, math
import cairo, colorsys
intensities = {
0: colorsys.hls_to_rgb(240.0/360.0, 0.15, 1.0),
1: colorsys.hls_to_rgb(240.0/360.0, 0.2, 1.0),
2: colorsys.hls_to_rgb(200.0/360.0, 0.4, 1.0),
3: colorsys.hls_to_rgb(160.0/360.0, 0.4, 1.0),
4: colorsys.hls_to_rgb(120.0/360.0, 0.5, 1.0),
5: colorsys.hls_to_rgb(80.0/360.0, 0.5, 1.0),
6: colorsys.hls_to_rgb(40.0/360.0, 0.6, 1.0),
7: colorsys.hls_to_rgb(0.0/360.0, 0.7, 1.0)
}
def color_for(intensity):
r,g,b = intensities[intensity]
return cairo.SolidPattern(r,g,b,1.0)
# mercator projection (yeah, it's not great, but it's simple)
# lat, lon are in _arcminutes_
def project(lat,lon):
lat /= 60.0
lat = math.pi * lat / 180.0
lon /= 60.0
lon -= 360.0
lon = math.pi * lon / 180.0
x = lon
y = math.log(math.tan(math.pi/4.0 + lat/2.0))
return (x,y)
images = {}
while True:
line = sys.stdin.readline()
if not line: break
words = line.strip().split(' ')
if words[0] != 'NEXRAD': continue
nexrad, maptype, maptime, sf, latN, lonW, latSize, lonSize, blockdata = words
sf = int(sf)
latN = int(latN)
lonW = int(lonW)
latSize = int(latSize)
lonSize = int(lonSize)
key = maptype + '/' + maptime
if not key in images:
images[key] = {
'type' : maptype,
'time' : maptime,
'lat_min' : latN - latSize,
'lat_max' : latN,
'lon_min' : lonW,
'lon_max' : lonW + lonSize,
'blocks' : {
sf : [ (latN, lonW, latSize, lonSize, blockdata) ]
}
}
else:
image = images[key]
image['lat_min'] = min(image['lat_min'], latN - latSize)
image['lat_max'] = max(image['lat_max'], latN)
image['lon_min'] = min(image['lon_min'], lonW)
image['lon_max'] = max(image['lon_max'], lonW + lonSize)
if not sf in image['blocks']:
image['blocks'][sf] = [ (latN, lonW, latSize, lonSize, blockdata) ]
else:
image['blocks'][sf].append( (latN, lonW, latSize, lonSize, blockdata) )
for image in images.values():
lat_min = image['lat_min']
lat_max = image['lat_max']
lon_min = image['lon_min']
lon_max = image['lon_max']
# find most detailed scale; scale our image accordingly
sf = min(image['blocks'].keys())
if sf == 1: scale = 5.0
elif sf == 2: scale = 9.0
else: scale = 1.0
pixels_per_degree = 80.0 / scale
# project, find scale
x0,y0 = project(lat_min,lon_min)
x1,y1 = project(lat_min,lon_max)
x2,y2 = project(lat_max,lon_min)
x3,y3 = project(lat_max,lon_max)
xmin = min(x0,x1,x2,x3)
xmax = max(x0,x1,x2,x3)
ymin = min(y0,y1,y2,y3)
ymax = max(y0,y1,y2,y3)
xsize = int(pixels_per_degree * 180.0 * (xmax - xmin) / math.pi)
ysize = int(pixels_per_degree * 180.0 * (ymax - ymin) / math.pi)
print image['type'], image['time'], 'dimensions', xsize, ysize, 'layers', len(image['blocks'])
surface = cairo.ImageSurface(cairo.FORMAT_RGB24, xsize, ysize)
cc = cairo.Context(surface)
cc.set_antialias(cairo.ANTIALIAS_NONE)
cc.scale(1.0 * xsize / (xmax - xmin), -1.0 * ysize / (ymax - ymin))
cc.translate(-xmin, -ymax)
if image['type'] == 'CONUS':
cc.set_source(color_for(0))
else:
r,g,b = colorsys.hls_to_rgb(270.0/360.0, 0.10, 1.0)
cc.set_source(cairo.SolidPattern(r,g,b,1.0))
cc.paint()
for sf in sorted(image['blocks'].keys(), reverse=True): # lowest res first
for latN, lonW, latSize, lonSize, data in image['blocks'][sf]:
for y in xrange(4):
for x in xrange(32):
intensity = int(data[x+y*32])
lat = latN - y * latSize / 4.0
lon = lonW + x * lonSize / 32.0
cc.move_to(*project(lat,lon))
cc.line_to(*project(lat-latSize/4.0,lon))
cc.line_to(*project(lat-latSize/4.0,lon+lonSize/32.0))
cc.line_to(*project(lat,lon+lonSize/32.0))
cc.close_path()
cc.set_source(color_for(intensity))
cc.fill()
surface.write_to_png('nexrad_%s_%s.png' % (image['type'], image['time']))

199
dump978/reader.c 100644
Wyświetl plik

@ -0,0 +1,199 @@
//
// Copyright 2015, Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file 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. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include "uat.h"
#include "reader.h"
struct dump978_reader {
int fd;
char buf[4096];
uint8_t frame[UPLINK_FRAME_DATA_BYTES]; // max uplink frame size
int used;
};
static int process_input(struct dump978_reader *reader, frame_handler_t handler, void *handler_data);
static int process_line(struct dump978_reader *reader, frame_handler_t handler, void *handler_data, char *p, char *end);
static int hexbyte(char *buf);
struct dump978_reader *dump978_reader_new(int fd, int nonblock)
{
struct dump978_reader *reader = calloc(1, sizeof(*reader));
if (!reader)
return NULL;
if (nonblock) {
int flags = fcntl(fd, F_GETFL);
if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
int save_errno = errno;
free(reader);
errno = save_errno;
return NULL;
}
}
reader->fd = fd;
reader->used = 0;
return reader;
}
int dump978_read_frames(struct dump978_reader *reader,
frame_handler_t handler,
void *handler_data)
{
int framecount = 0;
ssize_t bytes_read;
if (!reader) {
errno = EINVAL;
return -1;
}
for (;;) {
if (reader->used == sizeof(reader->buf)) {
// line too long, ditch input
reader->used = 0;
}
bytes_read = read(reader->fd,
reader->buf + reader->used,
sizeof(reader->buf) - reader->used);
if (bytes_read <= 0)
break;
reader->used += bytes_read;
framecount += process_input(reader, handler, handler_data);
}
if (bytes_read == 0)
return framecount; // EOF
// only report EAGAIN et al if no frames were read
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
return (framecount > 0 ? framecount : -1);
return -1; // propagate unexpected error
}
void dump978_reader_free(struct dump978_reader *reader)
{
if (!reader)
return;
free(reader);
}
static int process_input(struct dump978_reader *reader, frame_handler_t handler, void *handler_data)
{
char *p = reader->buf;
char *end = reader->buf + reader->used;
int framecount = 0;
while (p < end) {
char *newline;
newline = memchr(p, '\n', end - p);
if (newline == NULL)
break;
if (*p == '-' || *p == '+')
framecount += process_line(reader, handler, handler_data, p, newline);
p = newline+1;
}
if (p >= end) {
reader->used = 0;
} else {
reader->used = end - p;
memmove(reader->buf, p, reader->used);
}
return framecount;
}
static int process_line(struct dump978_reader *reader, frame_handler_t handler, void *handler_data, char *p, char *end)
{
uint8_t *out;
int len = 0;
frame_type_t frametype;
if (*p == '-')
frametype = UAT_DOWNLINK;
else if (*p == '+')
frametype = UAT_UPLINK;
else
return 0;
out = reader->frame;
++p;
while (p < end) {
int byte;
if (p[0] == ';') {
// ignore rest of line
handler(frametype, reader->frame, len, handler_data);
return 1;
}
if (len >= sizeof(reader->frame))
return 0; // oversized frame
byte = hexbyte(p);
if (byte < 0)
return 0; // badly formatted byte
++len;
*out++ = byte;
p += 2;
}
return 0; // ran off the end without seeing semicolon
}
static int hexbyte(char *buf)
{
int i;
char c;
c = buf[0];
if (c >= '0' && c <= '9')
i = (c - '0');
else if (c >= 'a' && c <= 'f')
i = (c - 'a' + 10);
else if (c >= 'A' && c <= 'F')
i = (c - 'A' + 10);
else
return -1;
i <<= 4;
c = buf[1];
if (c >= '0' && c <= '9')
return i | (c - '0');
else if (c >= 'a' && c <= 'f')
return i | (c - 'a' + 10);
else if (c >= 'A' && c <= 'F')
return i | (c - 'A' + 10);
else
return -1;
}

63
dump978/reader.h 100644
Wyświetl plik

@ -0,0 +1,63 @@
//
// Copyright 2015, Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file 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. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef DUMP978_READER_H
#define DUMP978_READER_H
#include <stdint.h>
struct dump978_reader;
typedef enum { UAT_UPLINK, UAT_DOWNLINK } frame_type_t;
// Function pointer type for a handler called by dump978_read_frames().
// It is called with arguments:
// t: frame type (UAT_UPLINK or UAT_DOWNLINK)
// f: pointer to frame data buffer
// l: length of frame data
// d: value of handler_data passed to dump978_read_frames
// The frame data buffer is a shared buffer owned by the caller
// and may be reused after return; if the handler needs to
// preserve the data after returning, it should take a copy.
typedef void (*frame_handler_t)(frame_type_t t,uint8_t *f,int l,void *d);
// Allocate a new reader that reads from file descriptor 'fd'.
// If 'nonblock' is nonzero, the FD will be made nonblocking.
// Returns the reader, or NULL on error with errno set.
struct dump978_reader *dump978_reader_new(int fd, int nonblock);
// Free a reader previously created by dump978_reader_new.
// Does not close the underlying file descriptor.
void dump978_reader_free(struct dump978_reader *reader);
// Read frames from the given reader.
// Pass complete frames to 'handler', passing 'handler_data'
// as the 4th argument.
//
// Returns a positive number of frames read on success.
// Returns 0 on EOF
// Returns <0 on error with errno set.
// If the underlying FD is nonblocking and no frames are
// available, returns <0 with errno = EAGAIN/EINTR/EWOULDBLOCK.
int dump978_read_frames(struct dump978_reader *reader,
frame_handler_t handler,
void *handler_data);
#endif

Plik binarny nie jest wyświetlany.

44
dump978/uat.h 100644
Wyświetl plik

@ -0,0 +1,44 @@
// Part of dump978, a UAT decoder.
//
// Copyright 2015, Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file 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. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef UAT_H
#define UAT_H
// Frame size constants
#define SHORT_FRAME_DATA_BITS (144)
#define SHORT_FRAME_BITS (SHORT_FRAME_DATA_BITS+96)
#define SHORT_FRAME_DATA_BYTES (SHORT_FRAME_DATA_BITS/8)
#define SHORT_FRAME_BYTES (SHORT_FRAME_BITS/8)
#define LONG_FRAME_DATA_BITS (272)
#define LONG_FRAME_BITS (LONG_FRAME_DATA_BITS+112)
#define LONG_FRAME_DATA_BYTES (LONG_FRAME_DATA_BITS/8)
#define LONG_FRAME_BYTES (LONG_FRAME_BITS/8)
#define UPLINK_BLOCK_DATA_BITS (576)
#define UPLINK_BLOCK_BITS (UPLINK_BLOCK_DATA_BITS+160)
#define UPLINK_BLOCK_DATA_BYTES (UPLINK_BLOCK_DATA_BITS/8)
#define UPLINK_BLOCK_BYTES (UPLINK_BLOCK_BITS/8)
#define UPLINK_FRAME_BLOCKS (6)
#define UPLINK_FRAME_DATA_BITS (UPLINK_FRAME_BLOCKS * UPLINK_BLOCK_DATA_BITS)
#define UPLINK_FRAME_BITS (UPLINK_FRAME_BLOCKS * UPLINK_BLOCK_BITS)
#define UPLINK_FRAME_DATA_BYTES (UPLINK_FRAME_DATA_BITS/8)
#define UPLINK_FRAME_BYTES (UPLINK_FRAME_BITS/8)
#endif

655
dump978/uat2esnt.c 100644
Wyświetl plik

@ -0,0 +1,655 @@
//
// Copyright 2015, Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file 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. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "uat.h"
#include "uat_decode.h"
#include "reader.h"
static void checksum_and_send(uint8_t *frame, int len, uint32_t parity);
// If you call this with constants for firstbit/lastbit
// gcc will do a pretty good job of crunching it down
// to just a couple of operations. Even more so if value
// is also constant.
static inline void setbits(uint8_t *frame, unsigned firstbit, unsigned lastbit, uint32_t value)
{
// convert to 0-based:
unsigned lb = lastbit-1;
// align value with byte layout:
unsigned offset = 7 - (lb&7);
unsigned nb = (lastbit - firstbit + 1 + offset);
uint32_t mask = (1 << (lastbit-firstbit+1))-1;
uint32_t imask = ~(mask << offset);
uint32_t aligned = (value & mask) << offset;
frame[lb >> 3] = (frame[lb >> 3] & imask) | aligned;
if (nb > 8)
frame[(lb >> 3) - 1] = (frame[(lb >> 3) - 1] & (imask >> 8)) | (aligned >> 8);
if (nb > 16)
frame[(lb >> 3) - 2] = (frame[(lb >> 3) - 2] & (imask >> 16)) | (aligned >> 16);
if (nb > 24)
frame[(lb >> 3) - 3] = (frame[(lb >> 3) - 3] & (imask >> 24)) | (aligned >> 24);
}
static int encode_altitude(int ft)
{
int i;
i = (ft + 1000) / 25;
if (i < 0) i = 0;
if (i > 0x7FF) i = 0x7FF;
return (i & 0x000F) | 0x0010 | ((i & 0x07F0) << 1);
}
static int encode_ground_speed(int kt)
{
if (kt > 175)
return 124;
if (kt > 100)
return (kt - 100) / 5 + 108;
if (kt > 70)
return (kt - 70) / 2 + 93;
if (kt > 15)
return (kt - 15) + 38;
if (kt > 2)
return (kt - 2) * 2 + 11;
if (kt == 2)
return 12;
if (kt == 1)
return 8;
return 1;
}
static int encode_air_speed(int kt, int supersonic)
{
int sign;
if (kt < 0) {
sign = 0x0400;
kt = -kt;
} else {
sign = 0;
}
if (supersonic)
kt = kt / 4;
++kt;
if (kt > 1023)
kt = 1023;
return kt | sign;
}
static int encode_vert_rate(int rate)
{
int sign;
if (rate < 0) {
sign = 0x200;
rate = -rate;
} else {
sign = 0;
}
rate = (rate / 64) + 1;
if (rate > 511)
rate = 511;
return rate | sign;
}
static double cprMod(double a, double b) {
double res = fmod(a, b);
if (res < 0) res += b;
return res;
}
static int cprNL(double lat)
{
if (lat < 0) lat = -lat;
if (lat < 10.47047130) return 59;
if (lat < 14.82817437) return 58;
if (lat < 18.18626357) return 57;
if (lat < 21.02939493) return 56;
if (lat < 23.54504487) return 55;
if (lat < 25.82924707) return 54;
if (lat < 27.93898710) return 53;
if (lat < 29.91135686) return 52;
if (lat < 31.77209708) return 51;
if (lat < 33.53993436) return 50;
if (lat < 35.22899598) return 49;
if (lat < 36.85025108) return 48;
if (lat < 38.41241892) return 47;
if (lat < 39.92256684) return 46;
if (lat < 41.38651832) return 45;
if (lat < 42.80914012) return 44;
if (lat < 44.19454951) return 43;
if (lat < 45.54626723) return 42;
if (lat < 46.86733252) return 41;
if (lat < 48.16039128) return 40;
if (lat < 49.42776439) return 39;
if (lat < 50.67150166) return 38;
if (lat < 51.89342469) return 37;
if (lat < 53.09516153) return 36;
if (lat < 54.27817472) return 35;
if (lat < 55.44378444) return 34;
if (lat < 56.59318756) return 33;
if (lat < 57.72747354) return 32;
if (lat < 58.84763776) return 31;
if (lat < 59.95459277) return 30;
if (lat < 61.04917774) return 29;
if (lat < 62.13216659) return 28;
if (lat < 63.20427479) return 27;
if (lat < 64.26616523) return 26;
if (lat < 65.31845310) return 25;
if (lat < 66.36171008) return 24;
if (lat < 67.39646774) return 23;
if (lat < 68.42322022) return 22;
if (lat < 69.44242631) return 21;
if (lat < 70.45451075) return 20;
if (lat < 71.45986473) return 19;
if (lat < 72.45884545) return 18;
if (lat < 73.45177442) return 17;
if (lat < 74.43893416) return 16;
if (lat < 75.42056257) return 15;
if (lat < 76.39684391) return 14;
if (lat < 77.36789461) return 13;
if (lat < 78.33374083) return 12;
if (lat < 79.29428225) return 11;
if (lat < 80.24923213) return 10;
if (lat < 81.19801349) return 9;
if (lat < 82.13956981) return 8;
if (lat < 83.07199445) return 7;
if (lat < 83.99173563) return 6;
if (lat < 84.89166191) return 5;
if (lat < 85.75541621) return 4;
if (lat < 86.53536998) return 3;
if (lat < 87.00000000) return 2;
else return 1;
}
static int cprN(double lat, int odd)
{
int nl = cprNL(lat) - (odd ? 1 : 0);
if (nl < 1)
nl = 1;
return nl;
}
static int encode_cpr_lat(double lat, double lon, int odd, int surface)
{
int NbPow = (surface ? 1<<19 : 1<<17);
double Dlat = 360.0 / (odd ? 59 : 60);
int YZ = floor(NbPow * cprMod(lat, Dlat) / Dlat + 0.5);
return YZ & 0x1FFFF; // always a 17-bit field
}
static int encode_cpr_lon(double lat, double lon, int odd, int surface)
{
int NbPow = (surface ? 1<<19 : 1<<17);
double Dlat = 360.0 / (odd ? 59 : 60);
int YZ = floor(NbPow * cprMod(lat, Dlat) / Dlat + 0.5);
double Rlat = Dlat * (1.0 * YZ / NbPow + floor(lat / Dlat));
double Dlon = (360.0 / cprN(Rlat, odd));
int XZ = floor(NbPow * cprMod(lon, Dlon) / Dlon + 0.5);
return XZ & 0x1FFFF; // always a 17-bit field
}
static int encode_imf(struct uat_adsb_mdb *mdb)
{
// Encode the IMF bit for DF 18; this is 0 if the address
// is a regular 24-bit ICAO address, or 1 if it uses a
// different format.
switch (mdb->address_qualifier) {
case AQ_ADSB_ICAO:
case AQ_TISB_ICAO:
return 0;
default:
return 1;
}
}
static void send_altitude_only(struct uat_adsb_mdb *mdb)
{
uint8_t esnt_frame[14];
int raw_alt;
// Need barometric altitude, see if we have it
if (mdb->altitude_type == ALT_BARO) {
raw_alt = encode_altitude(mdb->altitude);
} else if (mdb->sec_altitude_type == ALT_BARO) {
raw_alt = encode_altitude(mdb->sec_altitude);
} else {
raw_alt = 0;
}
setbits(esnt_frame, 1, 5, 18); // DF=18, ES/NT
setbits(esnt_frame, 6, 8, 6); // CF=6, ADS-R
setbits(esnt_frame, 9, 32, mdb->address); // AA
// ES:
setbits(esnt_frame+4, 1, 5, 0); // FORMAT TYPE CODE = 0, barometric altitude with no position
setbits(esnt_frame+4, 6, 7, 0); // SURVEILLANCE STATUS normal
setbits(esnt_frame+4, 8, 8, encode_imf(mdb)); // IMF
setbits(esnt_frame+4, 9, 20, raw_alt); // ALTITUDE
setbits(esnt_frame+4, 21, 21, 0); // TIME (T)
setbits(esnt_frame+4, 22, 22, 0); // CPR FORMAT (F)
setbits(esnt_frame+4, 23, 39, 0); // ENCODED LATITUDE
setbits(esnt_frame+4, 40, 56, 0); // ENCODED LONGITUDE
checksum_and_send(esnt_frame, 14, 0);
}
static void maybe_send_surface_position(struct uat_adsb_mdb *mdb)
{
uint8_t esnt_frame[14];
if (mdb->airground_state != AG_GROUND)
return; // nope!
setbits(esnt_frame, 1, 5, 18); // DF=18, ES/NT
setbits(esnt_frame, 6, 8, 6); // CF=6, ADS-R
setbits(esnt_frame, 9, 32, mdb->address); // AA
setbits(esnt_frame+4, 1, 5, 8); // FORMAT TYPE CODE = 8, surface position (NUCp=6)
if (!mdb->speed_valid) {
setbits(esnt_frame+4, 6, 12, 0); // MOVEMENT: invalid
} else {
setbits(esnt_frame+4, 6, 12, encode_ground_speed(mdb->speed)); // MOVEMENT
}
if (mdb->track_type != TT_TRACK) {
setbits(esnt_frame+4, 13, 13, 0); // STATUS for ground track: invalid
setbits(esnt_frame+4, 14, 20, 0); // GROUND TRACK (TRUE)
} else {
setbits(esnt_frame+4, 13, 13, 1); // STATUS for ground track: valid
setbits(esnt_frame+4, 14, 20, mdb->track * 128 / 360); // GROUND TRACK (TRUE)
}
setbits(esnt_frame+4, 21, 21, encode_imf(mdb)); // IMF
// even frame:
setbits(esnt_frame+4, 22, 22, 0); // CPR FORMAT (F) = even
setbits(esnt_frame+4, 23, 39, encode_cpr_lat(mdb->lat, mdb->lon, 0, 1)); // ENCODED LATITUDE
setbits(esnt_frame+4, 40, 56, encode_cpr_lon(mdb->lat, mdb->lon, 0, 1)); // ENCODED LONGITUDE
checksum_and_send(esnt_frame, 14, 0);
// odd frame:
setbits(esnt_frame+4, 22, 22, 1); // CPR FORMAT (F) = odd
setbits(esnt_frame+4, 23, 39, encode_cpr_lat(mdb->lat, mdb->lon, 1, 1)); // ENCODED LATITUDE
setbits(esnt_frame+4, 40, 56, encode_cpr_lon(mdb->lat, mdb->lon, 1, 1)); // ENCODED LONGITUDE
checksum_and_send(esnt_frame, 14, 0);
}
static void maybe_send_air_position(struct uat_adsb_mdb *mdb)
{
uint8_t esnt_frame[14];
int raw_alt;
if (mdb->airground_state != AG_SUPERSONIC && mdb->airground_state != AG_SUBSONIC)
return; // nope!
if (!mdb->position_valid) {
send_altitude_only(mdb);
return;
}
setbits(esnt_frame, 1, 5, 18); // DF=18, ES/NT
setbits(esnt_frame, 6, 8, 6); // CF=6, ADS-R
setbits(esnt_frame, 9, 32, mdb->address); // AA
// decide on a metype
switch (mdb->altitude_type) {
case ALT_BARO:
setbits(esnt_frame+4, 1, 5, 18); // FORMAT TYPE CODE = 18, airborne position (baro alt)
raw_alt = encode_altitude(mdb->altitude);
break;
case ALT_GEO:
setbits(esnt_frame+4, 1, 5, 22); // FORMAT TYPE CODE = 22, airborne position (GNSS alt)
raw_alt = encode_altitude(mdb->altitude);
break;
default:
setbits(esnt_frame+4, 1, 5, 18); // FORMAT TYPE CODE = 18, airborne position (baro alt)
raw_alt = 0; // unavailable
break;
}
setbits(esnt_frame+4, 6, 7, 0); // SURVEILLANCE STATUS normal
setbits(esnt_frame+4, 8, 8, encode_imf(mdb)); // IMF
setbits(esnt_frame+4, 9, 20, raw_alt); // ALTITUDE
setbits(esnt_frame+4, 21, 21, 0); // TIME (T)
// even frame:
setbits(esnt_frame+4, 22, 22, 0); // CPR FORMAT (F) - even
setbits(esnt_frame+4, 23, 39, encode_cpr_lat(mdb->lat, mdb->lon, 0, 0)); // ENCODED LATITUDE
setbits(esnt_frame+4, 40, 56, encode_cpr_lon(mdb->lat, mdb->lon, 0, 0)); // ENCODED LONGITUDE
checksum_and_send(esnt_frame, 14, 0);
// odd frame:
setbits(esnt_frame+4, 22, 22, 1); // CPR FORMAT (F) - odd
setbits(esnt_frame+4, 23, 39, encode_cpr_lat(mdb->lat, mdb->lon, 1, 0)); // ENCODED LATITUDE
setbits(esnt_frame+4, 40, 56, encode_cpr_lon(mdb->lat, mdb->lon, 1, 0)); // ENCODED LONGITUDE
checksum_and_send(esnt_frame, 14, 0);
}
static void maybe_send_air_velocity(struct uat_adsb_mdb *mdb)
{
uint8_t esnt_frame[14];
int supersonic;
if (mdb->airground_state != AG_SUPERSONIC && mdb->airground_state != AG_SUBSONIC)
return; // nope!
if (!mdb->ew_vel_valid && !mdb->ns_vel_valid && mdb->vert_rate_source == ALT_INVALID) {
// not really any point sending this
return;
}
setbits(esnt_frame, 1, 5, 18); // DF=18, ES/NT
setbits(esnt_frame, 6, 8, 6); // CF=6, ADS-R
setbits(esnt_frame, 9, 32, mdb->address); // AA
supersonic = (mdb->airground_state == AG_SUPERSONIC);
setbits(esnt_frame+4, 1, 5, 19); // FORMAT TYPE CODE = 19, airborne velocity
if (supersonic)
setbits(esnt_frame+4, 6, 8, 2); // SUBTYPE = 2, supersonic, speed over ground
else
setbits(esnt_frame+4, 6, 8, 1); // SUBTYPE = 1, subsonic, speed over ground
setbits(esnt_frame+4, 9, 9, encode_imf(mdb)); // IMF
setbits(esnt_frame+4, 10, 10, 0); // IFR
setbits(esnt_frame+4, 11, 13, 0); // NAVIGATIONAL UNCERTAINTY CATEGORY FOR VELOCITY
// EAST/WEST DIRECTION BIT + EAST/WEST VELOCITY
if (!mdb->ew_vel_valid)
setbits(esnt_frame+4, 14, 24, 0);
else
setbits(esnt_frame+4, 14, 24, encode_air_speed(mdb->ew_vel, supersonic));
// NORTH/SOUTH DIRECTION BIT + NORTH/SOUTH VELOCITY
if (!mdb->ns_vel_valid)
setbits(esnt_frame+4, 25, 35, 0);
else
setbits(esnt_frame+4, 25, 35, encode_air_speed(mdb->ns_vel, supersonic));
switch (mdb->vert_rate_source) {
case ALT_BARO:
setbits(esnt_frame+4, 36, 36, 0); // SOURCE = BARO
setbits(esnt_frame+4, 37, 46, encode_vert_rate(mdb->vert_rate)); // SIGN BIT FOR VERTICAL RATE + VERTICAL RATE
break;
case ALT_GEO:
setbits(esnt_frame+4, 36, 36, 1); // SOURCE = GNSS
setbits(esnt_frame+4, 37, 46, encode_vert_rate(mdb->vert_rate)); // SIGN BIT FOR VERTICAL RATE + VERTICAL RATE
break;
default:
setbits(esnt_frame+4, 36, 36, 0); // SOURCE = BARO
setbits(esnt_frame+4, 37, 46, 0); // SIGN BIT FOR VERTICAL RATE + VERTICAL RATE = 0, no information
break;
}
setbits(esnt_frame+4, 47, 48, 0); // RESERVED FOR TURN INDICATOR
if (mdb->altitude_type != ALT_INVALID && mdb->sec_altitude_type != ALT_INVALID) {
int delta, sign;
if (mdb->altitude < mdb->sec_altitude) { // secondary above primary
delta = mdb->sec_altitude - mdb->altitude;
sign = mdb->altitude_type == ALT_BARO ? 0 : 1;
} else { // primary above secondary
delta = mdb->altitude - mdb->sec_altitude;
sign = mdb->altitude_type == ALT_BARO ? 1 : 0;
}
delta = delta / 25 + 1;
if (delta >= 127) delta = 127;
setbits(esnt_frame+4, 49, 49, sign); // DIFFERENCE SIGN BIT
setbits(esnt_frame+4, 50, 56, delta); // GNSS ALT DIFFERENCE FROM BARO ALT
} else {
setbits(esnt_frame+4, 49, 49, 0); // DIFFERENCE SIGN BIT
setbits(esnt_frame+4, 50, 56, 0); // GNSS ALT DIFFERENCE FROM BARO ALT = 0, no information
}
checksum_and_send(esnt_frame, 14, 0);
}
// yeah, this could be done with a lookup table, meh.
static char *ais_charset = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?";
static uint8_t char_to_ais(int ch)
{
char *match;
if (!ch)
return 32;
match = strchr(ais_charset, ch);
if (match)
return (uint8_t)(match - ais_charset);
else
return 32;
}
static unsigned encodeSquawk(char *squawkStr)
{
unsigned squawk = strtoul(squawkStr, NULL, 16);
unsigned encoded = 0;
if (squawk & 0x1000) encoded |= 0x0800; // A1
if (squawk & 0x2000) encoded |= 0x0200; // A2
if (squawk & 0x4000) encoded |= 0x0080; // A4
if (squawk & 0x0100) encoded |= 0x0020; // B1
if (squawk & 0x0200) encoded |= 0x0008; // B2
if (squawk & 0x0400) encoded |= 0x0002; // B4
if (squawk & 0x0010) encoded |= 0x1000; // C1
if (squawk & 0x0020) encoded |= 0x0400; // C2
if (squawk & 0x0040) encoded |= 0x0100; // C4
if (squawk & 0x0001) encoded |= 0x0010; // D1
if (squawk & 0x0002) encoded |= 0x0004; // D2
if (squawk & 0x0004) encoded |= 0x0001; // D4
return encoded;
}
static void maybe_send_callsign(struct uat_adsb_mdb *mdb)
{
uint8_t esnt_frame[14];
int imf = encode_imf(mdb);
// NB: we choose a CF value based on the address type (IMF value);
// we shouldn't send CF=6 with no IMF bit for non-ICAO addresses
// (see doc 9871 B.3.4.3)
switch (mdb->callsign_type) {
case CS_CALLSIGN:
setbits(esnt_frame, 1, 5, 18); // DF=18, ES/NT
setbits(esnt_frame, 6, 8, imf ? 5 : 6); // CF=6 for ICAO, CF=5 for non-ICAO
setbits(esnt_frame, 9, 32, mdb->address); // AA
if (mdb->emitter_category <= 7) {
setbits(esnt_frame+4, 1, 5, 4); // FORMAT TYPE CODE = 4, aircraft category A
setbits(esnt_frame+4, 6, 8, mdb->emitter_category & 7); // AIRCRAFT CATEGORY (A0 - A7)
} else if (mdb->emitter_category <= 15) {
setbits(esnt_frame+4, 1, 5, 3); // FORMAT TYPE CODE = 3, aircraft category B
setbits(esnt_frame+4, 6, 8, mdb->emitter_category & 7); // AIRCRAFT CATEGORY (B0 - B7)
} else if (mdb->emitter_category <= 23) {
setbits(esnt_frame+4, 1, 5, 2); // FORMAT TYPE CODE = 2, aircraft category C
setbits(esnt_frame+4, 6, 8, mdb->emitter_category & 7); // AIRCRAFT CATEGORY (C0 - C7)
} else if (mdb->emitter_category <= 31) {
setbits(esnt_frame+4, 1, 5, 1); // FORMAT TYPE CODE = 1, aircraft category D
setbits(esnt_frame+4, 6, 8, mdb->emitter_category & 7); // AIRCRAFT CATEGORY (D0 - D7)
} else {
// reserved, map to A0
setbits(esnt_frame+4, 1, 5, 4); // FORMAT TYPE CODE = 4, aircraft category A
setbits(esnt_frame+4, 6, 8, 0); // AIRCRAFT CATEGORY A0
}
// Map callsign
setbits(esnt_frame+4, 9, 14, char_to_ais(mdb->callsign[0]));
setbits(esnt_frame+4, 15, 20, char_to_ais(mdb->callsign[1]));
setbits(esnt_frame+4, 21, 26, char_to_ais(mdb->callsign[2]));
setbits(esnt_frame+4, 27, 32, char_to_ais(mdb->callsign[3]));
setbits(esnt_frame+4, 33, 38, char_to_ais(mdb->callsign[4]));
setbits(esnt_frame+4, 39, 44, char_to_ais(mdb->callsign[5]));
setbits(esnt_frame+4, 45, 50, char_to_ais(mdb->callsign[6]));
setbits(esnt_frame+4, 51, 56, char_to_ais(mdb->callsign[7]));
checksum_and_send(esnt_frame, 14, 0);
break;
case CS_SQUAWK:
if (imf) {
// Non-ICAO address, send as DF18 "test message"
setbits(esnt_frame, 1, 5, 18); // DF=18, ES/NT
setbits(esnt_frame, 6, 8, 5); // CF=5, TIS-B retransmission with non-ICAO address
setbits(esnt_frame, 9, 32, mdb->address); // AA
setbits(esnt_frame+4, 1, 5, 23); // FORMAT TYPE CODE = 23, test message
setbits(esnt_frame+4, 6, 8, 7); // subtype = 7, squawk
setbits(esnt_frame+4, 9, 21, encodeSquawk(mdb->callsign));
checksum_and_send(esnt_frame, 14, 0);
} else {
// ICAO address, send as DF5
setbits(esnt_frame, 1, 5, 5); // DF=5, Surveillance Identity Reply
setbits(esnt_frame, 6, 8, 0); // Flight Status
setbits(esnt_frame, 9, 13, 0); // Downlink Request
setbits(esnt_frame, 14, 19, 0); // Utility Message
setbits(esnt_frame, 20, 32, encodeSquawk(mdb->callsign)); // Identity
checksum_and_send(esnt_frame, 7, mdb->address); // put address in checksum (Address/Parity)
}
break;
default:
break;
}
}
// Generator polynomial for the Mode S CRC:
#define MODES_GENERATOR_POLY 0xfff409U
// CRC values for all single-byte messages;
// used to speed up CRC calculation.
static uint32_t crc_table[256];
static void initCrcTables()
{
int i;
for (i = 0; i < 256; ++i) {
uint32_t c = i << 16;
int j;
for (j = 0; j < 8; ++j) {
if (c & 0x800000)
c = (c<<1) ^ MODES_GENERATOR_POLY;
else
c = (c<<1);
}
crc_table[i] = c & 0x00ffffff;
}
}
static uint32_t checksum(uint8_t *message, int n)
{
uint32_t rem = 0;
int i;
for (i = 0; i < n; ++i) {
rem = (rem << 8) ^ crc_table[message[i] ^ ((rem & 0xff0000) >> 16)];
rem = rem & 0xffffff;
}
return rem;
}
static void checksum_and_send(uint8_t *frame, int len, uint32_t parity)
{
int j;
uint32_t rem = checksum(frame, len-3) ^ parity;
frame[len-3] = (rem & 0xFF0000) >> 16;
frame[len-2] = (rem & 0x00FF00) >> 8;
frame[len-1] = (rem & 0x0000FF);
fprintf(stdout, "*");
for (j = 0; j < len; j++)
fprintf(stdout, "%02X", frame[j]);
fprintf(stdout, ";\n");
fflush(stdout);
}
static void generate_esnt(struct uat_adsb_mdb *mdb)
{
maybe_send_surface_position(mdb);
maybe_send_air_position(mdb);
maybe_send_air_velocity(mdb);
maybe_send_callsign(mdb);
}
static void handle_frame(frame_type_t type, uint8_t *frame, int len, void *extra)
{
if (type == UAT_DOWNLINK) {
struct uat_adsb_mdb mdb;
uat_decode_adsb_mdb(frame, &mdb);
generate_esnt(&mdb);
}
}
int main(int argc, char **argv)
{
struct dump978_reader *reader;
int framecount;
initCrcTables();
reader = dump978_reader_new(0,0);
if (!reader) {
perror("dump978_reader_new");
return 1;
}
while ((framecount = dump978_read_frames(reader, handle_frame, NULL)) > 0)
;
if (framecount < 0) {
perror("dump978_read_frames");
return 1;
}
return 0;
}

372
dump978/uat2json.c 100644
Wyświetl plik

@ -0,0 +1,372 @@
//
// Copyright 2015, Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file 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. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <time.h>
#include <sys/select.h>
#include <errno.h>
#include "uat.h"
#include "uat_decode.h"
#include "reader.h"
#define NON_ICAO_ADDRESS 0x1000000U
struct aircraft {
struct aircraft *next;
uint32_t address;
uint32_t messages;
time_t last_seen;
time_t last_seen_pos;
int position_valid : 1;
int altitude_valid : 1;
int track_valid : 1;
int speed_valid : 1;
int vert_rate_valid : 1;
airground_state_t airground_state;
char callsign[9];
char squawk[9];
// if position_valid:
double lat;
double lon;
// if altitude_valid:
int32_t altitude; // in feet
// if track_valid:
uint16_t track;
// if speed_valid:
uint16_t speed; // in kts
// if vert_rate_valid:
int16_t vert_rate; // in ft/min
};
static struct aircraft *aircraft_list;
static time_t NOW;
static const char *json_dir;
static struct aircraft *find_aircraft(uint32_t address)
{
struct aircraft *a;
for (a = aircraft_list; a; a = a->next)
if (a->address == address)
return a;
return NULL;
}
static struct aircraft *find_or_create_aircraft(uint32_t address)
{
struct aircraft *a = find_aircraft(address);
if (a)
return a;
a = calloc(1, sizeof(*a));
a->address = address;
a->airground_state = AG_RESERVED;
a->next = aircraft_list;
aircraft_list = a;
return a;
}
static void expire_old_aircraft()
{
struct aircraft *a, **last;
for (last = &aircraft_list, a = *last; a; a = *last) {
if ((NOW - a->last_seen) > 300) {
*last = a->next;
free(a);
} else {
last = &a->next;
}
}
}
static uint32_t message_count;
static void process_mdb(struct uat_adsb_mdb *mdb)
{
struct aircraft *a;
uint32_t addr;
++message_count;
switch (mdb->address_qualifier) {
case AQ_ADSB_ICAO:
case AQ_TISB_ICAO:
addr = mdb->address;
break;
default:
addr = mdb->address | NON_ICAO_ADDRESS;
break;
}
a = find_or_create_aircraft(addr);
a->last_seen = NOW;
++a->messages;
// copy state into aircraft
if (mdb->airground_state != AG_RESERVED)
a->airground_state = mdb->airground_state;
if (mdb->position_valid) {
a->position_valid = 1;
a->lat = mdb->lat;
a->lon = mdb->lon;
a->last_seen_pos = NOW;
}
if (mdb->altitude_type != ALT_INVALID) {
a->altitude_valid = 1;
a->altitude = mdb->altitude;
}
if (mdb->track_type != TT_INVALID) {
a->track_valid = 1;
a->track = mdb->track;
}
if (mdb->speed_valid) {
a->speed_valid = 1;
a->speed = mdb->speed;
}
if (mdb->vert_rate_source != ALT_INVALID) {
a->vert_rate_valid = 1;
a->vert_rate = mdb->vert_rate;
}
if (mdb->callsign_type == CS_CALLSIGN)
strcpy(a->callsign, mdb->callsign);
else if (mdb->callsign_type == CS_SQUAWK)
strcpy(a->squawk, mdb->callsign);
if (mdb->sec_altitude_type != ALT_INVALID) {
// only use secondary if no primary is available
if (!a->altitude_valid || mdb->altitude_type == ALT_INVALID) {
a->altitude_valid = 1;
a->altitude = mdb->sec_altitude;
}
}
}
static int write_receiver_json(const char *dir)
{
char path[PATH_MAX];
FILE *f;
if (snprintf(path, PATH_MAX, "%s/receiver.json.new", dir) >= PATH_MAX) {
fprintf(stderr, "write_receiver_json: path too long\n");
return 0;
}
if (!(f = fopen(path, "w"))) {
fprintf(stderr, "fopen(%s): %m\n", path);
return 0;
}
fprintf(f,
"{\n"
" \"version\" : \"dump978-uat2json\",\n"
" \"refresh\" : 1000,\n"
" \"history\" : 0\n"
"}\n");
fclose(f);
return 1;
}
static int write_aircraft_json(const char *dir)
{
char path[PATH_MAX];
char path_new[PATH_MAX];
FILE *f;
struct aircraft *a;
if (snprintf(path, PATH_MAX, "%s/aircraft.json", dir) >= PATH_MAX || snprintf(path_new, PATH_MAX, "%s/aircraft.json.new", dir) >= PATH_MAX) {
fprintf(stderr, "write_aircraft_json: path too long\n");
return 0;
}
if (!(f = fopen(path_new, "w"))) {
fprintf(stderr, "fopen(%s): %m\n", path_new);
return 0;
}
fprintf(f,
"{\n"
" \"now\" : %u,\n"
" \"messages\" : %u,\n"
" \"aircraft\" : [\n",
(unsigned)NOW,
message_count);
for (a = aircraft_list; a; a = a->next) {
if (a != aircraft_list)
fprintf(f, ",\n");
fprintf(f,
" {\"hex\":\"%s%06x\"",
(a->address & NON_ICAO_ADDRESS) ? "~" : "",
a->address & 0xFFFFFF);
if (a->squawk[0])
fprintf(f, ",\"squawk\":\"%s\"", a->squawk);
if (a->callsign[0])
fprintf(f, ",\"flight\":\"%s\"", a->callsign);
if (a->position_valid)
fprintf(f, ",\"lat\":%.6f,\"lon\":%.6f,\"seen_pos\":%u", a->lat, a->lon, (unsigned) (NOW - a->last_seen_pos));
if (a->altitude_valid)
fprintf(f, ",\"altitude\":%d", a->altitude);
if (a->vert_rate_valid)
fprintf(f, ",\"vert_rate\":%d", a->vert_rate);
if (a->track_valid)
fprintf(f, ",\"track\":%u", a->track);
if (a->speed_valid)
fprintf(f, ",\"speed\":%u", a->speed);
fprintf(f, ",\"messages\":%u,\"seen\":%u,\"rssi\":0}",
a->messages, (unsigned) (NOW - a->last_seen));
}
fprintf(f,
"\n ]\n"
"}\n");
fclose(f);
if (rename(path_new, path) < 0) {
fprintf(stderr, "rename(%s,%s): %m\n", path_new, path);
return 0;
}
return 1;
}
static void periodic_work()
{
static time_t next_write;
if (NOW >= next_write) {
expire_old_aircraft();
write_aircraft_json(json_dir);
next_write = NOW + 1;
}
}
static void handle_frame(frame_type_t type, uint8_t *frame, int len, void *extra)
{
struct uat_adsb_mdb mdb;
if (type != UAT_DOWNLINK)
return;
if (len == SHORT_FRAME_DATA_BYTES) {
if ((frame[0] >> 3) != 0) {
fprintf(stderr, "short frame with non-zero type\n");
return;
}
} else if (len == LONG_FRAME_DATA_BYTES) {
if ((frame[0] >> 3) == 0) {
fprintf(stderr, "long frame with zero type\n");
return;
}
} else {
fprintf(stderr, "odd frame size: %d\n", len);
return;
}
uat_decode_adsb_mdb(frame, &mdb);
//uat_display_adsb_mdb(&mdb, stdout);
process_mdb(&mdb);
}
static void read_loop()
{
struct dump978_reader *reader;
reader = dump978_reader_new(0, 1);
if (!reader) {
perror("dump978_reader_new");
return;
}
for (;;) {
fd_set readset, writeset, excset;
struct timeval timeout;
int framecount;
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_ZERO(&excset);
FD_SET(0, &readset);
FD_SET(0, &excset);
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
select(1, &readset, &writeset, &excset, &timeout);
NOW = time(NULL);
framecount = dump978_read_frames(reader, handle_frame, NULL);
if (framecount == 0)
break;
if (framecount < 0 && errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) {
perror("dump978_read_frames");
break;
}
periodic_work();
}
dump978_reader_free(reader);
}
int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr,
"Syntax: %s <dir>\n"
"\n"
"Reads UAT messages on stdin.\n"
"Periodically writes aircraft state to <dir>/aircraft.json\n"
"Also writes <dir>/receiver.json once on startup\n",
argv[0]);
return 1;
}
json_dir = argv[1];
if (!write_receiver_json(json_dir)) {
fprintf(stderr, "Failed to write receiver.json - check permissions?\n");
return 1;
}
read_loop();
write_aircraft_json(json_dir);
return 0;
}

61
dump978/uat2text.c 100644
Wyświetl plik

@ -0,0 +1,61 @@
//
// Copyright 2015, Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file 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. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdio.h>
#include "uat.h"
#include "uat_decode.h"
#include "reader.h"
void handle_frame(frame_type_t type, uint8_t *frame, int len, void *extra)
{
if (type == UAT_DOWNLINK) {
struct uat_adsb_mdb mdb;
uat_decode_adsb_mdb(frame, &mdb);
uat_display_adsb_mdb(&mdb, stdout);
} else {
struct uat_uplink_mdb mdb;
uat_decode_uplink_mdb(frame, &mdb);
uat_display_uplink_mdb(&mdb, stdout);
}
fprintf(stdout, "\n");
fflush(stdout);
}
int main(int argc, char **argv)
{
struct dump978_reader *reader;
int framecount;
reader = dump978_reader_new(0,0);
if (!reader) {
perror("dump978_reader_new");
return 1;
}
while ((framecount = dump978_read_frames(reader, handle_frame, NULL)) > 0)
;
if (framecount < 0) {
perror("dump978_read_frames");
return 1;
}
return 0;
}

Wyświetl plik

@ -0,0 +1,949 @@
// Part of dump978, a UAT decoder.
//
// Copyright 2015, Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file 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. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <math.h>
#include <string.h>
#include <assert.h>
#include "uat.h"
#include "uat_decode.h"
static void uat_decode_hdr(uint8_t *frame, struct uat_adsb_mdb *mdb)
{
mdb->mdb_type = (frame[0] >> 3) & 0x1f;
mdb->address_qualifier = (address_qualifier_t) (frame[0] & 0x07);
mdb->address = (frame[1] << 16) | (frame[2] << 8) | frame[3];
}
static const char *address_qualifier_names[8] = {
"ICAO address via ADS-B",
"reserved (national use)",
"ICAO address via TIS-B",
"TIS-B track file address",
"Vehicle address",
"Fixed ADS-B Beacon Address",
"reserved (6)",
"reserved (7)"
};
static void uat_display_hdr(const struct uat_adsb_mdb *mdb, FILE *to)
{
fprintf(to,
"HDR:\n"
" MDB Type: %d\n"
" Address: %06X (%s)\n",
mdb->mdb_type,
mdb->address,
address_qualifier_names[mdb->address_qualifier]);
}
static double dimensions_widths[16] = {
11.5, 23, 28.5, 34, 33, 38, 39.5, 45, 45, 52, 59.5, 67, 72.5, 80, 80, 90
};
static void uat_decode_sv(uint8_t *frame, struct uat_adsb_mdb *mdb)
{
uint32_t raw_lat, raw_lon, raw_alt;
mdb->has_sv = 1;
mdb->nic = (frame[11] & 15);
raw_lat = (frame[4] << 15) | (frame[5] << 7) | (frame[6] >> 1);
raw_lon = ((frame[6] & 0x01) << 23) | (frame[7] << 15) | (frame[8] << 7) | (frame[9] >> 1);
if (mdb->nic != 0 || raw_lat != 0 || raw_lon != 0) {
mdb->position_valid = 1;
mdb->lat = raw_lat * 360.0 / 16777216.0;
if (mdb->lat > 90)
mdb->lat -= 180;
mdb->lon = raw_lon * 360.0 / 16777216.0;
if (mdb->lon > 180)
mdb->lon -= 360;
}
raw_alt = (frame[10] << 4) | ((frame[11] & 0xf0) >> 4);
if (raw_alt != 0) {
mdb->altitude_type = (frame[9] & 1) ? ALT_GEO : ALT_BARO;
mdb->altitude = (raw_alt - 1) * 25 - 1000;
}
mdb->airground_state = (frame[12] >> 6) & 0x03;
switch (mdb->airground_state) {
case AG_SUBSONIC:
case AG_SUPERSONIC:
{
int raw_ns, raw_ew, raw_vvel;
raw_ns = ((frame[12] & 0x1f) << 6) | ((frame[13] & 0xfc) >> 2);
if ((raw_ns & 0x3ff) != 0) {
mdb->ns_vel_valid = 1;
mdb->ns_vel = ((raw_ns & 0x3ff) - 1);
if (raw_ns & 0x400)
mdb->ns_vel = 0 - mdb->ns_vel;
if (mdb->airground_state == AG_SUPERSONIC)
mdb->ns_vel *= 4;
}
raw_ew = ((frame[13] & 0x03) << 9) | (frame[14] << 1) | ((frame[15] & 0x80) >> 7);
if ((raw_ew & 0x3ff) != 0) {
mdb->ew_vel_valid = 1;
mdb->ew_vel = ((raw_ew & 0x3ff) - 1);
if (raw_ew & 0x400)
mdb->ew_vel = 0 - mdb->ew_vel;
if (mdb->airground_state == AG_SUPERSONIC)
mdb->ew_vel *= 4;
}
if (mdb->ns_vel_valid && mdb->ew_vel_valid) {
if (mdb->ns_vel != 0 || mdb->ew_vel != 0) {
mdb->track_type = TT_TRACK;
mdb->track = (uint16_t)(360 + 90 - atan2(mdb->ns_vel, mdb->ew_vel) * 180 / M_PI) % 360;
}
mdb->speed_valid = 1;
mdb->speed = (int) sqrt(mdb->ns_vel * mdb->ns_vel + mdb->ew_vel * mdb->ew_vel);
}
raw_vvel = ((frame[15] & 0x7f) << 4) | ((frame[16] & 0xf0) >> 4);
if ((raw_vvel & 0x1ff) != 0) {
mdb->vert_rate_source = (raw_vvel & 0x400) ? ALT_BARO : ALT_GEO;
mdb->vert_rate = ((raw_vvel & 0x1ff) - 1) * 64;
if (raw_vvel & 0x200)
mdb->vert_rate = 0 - mdb->vert_rate;
}
}
break;
case AG_GROUND:
{
int raw_gs, raw_track;
raw_gs = ((frame[12] & 0x1f) << 6) | ((frame[13] & 0xfc) >> 2);
if (raw_gs != 0) {
mdb->speed_valid = 1;
mdb->speed = ((raw_gs & 0x3ff) - 1);
}
raw_track = ((frame[13] & 0x03) << 9) | (frame[14] << 1) | ((frame[15] & 0x80) >> 7);
switch ((raw_track & 0x0600)>>9) {
case 1: mdb->track_type = TT_TRACK; break;
case 2: mdb->track_type = TT_MAG_HEADING; break;
case 3: mdb->track_type = TT_TRUE_HEADING; break;
}
if (mdb->track_type != TT_INVALID)
mdb->track = (raw_track & 0x1ff) * 360 / 512;
mdb->dimensions_valid = 1;
mdb->length = 15 + 10 * ((frame[15] & 0x38) >> 3);
mdb->width = dimensions_widths[(frame[15] & 0x78) >> 3];
mdb->position_offset = (frame[15] & 0x04) ? 1 : 0;
}
break;
case AG_RESERVED:
// nothing
break;
}
if ((frame[0] & 7) == 2 || (frame[0] & 7) == 3) {
mdb->utc_coupled = 0;
mdb->tisb_site_id = (frame[16] & 0x0f);
} else {
mdb->utc_coupled = (frame[16] & 0x08) ? 1 : 0;
mdb->tisb_site_id = 0;
}
}
static void uat_display_sv(const struct uat_adsb_mdb *mdb, FILE *to)
{
if (!mdb->has_sv)
return;
fprintf(to,
"SV:\n"
" NIC: %u\n",
mdb->nic);
if (mdb->position_valid)
fprintf(to,
" Latitude: %+.4f\n"
" Longitude: %+.4f\n",
mdb->lat,
mdb->lon);
switch (mdb->altitude_type) {
case ALT_BARO:
fprintf(to,
" Altitude: %d ft (barometric)\n",
mdb->altitude);
break;
case ALT_GEO:
fprintf(to,
" Altitude: %d ft (geometric)\n",
mdb->altitude);
break;
default:
break;
}
if (mdb->ns_vel_valid)
fprintf(to,
" N/S velocity: %d kt\n",
mdb->ns_vel);
if (mdb->ew_vel_valid)
fprintf(to,
" E/W velocity: %d kt\n",
mdb->ew_vel);
switch (mdb->track_type) {
case TT_TRACK:
fprintf(to,
" Track: %u\n",
mdb->track);
break;
case TT_MAG_HEADING:
fprintf(to,
" Heading: %u (magnetic)\n",
mdb->track);
break;
case TT_TRUE_HEADING:
fprintf(to,
" Heading: %u (true)\n",
mdb->track);
break;
default:
break;
}
if (mdb->speed_valid)
fprintf(to,
" Speed: %u kt\n",
mdb->speed);
switch (mdb->vert_rate_source) {
case ALT_BARO:
fprintf(to,
" Vertical rate: %d ft/min (from barometric altitude)\n",
mdb->vert_rate);
break;
case ALT_GEO:
fprintf(to,
" Vertical rate: %d ft/min (from geometric altitude)\n",
mdb->vert_rate);
break;
default:
break;
}
if (mdb->dimensions_valid)
fprintf(to,
" Dimensions: %.1fm L x %.1fm W%s\n",
mdb->length, mdb->width,
mdb->position_offset ? " (position offset applied)" : "");
fprintf(to,
" UTC coupling: %s\n"
" TIS-B site ID: %u\n",
mdb->utc_coupled ? "yes" : "no",
mdb->tisb_site_id);
}
static char base40_alphabet[40] = "0123456789ABCDEFGHIJKLMNOPQRTSUVWXYZ ..";
static void uat_decode_ms(uint8_t *frame, struct uat_adsb_mdb *mdb)
{
uint16_t v;
int i;
mdb->has_ms = 1;
v = (frame[17]<<8) | (frame[18]);
mdb->emitter_category = (v/1600) % 40;
mdb->callsign[0] = base40_alphabet[(v/40) % 40];
mdb->callsign[1] = base40_alphabet[v % 40];
v = (frame[19]<<8) | (frame[20]);
mdb->callsign[2] = base40_alphabet[(v/1600) % 40];
mdb->callsign[3] = base40_alphabet[(v/40) % 40];
mdb->callsign[4] = base40_alphabet[v % 40];
v = (frame[21]<<8) | (frame[22]);
mdb->callsign[5] = base40_alphabet[(v/1600) % 40];
mdb->callsign[6] = base40_alphabet[(v/40) % 40];
mdb->callsign[7] = base40_alphabet[v % 40];
mdb->callsign[8] = 0;
// trim trailing spaces
for (i = 7; i >= 0; --i) {
if (mdb->callsign[i] == ' ')
mdb->callsign[i] = 0;
else
break;
}
mdb->emergency_status = (frame[23] >> 5) & 7;
mdb->uat_version = (frame[23] >> 2) & 7;
mdb->sil = (frame[23] & 3);
mdb->transmit_mso = (frame[24] >> 2) & 0x3f;
mdb->nac_p = (frame[25] >> 4) & 15;
mdb->nac_v = (frame[25] >> 1) & 7;
mdb->nic_baro = (frame[25] & 1);
mdb->has_cdti = (frame[26] & 0x80 ? 1 : 0);
mdb->has_acas = (frame[26] & 0x40 ? 1 : 0);
mdb->acas_ra_active = (frame[26] & 0x20 ? 1 : 0);
mdb->ident_active = (frame[26] & 0x10 ? 1 : 0);
mdb->atc_services = (frame[26] & 0x08 ? 1 : 0);
mdb->heading_type = (frame[26] & 0x04 ? HT_MAGNETIC : HT_TRUE);
if (mdb->callsign[0])
mdb->callsign_type = (frame[26] & 0x02 ? CS_CALLSIGN : CS_SQUAWK);
}
static const char *emitter_category_names[40] = {
"No information", // A0
"Light <= 7000kg",
"Medium Wake 7000-34000kg",
"Medium Wake 34000-136000kg",
"Medium Wake High Vortex 34000-136000kg",
"Heavy >= 136000kg",
"Highly Maneuverable",
"Rotorcraft", // A7
"reserved (8)", // B0
"Glider/Sailplane",
"Lighter than air",
"Parachutist / sky diver",
"Ultra light / hang glider / paraglider",
"reserved (13)",
"UAV",
"Space / transatmospheric", // B7
"reserved (16)", // C0
"Emergency vehicle",
"Service vehicle",
"Point obstacle",
"Cluster obstacle",
"Line obstacle",
"reserved (22)",
"reserved (23)", // C7
"reserved (24)",
"reserved (25)",
"reserved (26)",
"reserved (27)",
"reserved (28)",
"reserved (29)",
"reserved (30)",
"reserved (31)",
"reserved (32)",
"reserved (33)",
"reserved (34)",
"reserved (35)",
"reserved (36)",
"reserved (37)",
"reserved (38)",
"reserved (39)"
};
static const char *emergency_status_names[8] = {
"No emergency",
"General emergency",
"Lifeguard / Medical emergency",
"Minimum fuel",
"No communications",
"Unlawful interference",
"Downed aircraft",
"reserved"
};
static void uat_display_ms(const struct uat_adsb_mdb *mdb, FILE *to)
{
if (!mdb->has_ms)
return;
fprintf(to,
"MS:\n"
" Emitter category: %s\n"
" Callsign: %s%s\n"
" Emergency status: %s\n"
" UAT version: %u\n"
" SIL: %u\n"
" Transmit MSO: %u\n"
" NACp: %u\n"
" NACv: %u\n"
" NICbaro: %u\n"
" Capabilities: %s%s\n"
" Active modes: %s%s%s\n"
" Target track type: %s\n",
emitter_category_names[mdb->emitter_category],
mdb->callsign_type == CS_SQUAWK ? "squawk " : "",
mdb->callsign_type == CS_INVALID ? "unavailable" : mdb->callsign,
emergency_status_names[mdb->emergency_status],
mdb->uat_version,
mdb->sil,
mdb->transmit_mso,
mdb->nac_p,
mdb->nac_v,
mdb->nic_baro,
mdb->has_cdti ? "CDTI " : "", mdb->has_acas ? "ACAS " : "",
mdb->acas_ra_active ? "ACASRA " : "", mdb->ident_active ? "IDENT " : "", mdb->atc_services ? "ATC " : "",
mdb->heading_type == HT_MAGNETIC ? "magnetic heading" : "true heading");
}
static void uat_decode_auxsv(uint8_t *frame, struct uat_adsb_mdb *mdb)
{
int raw_alt = (frame[29] << 4) | ((frame[30] & 0xf0) >> 4);
if (raw_alt != 0) {
mdb->sec_altitude = (raw_alt - 1) * 25 - 1000;
mdb->sec_altitude_type = (frame[9] & 1) ? ALT_BARO : ALT_GEO;
} else {
mdb->sec_altitude_type = ALT_INVALID;
}
mdb->has_auxsv = 1;
}
static void uat_display_auxsv(const struct uat_adsb_mdb *mdb, FILE *to)
{
if (!mdb->has_auxsv)
return;
fprintf(to,
"AUXSV:\n");
switch (mdb->sec_altitude_type) {
case ALT_BARO:
fprintf(to,
" Sec. altitude: %d ft (barometric)\n",
mdb->sec_altitude);
break;
case ALT_GEO:
fprintf(to,
" Sec. altitude: %d ft (geometric)\n",
mdb->sec_altitude);
break;
default:
fprintf(to,
" Sec. altitude: unavailable\n");
break;
}
}
void uat_decode_adsb_mdb(uint8_t *frame, struct uat_adsb_mdb *mdb)
{
static struct uat_adsb_mdb mdb_zero;
*mdb = mdb_zero;
uat_decode_hdr(frame, mdb);
switch (mdb->mdb_type) {
case 0: // HDR SV
case 4: // HDR SV (TC+0) (TS)
case 7: // HDR SV reserved
case 8: // HDR SV reserved
case 9: // HDR SV reserved
case 10: // HDR SV reserved
uat_decode_sv(frame, mdb);
break;
case 1: // HDR SV MS AUXSV
uat_decode_sv(frame, mdb);
uat_decode_ms(frame, mdb);
uat_decode_auxsv(frame, mdb);
break;
case 2: // HDR SV AUXSV
case 5: // HDR SV (TC+1) AUXSV
case 6: // HDR SV (TS) AUXSV
uat_decode_sv(frame, mdb);
uat_decode_auxsv(frame, mdb);
break;
case 3: // HDR SV MS (TS)
uat_decode_sv(frame, mdb);
uat_decode_ms(frame, mdb);
break;
default:
break;
}
}
void uat_display_adsb_mdb(const struct uat_adsb_mdb *mdb, FILE *to)
{
uat_display_hdr(mdb, to);
uat_display_sv(mdb, to);
uat_display_ms(mdb, to);
uat_display_auxsv(mdb, to);
}
static void uat_decode_info_frame(struct uat_uplink_info_frame *frame)
{
unsigned t_opt;
frame->is_fisb = 0;
if (frame->type != 0)
return; // not FIS-B
if (frame->length < 4) // too short for FIS-B
return;
t_opt = ((frame->data[1] & 0x01) << 1) | (frame->data[2] >> 7);
switch (t_opt) {
case 0: // Hours, Minutes
frame->fisb.monthday_valid = 0;
frame->fisb.seconds_valid = 0;
frame->fisb.hours = (frame->data[2] & 0x7c) >> 2;
frame->fisb.minutes = ((frame->data[2] & 0x03) << 4) | (frame->data[3] >> 4);
frame->fisb.length = frame->length - 4;
frame->fisb.data = frame->data + 4;
break;
case 1: // Hours, Minutes, Seconds
if (frame->length < 5)
return;
frame->fisb.monthday_valid = 0;
frame->fisb.seconds_valid = 1;
frame->fisb.hours = (frame->data[2] & 0x7c) >> 2;
frame->fisb.minutes = ((frame->data[2] & 0x03) << 4) | (frame->data[3] >> 4);
frame->fisb.seconds = ((frame->data[3] & 0x0f) << 2) | (frame->data[4] >> 6);
frame->fisb.length = frame->length - 5;
frame->fisb.data = frame->data + 5;
break;
case 2: // Month, Day, Hours, Minutes
if (frame->length < 5)
return;
frame->fisb.monthday_valid = 1;
frame->fisb.seconds_valid = 0;
frame->fisb.month = (frame->data[2] & 0x78) >> 3;
frame->fisb.day = ((frame->data[2] & 0x07) << 2) | (frame->data[3] >> 6);
frame->fisb.hours = (frame->data[3] & 0x3e) >> 1;
frame->fisb.minutes = ((frame->data[3] & 0x01) << 5) | (frame->data[4] >> 3);
frame->fisb.length = frame->length - 5; // ???
frame->fisb.data = frame->data + 5;
break;
case 3: // Month, Day, Hours, Minutes, Seconds
if (frame->length < 6)
return;
frame->fisb.monthday_valid = 1;
frame->fisb.seconds_valid = 1;
frame->fisb.month = (frame->data[2] & 0x78) >> 3;
frame->fisb.day = ((frame->data[2] & 0x07) << 2) | (frame->data[3] >> 6);
frame->fisb.hours = (frame->data[3] & 0x3e) >> 1;
frame->fisb.minutes = ((frame->data[3] & 0x01) << 5) | (frame->data[4] >> 3);
frame->fisb.seconds = ((frame->data[4] & 0x03) << 3) | (frame->data[5] >> 5);
frame->fisb.length = frame->length - 6;
frame->fisb.data = frame->data + 6;
break;
}
frame->fisb.a_flag = (frame->data[0] & 0x80) ? 1 : 0;
frame->fisb.g_flag = (frame->data[0] & 0x40) ? 1 : 0;
frame->fisb.p_flag = (frame->data[0] & 0x20) ? 1 : 0;
frame->fisb.product_id = ((frame->data[0] & 0x1f) << 6) | (frame->data[1] >> 2);
frame->fisb.s_flag = (frame->data[1] & 0x02) ? 1 : 0;
frame->is_fisb = 1;
}
void uat_decode_uplink_mdb(uint8_t *frame, struct uat_uplink_mdb *mdb)
{
mdb->position_valid = (frame[5] & 0x01) ? 1 : 0;
/* Even with position_valid = 0, there seems to be plausible data here.
* Decode it always.
*/
/*if (mdb->position_valid)*/ {
uint32_t raw_lat = (frame[0] << 15) | (frame[1] << 7) | (frame[2] >> 1);
uint32_t raw_lon = ((frame[2] & 0x01) << 23) | (frame[3] << 15) | (frame[4] << 7) | (frame[5] >> 1);
mdb->lat = raw_lat * 360.0 / 16777216.0;
if (mdb->lat > 90)
mdb->lat -= 180;
mdb->lon = raw_lon * 360.0 / 16777216.0;
if (mdb->lon > 180)
mdb->lon -= 360;
}
mdb->utc_coupled = (frame[6] & 0x80) ? 1 : 0;
mdb->app_data_valid = (frame[6] & 0x20) ? 1 : 0;
mdb->slot_id = (frame[6] & 0x1f);
mdb->tisb_site_id = (frame[7] >> 4);
if (mdb->app_data_valid) {
uint8_t *data, *end;
memcpy(mdb->app_data, frame+8, 424);
mdb->num_info_frames = 0;
data = mdb->app_data;
end = mdb->app_data + 424;
while (mdb->num_info_frames < UPLINK_MAX_INFO_FRAMES && data+2 <= end) {
struct uat_uplink_info_frame *frame = &mdb->info_frames[mdb->num_info_frames];
frame->length = (data[0] << 1) | (data[1] >> 7);
frame->type = (data[1] & 0x0f);
if (data + frame->length + 2 > end) {
// overrun?
break;
}
if (frame->length == 0 && frame->type == 0) {
break; // no more frames
}
frame->data = data + 2;
uat_decode_info_frame(frame);
data += frame->length + 2;
++mdb->num_info_frames;
}
}
}
static void display_generic_data(uint8_t *data, uint16_t length, FILE *to)
{
unsigned i;
fprintf(to,
" Data: ");
for (i = 0; i < length; i += 16) {
unsigned j;
if (i > 0)
fprintf(to,
" ");
for (j = i; j < i+16; ++j) {
if (j < length)
fprintf(to, "%02X ", data[j]);
else
fprintf(to, " ");
}
for (j = i; j < i+16 && j < length; ++j) {
fprintf(to, "%c",
(data[j] >= 32 && data[j] < 127) ? data[j] : '.');
}
fprintf(to, "\n");
}
}
// The odd two-string-literals here is to avoid \0x3ABCDEF being interpreted as a single (very large valued) character
static const char *dlac_alphabet = "\x03" "ABCDEFGHIJKLMNOPQRSTUVWXYZ\x1A\t\x1E\n| !\"#$%&'()*+,-./0123456789:;<=>?";
static const char *decode_dlac(uint8_t *data, unsigned bytelen)
{
static char buf[1024];
uint8_t *end = data + bytelen;
char *p = buf;
int step = 0;
int tab = 0;
while (data < end) {
int ch;
assert(step >= 0 && step <= 3);
switch (step) {
case 0:
ch = data[0] >> 2;
++data;
break;
case 1:
ch = ((data[-1] & 0x03) << 4) | (data[0] >> 4);
++data;
break;
case 2:
ch = ((data[-1] & 0x0f) << 2) | (data[0] >> 6);
break;
case 3:
ch = data[0] & 0x3f;
++data;
break;
}
if (tab) {
while (ch > 0)
*p++ = ' ', ch--;
tab = 0;
} else if (ch == 28) { // tab
tab = 1;
} else {
*p++ = dlac_alphabet[ch];
}
step = (step+1)%4;
}
*p = 0;
return buf;
}
static const char *get_fisb_product_name(uint16_t product_id)
{
switch (product_id) {
case 0: case 20: return "METAR and SPECI";
case 1: case 21: return "TAF and Amended TAF";
case 2: case 22: return "SIGMET";
case 3: case 23: return "Convective SIGMET";
case 4: case 24: return "AIRMET";
case 5: case 25: return "PIREP";
case 6: case 26: return "AWW";
case 7: case 27: return "Winds and Temperatures Aloft";
case 8: return "NOTAM (Including TFRs) and Service Status";
case 9: return "Aerodrome and Airspace – D-ATIS";
case 10: return "Aerodrome and Airspace - TWIP";
case 11: return "Aerodrome and Airspace - AIRMET";
case 12: return "Aerodrome and Airspace - SIGMET/Convective SIGMET";
case 13: return "Aerodrome and Airspace - SUA Status";
case 51: return "National NEXRAD, Type 0 - 4 level";
case 52: return "National NEXRAD, Type 1 - 8 level (quasi 6-level VIP)";
case 53: return "National NEXRAD, Type 2 - 8 level";
case 54: return "National NEXRAD, Type 3 - 16 level";
case 55: return "Regional NEXRAD, Type 0 - low dynamic range";
case 56: return "Regional NEXRAD, Type 1 - 8 level (quasi 6-level VIP)";
case 57: return "Regional NEXRAD, Type 2 - 8 level";
case 58: return "Regional NEXRAD, Type 3 - 16 level";
case 59: return "Individual NEXRAD, Type 0 - low dynamic range";
case 60: return "Individual NEXRAD, Type 1 - 8 level (quasi 6-level VIP)";
case 61: return "Individual NEXRAD, Type 2 - 8 level";
case 62: return "Individual NEXRAD, Type 3 - 16 level";
case 63: return "Global Block Representation - Regional NEXRAD, Type 4 – 8 level";
case 64: return "Global Block Representation - CONUS NEXRAD, Type 4 - 8 level";
case 81: return "Radar echo tops graphic, scheme 1: 16-level";
case 82: return "Radar echo tops graphic, scheme 2: 8-level";
case 83: return "Storm tops and velocity";
case 101: return "Lightning strike type 1 (pixel level)";
case 102: return "Lightning strike type 2 (grid element level)";
case 151: return "Point phenomena, vector format";
case 201: return "Surface conditions/winter precipitation graphic";
case 202: return "Surface weather systems";
case 254: return "AIRMET, SIGMET: Bitmap encoding";
case 351: return "System Time";
case 352: return "Operational Status";
case 353: return "Ground Station Status";
case 401: return "Generic Raster Scan Data Product APDU Payload Format Type 1";
case 402: case 411: return "Generic Textual Data Product APDU Payload Format Type 1";
case 403: return "Generic Vector Data Product APDU Payload Format Type 1";
case 404: case 412: return "Generic Symbolic Product APDU Payload Format Type 1";
case 405: case 413: return "Generic Textual Data Product APDU Payload Format Type 2";
case 600: return "FISDL Products – Proprietary Encoding";
case 2000: return "FAA/FIS-B Product 1 – Developmental";
case 2001: return "FAA/FIS-B Product 2 – Developmental";
case 2002: return "FAA/FIS-B Product 3 – Developmental";
case 2003: return "FAA/FIS-B Product 4 – Developmental";
case 2004: return "WSI Products - Proprietary Encoding";
case 2005: return "WSI Developmental Products";
default: return "unknown";
}
}
static const char *get_fisb_product_format(uint16_t product_id)
{
switch (product_id) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
case 351: case 352: case 353:
case 402: case 405:
return "Text";
case 8: case 9: case 10: case 11: case 12: case 13:
return "Text/Graphic";
case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27:
case 411: case 413:
return "Text (DLAC)";
case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58:
case 59: case 60: case 61: case 62: case 63: case 64:
case 81: case 82: case 83:
case 101: case 102:
case 151:
case 201: case 202:
case 254:
case 401:
case 403:
case 404:
return "Graphic";
case 412:
return "Graphic (DLAC)";
case 600: case 2004:
return "Proprietary";
case 2000: case 2001: case 2002: case 2003: case 2005:
return "Developmental";
default:
return "unknown";
}
}
static void uat_display_fisb_frame(const struct fisb_apdu *apdu, FILE *to)
{
fprintf(to,
"FIS-B:\n"
" Flags: %s%s%s%s\n"
" Product ID: %u (%s) - %s\n",
apdu->a_flag ? "A" : "",
apdu->g_flag ? "G" : "",
apdu->p_flag ? "P" : "",
apdu->s_flag ? "S" : "",
apdu->product_id,
get_fisb_product_name(apdu->product_id),
get_fisb_product_format(apdu->product_id));
fprintf(to,
" Product time: ");
if (apdu->monthday_valid)
fprintf(to, "%u/%u ", apdu->month, apdu->day);
fprintf(to, "%02u:%02u", apdu->hours, apdu->minutes);
if (apdu->seconds_valid)
fprintf(to, ":%02u", apdu->seconds);
fprintf(to, "\n");
switch (apdu->product_id) {
case 413:
{
// Generic text, DLAC
const char *text = decode_dlac(apdu->data, apdu->length);
const char *report = text;
while (report) {
char report_buf[1024];
const char *next_report;
char *p, *r;
next_report = strchr(report, '\x1e'); // RS
if (!next_report)
next_report = strchr(report, '\x03'); // ETX
if (next_report) {
memcpy(report_buf, report, next_report - report);
report_buf[next_report - report] = 0;
report = next_report + 1;
} else {
strcpy(report_buf, report);
report = NULL;
}
if (!report_buf[0])
continue;
r = report_buf;
p = strchr(r, ' ');
if (p) {
*p = 0;
fprintf(to,
" Report type: %s\n",
r);
r = p+1;
}
p = strchr(r, ' ');
if (p) {
*p = 0;
fprintf(to,
" Report location: %s\n",
r);
r = p+1;
}
p = strchr(r, ' ');
if (p) {
*p = 0;
fprintf(to,
" Report time: %s\n",
r);
r = p+1;
}
fprintf(to,
" Text:\n%s\n",
r);
}
}
break;
default:
display_generic_data(apdu->data, apdu->length, to);
break;
}
}
static const char *info_frame_type_names[16] = {
"FIS-B APDU",
"Reserved for Developmental Use",
"Reserved for Future Use (2)",
"Reserved for Future Use (3)",
"Reserved for Future Use (4)",
"Reserved for Future Use (5)",
"Reserved for Future Use (6)",
"Reserved for Future Use (7)",
"Reserved for Future Use (8)",
"Reserved for Future Use (9)",
"Reserved for Future Use (10)",
"Reserved for Future Use (11)",
"Reserved for Future Use (12)",
"Reserved for Future Use (13)",
"Reserved for Future Use (14)",
"TIS-B/ADS-R Service Status"
};
static void uat_display_uplink_info_frame(const struct uat_uplink_info_frame *frame, FILE *to)
{
fprintf(to,
"INFORMATION FRAME:\n"
" Length: %u bytes\n"
" Type: %u (%s)\n",
frame->length,
frame->type,
info_frame_type_names[frame->type]);
if (frame->length > 0) {
if (frame->is_fisb)
uat_display_fisb_frame(&frame->fisb, to);
else {
display_generic_data(frame->data, frame->length, to);
}
}
}
void uat_display_uplink_mdb(const struct uat_uplink_mdb *mdb, FILE *to)
{
fprintf(to,
"UPLINK:\n");
fprintf(to,
" Site Latitude: %+.4f%s\n"
" Site Longitude: %+.4f%s\n",
mdb->lat, mdb->position_valid ? "" : " (possibly invalid)",
mdb->lon, mdb->position_valid ? "" : " (possibly invalid)");
fprintf(to,
" UTC coupled: %s\n"
" Slot ID: %u\n"
" TIS-B Site ID: %u\n",
mdb->utc_coupled ? "yes" : "no",
mdb->slot_id,
mdb->tisb_site_id);
if (mdb->app_data_valid) {
unsigned i;
for (i = 0; i < mdb->num_info_frames; ++i)
uat_display_uplink_info_frame(&mdb->info_frames[i], to);
}
}

Wyświetl plik

@ -0,0 +1,192 @@
// Part of dump978, a UAT decoder.
//
// Copyright 2015, Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file 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. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef UAT_DECODE_H
#define UAT_DECODE_H
#include <stdint.h>
#include <stdio.h>
#include "uat.h"
//
// Datatypes
//
typedef enum { AQ_ADSB_ICAO=0, AQ_NATIONAL=1, AQ_TISB_ICAO=2, AQ_TISB_OTHER=3, AQ_VEHICLE=4,
AQ_FIXED_BEACON=5, AQ_RESERVED_6=6, AQ_RESERVED_7=7 } address_qualifier_t;
typedef enum { ALT_INVALID=0, ALT_BARO, ALT_GEO } altitude_type_t;
typedef enum { AG_SUBSONIC=0, AG_SUPERSONIC=1, AG_GROUND=2, AG_RESERVED=3 } airground_state_t;
typedef enum { TT_INVALID=0, TT_TRACK, TT_MAG_HEADING, TT_TRUE_HEADING } track_type_t;
typedef enum { HT_INVALID=0, HT_MAGNETIC, HT_TRUE } heading_type_t;
typedef enum { CS_INVALID=0, CS_CALLSIGN, CS_SQUAWK } callsign_type_t;
struct uat_adsb_mdb {
// presence bits
int has_sv : 1;
int has_ms : 1;
int has_auxsv : 1;
int position_valid : 1;
int ns_vel_valid : 1;
int ew_vel_valid : 1;
int speed_valid : 1;
int dimensions_valid : 1;
//
// HDR
//
uint8_t mdb_type;
address_qualifier_t address_qualifier;
uint32_t address;
//
// SV
//
// if position_valid:
double lat;
double lon;
altitude_type_t altitude_type;
int32_t altitude; // in feet
uint8_t nic;
airground_state_t airground_state;
// if ns_vel_valid:
int16_t ns_vel; // in kts
// if ew_vel_valid:
int16_t ew_vel; // in kts
track_type_t track_type;
uint16_t track;
// if speed_valid:
uint16_t speed; // in kts
altitude_type_t vert_rate_source;
int16_t vert_rate; // in ft/min
// if lengthwidth_valid:
double length; // in meters (just to be different)
double width; // in meters (just to be different)
int position_offset : 1; // true if Position Offset Applied
int utc_coupled : 1; // true if UTC Coupled flag is set (ADS-B)
uint8_t tisb_site_id; // TIS-B site ID, or zero in ADS-B messages
//
// MS
//
uint8_t emitter_category;
callsign_type_t callsign_type;
char callsign[9];
uint8_t emergency_status;
uint8_t uat_version;
uint8_t sil;
uint8_t transmit_mso;
uint8_t nac_p;
uint8_t nac_v;
uint8_t nic_baro;
// capabilities:
int has_cdti : 1;
int has_acas : 1;
// operational modes:
int acas_ra_active : 1;
int ident_active : 1;
int atc_services : 1;
heading_type_t heading_type;
//
// AUXSV
altitude_type_t sec_altitude_type;
int32_t sec_altitude; // in feet
};
//
// Decode/display prototypes
//
void uat_decode_adsb_mdb(uint8_t *frame, struct uat_adsb_mdb *mdb);
void uat_display_adsb_mdb(const struct uat_adsb_mdb *mdb, FILE *to);
//
// UPLINK
//
// assume 6 byte frames: 2 header bytes, 4 byte payload
// (TIS-B heartbeat with one address, or empty FIS-B APDU)
#define UPLINK_MAX_INFO_FRAMES (424/6)
struct fisb_apdu {
int a_flag : 1;
int g_flag : 1;
int p_flag : 1;
int s_flag : 1;
int monthday_valid : 1;
int seconds_valid : 1;
uint16_t product_id;
uint8_t month; // if monthday_valid
uint8_t day; // if monthday_valid
uint8_t hours;
uint8_t minutes;
uint8_t seconds; // if seconds_valid
uint16_t length;
uint8_t *data;
};
struct uat_uplink_info_frame {
int is_fisb : 1;
uint16_t length;
uint8_t type;
uint8_t *data; // points within the containing appdata
// if is_fisb:
struct fisb_apdu fisb;
};
struct uat_uplink_mdb {
int position_valid : 1;
int utc_coupled : 1;
int app_data_valid : 1;
// if position_valid:
double lat;
double lon;
uint8_t slot_id;
uint8_t tisb_site_id;
// if app_data_valid:
uint8_t app_data[424];
unsigned num_info_frames;
struct uat_uplink_info_frame info_frames[UPLINK_MAX_INFO_FRAMES];
};
void uat_decode_uplink_mdb(uint8_t *frame, struct uat_uplink_mdb *mdb);
void uat_display_uplink_mdb(const struct uat_uplink_mdb *mdb, FILE *to);
#endif

Wyświetl plik

@ -0,0 +1,26 @@
Spindle is licensed under the terms of the MIT license reproduced below.
#####################################################
Copyright (c) 2012 Alex Bradbury <asb@asbradbury.org>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

Wyświetl plik

@ -0,0 +1,82 @@
# spindle - a tool to help spin distribution images
## Description
spindle is a set of scripts to aid building and working on a distribution
image. I've been using this tool to generate Debian wheezy images for the
Raspberry Pi, with the aim of producing reproducible, unbooted, clean setups
that require no manual intervention. It works by producing a series of image
files in QEMU's QED format (I exploit the format's support for backing files
and copy on write).
It's not massively user friendly yet, but hopefully that should soon change
(and of course, patches are welcome).
## Project links
* [Home](http://asbradbury.org/projects/spindle/)
* [Source](https://github.com/asb/spindle)
* [Issues](https://github.com/asb/spindle/issues)
## Current scripts
* `setup_spindle_environment`: Sets up an schroot using wheezy and installs
the pre-requisites needed for spindle (mainly QEMU, as it turns out I haven't
used augeas). If you don't use this, please make sure you have at least QEMU
1.0.1
* `wheezy-stage0`: Create and partition an SD card image, perform the initial
debootstrap on the host and copy the files to the SD image.
* `wheezy-stage1`: Complete second stage of debootstrap under QEMU after first
setting up a squashfs filesystem derived from Rob Landley's excellent
Aboriginal Linux. Setup dropbear.
* `wheezy-stage2`: Add in Raspberry Pi 'firmware' and do misc config (e.g.
fstab, network interfaces, hostname). The resulting image is bootable.
* `wheezy-stage3`: Install and configure a few useful packages (such as
ifplugd, sudo).
* `wheezy-stage4-lxde`: Set up the lxde desktop.
* `wheezy-stage4-lxde-edu`: Install MIT Scratch, Python development tools and
other packages.
## Getting started
The following describes how to start building SD card images using spindle.
The process isn't massively user friendly for people with no experience at
all, but if you're currently doing this by hand then hopefully you'll find it
helpful. Note that executing the `downgrade_qemu` script is necessary on most
Debian and Ubuntu versions right now.
sudo ./setup_spindle_environment my_spindle_chroot
sudo modprobe nbd max_part=16
schroot -c spindle
sudo ./downgrade_qemu
./wheezy-stage0
./wheezy-stage1
./wheezy-stage2
./wheezy-stage3
./wheezy-stage4-lxde
./helper export_image_for_release out/stage4-lxde.qed stage4-lxde.img
Now you can write stage4-lxde.img to SD card.
Take a look at `wheezy-stage4-lxde` to see how to add your own stage if you
want further customisation.
## HACKING
If you want to contribute, please do file issues on the bug tracker or send in
patches/pull requests.
spindle is written in POSIX shell script and tries to make use of QEMU where
possible for manipulating the filesystem of the target being generated. Look
at the current scripts for examples. Please do talk to me if you're thinking
of any large refactoring.
Good resources for shell scripting include:
* `man dash`
* [The POSIX standard](http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html)
* [Insufficiently known POSIX shell features](http://apenwarr.ca/log/?m=201102#28)
* [Common shell scripting mistakes](http://www.pixelbeat.org/programming/shell_script_mistakes.html)
## License
MIT. See the LICENSE file.
## Contact
Author: Alex Bradbury
Email: <asb@asbradbury.org>
Homepage: <http://asbradbury.org/>

Wyświetl plik

@ -0,0 +1,446 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
set -e
. ./config
run_qemu() {
rm fifo.out fifo.in || true
mkfifo fifo.out fifo.in
qemu-system-arm -M versatilepb -cpu arm1136-r2 -m 256 -nographic -no-reboot \
-kernel zImage -hda qemu_rootfs.sqf -drive file=$1,index=1,media=disk,cache=unsafe \
-drive file=wheezy_apt_cache.$IMGFORMAT,index=2,media=disk,cache=unsafe \
-append "root=/dev/sda rw init=/sbin/init.sh panic=1 PATH=/bin:/sbin console=ttyAMA0 HOST=armv6l"\
-net nic,model=rtl8139 -net user -redir tcp:22000::22 -daemonize -serial pipe:fifo \
-pidfile qemu.pid
sleep 10
}
ssh_in_to_qemu() {
ssh -i qemu_arm_key -p 22000 -lroot localhost "$@"
}
scp_in_to_qemu() {
scp -i qemu_arm_key -P 22000 "$1" root@localhost:"$2"
}
scp_r_from_qemu() {
scp -r -i qemu_arm_key -P 22000 root@localhost:"$1" "$2"
}
onvm_chroot() {
ssh_in_to_qemu chroot /mnt "$@"
}
shutdown_qemu() {
ssh_in_to_qemu "sync && umount -a" || true
echo "exit" > fifo.in
sleep 5
if [ -e qemu.pid ]; then
QEMU_PID=$(cat qemu.pid)
while [ -n "$QEMU_PID" ]; do
set +e
kill -0 $QEMU_PID 2>/dev/null
if [ $? -eq 0 ]; then
printf "Qemu pid %s not finished yet. Waiting\n" "$QEMU_PID"
sleep 1
else
QEMU_PID=""
fi
set -e
done
fi
rm fifo.in
rm fifo.out
# sleep 15
}
attach_image_to_nbd() {
# use -v as we seem to have problems otherwise...
sudo qemu-nbd --nocache -v -c $2 $1 &
sleep 5
}
detach_image_from_nbd() {
sudo qemu-nbd -d $1
}
inspect_image() {
cd work
qemu-img create -f $IMGFORMAT -b ../$1 temp.$IMGFORMAT
# Sigh http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=390433
trap '[ -p fifo.in ] && shutdown_qemu' EXIT
trap '[ -p fifo.in ] && shutdown_qemu; trap - INT; kill -INT $$' INT
run_qemu temp.$IMGFORMAT
ssh_in_to_qemu # -t chroot /mnt bash -l
shutdown_qemu
cd $OLDPWD
}
branch_image() {
qemu-img create -f $IMGFORMAT -b $1 $2
}
write_image() {
attach_image_to_nbd $1 /dev/nbd0 &&
sudo dd if=/dev/nbd0 of=$2 bs=4M &&
detach_image_from_nbd /dev/nbd0
}
convert_image() {
qemu-img convert -f $IMGFORMAT -O raw $1 $2
}
export_image_for_release() {
cd work
qemu-img create -f $IMGFORMAT -b ../$1 temp.$IMGFORMAT
run_qemu temp.$IMGFORMAT
# Change mirror in sources.list to our preferred one. This will go horribly
# wrong if there is more than one entry in sources.list
onvm_chroot sh -l -ex <<\EOF
if grep armhf /etc/rpi-issue; then
sed -i /etc/apt/sources.list -e "s|^deb [^ ]*|deb http://mirrordirector.raspbian.org/raspbian/|"
else
sed -i /etc/apt/sources.list -e "s|^deb [^ ]*|deb http://http.debian.net/debian|"
fi
cp /usr/share/doc/raspi-config/sample_profile_d.sh /etc/profile.d/raspi-config.sh
apt-get update
# Default to a known-good nameserver
printf "nameserver 8.8.8.8\n" > /etc/resolv.conf
/etc/init.d/fake-hwclock stop # save current time
#rm /usr/bin/raspi-config
#cd /usr/bin
#wget https://raw.github.com/asb/raspi-config/master/raspi-config
#chmod +x raspi-config
cat <<EOF1 > /etc/apt/sources.list.d/raspi.list
deb http://archive.raspberrypi.org/debian/ wheezy main
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
#deb-src http://archive.raspberrypi.org/debian/ wheezy main
EOF1
apt-get update
EOF
shutdown_qemu
attach_image_to_nbd temp.$IMGFORMAT /dev/nbd0
sudo zerofree -v /dev/nbd0p2
mkdir -p rootfs boot
sudo mount $BOOT_DEV boot
sudo mount $ROOT_DEV rootfs
sudo cp rootfs/etc/rpi-issue boot/issue.txt
sudo wget http://asbradbury.org/tmp/raspi/oracle_license.txt -O boot/LICENSE.oracle
[ -n "$RASPBIAN" ] && sudo mv rootfs/etc/ld.so.preload.disable rootfs/etc/ld.so.preload
if [ -n "$NOOBS" ]; then
mkdir -p ../noobs
sudo tar -C boot -cJf ../noobs/boot.tar.xz --preserve .
sudo tar -C rootfs -cJf ../noobs/root.tar.xz --preserve .
cat <<\EOF > ../noobs/partition_setup.sh
#!/bin/sh
set -ex
if [ -z "$part1" ] || [ -z "$part2" ]; then
printf "Error: missing environment variable part1 or part2\n" 1>&2
exit 1
fi
mkdir -p /tmp/1 /tmp/2
mount "$part1" /tmp/1
mount "$part2" /tmp/2
sed /tmp/1/cmdline.txt -i -e "s|root=/dev/[^ ]*|root=${part2}|"
sed /tmp/2/etc/fstab -i -e "s|^.* / |${part2} / |"
sed /tmp/2/etc/fstab -i -e "s|^.* /boot |${part1} /boot |"
umount /tmp/1
umount /tmp/2
EOF
cat <<\EOF > ../noobs/partitions.json
{
"partitions": [
{
"label": "boot",
"filesystem_type": "FAT",
"partition_size_nominal": 60,
"want_maximised": false,
"uncompressed_tarball_size": 19
},
{
"label": "root",
"filesystem_type": "ext4",
"partition_size_nominal": 2500,
"want_maximised": true,
"mkfs_options": "-O ^huge_file",
"uncompressed_tarball_size": 2280
}
]
}
EOF
cat <<\EOF > ../noobs/flavours.json
{
"flavours": [
{
"name": "Raspbian - Boot to Scratch",
"description": "A version of Raspbian that boots straight into Scratch"
},
{
"name": "Raspbian",
"description": "A Debian wheezy port, optimised for the Raspberry Pi"
}
]
}
EOF
cat <<\EOF > ../noobs/os.json
{
"name": "Raspbian",
"version": "wheezy",
"release_date": "2015-02-16",
"kernel": "3.18",
"description": "A community-created port of Debian wheezy, optimised for the Raspberry Pi"
}
EOF
cat <<\EOF > ../noobs/release_notes.txt
2015-02-16:
* Newer firmware with various fixes
* New Sonic Pi release
* Pi2 compatible RPi.GPIO
* Updated Wolfram Mathematica
2015-01-31:
* Support for Pi2
* Newer firmware
* New Sonic Pi release
* Updated Scratch
* New Wolfram Mathematica release
* Updated Epiphany
2014-12-24:
* Fix regression with omission of python-pygame
2014-12-22:
* New firmware with variosu fixes and improvements
* New UI configuration for lxde
* Various package updates
* python3-pygame preinstalled
* 'nuscratch', scratch running on the Cog StackVM
* Misc other changes
2014-09-09:
* New firmware with various fixes and improvements
* Minecraft Pi pre-installed
* Sonic Pi upgraded to 2.0
* Include Epiphany browser work from Collabora
* Switch to Java 8 from Java 7
* Updated Mathematica
* Misc minor configuration changes
2014-06-20:
* New firmware with various fixes, and kernel bugfix
2014-06-02:
* Many, many firmware updates with major USB improvements
* pyserial installed by default
* picamera installed by default
2014-01-07:
* Firmware updated
* Some space saved on the root filesystem
2013-12-20:
* Firmware updated, includes V4L2 fixes
* Update omxplayer
2013-12-18:
* Firmware updated and now using kernel 3.10. Many, many improvements
* fbturbo XOrg driver is now included and enabled by default. Thanks to
ssvb https://github.com/ssvb/xf86-video-fbturbo
* Update Scratch image with further bug fixes
* Include Wolfram Mathematica
* Update to PyPy 2.2
* Update omxplayer
* Include v4l-utils for use with experimental V4L2 Raspberry Pi camera driver
* Update squeak-vm to fix issues with loading JPEGs
2013-09-25:
* Update Scratch image for further performance improvements
* Include Oracle JDK
* At least a 4GiB SD card is now required (see above)
* Include PyPy 2.1
* Include base piface packages
* Update raspi-config to include bugfix for inheriting language settings
from NOOBS
2013-09-10:
* Updated to current top of tree firmware
* Update squeak-vm, including fastblit optimised for the Raspbery Pi
* Include Sonic Pi and a fixed jackd2 package
* Support boot to Scratch
* Inherit keyboard and language settings from NOOBS
EOF
wget http://asbradbury.org/tmp/raspi/marketing.tar -O ../noobs/marketing.tar
fi
sleep 10
sudo umount $BOOT_DEV
sudo umount $ROOT_DEV
detach_image_from_nbd /dev/nbd0
convert_image temp.$IMGFORMAT ../$2
}
disable_starting_services() {
ssh_in_to_qemu chroot /mnt sh -ex - <<EOF
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
printf '#!/bin/sh\nexit 101\n' > /usr/sbin/policy-rc.d
chmod 755 /usr/sbin/policy-rc.d
EOF
}
allow_starting_services() {
ssh_in_to_qemu chroot /mnt sh -ex - <<EOF
rm /usr/sbin/policy-rc.d
EOF
}
save_space_using_hardlink() {
onvm_chroot sh -l -e - <<\EOF
hardlink -t /usr/share/doc
EOF
}
mount_apt_cache() {
ssh_in_to_qemu sh -e - <<EOF
mount -o noatime /dev/sdc /mnt/var/cache/apt
EOF
}
download_if_necessary() {
[ -f $(basename "$1") ] || wget "$1"
}
get_git_hash() {
git log --pretty=format:'%h' -n 1
}
update_issue() {
GIT_HASH=$(get_git_hash) &&
CUR_DATE=$(date "+%Y-%m-%d")
onvm_chroot sh -l -e <<EOF
printf "Raspberry Pi reference $CUR_DATE ($TGT_ARCH)\nGenerated using spindle, http://asbradbury.org/projects/spindle/, $GIT_HASH, $CURIMG\n" > /etc/rpi-issue
EOF
}
# Create a list of all installed packages, all manually installed packages and
# the debconf selections
fingerprint_debian() {
FNGPRNT_DIR="$CURIMG.fingerprint" &&
onvm_chroot sh -l -e <<EOF &&
mkdir -p "/tmp/$FNGPRNT_DIR"
cd "/tmp/$FNGPRNT_DIR"
dpkg --get-selections > dpkg_selections
dpkg -l > dpkg_l
apt-mark showauto > apt-mark_showauto
debconf-get-selections > debconf_selections
EOF
scp_r_from_qemu "/mnt/tmp/$FNGPRNT_DIR" . &&
cd "$FNGPRNT_DIR" &&
grep "[[:space:]]install$" dpkg_selections | cut -f1 | sort apt-mark_showauto - | uniq -u > manually_installed_packages &&
cd "$OLDPWD"
}
finish_image() {
chmod -w $CURIMG &&
mkdir -p ../$OUTDIR &&
mv -f $CURIMG ../$OUTDIR &&
if [ -d "$CURIMG.fingerprint" ]; then
rm -rf "../$OUTDIR/$CURIMG.fingerprint" &&
mv "$CURIMG.fingerprint" ../$OUTDIR
fi &&
FINISHED_SUCCESSFULLY=1 &&
printf "Completed script successfully\n"
}
# Usage: ask_yn default prompt [printf_args...]
# Read a Yes / No user response. If $ASK_YN_USE_DEFAULT is set, assume the
# default. Return of 0 indicates a yes, and non-zero is no.
ask_yn() {
OPT="y/n"
case "$1" in
y*|Y*) OPT="Y/n"; RET=0;;
n*|N*) OPT="y/N"; RET=1;;
*) die "Programmer error: invalid argument to ask_yn"
esac
shift
if [ "$ASK_YN_USE_DEFAULT" ]; then
return $RET
else
PROMPT=$1
shift
printf "$PROMPT [$OPT]: " "$@" && read YN
case "$YN" in
y*|Y*) return 0;;
n*|N*) return 1;;
"") return $RET
esac
fi
}
# Usage: read_val var default prompt [printf_args...]
read_val() {
RV_VAR=$1
RV_DEFAULT=$2
RV_PROMPT=$3
shift 3
printf "$RV_PROMPT [$RV_DEFAULT]: " "$@" && read RV_VAL
[ -z "$RV_VAL" ] && RV_VAL=$RV_DEFAULT
eval "$RV_VAR=\$RV_VAL"
}
die() {
FMTSTR=$1
shift
printf "Died: $FMTSTR\n" "$@" >&2
exit 1
}
# do a task
# Inspects $DOTASK_MODE to see if the user:
# e*: wants to have the command echoed
# q*: wants to be questioned as to whether to run, skip or quit.
# If the task fails it asks the user whether to quit (default: y), or if
# $DOTASK_QUIT_ON_FAILURE is set then quit without asking the user.
dotask() {
case "$DOTASK_MODE" in
e*) printf "Run: '%s'\n" "$*"; false;;
q*) printf "Run: '%s' [Y/n/q] ? " "$*" && read SHOULD_RUN;
case "$SHOULD_RUN" in
n*|N*|s*|S*) printf "Skip '%s'\n" "$*";;
q*|Q*) die "Exit at user request";;
*) false;;
esac;;
*) false;;
esac || "$@" || { RC=$?
[ -z "$DOTASK_QUIT_ON_FAILURE" ] && printf "'%s' failed (returned $RC) - Quit? [Y/n] : " "$*" && read YN
case "$YN" in n*|N*) true ;; *) die "Failed while performing task: %s" "$*";; esac;
}
}
FINISHED_SUCCESSFULLY=0
CLEANED_UP=0
WAS_TRAPPED=0
# Sigh http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=390433
trap 'WAS_TRAPPED=1; universal_cleanup' EXIT
trap 'WAS_TRAPPED=1; universal_cleanup; trap - INT; kill -INT $$' INT
universal_cleanup() {
set +e
if [ $CLEANED_UP -ne 1 ]; then
printf "Initiating cleanup\n"
trap - INT
trap - EXIT
[ -p fifo.in ] && shutdown_qemu
[ -b "$BOOT_DEV" ] && sudo umount $BOOT_DEV
[ -b "$ROOT_DEV" ] && sudo umount $ROOT_DEV
[ -b "$NBD_DEV" ] && sudo umount $NBD_DEV
[ -b "$NBD_DEV" ] && detach_image_from_nbd $NBD_DEV
fi
if [ $WAS_TRAPPED -eq 1 ] && [ $FINISHED_SUCCESSFULLY -eq 0 ]; then
printf "Did not complete script successfully\n"
fi
set -e
}

Wyświetl plik

@ -0,0 +1,25 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
RASPBIAN=1
if [ -n "$RASPBIAN" ]; then
TGT_ARCH=armhf
DEB_MIRROR=http://mirror.ox.ac.uk/sites/archive.raspbian.org/archive/raspbian/
else
TGT_ARCH=armel
#DEB_MIRROR=http://ftp.uk.debian.org/debian
DEB_MIRROR=http://www-uxsup.csx.cam.ac.uk/pub/linux/debian
fi
NBD_DEV=/dev/nbd0
BOOT_DEV="$NBD_DEV"p1
ROOT_DEV="$NBD_DEV"p2
IMGFORMAT=qed
SDSIZE=3125M
# Changing these isn't currently supported
WORKDIR=work
OUTDIR=out

Wyświetl plik

@ -0,0 +1,25 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
if [ $(id -u) -ne 0 ]; then
printf "Script must be run as root\n"
exit 1
fi
mkdir -p qemu_downgrade
cd qemu_downgrade
MYARCH=$(dpkg --print-architecture)
wget http://snapshot.debian.org/archive/debian/20120306T041809Z/pool/main/q/qemu/qemu_1.0.1%2Bdfsg-1_${MYARCH}.deb
wget http://snapshot.debian.org/archive/debian-ports/20120310T114351Z/pool/main/q/qemu/qemu-keymaps_1.0.1%2Bdfsg-1_all.deb
wget http://snapshot.debian.org/archive/debian/20120306T041809Z/pool/main/q/qemu/qemu-system_1.0.1%2Bdfsg-1_${MYARCH}.deb
wget http://snapshot.debian.org/archive/debian/20120306T041809Z/pool/main/q/qemu/qemu-user_1.0.1%2Bdfsg-1_${MYARCH}.deb
wget http://snapshot.debian.org/archive/debian/20120308T042544Z/pool/main/q/qemu/qemu-utils_1.0.1%2Bdfsg-1_${MYARCH}.deb
wget http://snapshot.debian.org/archive/debian/20120303T221521Z/pool/main/c/ceph/librbd1_0.43-1_${MYARCH}.deb
wget http://snapshot.debian.org/archive/debian/20120303T221521Z/pool/main/c/ceph/librados2_0.43-1_${MYARCH}.deb
sudo dpkg -i *
sudo apt-get install -f
printf "Hopefully downgraded to qemu 1.0.1 successfully, take a look...\n"
dpkg -l | grep qemu

Wyświetl plik

@ -0,0 +1,24 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
# NOTE: this script is rather hacky, in that you probably want to run it
# outside of the schroot set up for spindle...Ideally we'd be booting with an
# nbd rootfs anyway, so this is just a stopgap
set -ex
. ./common
[ "$1" ] || die "No image name given"
[ -b "$NBD_DEV" ] || die "nbd device '%s' does not exist. Try sudo modprobe nbd max_part=16" "$NBD_DEV"
dotask schroot -c spindle -- qemu-img create -f qed -b $1 nfs.qed
mkdir -p nfs_export
dotask sudo schroot -c spindle -- qemu-nbd --nocache -v -c /dev/nbd0 nfs.qed &
sleep 5
dotask sudo mount /dev/nbd0p2 nfs_export # have to do it outside of schroot!
NFS_PATH=$(readlink -m nfs_export)
dotask sudo exportfs -v -i -o async,rw,no_root_squash ":$NFS_PATH"
while true; do
sleep 60
done

Wyświetl plik

@ -0,0 +1,73 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
# TODO: this script is very rough and ready.
set -ex
printf "NOTICE: this script is only intended to work in an unmodified form\n"
printf "a recent Arch Linux install (with 3.8.x kernel).\n"
printf "You'll need to use grow_image to expand the rootfs above 2GiB\n"
printf "To get all deps, you want to do:\n\n"
# 1.1.0 f2fs-tools release is no good as we need commit
# http://git.kernel.org/cgit/linux/kernel/git/jaegeuk/f2fs-tools.git/commit/?id=07b815d39509135e35856cfd30b83930a0af8250
cat <<"EOF"
pacman -S wget unzip zip parted git
git clone git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git
cd f2fs-tools
autoreconf -fi
./configure && make && make install
curl https://aur.archlinux.org/packages/f2/f2fs-tools-git/f2fs-tools-git.tar.gz | tar xz
cd f2fs-tools-git
makepkg -si
cd ..
EOF
sleep 5
if [ $(id -u) -ne 0 ]; then
printf "Script must be run as root\n"
exit 1
fi
if [ ! "$1" ]; then
printf "Usage: ./f2fsify IMAGEFILE\n"
exit 1
fi
IMAGEFILE="$1"
modprobe f2fs
modprobe loop
BOOT_START=$(parted "$IMAGEFILE" -ms unit s p | grep "^1" | cut -f 2 -d:)
BOOT_START_BYTES=$((${BOOT_START%s}*512))
ROOT_START=$(parted "$IMAGEFILE" -ms unit s p | grep "^2" | cut -f 2 -d:)
ROOT_START_BYTES=$((${ROOT_START%s}*512))
# Back up the rootfs content
LOOP_DEV=$(losetup -f)
losetup --offset "$ROOT_START_BYTES" -v $LOOP_DEV "$IMAGEFILE"
mkdir -p rootfs
mount $LOOP_DEV rootfs
tar -cz rootfs > rootfs.tar.gz
umount rootfs
# Make the f2fs rootfs
mkfs.f2fs $LOOP_DEV
mount $LOOP_DEV rootfs
tar -xvf rootfs.tar.gz
sed -i rootfs/etc/fstab -e "s/ext4/f2fs/"
cat rootfs/etc/fstab
umount rootfs
losetup -d $LOOP_DEV
# Fix cmdline.txt on boot partition
losetup --offset "$BOOT_START_BYTES" -v $LOOP_DEV "$IMAGEFILE"
mkdir -p boot
mount $LOOP_DEV boot
sed -i boot/cmdline.txt -e "s/ext4/f2fs/"
cat boot/cmdline.txt
umount boot
losetup -d $LOOP_DEV
printf "Done!\n"

Wyświetl plik

@ -0,0 +1,66 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
# TODO: this script is very rough and ready. Currently grows an image to ~4GiB
set -x
if [ $(id -u) -ne 0 ]; then
printf "Script must be run as root\n"
exit 1
fi
if [ ! "$1" ]; then
printf "Usage: ./grow_image IMAGEFILE\n"
exit 1
fi
IMAGEFILE="$1"
# Grow the image file
dd of="$IMAGEFILE" bs=1 seek=3700M count=0
# Just use losetup to create a loopback device. fdisk will operate on files,
# but it complains about the number of cylinders not being set
LOOP_DEV=$(losetup -f)
losetup -v $LOOP_DEV "$IMAGEFILE"
# Partition resizing code same as in http://github.com/asb/raspi-config
PART_START=$(parted "$IMAGEFILE" -ms unit s p | grep "^2" | cut -f 2 -d:)
if [ ! "$PART_START" ]; then
printf "Failed to extract root partition offset\n"
fi
fdisk -cu $LOOP_DEV <<EOF
p
d
2
n
p
2
$PART_START
p
w
EOF
losetup -d $LOOP_DEV
# We know the offset anyway so let's just use losetup directly rather than
# bothering with kpartx
PART_START_BYTES=$((${PART_START%s}*512))
losetup --offset "$PART_START_BYTES" -v $LOOP_DEV "$IMAGEFILE"
# Sanity check
file -s $LOOP_DEV
# Run resize2fs
e2fsck -f $LOOP_DEV
resize2fs -p $LOOP_DEV
# Unmount it all
losetup -d $LOOP_DEV
printf "Success! (hopefully)\n"

Wyświetl plik

@ -0,0 +1,13 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
set -e
. ./common
if [ $# -ne 0 ]; then
set -x
"$@"
fi

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 47 KiB

Wyświetl plik

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="570" height="720">
<path d="m 158.375,1.65625 c -3.6193,0.1123192 -7.51715,1.4493266 -11.9375,4.9375 C 135.61054,2.4174496 125.11041,0.9665612 115.71875,9.46875 101.22489,7.5879922 96.508461,11.469494 92.9375,16 89.754953,15.934135 69.118652,12.72793 59.65625,26.84375 35.874602,24.030329 28.359472,40.831625 36.875,56.5 c -4.856911,7.518955 -9.889503,14.947226 1.46875,29.28125 -4.018006,7.983514 -1.527431,16.64403 7.9375,27.125 -2.497857,11.2226 2.412077,19.14086 11.21875,25.3125 -1.64709,15.35756 14.083505,24.28743 18.78125,27.46875 1.803677,8.94868 5.56291,17.3927 23.53125,22.0625 2.96323,13.3361 13.76206,15.63906 24.21875,18.4375 -34.561929,20.08954 -64.20067,46.52266 -64,111.375 l -5.0625,9.03125 C 15.337882,350.69604 -20.316547,428.16001 35.4375,491.125 c 3.641871,19.70838 9.749589,33.86396 15.1875,49.53125 8.133834,63.13058 61.21763,92.69161 75.21875,96.1875 20.51653,15.62812 42.36818,30.45672 71.9375,40.84375 27.87515,28.74946 58.07388,39.7064 88.4375,39.6875 0.44515,-2.8e-4 0.89853,0.005 1.34375,0 30.36363,0.0189 60.56235,-10.93804 88.4375,-39.6875 29.56932,-10.38703 51.42097,-25.21563 71.9375,-40.84375 14.00112,-3.49589 67.08492,-33.05692 75.21875,-96.1875 5.43791,-15.66729 11.54562,-29.82287 15.1875,-49.53125 55.75404,-62.96499 20.09961,-140.42896 -19.53125,-164.53125 L 513.75,317.5625 c 0.20067,-64.85234 -29.43807,-91.28546 -64,-111.375 10.45669,-2.79844 21.25552,-5.1014 24.21875,-18.4375 17.96834,-4.6698 21.72758,-13.11382 23.53125,-22.0625 4.69775,-3.18132 20.42834,-12.11119 18.78125,-27.46875 8.80668,-6.17164 13.71661,-14.0899 11.21875,-25.3125 9.46494,-10.48097 11.9555,-19.141487 7.9375,-27.125 C 546.79575,71.447226 541.76316,64.018955 536.90625,56.5 545.42178,40.831625 537.90665,24.030329 514.125,26.84375 504.6626,12.72793 484.0263,15.934135 480.84375,16 477.27279,11.469494 472.55636,7.587992 458.0625,9.46875 448.67084,0.96656132 438.17071,2.41745 427.34375,6.59375 414.48455,-3.5536631 405.97149,4.580454 396.25,7.65625 380.67615,2.568472 377.11698,9.5371578 369.46875,12.375 352.4935,8.7869238 347.33315,16.598532 339.1875,24.84375 l -9.46875,-0.1875 c -25.61054,15.093115 -38.33378,45.825501 -42.84375,61.625 -4.51206,-15.801979 -17.20647,-46.534542 -42.8125,-61.625 l -9.46875,0.1875 C 226.4481,16.598532 221.28775,8.7869235 204.3125,12.375 196.66427,9.5371583 193.1051,2.5684729 177.53125,7.65625 c -6.37973,-2.0184911 -12.24667,-6.2144276 -19.15625,-6 z" style="fill:#000000" />
<path d="m 107.39184,68.055583 c 67.94767,35.031357 107.44689,63.368967 129.08717,87.504467 -11.08235,44.41759 -68.89638,46.44464 -90.03559,45.19858 4.32842,-2.01474 7.93988,-4.42778 9.22051,-8.13574 -5.30449,-3.76981 -24.11289,-0.39719 -37.24363,-7.77416 5.04407,-1.04499 7.40348,-2.06302 9.76289,-5.78542 -12.40571,-3.9567 -25.76862,-7.36642 -33.627746,-13.92116 4.241253,0.0524 8.201156,0.9488 13.740366,-2.89271 -11.111694,-5.98819 -22.969108,-10.73351 -32.18139,-19.88738 5.745213,-0.14063 11.939452,-0.0568 13.740371,-2.16953 -10.17044,-6.30068 -18.751242,-13.30787 -25.853592,-20.97215 8.039979,0.97052 11.435284,0.13478 13.378782,-1.26556 -7.687795,-7.87419 -17.417559,-14.52319 -22.056911,-24.22644 5.969606,2.057484 11.431249,2.84506 15.36752,-0.180795 -2.612365,-5.893453 -13.805413,-9.369618 -20.248967,-23.141676 6.284359,0.609377 12.949606,1.371108 14.282753,0 C 61.802068,58.517346 56.796919,51.835885 51.887978,44.913906 65.338021,44.714177 85.715734,44.966253 84.792549,43.82914 l -8.31654,-8.497335 c 13.137617,-3.537241 26.580651,0.568164 36.339661,3.615887 4.38186,-3.457681 -0.0776,-7.82998 -5.42383,-12.294015 11.16496,1.490646 21.25382,4.057389 30.37345,7.593362 4.87238,-4.399329 -3.16389,-8.798658 -7.05098,-13.197987 17.24936,3.272568 24.55716,7.87068 31.81981,12.47481 5.26935,-5.050799 0.30166,-9.343299 -3.2543,-13.740371 13.00566,4.817048 19.70478,11.035551 26.75756,17.175463 2.39119,-3.227053 6.07494,-5.592408 1.62715,-13.378781 9.23416,5.322725 16.18926,11.59506 21.33374,18.621817 5.71336,-3.637941 3.40387,-8.613023 3.43509,-13.197987 9.59665,7.806516 15.68687,16.11395 23.14168,24.226443 1.50169,-1.093437 2.81661,-4.80171 3.97747,-10.666867 22.89539,22.211815 55.24591,78.158241 8.31654,100.340861 C 207.95028,109.95728 160.25292,86.016909 107.39184,68.055583 z" style="fill:#75a928" />
<path d="M 467.92487,68.055583 C 399.9772,103.08694 360.47798,131.42455 338.8377,155.56005 c 11.08235,44.41759 68.89638,46.44464 90.03559,45.19858 -4.32842,-2.01474 -7.93988,-4.42778 -9.22051,-8.13574 5.30449,-3.76981 24.11289,-0.39719 37.24363,-7.77416 -5.04407,-1.04499 -7.40348,-2.06302 -9.76289,-5.78542 12.40571,-3.9567 25.76862,-7.36642 33.62775,-13.92116 -4.24126,0.0524 -8.20116,0.9488 -13.74037,-2.89271 11.11169,-5.98819 22.96911,-10.73351 32.18139,-19.88738 -5.74521,-0.14063 -11.93945,-0.0568 -13.74037,-2.16953 10.17044,-6.30068 18.75124,-13.30787 25.85359,-20.97215 -8.03998,0.97052 -11.43528,0.13478 -13.37878,-1.26556 7.68779,-7.87419 17.41756,-14.52319 22.05691,-24.22644 -5.96961,2.057484 -11.43125,2.84506 -15.36752,-0.180795 2.61237,-5.893453 13.80541,-9.369618 20.24897,-23.141676 -6.28436,0.609377 -12.94961,1.371108 -14.28276,0 2.92231,-11.888563 7.92746,-18.570024 12.8364,-25.492003 -13.45004,-0.199729 -33.82775,0.05235 -32.90457,-1.084766 l 8.31654,-8.497335 c -13.13762,-3.537241 -26.58065,0.568164 -36.33966,3.615887 -4.38186,-3.457681 0.0776,-7.82998 5.42383,-12.294015 -11.16496,1.490646 -21.25382,4.057389 -30.37345,7.593362 -4.87238,-4.399329 3.16389,-8.798658 7.05098,-13.197987 -17.24936,3.272568 -24.55716,7.87068 -31.81981,12.47481 -5.26935,-5.050799 -0.30166,-9.343299 3.2543,-13.740371 -13.00566,4.817048 -19.70478,11.035551 -26.75756,17.175463 -2.39119,-3.227053 -6.07494,-5.592408 -1.62715,-13.378781 -9.23416,5.322725 -16.18926,11.59506 -21.33374,18.621817 -5.71336,-3.637941 -3.40387,-8.613023 -3.43509,-13.197987 -9.59665,7.806516 -15.68687,16.11395 -23.14168,24.226443 -1.50169,-1.093437 -2.81661,-4.80171 -3.97747,-10.666867 -22.89539,22.211815 -55.24591,78.158241 -8.31654,100.340861 39.91877,-32.94716 87.61613,-56.887531 140.47721,-74.848857 z" style="fill:#75a928" />
<path d="m 365.2046,521.84937 a 71.956154,66.532318 0 1 1 -143.91231,0 71.956154,66.532318 0 1 1 143.91231,0 z" transform="matrix(1.131107,0,0,1.1280497,-43.139135,-68.310983)" style="fill:#bc1142" />
<path d="m 262.84091,276.64774 a 61.875,28.125 0 1 1 -123.75,0 61.875,28.125 0 1 1 123.75,0 z" transform="matrix(0.76741684,-1.1613112,2.171115,1.4224368,-560.88858,217.68859)" style="fill:#bc1142" />
<path d="m 262.84091,276.64774 a 61.875,28.125 0 1 1 -123.75,0 61.875,28.125 0 1 1 123.75,0 z" transform="matrix(-0.76741684,-1.1613112,-2.171115,1.4224368,1134.8288,213.68859)" style="fill:#bc1142" />
<path d="M 72.910253,342.0878 C 109.32447,332.33088 85.201845,492.72431 55.576871,479.56357 22.990103,453.35089 12.493801,376.58814 72.910253,342.0878 z" style="fill:#bc1142" />
<path d="m 493.67828,340.0878 c -36.41422,-9.75692 -12.2916,150.63651 17.33338,137.47577 32.58677,-26.21268 43.08307,-102.97543 -17.33338,-137.47577 z" style="fill:#bc1142" />
<path d="m 369.97158,220.6534 c 62.83486,-10.61013 115.11594,26.72229 113.01138,94.85796 -2.06693,26.12112 -136.15872,-90.96907 -113.01138,-94.85796 z" style="fill:#bc1142" />
<path d="M 196.35975,218.6534 C 133.52489,208.04327 81.24381,245.37569 83.34837,313.51136 85.4153,339.63248 219.50709,222.54229 196.35975,218.6534 z" style="fill:#bc1142" />
<path d="m 286.61932,202.75568 c -37.50259,-0.97548 -73.49548,27.83418 -73.58158,44.54443 -0.10462,20.30426 29.6512,41.09266 73.83726,41.62035 45.12305,0.32321 73.91561,-16.64049 74.0611,-37.59409 0.16484,-23.73996 -41.03879,-48.93744 -74.31678,-48.57069 z" style="fill:#bc1142" />
<path d="m 288.90937,619.11675 c 32.69744,-1.42711 76.57083,10.53196 76.6568,26.39598 0.5427,15.4052 -39.78969,50.21055 -78.82634,49.53765 -40.42729,1.74391 -80.06908,-33.11559 -79.54951,-45.19859 -0.60506,-17.71593 49.226,-31.54796 81.71905,-30.73504 z" style="fill:#bc1142" />
<path d="m 168.13874,525.10369 c 23.2791,28.04573 33.89066,77.31899 14.46355,91.84353 -18.37917,11.08784 -63.01228,6.52162 -94.736237,-39.05157 -21.395052,-38.24168 -18.637584,-77.15663 -3.615887,-88.58924 22.464424,-13.68429 57.173424,4.79902 83.888574,35.79728 z" style="fill:#bc1142" />
<path d="m 405.0209,516.21177 c -25.18682,29.50165 -39.21227,83.30951 -20.83785,100.6428 17.56828,13.46361 64.7292,11.58162 99.56566,-36.75574 25.29599,-32.46471 16.82013,-86.68225 2.37077,-101.07511 -21.46408,-16.60213 -52.27691,4.64489 -81.09858,37.18805 z" style="fill:#bc1142" />
</svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 8.7 KiB

Wyświetl plik

@ -0,0 +1,31 @@
# QA checklist
This document contains a list of things which should be tested before
releasing a distribution image as 'finished'.
## Platform specific
* The latest version of the 'firmware' is included
* /dev/vchiq is owned by group 'video'
## Basic configuration
* ifplugd is installed and properly configured
* A default user has been created
* If a desktop environment is installed, it defaults to Raspberry Pi branding
* sshd either starts at boot or is trivial to enable (and this mechanism has
been tested)
* An NTP daemon is installed and configured
* eth0 isn't renamed when the same SD card is put in a different Raspberry Pi
* sudo is installed and configured
* ssh host keys have been removed and will be generated on first boot or first
invocation of sshd
* `apt-get clean` has been run to remove cached packages
## Functionality tests for desktop images
* When plugging in a USB memory stick, it is automatically mounted
* Wireless dongles with free firmware work out of the box
* The default browser works for GMail and other JavaScript-heavy sites
* `/opt/vc/bin/tvservice` has been verified to work
* Verify after installing gparted it can be launched from the graphical menu
and that in pcmanfm 'open folder as root' works (checks PolicyKit
configuration).
* Run fsck on the root partition to ensure the image generation process
produced a clean filesystem

Wyświetl plik

@ -0,0 +1,117 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
set -e
SCHROOT_SPINDLE_CONF=/etc/schroot/chroot.d/spindle
ETC_SCHROOT_SPINDLE=/etc/schroot/spindle
if [ $(id -u) -ne 0 ]; then
printf "Script must be run as root\n"
exit 1
fi
show_usage() {
printf "./setup_spindle_environment DIRNAME\n"
}
ensure_installed() {
for PKG in "$@"; do
dpkg --get-selections "$PKG" | grep -q "[[:space:]]install$" || apt-get install "$PKG" || die "Failed to install $PKG"
done
}
[ "$1" ] || show_usage
TARGET_DIR=$(readlink -m "$1")
. ./common
ensure_installed schroot debootstrap debian-archive-keyring
ask_yn y "About to set up chroot in '%s'. Ok?" "$TARGET_DIR" || die "You said no. Exiting"
read_val USERS "${USERS-$SUDO_USER}" "What user should be able to schroot?"
[ -z "$USERS" ] && die "You didn't list any users"
if [ -e "$SCHROOT_SPINDLE_CONF" ]; then
ask_yn y "Overwrite existing config '$SCHROOT_SPINDLE_CONF'?" || die "You said no. Exiting"
rm -rf "$ETC_SCHROOT_SPINDLE"
fi
mkdir -p $(dirname "$SCHROOT_SPINDLE_CONF")
cat << EOF > "$SCHROOT_SPINDLE_CONF" || die "Failed to configure schroot"
[spindle]
type=directory
description=Debian wheezy for spindle
directory=$TARGET_DIR
preserve-environment=true
script-config=spindle/config
users=$USERS
groups=$USERS
root-groups=root
EOF
printf "\nCreated %s:\n\n" "$SCHROOT_SPINDLE_CONF"
cat "$SCHROOT_SPINDLE_CONF"
printf "\n"
if [ ! -e $ETC_SCHROOT_SPINDLE ]; then
if [ -e /etc/schroot/default ]; then
cp -a /etc/schroot/default $ETC_SCHROOT_SPINDLE
else
## Should work for schroot 1.4 as in Ubuntu 10.04
mkdir $ETC_SCHROOT_SPINDLE
for FN in copyfiles mount nssdatabases; do
cp -a /etc/schroot/${FN}-defaults $ETC_SCHROOT_SPINDLE/$FN
done
mv $ETC_SCHROOT_SPINDLE/mount $ETC_SCHROOT_SPINDLE/fstab
fi
fi
cat << EOF > $ETC_SCHROOT_SPINDLE/config
# Filesystems to mount inside the chroot.
FSTAB="$ETC_SCHROOT_SPINDLE/fstab"
# Files to copy from the host system into the chroot.
COPYFILES="$ETC_SCHROOT_SPINDLE/copyfiles"
# System NSS databases to copy into the chroot.
NSSDATABASES="$ETC_SCHROOT_SPINDLE/nssdatabases"
EOF
# We want rbind of /home for cases where /home is provided by autofs
# See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=648459
sed $ETC_SCHROOT_SPINDLE/fstab -e "s|^\(/home.*\),bind\(.*\)|\1,rbind\2|" > $ETC_SCHROOT_SPINDLE/fstab.new || true
mv $ETC_SCHROOT_SPINDLE/fstab.new $ETC_SCHROOT_SPINDLE/fstab || true
# Delete rather than comment out, as schroot 1.4 has no support for comments
# in nssdatabases
sed -i $ETC_SCHROOT_SPINDLE/nssdatabases -e "/^passwd$/d"
sed -i $ETC_SCHROOT_SPINDLE/nssdatabases -e "/^shadow$/d"
sed -i $ETC_SCHROOT_SPINDLE/nssdatabases -e "/^group$/d"
debootstrap \
--include="qemu,bash-completion,augeas-tools,debootstrap,less,\
sudo,parted,openssh-client,e2fsprogs,dosfstools,squashfs-tools,bzip2,git,zerofree" \
wheezy "$TARGET_DIR" http://http.debian.net/debian || die "Debootstrap failed"
rm "$TARGET_DIR/dev/shm" # required on my 10.04 for schroot to work
# Copy passwd/shadow/group databases
getent passwd > "$TARGET_DIR/etc/passwd"
getent shadow > "$TARGET_DIR/etc/shadow"
getent group > "$TARGET_DIR/etc/group"
# Disable launch of services in chroot
printf '#!/bin/sh\nexit 101\n' > "$TARGET_DIR"/usr/sbin/policy-rc.d
chmod 755 "$TARGET_DIR"/usr/sbin/policy-rc.d
# Make sure sudo is enabled within chroot
chmod +w "$TARGET_DIR"/etc/sudoers
echo "%admin ALL=(ALL) ALL" >> "$TARGET_DIR"/etc/sudoers
chmod -w "$TARGET_DIR"/etc/sudoers
printf "Please enter the password you would like for your schroot user (needed for sudo)\n"
schroot -c spindle --directory=/tmp passwd $USERS
printf "\nchroot created at '%s'. Use \`schroot -c spindle\` to enter it\n" "$TARGET_DIR"
FINISHED_SUCCESSFULLY=1

Wyświetl plik

@ -0,0 +1,74 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
# TODO: this script is very rough and ready. Currently shrinks ext4 image to
# minimum size. Should really be refactored and merged with grow_image
set -x
if [ $(id -u) -ne 0 ]; then
printf "Script must be run as root\n"
exit 1
fi
if [ ! "$1" ]; then
printf "Usage: ./shrink_image IMAGEFILE\n"
exit 1
fi
IMAGEFILE="$1"
# Partition resizing code same as in http://github.com/asb/raspi-config
PART_START=$(parted "$IMAGEFILE" -ms unit s p | grep "^2" | cut -f 2 -d:)
if [ ! "$PART_START" ]; then
printf "Failed to extract root partition offset\n"
fi
# Just use losetup to create a loopback device. fdisk will operate on files,
# but it complains about the number of cylinders not being set
LOOP_DEV=$(losetup -f)
# We know the offset anyway so let's just use losetup directly rather than
# bothering with kpartx
PART_START_BYTES=$((${PART_START%s}*512))
losetup --offset "$PART_START_BYTES" -v $LOOP_DEV "$IMAGEFILE"
# Sanity check
file -s $LOOP_DEV
# Run resize2fs
e2fsck -f $LOOP_DEV
resize2fs -M $LOOP_DEV
EXT4_BLCKCNT=$(sudo tune2fs -l /dev/loop0 | grep "^Block count" | cut -d ":" -f 2 | tr -d ' ')
EXT4_BLKSIZE=$(sudo tune2fs -l /dev/loop0 | grep "^Block size" | cut -d ":" -f 2 | tr -d ' ')
EXT4_FS_BYTES=$(($EXT4_BLCKCNT * $EXT4_BLKSIZE))
# Unmount it all
losetup -d $LOOP_DEV
NEW_IMG_BYTES=$(($EXT4_FS_BYTES + $PART_START_BYTES + 4194304))
# Shrink the image file
dd if=/dev/null of="$IMAGEFILE" bs=$NEW_IMG_BYTES seek=1
losetup -v $LOOP_DEV "$IMAGEFILE"
fdisk -cu $LOOP_DEV <<EOF
p
d
2
n
p
2
$PART_START
p
w
EOF
losetup -d $LOOP_DEV
printf "Success! (hopefully)\n"

Wyświetl plik

@ -0,0 +1,67 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
set -e
. ./common
CURIMG=stage0.$IMGFORMAT
create_partition_table() {
# TODO: partition sizes shouldn't be hard-coded
sudo parted $1 <<EOF
unit b
mklabel msdos
mkpart primary fat32 $(expr 4 \* 1024 \* 1024) $(expr 60 \* 1024 \* 1024 - 1)
mkpart primary ext4 $(expr 60 \* 1024 \* 1024) 100%
print
quit
EOF
}
do_debootstrap() {
# Need bzip2 for http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=657560
sudo debootstrap --components=main,contrib,non-free \
--verbose \
--foreign --arch $TGT_ARCH --include=bzip2 \
--no-check-gpg \
$1 $2 $DEB_MIRROR
}
APT_CACHE_IMG=wheezy_apt_cache.$IMGFORMAT
mkdir -p $WORKDIR
cd $WORKDIR
[ -b "$NBD_DEV" ] || die "nbd device '%s' does not exist. Try sudo modprobe nbd max_part=16" "$NBD_DEV"
# Delete apt cache if it was not successfully created
[ -e "$APT_CACHE_IMG.wip" ] && rm "$APT_CACHE_IMG"
if ! [ -f "$APT_CACHE_IMG" ]; then
printf "No apt cache disk image exists. Making one.\n"
dotask qemu-img create -f $IMGFORMAT $APT_CACHE_IMG 4G
touch "$APT_CACHE_IMG.wip"
sudo -v
dotask attach_image_to_nbd $APT_CACHE_IMG $NBD_DEV
dotask sudo mkfs.ext4 -O ^huge_file $NBD_DEV
mkdir -p rootfs
dotask sudo mount $NBD_DEV rootfs
sudo mkdir -p rootfs/archives/partial
sudo touch rootfs/archives/lock
dotask sudo umount $NBD_DEV
dotask detach_image_from_nbd $NBD_DEV
rm "$APT_CACHE_IMG.wip"
fi
dotask qemu-img create -f $IMGFORMAT $CURIMG $SDSIZE
sudo -v
dotask attach_image_to_nbd $CURIMG $NBD_DEV
dotask create_partition_table $NBD_DEV
dotask sudo mkdosfs -n boot -S 512 -s 16 -v $BOOT_DEV
dotask sudo mkfs.ext4 -O ^huge_file $ROOT_DEV
mkdir -p boot
dotask sudo mount $BOOT_DEV boot
mkdir -p rootfs
dotask sudo mount $ROOT_DEV rootfs
dotask do_debootstrap wheezy rootfs
universal_cleanup
dotask finish_image

Wyświetl plik

@ -0,0 +1,146 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
set -e
. ./common
CURIMG=stage1.$IMGFORMAT
# Security for these keys doesn't matter: just using ssh as it's convenient
# It's not easy to disable authentication, so just use passwordless keys.
# could be generated with dropbearkey -t dss -f
# ./etc/dropbear/dropbear_dss_host_key and base64 encoding the result
DROPBEAR_DSS_KEY=$(cat <<EOF
AAAAB3NzaC1kc3MAAACBANfidOdFkDa7co3actgF4sQ0R8sYTzQ5jLAx23nwy5HKDt5pzwXKnkjq
wBm7/CsC7/WHozTlRSIwA+9jlZlteOUzALTUkICVA24rg90gjqiR5Gzqd6nSB1iKWjbTX5rxR+9j
HcVzfp832HHTRJgthQ035Em+6lJJ4PpIgRhDDE2jAAAAFQDlWsVzKm4G24GQnGxDuhGsrC2i5wAA
AIBelNlG6om0WZYsP9M1kA9DCaWaWVLVt/o7AeSjTT1/f7E2xwluPBRLqKMYdWab4EdkoZLL9QU/
c4t6vRSYMZ8dxT8fpZ49HZLMrg6Defxb5Us6IaMGJwEXKx5s1p37S2SMs2oYLBAxtTv3a2WvVGxO
mTFe6O1QV8C2/0Mml92S5wAAAIEAtaxaCnAIu1FJ4GJLAoKDQA2OZElYgMoD6WGn1JMYjdKa3xE0
8pl/IBt+OTZ3TR8ifuB0NrS6jlSi6pZVeqauZyZIkiIJPBULcsXWm98meeQpi0sz+uVyGSxVcVGT
icg5BSkoPHjAC4KrojvTKR85PPgW1rMeJ3sGgtSXsTVMEVQAAAAVALRiKgnxo7cCasEP41n3Kd3n
/5PB
EOF
)
# could be generated with sh-keygen -t dsa -f qemu_arm_key -N ""
PRIVATE_SSH_KEY=$(cat <<EOF
-----BEGIN DSA PRIVATE KEY-----
MIIBvAIBAAKBgQCndCU8k4fuxWa2phVz9s2WH2OtwYuNxn3I7VfW9WZt+La3DaKg
cjJo2yxT+PWbicdzZ7+bKn50F/9SJd+RgzcCrSHszOewpmDJfJQHrVje5A3XgfBF
3DZZzsRS3b4bR+24z7ws++qSL0UdQhX9R8V2UUPEw0B3tDZMsEB6os2D4wIVAP0K
CXSFvoyrSkxOV9SfLHY/wPbxAoGBAJa08pbR+BYR/5t6M2QMN+Hj87eReJ4Gov+j
ZGPFhVpQ7gdKllRMzWIxgb7UkxfXzXUhZSJHWOF66eFAP+zjEwiALYJVIcWCd19y
E3dP7qB9VTQdNYGrW0DA4oaxBL1AmnPtbrfT8mPs48dKoMoKYocoBYYASmu/hKU0
JTF5qtjTAoGAXHA/KTiu/w/e0LjX9aeMLu4+U9o+8AcRKKFUVsu2ADmrHTzPFE1F
0iBERYkCnm+n4ilOdL+YQTStyNzbsj8lgsc+PRB5f3S2o+Cd4ADC8E+A+FYrmYPK
duaZG6byxosiuE0SFPSnXtFHyw8uRH6ZFe/Z2qbdevgFO6ZU1kcvM4UCFQDnvfA8
2jtIk4Lc55jgJBl2ygLvwg==
-----END DSA PRIVATE KEY-----
EOF
)
# could be generated with sh-keygen -t dsa -f qemu_arm_key -N ""
PUBLIC_SSH_KEY="ssh-dss \
AAAAB3NzaC1kc3MAAACBAKd0JTyTh+7FZramFXP2zZYfY63Bi43GfcjtV9b1Zm34\
trcNoqByMmjbLFP49ZuJx3Nnv5sqfnQX/1Il35GDNwKtIezM57CmYMl8lAetWN7k\
DdeB8EXcNlnOxFLdvhtH7bjPvCz76pIvRR1CFf1HxXZRQ8TDQHe0NkywQHqizYPj\
AAAAFQD9Cgl0hb6Mq0pMTlfUnyx2P8D28QAAAIEAlrTyltH4FhH/m3ozZAw34ePz\
t5F4ngai/6NkY8WFWlDuB0qWVEzNYjGBvtSTF9fNdSFlIkdY4Xrp4UA/7OMTCIAt\
glUhxYJ3X3ITd0/uoH1VNB01gatbQMDihrEEvUCac+1ut9PyY+zjx0qgygpihygF\
hgBKa7+EpTQlMXmq2NMAAACAXHA/KTiu/w/e0LjX9aeMLu4+U9o+8AcRKKFUVsu2\
ADmrHTzPFE1F0iBERYkCnm+n4ilOdL+YQTStyNzbsj8lgsc+PRB5f3S2o+Cd4ADC\
8E+A+FYrmYPKduaZG6byxosiuE0SFPSnXtFHyw8uRH6ZFe/Z2qbdevgFO6ZU1kcv\
M4U= asb@ulala"
setup_dropbear() {
chmod +x dropbearmulti-armv6l &&
cp -a dropbearmulti-armv6l qemu_rootfs/bin/dropbear &&
cd qemu_rootfs/bin &&
ln -s dropbear scp &&
cd "$OLDPWD" &&
mkdir -p qemu_rootfs/etc/dropbear &&
printf "%s" "$DROPBEAR_DSS_KEY" | base64 -d > qemu_rootfs/etc/dropbear/dropbear_dss_host_key &&
printf "%s" "$PRIVATE_SSH_KEY" > qemu_arm_key &&
chmod 600 qemu_arm_key &&
printf "%s" "$PUBLIC_SSH_KEY" > qemu_arm_key.pub &&
cp -a qemu_arm_key.pub qemu_rootfs/root
}
INIT_SH=$(cat <<\EOF
#!/bin/sh
export HOME=/home/root
mount -t proc proc proc
mount -t sysfs sys sys
mount -t devtmpfs dev dev
mkdir -p dev/pts
mount -t devpts dev/pts dev/pts
export PS1='($HOST) \w \$ '
export PATH
ifconfig eth0 10.0.2.15
route add default gw 10.0.2.2
[ "$(date +%s)" -lt 1000 ] && rdate 10.0.2.2 # or time-b.nist.gov
mount -t tmpfs /tmp /tmp
mount -o noatime /dev/sdb2 /mnt
[ -d /mnt/tmp ] && mount --bind /tmp /mnt/tmp
mount -t tmpfs /home /home
mkdir -p /home/root
cd $HOME
mkdir -p /home/root/.ssh
cp -a /root/qemu_arm_key.pub /home/root/.ssh/authorized_keys
chmod 600 /home/root/.ssh/authorized_keys
dropbear -E -s
exec /sbin/oneit -c /dev/ttyAMA0 /bin/ash
EOF
)
replace_init_sh() {
printf "%s" "$INIT_SH" > qemu_rootfs/sbin/init.sh
}
do_second_stage_debootstrap() {
onvm_chroot sh -ex - <<EOF
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
./debootstrap/debootstrap --second-stage
apt-get clean
EOF
}
# Made redundant by firmware debs
configure_udev() {
onvm_chroot sh -e - <<EOF
printf 'SUBSYSTEM=="vchiq", GROUP="video", MODE="0660"\n' > /etc/udev/rules.d/10-local-rpi.rules
EOF
}
cd $WORKDIR
dotask branch_image ../$OUTDIR/stage0.$IMGFORMAT $CURIMG
dotask download_if_necessary http://asbradbury.org/tmp/raspi/simple-root-filesystem-armv6l.tar.bz2
dotask download_if_necessary http://asbradbury.org/tmp/raspi/system-image-armv6l.tar.bz2
dotask download_if_necessary http://asbradbury.org/tmp/raspi/dropbearmulti-armv6l
[ -f zImage ] || tar -xf system-image-armv6l.tar.bz2 --strip-components=1 system-image-armv6l/zImage
tar -xvf simple-root-filesystem-armv6l.tar.bz2
rm -rf qemu_rootfs
mv simple-root-filesystem-armv6l qemu_rootfs
dotask setup_dropbear
dotask replace_init_sh
dotask mksquashfs qemu_rootfs qemu_rootfs.sqf -noappend -all-root
dotask run_qemu $CURIMG
dotask do_second_stage_debootstrap
#dotask configure_udev
dotask shutdown_qemu
dotask finish_image

Wyświetl plik

@ -0,0 +1,359 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
set -ex
. ./common
CURIMG=stage2.$IMGFORMAT
# Make changes to /etc/skel before we start adding new users
modify_etc_skel() {
onvm_chroot sh -l -ex - <<\EOF
# Essentially the same as the default debian one, but enable color by default
# and slightly tweak PS1
cat <<\EOF1 > /etc/skel/.bashrc
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth
# append to the history file, don't overwrite it
shopt -s histappend
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000
# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize
# If set, the pattern "**" used in a pathname expansion context will
# match all files and zero or more directories and subdirectories.
#shopt -s globstar
# make less more friendly for non-text input files, see lesspipe(1)
#[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
xterm-color) color_prompt=yes;;
esac
# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
force_color_prompt=yes
if [ -n "$force_color_prompt" ]; then
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
# We have color support; assume it's compliant with Ecma-48
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
# a case would tend to support setf rather than setaf.)
color_prompt=yes
else
color_prompt=
fi
fi
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\] \[\033[01;34m\]\w \$\[\033[00m\] '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
unset color_prompt force_color_prompt
# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
;;
*)
;;
esac
# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
alias ls='ls --color=auto'
#alias dir='dir --color=auto'
#alias vdir='vdir --color=auto'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
fi
# some more ls aliases
#alias ll='ls -l'
#alias la='ls -A'
#alias l='ls -CF'
# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi
# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
. /etc/bash_completion
fi
EOF1
EOF
}
# For now we add a root password (this is a totally minimal system). It should be
# disabled at a later stage
configure_users() {
onvm_chroot sh -l -ex - <<EOF
adduser --disabled-password --gecos "" pi
echo "pi:raspberry" | chpasswd
echo "root:root" | chpasswd
EOF
}
configure_fstab() {
onvm_chroot sh -l -e - <<EOF1
cat <<EOF2 > /etc/fstab
proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat defaults 0 2
/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
EOF2
# Automatically repair if fsck finds issues
sed -i /etc/default/rcS -e "s/^#FSCKFIX=no/FSCKFIX=yes/"
EOF1
}
configure_sources_list() {
SECTIONS="main contrib non-free"
if [ -n "$RASPBIAN" ]; then
SECTIONS="$SECTIONS rpi"
fi
onvm_chroot sh -l -e - <<EOF
printf "deb $DEB_MIRROR wheezy $SECTIONS\n" > /etc/apt/sources.list
printf "# Uncomment line below then 'apt-get update' to enable 'apt-get source'\n" >> /etc/apt/sources.list
printf "#deb-src $DEB_MIRROR wheezy $SECTIONS\n" >> /etc/apt/sources.list
EOF
}
configure_network_interfaces() {
onvm_chroot sh -l -e - <<\EOF1
cat <<EOF2 > /etc/network/interfaces
auto lo
iface lo inet loopback
iface eth0 inet dhcp
EOF2
# Use the qemu default nameserver
printf "nameserver 10.0.2.3\n" > /etc/resolv.conf
EOF1
}
configure_hostname() {
onvm_chroot sh -l -e - <<EOF
echo raspberrypi > /etc/hostname
printf "127.0.1.1\traspberrypi\n" >> /etc/hosts
EOF
}
disable_eth_and_wlan_renaming() {
onvm_chroot sh -l -e - <<EOF
sed -i -e 's/KERNEL\!="eth\*|ath\*|wlan\*\[0-9\]/KERNEL\!="ath\*/' /lib/udev/rules.d/75-persistent-net-generator.rules
dpkg-divert --add --local /lib/udev/rules.d/75-persistent-net-generator.rules
EOF
}
# Due to a change of behaviour in getty, we must pass --noclear to ensure our
# boot messages don't get cleared
# Also, spawn a getty on the serial line
configure_inittab() {
onvm_chroot sh -l -e - <<\EOF
sed -i -e "s/^\(1:2345.*\)getty\(.*tty1\)$/\1getty --noclear\2/" /etc/inittab
printf "\n#Spawn a getty on Raspberry Pi serial line\n" >> /etc/inittab
printf "T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100\n" >> /etc/inittab
EOF
}
adjust_motd() {
onvm_chroot sh -l -e <<\EOF1
cat <<EOF2 >> /etc/motd.tail
Type 'startx' to launch a graphical session
EOF2
EOF1
}
install_firmware() {
onvm_chroot sh -l -e - <<EOF
#echo "deb http://archive.raspberrypi.org/debian/ wheezy main" > /etc/apt/sources.list.d/raspi.list
echo "deb http://archive.raspberrypi.org/debian/ wheezy main untested" > /etc/apt/sources.list.d/raspi.list
apt-key add - <<EOF1
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.12 (GNU/Linux)
mQENBE/d7o8BCACrwqQacGJfn3tnMzGui6mv2lLxYbsOuy/+U4rqMmGEuo3h9m92
30E2EtypsoWczkBretzLUCFv+VUOxaA6sV9+puTqYGhhQZFuKUWcG7orf7QbZRuu
TxsEUepW5lg7MExmAu1JJzqM0kMQX8fVyWVDkjchZ/is4q3BPOUCJbUJOsE+kK/6
8kW6nWdhwSAjfDh06bA5wvoXNjYoDdnSZyVdcYCPEJXEg5jfF/+nmiFKMZBraHwn
eQsepr7rBXxNcEvDlSOPal11fg90KXpy7Umre1UcAZYJdQeWcHu7X5uoJx/MG5J8
ic6CwYmDaShIFa92f8qmFcna05+lppk76fsnABEBAAG0IFJhc3BiZXJyeSBQaSBB
cmNoaXZlIFNpZ25pbmcgS2V5iQE4BBMBAgAiBQJP3e6PAhsDBgsJCAcDAgYVCAIJ
CgsEFgIDAQIeAQIXgAAKCRCCsSmSf6MwPk6vB/9pePB3IukU9WC9Bammh3mpQTvL
OifbkzHkmAYxzjfK6D2I8pT0xMxy949+ThzJ7uL60p6T/32ED9DR3LHIMXZvKtuc
mQnSiNDX03E2p7lIP/htoxW2hDP2n8cdlNdt0M9IjaWBppsbO7IrDppG2B1aRLni
uD7v8bHRL2mKTtIDLX42Enl8aLAkJYgNWpZyPkDyOqamjijarIWjGEPCkaURF7g4
d44HvYhpbLMOrz1m6N5Bzoa5+nq3lmifeiWKxioFXU+Hy5bhtAM6ljVb59hbD2ra
X4+3LXC9oox2flmQnyqwoyfZqVgSQa0B41qEQo8t1bz6Q1Ti7fbMLThmbRHiuQEN
BE/d7o8BCADNlVtBZU63fm79SjHh5AEKFs0C3kwa0mOhp9oas/haDggmhiXdzeD3
49JWz9ZTx+vlTq0s+I+nIR1a+q+GL+hxYt4HhxoA6vlDMegVfvZKzqTX9Nr2VqQa
S4Kz3W5ULv81tw3WowK6i0L7pqDmvDqgm73mMbbxfHD0SyTt8+fk7qX6Ag2pZ4a9
ZdJGxvASkh0McGpbYJhk1WYD+eh4fqH3IaeJi6xtNoRdc5YXuzILnp+KaJyPE5CR
qUY5JibOD3qR7zDjP0ueP93jLqmoKltCdN5+yYEExtSwz5lXniiYOJp8LWFCgv5h
m8aYXkcJS1xVV9Ltno23YvX5edw9QY4hABEBAAGJAR8EGAECAAkFAk/d7o8CGwwA
CgkQgrEpkn+jMD5Figf/dIC1qtDMTbu5IsI5uZPX63xydaExQNYf98cq5H2fWF6O
yVR7ERzA2w33hI0yZQrqO6pU9SRnHRxCFvGv6y+mXXXMRcmjZG7GiD6tQWeN/3wb
EbAn5cg6CJ/Lk/BI4iRRfBX07LbYULCohlGkwBOkRo10T+Ld4vCCnBftCh5x2OtZ
TOWRULxP36y2PLGVNF+q9pho98qx+RIxvpofQM/842ZycjPJvzgVQsW4LT91KYAE
4TVf6JjwUM6HZDoiNcX6d7zOhNfQihXTsniZZ6rky287htsWVDNkqOi5T3oTxWUo
m++/7s3K3L0zWopdhMVcgg6Nt9gcjzqN1c0gy55L/g==
=mNSj
-----END PGP PUBLIC KEY BLOCK-----
EOF1
apt-get update
apt-get install -y libraspberrypi-bin libraspberrypi0 raspberrypi-bootloader
echo "deb http://archive.raspberrypi.org/debian/ wheezy main" > /etc/apt/sources.list.d/raspi.list
apt-get update
echo "dwc_otg.lpm_enable=0 console=ttyAMA0,115200 \
console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait" > /boot/cmdline.txt
cat <<EOF1 > /boot/config.txt
# For more options and information see
# http://www.raspberrypi.org/documentation/configuration/config-txt.md
# Some settings may impact device functionality. See link above for details
# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1
# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
#disable_overscan=1
# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16
# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720
# uncomment if hdmi display is not detected and composite is being output
#hdmi_force_hotplug=1
# uncomment to force a specific HDMI mode (this will force VGA)
#hdmi_group=1
#hdmi_mode=1
# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2
# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4
# uncomment for composite PAL
#sdtv_mode=2
#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800
EOF1
# cat <<EOF2 > /etc/modprobe.d/raspi-blacklist.conf
# # blacklist spi and i2c by default (many users don't need them)
# blacklist spi-bcm2708
# blacklist i2c-bcm2708
# blacklist snd-soc-pcm512x
# blacklist snd-soc-wm8804
# EOF2
cat <<EOF3 > /etc/modprobe.d/ipv6.conf
# Don't load ipv6 by default
alias net-pf-10 off
#alias ipv6 off
EOF3
EOF
}
# Relies on the fact my repo was already added in install_firmware
install_raspi_config() {
onvm_chroot sh -l -e - <<\EOF
apt-get install -y raspi-config
# Automatically log in on tty1 until raspi-config configures it to do
# otherwise
sed -i /etc/inittab -e "s|^\(1:2345.*getty.*tty1.*\)|\
#\1 # RPICFG_TO_ENABLE\n1:2345:respawn:/bin/login -f root tty1 </dev/tty1 >/dev/tty1 2>\&1 # RPICFG_TO_DISABLE|"
EOF
}
# Deprecated in favour of using the Debian packaging
download_and_extract_firmware_if_necessary() {
if ! [ -d firmware ]; then
git clone git://github.com/raspberrypi/firmware.git
fi
}
cd $WORKDIR
dotask branch_image ../$OUTDIR/stage1.$IMGFORMAT $CURIMG
dotask run_qemu $CURIMG
dotask mount_apt_cache
dotask disable_starting_services
dotask modify_etc_skel
dotask configure_users
dotask configure_fstab
dotask configure_sources_list
dotask configure_network_interfaces
dotask configure_hostname
dotask disable_eth_and_wlan_renaming
dotask configure_inittab
dotask adjust_motd
dotask install_firmware
dotask install_raspi_config
dotask update_issue
dotask allow_starting_services
dotask shutdown_qemu
#dotask download_and_extract_firmware_if_necessary
sudo -v
# We have to copy the /boot from root partition to boot partition. Temporary
# hack
dotask attach_image_to_nbd $CURIMG $NBD_DEV
mkdir -p boot
dotask sudo mount $BOOT_DEV boot
mkdir -p rootfs
dotask sudo mount $ROOT_DEV rootfs
dotask sudo mv rootfs/boot/* boot
universal_cleanup
dotask finish_image

Wyświetl plik

@ -0,0 +1,451 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
set -ex
. ./common
WORKDIR=work
OUTDIR=out
CURIMG=stage3.$IMGFORMAT
configure_apt() {
onvm_chroot sh -l -ex - <<\EOF
cat <<\EOF1 > /etc/apt/apt.conf.d/50raspi
# never use pdiffs. Current implementation is very slow on low-powered devices
Acquire::PDiffs "0";
# download up to 5 pdiffs:
#Acquire::PDiffs::FileLimit "5";
EOF1
EOF
}
set_debconf_selections() {
ssh_in_to_qemu chroot /mnt sh -l -ex - <<EOF
debconf-set-selections <<SELEOF
# System's default wordlist:
# Choices: english (Webster's Second International English wordlist), Manual symlinks setting
dictionaries-common dictionaries-common/default-wordlist select english (Webster's Second International English wordlist)
# Use Control+Alt+Backspace to terminate the X server?
keyboard-configuration keyboard-configuration/ctrl_alt_bksp boolean true
# Backend to use for TrueType handling on X:
# Choices: freetype, xtt
x-ttcidfont-conf x-ttcidfont-conf/tt_backend select freetype
# Character set to support:
# Choices: . Arabic, # Armenian, # Cyrillic - KOI8-R and KOI8-U, # Cyrillic - non-Slavic languages, # Cyrillic - Slavic languages (also Bosnian and Serbian Latin), . Ethiopic, # Georgian, # Greek, # Hebrew, # Lao, # Latin1 and Latin5 - western Europe and Turkic languages, # Latin2 - central Europe and Romanian, # Latin3 and Latin8 - Chichewa; Esperanto; Irish; Maltese and Welsh, # Latin7 - Lithuanian; Latvian; Maori and Marshallese, . Latin - Vietnamese, # Thai, . Combined - Latin; Slavic Cyrillic; Hebrew; basic Arabic, . Combined - Latin; Slavic Cyrillic; Greek, . Combined - Latin; Slavic and non-Slavic Cyrillic
console-setup console-setup/codeset47 select . Combined - Latin; Slavic Cyrillic; Greek
# Time zone:
# Choices: GMT, GMT+0, GMT+1, GMT+10, GMT+11, GMT+12, GMT+2, GMT+3, GMT+4, GMT+5, GMT+6, GMT+7, GMT+8, GMT+9, GMT-0, GMT-1, GMT-10, GMT-11, GMT-12, GMT-13, GMT-14, GMT-2, GMT-3, GMT-4, GMT-5, GMT-6, GMT-7, GMT-8, GMT-9, GMT0, Greenwich, UCT, UTC, Universal, Zulu
tzdata tzdata/Zones/Etc select UTC
# for internal use
console-setup console-setup/store_defaults_in_debconf_db boolean true
# Font for the console:
# Choices: Fixed, Terminus, TerminusBold, TerminusBoldVGA, VGA, Do not change the boot/kernel font
console-setup console-setup/fontface47 select Do not change the boot/kernel font
# Enable subpixel rendering for screen:
# Choices: Automatic, Always, Never
fontconfig-config fontconfig/subpixel_rendering select Automatic
# Method for toggling between national and Latin mode:
# Choices: Caps Lock, Right Alt (AltGr), Right Control, Right Shift, Right Logo key, Menu key, Alt+Shift, Control+Shift, Control+Alt, Alt+Caps Lock, Left Control+Left Shift, Left Alt, Left Control, Left Shift, Left Logo key, Scroll Lock key, No toggling
keyboard-configuration keyboard-configuration/toggle select No toggling
# Font size:
# Choices: 13, 14, 15, 16, 18
console-setup console-setup/fontsize-text47 select 16
# Locales to be generated:
# Choices: <SNIP>
locales locales/locales_to_be_generated multiselect en_GB.UTF-8 UTF-8
# Keyboard model:
# Choices: <SNIP>
keyboard-configuration keyboard-configuration/model select Generic 105-key (Intl) PC
# Users allowed to start the X server:
# Choices: Root Only, Console Users Only, Anybody
x11-common x11-common/xwrapper/allowed_users select Anybody
# Compose key:
# Choices: No compose key, Right Alt (AltGr), Right Control, Right Logo key, Menu key, Left Logo key, Caps Lock
keyboard-configuration keyboard-configuration/compose select No compose key
# Country of origin for the keyboard:
# Choices: <SNIP>
keyboard-configuration keyboard-configuration/layout select English (UK)
# for internal use
keyboard-configuration keyboard-configuration/layoutcode string gb
# Keymap to use:
# Choices: <SNIP>
keyboard-configuration keyboard-configuration/xkb-keymap select British English
# Choices: English (UK), English (UK) - English (UK\, Colemak), English (UK) - English (UK\, Dvorak), English (UK) - English (UK\, Dvorak with UK punctuation), English (UK) - English (UK\, extended WinKeys), English (UK) - English (UK\, international with dead keys), English (UK) - English (UK\, Macintosh), English (UK) - English (UK\, Macintosh international), Other
keyboard-configuration keyboard-configuration/variant select English (UK)
# Geographic area:
# Choices: Africa, America, Antarctica, Australia, Arctic, Asia, Atlantic, Europe, Indian, Pacific, SystemV, US, Etc
tzdata tzdata/Areas select Etc
# Method for temporarily toggling between national and Latin input:
# Choices: No temporary switch, Both Logo keys, Right Alt (AltGr), Right Logo key, Left Alt, Left Logo key
keyboard-configuration keyboard-configuration/switch select No temporary switch
# Encoding to use on the console:
# Choices: ARMSCII-8, CP1251, CP1255, CP1256, GEORGIAN-ACADEMY, GEORGIAN-PS, IBM1133, ISIRI-3342, ISO-8859-1, ISO-8859-10, ISO-8859-11, ISO-8859-13, ISO-8859-14, ISO-8859-15, ISO-8859-16, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6, ISO-8859-7, ISO-8859-8, ISO-8859-9, KOI8-R, KOI8-U, TIS-620, UTF-8, VISCII
console-setup console-setup/charmap47 select UTF-8
# Font tuning method for screen:
# Choices: Native, Autohinter, None
fontconfig-config fontconfig/hinting_type select Native
# Font size:
# Choices:
console-setup console-setup/fontsize-fb47 select 16
# The desktop environment to install when the desktop task is selected
# Choices: gnome, kde, xfce
tasksel tasksel/desktop multiselect xfce
# Key to function as AltGr:
# Choices: The default for the keyboard layout, No AltGr key, Right Alt (AltGr), Right Control, Right Logo key, Menu key, Left Alt, Left Logo key, Keypad Enter key, Both Logo keys, Both Alt keys
keyboard-configuration keyboard-configuration/altgr select The default for the keyboard layout
# Default locale for the system environment:
# Choices: None, en_GB.UTF-8
locales locales/default_environment_locale select en_GB.UTF-8
SELEOF
EOF
}
install_packages() {
# we may want to break out DEBIAN_FRONTEND=noninteractive
ssh_in_to_qemu chroot /mnt sh -l -ex - <<\EOF
apt-get update
# install some utils
apt-get install -y ssh locales less fbset sudo psmisc strace module-init-tools ifplugd ed ncdu
apt-get install -y console-setup keyboard-configuration debconf-utils parted unzip
apt-get install -y build-essential manpages-dev python bash-completion gdb pkg-config
apt-get install -y python-rpi.gpio v4l-utils
apt-get install -y lua5.1
[ "$(dpkg --print-architecture)" = armhf ] && apt-get install -y luajit
apt-get install -y hardlink ca-certificates curl
apt-get install -y fake-hwclock ntp nfs-common usbutils
apt-get install -y --no-install-recommends cifs-utils
echo "deb http://archive.raspberrypi.org/debian/ wheezy main untested" > /etc/apt/sources.list.d/raspi.list
apt-get update
apt-get install -y libraspberrypi-dev libraspberrypi-doc libfreetype6-dev
echo "deb http://archive.raspberrypi.org/debian/ wheezy main" > /etc/apt/sources.list.d/raspi.list
printf "# Uncomment line below then 'apt-get update' to enable 'apt-get source'\n" >> /etc/apt/sources.list.d/raspi.list
printf "#deb-src http://archive.raspberrypi.org/debian/ wheezy main\n" >> /etc/apt/sources.list.d/raspi.list
apt-get update
# Install stuff for wireless
apt-get install -y wpasupplicant wireless-tools firmware-atheros firmware-brcm80211 \
firmware-libertas firmware-ralink firmware-realtek
/etc/init.d/fake-hwclock stop # save current time
update-rc.d hwclock.sh disable
# Don't need to start these by default, wastes boot time
update-rc.d nfs-common disable
update-rc.d rpcbind disable
apt-get install -y dosfstools
EOF
}
cache_keymap() {
onvm_chroot sh -l -e - <<\EOF
setupcon --force --save-only -v
/etc/init.d/fake-hwclock stop # save current time
EOF
}
add_pi_user_to_groups() {
onvm_chroot sh -l -ex - <<\EOF
groupadd -f -r input
for GRP in adm dialout cdrom audio users sudo video games plugdev input; do
adduser pi $GRP
done
EOF
}
configure_useradd() {
onvm_chroot sh -l -ex - <<\EOF
sed -i /etc/default/useradd -e 's/^# SKEL=/SKEL=/'
sed -i /etc/default/useradd -e 's|^SHELL=.*$|SHELL=/bin/bash|'
EOF
}
make_udev_input_rule() {
onvm_chroot sh -l -e - <<EOF
printf 'SUBSYSTEM=="input", GROUP="input", MODE="0660"\n' > /etc/udev/rules.d/99-input.rules
EOF
}
configure_wifi() {
onvm_chroot sh -l -e - <<EOF
cat <<\EOF1 >> /etc/network/interfaces
allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp
EOF1
cat <<\EOF2 > /etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
EOF2
chmod 600 /etc/wpa_supplicant/wpa_supplicant.conf
adduser pi netdev
EOF
}
apply_noobs_os_config() {
onvm_chroot sh -l -ex - <<\EOF
cat <<\EOF1 > /etc/init.d/apply_noobs_os_config
#!/bin/sh
### BEGIN INIT INFO
# Provides: apply_noobs_os_config
# Required-Start:
# Required-Stop:
# Default-Start: 2
# Default-Stop:
# Short-Description: Apply config from /boot/os_config.json
# Description:
### END INIT INFO
. /lib/lsb/init-functions
set -e
case "$1" in
start)
log_daemon_msg "Applying config from /boot/os_config.json (if it exists)"
if raspi-config --apply-os-config; then
rm /etc/init.d/apply_noobs_os_config && update-rc.d apply_noobs_os_config remove
log_end_msg 0
else
log_end_msg 1
fi
;;
*)
echo "Usage: $0 start" >&2
exit 3
;;
esac
EOF1
chmod +x /etc/init.d/apply_noobs_os_config
update-rc.d apply_noobs_os_config start 2
EOF
}
remove_ssh_host_keys() {
onvm_chroot sh -l -ex - <<\EOF
rm -f /etc/ssh/ssh_host_*_key*
cat <<\RCL | tee /etc/rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi
exit 0
RCL
update-rc.d ssh disable # to be re-enabled at first boot when we regenerate ssh host keys
cat <<\EOF1 > /etc/init.d/regenerate_ssh_host_keys
#!/bin/sh
### BEGIN INIT INFO
# Provides: regenerate_ssh_host_keys
# Required-Start:
# Required-Stop:
# Default-Start: 2
# Default-Stop:
# Short-Description: Regenerate ssh host keys
# Description:
### END INIT INFO
. /lib/lsb/init-functions
set -e
case "$1" in
start)
log_daemon_msg "Regenerating ssh host keys (in background)"
nohup sh -c "yes | ssh-keygen -q -N '' -t dsa -f /etc/ssh/ssh_host_dsa_key && \
yes | ssh-keygen -q -N '' -t rsa -f /etc/ssh/ssh_host_rsa_key && \
yes | ssh-keygen -q -N '' -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key && \
update-rc.d ssh enable && sync && \
rm /etc/init.d/regenerate_ssh_host_keys && \
update-rc.d regenerate_ssh_host_keys remove && \
printf '\nfinished\n' && invoke-rc.d ssh start" > /var/log/regen_ssh_keys.log 2>&1 &
log_end_msg $?
;;
*)
echo "Usage: $0 start" >&2
exit 3
;;
esac
EOF1
chmod +x /etc/init.d/regenerate_ssh_host_keys
update-rc.d regenerate_ssh_host_keys start 2
EOF
}
configure_ifplugd() {
onvm_chroot sh -l -ex - <<\EOF
sed /etc/default/ifplugd -i -e 's/^INTERFACES.*/INTERFACES="auto"/'
sed /etc/default/ifplugd -i -e 's/^HOTPLUG_INTERFACES.*/HOTPLUG_INTERFACES="all"/'
EOF
}
add_opt_vc_lib_to_ld_so() {
onvm_chroot sh -l -ex - <<EOF
echo "/opt/vc/lib" > /etc/ld.so.conf.d/vmcs.conf
ldconfig
EOF
}
setup_sudoers() {
onvm_chroot sh -l -ex - <<EOF
chmod +w /etc/sudoers
echo "pi ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
chmod -w /etc/sudoers
usermod --pass='*' root # don't need root password any more
EOF
}
# We use a swap file rather than a swap partition for greater flexibility
setup_swap() {
onvm_chroot sh -l -e - <<EOF
apt-get -y install dphys-swapfile
echo "CONF_SWAPSIZE=100" > /etc/dphys-swapfile
EOF
}
setup_console_setup() {
onvm_chroot sh -l -e - <<\EOF1
cat <<\EOF2 > /etc/default/console-setup
# CONFIGURATION FILE FOR SETUPCON
# Consult the console-setup(5) manual page.
ACTIVE_CONSOLES="/dev/tty[1-6]"
CHARMAP="UTF-8"
CODESET="guess"
FONTFACE=""
FONTSIZE=""
VIDEOMODE=
# The following is an example how to use a braille font
# FONT='lat9w-08.psf.gz brl-8x8.psf'
EOF2
EOF1
}
# Spread the word about my favourite inputrc tweak
tweak_inputrc() {
onvm_chroot sh -l -e - <<\EOF1
cat <<\EOF2 >> /etc/inputrc
# mappings for up and down arrows search history
# "\e[B": history-search-forward
# "\e[A": history-search-backward
EOF2
EOF1
}
# It's not to have the sbin dirs in $PATH as that gives us ifconfig
fiddle_default_PATH() {
# This sed match is clearly brittle and specific to the current debian
# /etc/profile
onvm_chroot sh -l -ex - <<EOF
sed /etc/profile -i -e \
's|PATH="/usr/.*games.*$|PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games"|'
# need to fix ENV_PATH in /etc/login.defs
sed -i /etc/login.defs -e "s|^ENV_PATH.*|ENV_PATH PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games|"
EOF
}
add_qt5_apt_source() {
onvm_chroot sh -l -e <<\EOF
echo "deb http://archive.qmh-project.org/rpi-wheezy/debian/ unstable main" >> /etc/apt/sources.list.d/qt5pi.list
apt-get update
EOF
}
install_memcpy_replacement() {
onvm_chroot sh -l -e <<\EOF
apt-get install -y raspi-copies-and-fills
mv /etc/ld.so.preload /etc/ld.so.preload.disable
EOF
}
adjust_sysctl() {
onvm_chroot sh -l -e <<\EOF
printf "\n# rpi tweaks\nvm.swappiness=1\n" >> /etc/sysctl.conf
printf "vm.min_free_kbytes = 8192\n" >> /etc/sysctl.conf
# Only print important messages to console
sed /etc/sysctl.conf -i -e "s/\#kernel\.printk/kernel.printk/"
EOF
}
set_default_kernel_modules() {
onvm_chroot sh -e - <<EOF
printf 'snd-bcm2835\n' >> /etc/modules
EOF
}
configure_sound() {
onvm_chroot sh -e - <<EOF
cat <<\EOF1 > /etc/asound.conf
pcm.mmap0 {
type mmap_emul;
slave {
pcm "hw:0,0";
}
}
pcm.!default {
type plug;
slave {
pcm mmap0;
}
}
EOF1
EOF
}
cd $WORKDIR
dotask branch_image ../$OUTDIR/stage2.$IMGFORMAT $CURIMG
dotask run_qemu $CURIMG
dotask mount_apt_cache
dotask disable_starting_services
dotask configure_apt
dotask set_debconf_selections
dotask install_packages
dotask configure_ifplugd
dotask add_pi_user_to_groups
dotask configure_useradd
dotask make_udev_input_rule
dotask configure_wifi
#dotask add_opt_vc_lib_to_ld_so
dotask setup_sudoers
dotask setup_swap
dotask setup_console_setup
dotask cache_keymap
dotask tweak_inputrc
dotask fiddle_default_PATH
[ -n "$RASPBIAN" ] && dotask install_memcpy_replacement
dotask save_space_using_hardlink
#[ -z "$RASPBIAN" ] && dotask add_qt5_apt_source
dotask adjust_sysctl
dotask allow_starting_services
dotask remove_ssh_host_keys
dotask apply_noobs_os_config
dotask set_default_kernel_modules
# Latest firmware does not need mmap emulation, so skip asound.conf creation
#dotask configure_sound
dotask update_issue
dotask fingerprint_debian
dotask shutdown_qemu
dotask finish_image

Wyświetl plik

@ -0,0 +1,189 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
set -ex
. ./common
CURIMG=stage4-lxde.$IMGFORMAT
install_packages() {
# we may want to break out DEBIAN_FRONTEND=noninteractive
ssh_in_to_qemu chroot /mnt sh -l -ex - <<EOF
apt-get update
apt-get install --no-install-recommends -y xserver-xorg-video-fbdev
apt-get install --no-install-recommends -y xserver-xorg xinit
apt-get install -y gstreamer1.0-x gstreamer1.0-omx gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-alsa \
gstreamer1.0-libav
apt-get install --no-install-recommends -y epiphany-browser cgroup-bin
apt-get install --no-install-recommends -y lxde lxtask menu-xdg gksu
apt-get install -y xserver-xorg-video-fbturbo
apt-get install -y xpdf gtk2-engines alsa-utils
apt-get install -y --no-install-recommends netsurf-gtk zenity xdg-utils
apt-get install -y desktop-base lxpolkit
apt-get install -y --no-install-recommends gvfs-backends gvfs-fuse
apt-get install -y wpagui
apt-get install -y git-core rpi-update
EOF
}
# make gksu default to sudo mode
configure_gksu() {
onvm_chroot sh -l -e - <<\EOF
update-alternatives --set libgksu-gconf-defaults /usr/share/libgksu/debian/gconf-defaults.libgksu-sudo
update-gconf-defaults
EOF
}
install_wayland() {
onvm_chroot sh -l -ex - <<\EOF
echo "deb http://raspberrypi.collabora.com wheezy rpi" > /etc/apt/sources.list.d/collabora.list
apt-key add - <<EOF1
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.13 (GNU/Linux)
mQINBFGONkIBEADC69AVM/bJ15zZftt73ZtWzqER890BLRWYHNCCqidbcs+Ww2Bi
PGIfTOnsXQIGrdDKmtgjc4kskDTeG7VWCgmhzNBzvdNrfVYxv4EpzdWUxifEOYXo
RvEynwQ0AuehplOfZeVidzvWvBwuVDt0L3XRW8etjSYfjKSYnEVCsZW3EwVUs3zp
dyjHYjQSrjwaWfFZEtU7O4U6EUiGARJnOaim9bAh6fSsXy9qHDn4uFD3EjJgl9EK
XSmXYTMbkbajDwSBk4vAkZoP7VjgQKG2uVfDBqTvy3rXt1pwuJuzm/8RRn8g1esv
ZUhbdNDHzQi3GxWB2D7aPZCaEPMO5uD2+7d6KgkjoFXxx0iwqKnHYNp+ElT6J12b
AdzHqtCtOQFgkXqPCB/DQUo758Txwp5MRH3g7yCwsXBxx20gwzzAGNlVGH5f4Q8O
1UhbrqQuWkWroBGnq5277atUTZ+2lnaocVr7J2BFfndMwaGYLAV6QzQjvgyn5zyq
YiWDN85IljOR8ZJcONVcR6fjVpQpjERiiQxLI9ZyAGMkjvtcDVhGknWrddOF/H6d
txT/VEsQdcmZSjGSVzhgtdGweIelaO3cQHBXi1XKJ1L3nQeh4uR4aCJJBU+nlhLh
XyM8YC/TTfIluut/IlSR6/+baZTsnLY/AT2FMtMJoMKVRl5rhtiwQDYt+wARAQAB
tD5Db2xsYWJvcmEgUmFzcGJpYW4gQXJjaGl2ZSBTaWduaW5nIEtleSA8ZGFuaWVs
c0Bjb2xsYWJvcmEuY29tPokCOAQTAQIAIgUCUY42QgIbAwYLCQgHAwIGFQgCCQoL
BBYCAwECHgECF4AACgkQ7Uv5FAxQscXhWBAAjmHTmgB7rj+swhrVXHbGZ7KGWxun
EqXzAfpcP9n1aqVtF5foyRJ4wJD8l/CCR8RCO3zXHAVGg5QdXMMoWu/s6CjbZGiG
uvAXjt3UJR/J3X8hDtK28q8fDbjtI1u6AeDstgEI3ZhB4VjpbE+yAZS6in/wmndc
lOn7p4e0/RWnX3bLbp2z1AqeypTC2nm9L897O4CLYA1+0u4BCuLizrnR04BfN/ht
WBRVzdhWSCWSNWjT8ukr3GwR5mew11G355k2Op5FJfCzbvpDYm0xwkvWAmJ7WDHo
cicXmgW1GoSYn6MFX9fmYI2CJZi90oxL8IdCF8hIXMmT3MOjhVwvdNN+sXaqrOU1
vMMXwPDjEI4VO+yfz368rYUtHYluLN0ld0RunUsylpHZ6GbDh6/RRyY+pect9pHl
Y/EWj9YYRTyWBiJ0753dowy4lWjx93ZuGBOUqe+7ZiN5obyPzQzzeKRhq7FMphcw
6c2Df2/yCQliScS6XOvyaN7/nzuQ2M4KFCJ4q89vIXUrUTU2/HdplK4ErxEA5Vac
pcUAnyvYLeChB0mpWTiGvHGCIu90KXK/69Zxe1quybnqcT1jRo0ejICTzppDb4Lx
Q2WVHbsB3b3j+HvwTTcfdO4nodVmU3q8F4u+X5DLG0vPd2dyLgihh2Dleh9gZ6/7
ygRFDTY12IoIdXS5Ag0EUY42QgEQAK4YrUwDCdiY/uuuwscQwAdNOj6AOJ2DQemH
CpcdAIEMYqXlZgM+R+EFwU7FVk6c4Bk78jE/pwHQIdR9DwXTd/EqGPVv0jcYYEK/
OTWGgCXXrcpWPpW7ej3xhm0qN5fkr+QVweAtZ+Y/SdUbSOTRyAKZF3MzHL3/5S+h
axjErwxMlD1Ar2OIQ4TpL+rWqPWL2quSQbJW72U5ndFC7yGVWhaoxybzkr+sSPag
zVfYVYuUASUMvX4esbhB0p5y9DIY7oPGDLqB60mWW6UfshpPVkiim3z47lWoieox
dAy0KjWt9ae37gSNSxopVJ2OTyLaunsAXMMT6IYUlHSYkGg8iodSw+xNgzK/QzZz
ij4kzKdU0owKm+vsz9dCaIDHS09TrKj9EqEqFtJJm5X+u08JgO1iWqvTdQR3fLt4
hjipViSEHqweihG/10BtQH2XgRZy54FV9EynfYeLsB2Ln2/xbQiaONUWVnmPU1Dl
X8B7H4blivMkU47DOVKEGy8Doy16B9TycMZ+oBCekWSuLICNjLQLBvnFJaZV/1Nf
W49NY+WUDZCisTivWAlaya5SuVfqhhGHPnPqypk7HjqeYJxScDOF0F4xaWUZDqtk
HGaTnTNMU7eI5fKHNh7VcalY0DwGiWqS412IRFh0YjjxVIK552GsPHgBdKEgWIGI
zw8eMQLTABEBAAGJAh8EGAECAAkFAlGONkICGwwACgkQ7Uv5FAxQscXbMw//eq7s
9HAsmVq4OOUZF/UeYT4vbm8mpHrbuQd3zlOsXn8Z49G8cf1WFRUl6uCpLQ0tR6pJ
oC64oGPz8wMv3ZHXrb/CZM3o63hO4qv4Be9aCj+As3oXWNPOZ6Vwmx3rkiffeRig
ypY97pZhq00Kx6ycjfP0h2SUazZMuQEjawCeca8LDE+8jn/EEnnP7MgWm7EOVlkS
c/I08VWVqPOQGl1FuncbJ4KhBkrkmPoMUuz7D4Dq4fAzIS7PJkthzHdGkNoneo/X
pZRR1qfCwFBNvNzkCG3ECggevh3fTEkVvhnVTIvzq5GUi9PsjjNtAt8JPxsJgZkg
FJLPlJTgpm8KR9OiIKn1z9RodqXSUZhE7Cw/koNzzNpjfo4tB4OmNueiCXObNRrr
jIaacoqqok301Mk3SVNc3YyEa/9HN5DmETrQS+9fhukP2Frcr4wOHJCajvxa+Sl7
oryGCWXqvBpSEucw1FDkOgoe5EwHvcdu+dzVypY0JZoLHQDV69aTiHFsZhBu6Ves
hG/v4/wnBFL5f0cl9t53GmEDcjsg5VKbcTmCMG6Z6DbNIusYAz98ucAqGupzKvA0
3C/Ik0Y1LI8iEYXPiUbgSBCZ4RrJsdtbZDRyy357pSr+5eB6eXLy1eBC84jv/A6h
HXWu9eprthyEIX6pmEhqzMViFix7FVozfdn2H4U=
=zyWt
-----END PGP PUBLIC KEY BLOCK-----
EOF1
apt-get update
apt-get install -y --force-yes weston
EOF
}
install_omxplayer() {
onvm_chroot sh -l -e - <<\EOF
apt-get update
apt-get install -y omxplayer
EOF
}
configure_lxde() {
onvm_chroot sh -l -e <<\EOF
# first change theme to mist (seems to render noticably faster)
sed /etc/xdg/lxsession/LXDE/desktop.conf -i -e "s|sNet/ThemeName.*|sNet/ThemeName=Mist|"
# configure openbox so it doesn't ask apps to redraw while resizing
sed /etc/xdg/openbox/LXDE/rc.xml -i -e \
"s|<drawContents>yes</drawContents>|<drawContents>no</drawContents>|"
apt-get install -y raspberrypi-artwork
# change background
update-alternatives --install /usr/share/images/desktop-base/desktop-background \
desktop-background /usr/share/raspberrypi-artwork/raspberry-pi-logo.png 100
PCMANFMCFG=/etc/xdg/pcmanfm/LXDE/pcmanfm.conf
sed "$PCMANFMCFG" -i -e 's/^wallpaper_mode.*/wallpaper_mode=3/'
sed "$PCMANFMCFG" -i -e 's/^desktop_bg.*/desktop_bg=#ffffff/'
# while we're at it, let's not use xdg-su which Debian doesn't even provide
sed "$PCMANFMCFG" -i -e 's/^su_cmd.*/su_cmd=gksu %s/'
EOF
}
setup_automounting() {
onvm_chroot sh -l -e <<\EOF1
apt-get install -y udisks
cat <<EOF2 > /etc/polkit-1/localauthority/50-local.d/55-storage.pkla
[Storage Permissions]
Identity=unix-group:plugdev
Action=org.freedesktop.udisks.filesystem-mount;org.freedesktop.udisks.drive-eject;org.freedesktop.udisks.drive-detach;org.freedesktop.udisks.luks-unlock;org.freedesktop.udisks.inhibit-polling;org.freedesktop.udisks.drive-set-spindown
ResultAny=yes
ResultActive=yes
ResultInactive=no
EOF2
EOF1
}
install_and_configure_lightdm() {
onvm_chroot sh -l -e <<\EOF
apt-get install --no-install-recommends -y lightdm gnome-themes-standard-data gnome-icon-theme
apt-get install -y policykit-1
update-rc.d lightdm disable 2
sed -i /etc/lightdm/lightdm-gtk-greeter.conf -e "s/^background.*/background=#ffffff/"
# TODO: maybe change the computer icon to the Raspberry Pi logo? See
# https://wiki.archlinux.org/index.php/LightDM#Changing_the_Icon
# Source /etc/profile and ~/.profile through XSession.d to ensure PATH is set
# properly when lightdm is used.
cat <<\EOF1 > /etc/X11/Xsession.d/75source-profile
[ -f /etc/profile ] && . /etc/profile
[ -f "$HOME/.profile" ] && . "$HOME/.profile"
EOF1
EOF
}
install_qt5() {
onvm_chroot sh -l -e <<\EOF
apt-get update
apt-get install --allow-unauthenticated -y qt50-snapshot qt50-quick-particle-examples
EOF
}
cd $WORKDIR
dotask branch_image ../$OUTDIR/stage3.$IMGFORMAT $CURIMG
dotask run_qemu $CURIMG
dotask mount_apt_cache
dotask disable_starting_services
dotask install_packages
dotask configure_gksu
[ -n "$RASPBIAN" ] && dotask install_omxplayer
dotask configure_lxde
dotask install_and_configure_lightdm
dotask setup_automounting
#[ -z "$RASPBIAN" ] && dotask install_qt5
[ -n "$RASPBIAN" ] && dotask install_wayland
dotask save_space_using_hardlink
dotask allow_starting_services
dotask update_issue
dotask fingerprint_debian
dotask shutdown_qemu
dotask finish_image

Wyświetl plik

@ -0,0 +1,111 @@
#!/bin/sh
# Part of spindle http://asbradbury.org/projects/spindle
#
# See LICENSE file for copyright and license details
set -ex
. ./common
WORKDIR=work
OUTDIR=out
CURIMG=stage4-lxde-edu.$IMGFORMAT
install_packages() {
ssh_in_to_qemu chroot /mnt sh -l -ex - <<\EOF
apt-get update
apt-get upgrade -y
apt-get install -y python idle python3-pygame python-pygame python-tk
apt-get install -y python3 idle3 python3-tk
apt-get install -y python3-rpi.gpio
apt-get install -y python-serial python3-serial
apt-get install -y python-picamera python3-picamera
apt-get install -y debian-reference-en dillo x2x
apt-get install -y scratch nuscratch
apt-get install -y raspberrypi-ui-mods
apt-get install -y --no-install-recommends timidity # needed for some python game examples
[ "$(dpkg --print-architecture)" = armhf ] && apt-get install -y smartsim penguinspuzzle
[ "$(dpkg --print-architecture)" = armhf ] && apt-get install -y pistore
[ "$(dpkg --print-architecture)" = armhf ] && apt-get install -y sonic-pi
cat <<\EOF1 > /etc/udev/rules.d/40-scratch.rules
ATTRS{idVendor}=="0694", ATTRS{idProduct}=="0003", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev"
EOF1
# Requested for raspberry filling
apt-get install -y python3-numpy
# Install pypy
if [ "$(dpkg --print-architecture)" = armhf ]; then
apt-get install -y pypy-upstream
fi
apt-get install -y python3-pifacecommon python3-pifacedigitalio \
python3-pifacedigital-scratch-handler python-pifacecommon python-pifacedigitalio
if [ "$(dpkg --print-architecture)" = armhf ]; then
apt-get install -y java-common oracle-java8-jdk
apt-get install -y minecraft-pi python-minecraftpi
fi
EOF
}
install_wolfram() {
onvm_chroot sh -l -ex - <<\EOF
apt-get update
debconf-set-selections <<SELEOF
wolfram-engine shared/accepted-wolfram-eula boolean true
SELEOF
apt-get install -y wolfram-engine
EOF
}
setup_python_game_examples() {
onvm_chroot sh -l -e <<\EOF
cd /home/pi
wget "https://github.com/KenT2/python-games/tarball/master" -O python_games.tar.gz
tar -xvf python_games.tar.gz
mv KenT2-python-games* python_games
chmod +x python_games/launcher.sh
rm python_games.tar.gz
chown -R pi:pi python_games
EOF
}
# relies on the fact we made a Desktop directory in
# setup_python_game_examples
setup_desktop_icons() {
onvm_chroot sh -l -e <<\EOF
# We don't want desktop icons any more
rm -rf /home/pi/Desktop
EOF
}
# There are 2 menu entries for both of idle3 and idle2. Fix this
hide_redundant_idle_menu_entries() {
onvm_chroot sh -l -e <<\EOF
mkdir -p /usr/local/share/applications
for ENTRY in /usr/share/applications/idle-python*.desktop; do
cp -a $ENTRY /usr/local/share/applications
printf "NoDisplay=true\n" >> "/usr/local/share/applications/$(basename $ENTRY)"
done
EOF
}
cd $WORKDIR
dotask branch_image ../$OUTDIR/stage4-lxde.$IMGFORMAT $CURIMG
dotask run_qemu $CURIMG
dotask disable_starting_services
dotask mount_apt_cache
dotask install_packages
[ -n "$RASPBIAN" ] && dotask install_wolfram
dotask setup_python_game_examples
dotask setup_desktop_icons
dotask hide_redundant_idle_menu_entries
dotask save_space_using_hardlink
dotask allow_starting_services
dotask fingerprint_debian
dotask update_issue
dotask shutdown_qemu
dotask finish_image