Initial KISS support
This commit is contained in:
parent
9addf50a33
commit
6e3d8d9987
Binary file not shown.
|
@ -0,0 +1,18 @@
|
|||
Version 1.24: (courtesy of Nils Eilers)
|
||||
-- fixed exit code on success to be 0 instead of EINVAL
|
||||
-- added --self-powered flag
|
||||
Version 1.23:
|
||||
-- added GPLv2 licensing.
|
||||
Version 1.22:
|
||||
-- try again to preserve USB version from eeprom.
|
||||
Version 1.21:
|
||||
-- preserve USB version from eeprom; libusb no longer does this correctly (sigh).
|
||||
Version 1.10:
|
||||
-- now able to invert _all_ the serial and handshake lines (not just DTR).
|
||||
(courtesy of Jonas Meyer, thanks!)
|
||||
Version 1.09:
|
||||
Version 1.08:
|
||||
-- fix compiler warning from newer gcc
|
||||
-- Makefile fixes for latest Ubuntu & binutils
|
||||
Version 1.06:
|
||||
-- fix libftdi-0.19 API breakage by not using "BM_type_chip" from libftdi0-0.18.
|
|
@ -0,0 +1,341 @@
|
|||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin St, 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 Library 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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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 St, 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 Library General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,11 @@
|
|||
CFLAGS = -Wall -O2 -s -Werror
|
||||
LDFLAGS = -lusb -lftdi -s
|
||||
PROG = ft232r_prog
|
||||
|
||||
all: $(PROG)
|
||||
|
||||
$(PROG): $(PROG).c
|
||||
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f $(PROG)
|
Binary file not shown.
|
@ -0,0 +1,814 @@
|
|||
/*
|
||||
* ft232r_prog.c by Mark Lord. Copyright 2010-2013.
|
||||
*
|
||||
* This is a Linux command-line alternative to the FTDI MProg/FTProg utilities.
|
||||
* It is known to work only for FT232R chips at this time.
|
||||
*
|
||||
* 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, 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; see the file LICENSE.txt. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <ftdi.h>
|
||||
|
||||
#define MYVERSION "1.24"
|
||||
|
||||
static struct ftdi_context ftdi;
|
||||
static int verbose = 0;
|
||||
static const char *save_path = NULL, *restore_path = NULL;
|
||||
|
||||
enum cbus_mode {
|
||||
cbus_txden = 0,
|
||||
cbus_pwren = 1,
|
||||
cbus_rxled = 2,
|
||||
cbus_txled = 3,
|
||||
cbus_txrxled = 4,
|
||||
cbus_sleep = 5,
|
||||
cbus_clk48 = 6,
|
||||
cbus_clk24 = 7,
|
||||
cbus_clk12 = 8,
|
||||
cbus_clk6 = 9,
|
||||
cbus_io = 10,
|
||||
cbus_wr = 11,
|
||||
cbus_rd = 12,
|
||||
cbus_rxf = 13,
|
||||
};
|
||||
|
||||
static const char *cbus_mode_strings[] = {
|
||||
"TxDEN",
|
||||
"PwrEn",
|
||||
"RxLED",
|
||||
"TxLED",
|
||||
"TxRxLED",
|
||||
"Sleep",
|
||||
"Clk48",
|
||||
"Clk24",
|
||||
"Clk12",
|
||||
"Clk6",
|
||||
"IO",
|
||||
"WR",
|
||||
"RD",
|
||||
"RxF",
|
||||
NULL
|
||||
};
|
||||
|
||||
enum arg_type {
|
||||
arg_help,
|
||||
arg_dump,
|
||||
arg_verbose,
|
||||
arg_save,
|
||||
arg_restore,
|
||||
arg_cbus0,
|
||||
arg_cbus1,
|
||||
arg_cbus2,
|
||||
arg_cbus3,
|
||||
arg_cbus4,
|
||||
arg_manufacturer,
|
||||
arg_product,
|
||||
arg_old_serno,
|
||||
arg_new_serno,
|
||||
arg_self_powered,
|
||||
arg_max_bus_power,
|
||||
arg_high_current_io,
|
||||
arg_suspend_pull_down,
|
||||
arg_old_vid,
|
||||
arg_old_pid,
|
||||
arg_new_vid,
|
||||
arg_new_pid,
|
||||
arg_invert_txd,
|
||||
arg_invert_rxd,
|
||||
arg_invert_rts,
|
||||
arg_invert_cts,
|
||||
arg_invert_dtr,
|
||||
arg_invert_dsr,
|
||||
arg_invert_dcd,
|
||||
arg_invert_ri,
|
||||
};
|
||||
|
||||
static const char *arg_type_strings[] = {
|
||||
"--help",
|
||||
"--dump",
|
||||
"--verbose",
|
||||
"--save",
|
||||
"--restore",
|
||||
"--cbus0",
|
||||
"--cbus1",
|
||||
"--cbus2",
|
||||
"--cbus3",
|
||||
"--cbus4",
|
||||
"--manufacturer",
|
||||
"--product",
|
||||
"--old-serial-number",
|
||||
"--new-serial-number",
|
||||
"--self-powered",
|
||||
"--max-bus-power",
|
||||
"--high-current-io",
|
||||
"--suspend-pull-down",
|
||||
"--old-vid",
|
||||
"--old-pid",
|
||||
"--new-vid",
|
||||
"--new-pid",
|
||||
"--invert_txd",
|
||||
"--invert_rxd",
|
||||
"--invert_rts",
|
||||
"--invert_cts",
|
||||
"--invert_dtr",
|
||||
"--invert_dsr",
|
||||
"--invert_dcd",
|
||||
"--invert_ri",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *arg_type_help[] = {
|
||||
" # (show this help text)",
|
||||
" # (dump eeprom settings to stdout))",
|
||||
"# (show debug info and raw eeprom contents)",
|
||||
" # (save original eeprom contents to file)",
|
||||
"# (restore initial eeprom contents from file)",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
" <string> # (new USB manufacturer string)",
|
||||
" <string> # (new USB product name string)",
|
||||
"<string> # (current serial number of device to be reprogrammed)",
|
||||
"<string> # (new USB serial number string)",
|
||||
" [on|off] # (self powered)",
|
||||
" <number> # (max bus current in milli-amperes)",
|
||||
" [on|off] # (enable high [6mA @ 5V] drive current on CBUS pins)",
|
||||
"[on|off] # (force I/O pins into logic low state on suspend)",
|
||||
" <number> # (current vendor id of device to be reprogrammed, eg. 0x0403)",
|
||||
" <number> # (current product id of device to be reprogrammed, eg. 0x6001)",
|
||||
" <number> # (new/custom vendor id to be programmed)",
|
||||
" <number> # (new/custom product id be programmed)",
|
||||
" Inverts the current value of TXD",
|
||||
" Inverts the current value of RXD",
|
||||
" Inverts the current value of RTS",
|
||||
" Inverts the current value of CTS",
|
||||
" Inverts the current value of DTR",
|
||||
" Inverts the current value of DSR",
|
||||
" Inverts the current value of DCD",
|
||||
" Inverts the current value of RI",
|
||||
};
|
||||
|
||||
static const char *bool_strings[] = {
|
||||
"off",
|
||||
"on",
|
||||
"0",
|
||||
"1",
|
||||
"no",
|
||||
"yes",
|
||||
"disable",
|
||||
"enable",
|
||||
};
|
||||
|
||||
struct eeprom_fields {
|
||||
unsigned char byte01;
|
||||
unsigned char high_current_io; /* bool */
|
||||
unsigned char load_d2xx_driver; /* bool */
|
||||
unsigned char txd_inverted; /* bool */
|
||||
unsigned char rxd_inverted; /* bool */
|
||||
unsigned char rts_inverted; /* bool */
|
||||
unsigned char cts_inverted; /* bool */
|
||||
unsigned char dtr_inverted; /* bool */
|
||||
unsigned char dsr_inverted; /* bool */
|
||||
unsigned char dcd_inverted; /* bool */
|
||||
unsigned char ri_inverted; /* bool */
|
||||
unsigned char pnp_enabled; /* bool */
|
||||
enum cbus_mode cbus[5];
|
||||
unsigned char extras[112]; /* extra, undefined fields */
|
||||
struct ftdi_eeprom libftdi; /* stuff known to libftdi */
|
||||
unsigned char BM_type_chip; /* from libftdi-0.18, missing in 0.19 */
|
||||
|
||||
/* These are not actually eeprom values; here for convenience */
|
||||
unsigned short old_vid;
|
||||
unsigned short old_pid;
|
||||
const char *old_serno;
|
||||
unsigned short new_vid;
|
||||
unsigned short new_pid;
|
||||
};
|
||||
|
||||
static void dumpmem (const char *msg, void *addr, int len)
|
||||
{
|
||||
char *data = addr, hex[3 * 16 + 1], ascii[17];
|
||||
unsigned int i, offset = 0;
|
||||
|
||||
if (msg)
|
||||
printf("%s:\n", msg);
|
||||
for (i = 0; i < len;) {
|
||||
unsigned int i16 = i % 16;
|
||||
unsigned char c = data[i];
|
||||
sprintf(hex + (3 * i16), " %02x", c);
|
||||
ascii[i16] = (c < ' ' || c > '~') ? '.' : c;
|
||||
if (++i == len || i16 == 15) {
|
||||
ascii[i16 + 1] = '\0';
|
||||
for (; i16 != 15; ++i16)
|
||||
strcat(hex, " ");
|
||||
printf("%04x:%s %s\n", offset, hex, ascii);
|
||||
offset = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned short calc_crc (void *addr, int len)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned short crc = 0xaaaa;
|
||||
unsigned char *d8 = addr;
|
||||
|
||||
for (i = 0; i < len - 2; i += 2) {
|
||||
crc ^= d8[i] | (d8[i+1] << 8);
|
||||
crc = (crc << 1) | (crc >> 15);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
static void do_deinit (void)
|
||||
{
|
||||
ftdi_deinit(&ftdi);
|
||||
}
|
||||
|
||||
static void do_close (void)
|
||||
{
|
||||
ftdi_usb_close(&ftdi);
|
||||
}
|
||||
|
||||
static unsigned short verify_crc (void *addr, int len)
|
||||
{
|
||||
unsigned short crc = calc_crc(addr, len);
|
||||
unsigned char *d8 = addr;
|
||||
unsigned short actual = d8[len-2] | (d8[len-1] << 8);
|
||||
|
||||
if (crc != actual) {
|
||||
fprintf(stderr, "Bad CRC: crc=0x%04x, actual=0x%04x\n", crc, actual);
|
||||
exit(EINVAL);
|
||||
}
|
||||
if (verbose) printf("CRC: Okay (0x%04x)\n", crc);
|
||||
return crc;
|
||||
}
|
||||
|
||||
static unsigned short update_crc (void *addr, int len)
|
||||
{
|
||||
unsigned short crc = calc_crc(addr, len);
|
||||
unsigned char *d8 = addr;
|
||||
|
||||
d8[len-2] = crc;
|
||||
d8[len-1] = crc >> 8;
|
||||
return crc;
|
||||
}
|
||||
|
||||
static int match_arg (const char *arg, const char **possibles)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; possibles[i]; ++i) {
|
||||
if (0 == strcasecmp(possibles[i], arg))
|
||||
return i;
|
||||
}
|
||||
fprintf(stderr, "unrecognized arg: \"%s\"\n", arg);
|
||||
exit(EINVAL);
|
||||
return -1; /* never reached */
|
||||
}
|
||||
|
||||
static unsigned long unsigned_val (const char *arg, unsigned long max)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
errno = 0;
|
||||
val = strtoul(arg, NULL, 0);
|
||||
if (errno || val > max) {
|
||||
fprintf(stderr, "%s: bad value (max=0x%lx)\n", arg, max);
|
||||
exit(EINVAL);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void ee_dump (struct eeprom_fields *ee)
|
||||
{
|
||||
unsigned int c;
|
||||
|
||||
printf(" eeprom_size = %d\n", ee->libftdi.size);
|
||||
printf(" vendor_id = 0x%04x\n", ee->libftdi.vendor_id);
|
||||
printf(" product_id = 0x%04x\n", ee->libftdi.product_id);
|
||||
printf(" self_powered = %d\n", ee->libftdi.self_powered);
|
||||
printf(" remote_wakeup = %d\n", ee->libftdi.remote_wakeup);
|
||||
printf("suspend_pull_downs = %d\n", ee->libftdi.suspend_pull_downs);
|
||||
printf(" max_bus_power = %d mA\n", 2 * ee->libftdi.max_power);
|
||||
printf(" manufacturer = %s\n", ee->libftdi.manufacturer);
|
||||
printf(" product = %s\n", ee->libftdi.product);
|
||||
printf(" serialnum = %s\n", ee->libftdi.serial);
|
||||
printf(" high_current_io = %u\n", ee->high_current_io);
|
||||
printf(" load_d2xx_driver = %u\n", ee->load_d2xx_driver);
|
||||
printf(" txd_inverted = %u\n", ee->txd_inverted);
|
||||
printf(" rxd_inverted = %u\n", ee->rxd_inverted);
|
||||
printf(" rts_inverted = %u\n", ee->rts_inverted);
|
||||
printf(" cts_inverted = %u\n", ee->cts_inverted);
|
||||
printf(" dtr_inverted = %u\n", ee->dtr_inverted);
|
||||
printf(" dsr_inverted = %u\n", ee->dsr_inverted);
|
||||
printf(" dcd_inverted = %u\n", ee->dcd_inverted);
|
||||
printf(" ri_inverted = %u\n", ee->ri_inverted);
|
||||
|
||||
for (c = 0; c < 5; ++c)
|
||||
printf(" cbus[%u] = %s\n", c, cbus_mode_strings[ee->cbus[c]]);
|
||||
|
||||
if (verbose) {
|
||||
/* These fields are non-applicable for FT232R devices */
|
||||
printf(" usb_version = %d\n", ee->libftdi.usb_version);
|
||||
printf(" use_serialnum = %d (n/a)\n", ee->libftdi.use_serial);
|
||||
printf("change_usb_version = %d (n/a)\n", ee->libftdi.change_usb_version);
|
||||
printf(" pnp_enabled = %u (n/a)\n", ee->pnp_enabled);
|
||||
printf(" BM_type_chip = 0x%02x (n/a)\n", ee->BM_type_chip);
|
||||
printf(" in_is_isochronous = %d (n/a)\n", ee->libftdi.in_is_isochronous);
|
||||
printf("out_is_isochronous = %d (n/a)\n", ee->libftdi.out_is_isochronous);
|
||||
}
|
||||
};
|
||||
|
||||
static unsigned int calc_extras_offset (unsigned char *eeprom)
|
||||
{
|
||||
unsigned int str1 = (eeprom[0x0e] & 0x7f) + eeprom[0x0f];
|
||||
unsigned int str2 = (eeprom[0x10] & 0x7f) + eeprom[0x11];
|
||||
unsigned int str3 = (eeprom[0x12] & 0x7f) + eeprom[0x13];
|
||||
unsigned int offset;
|
||||
|
||||
if (str3 > str2)
|
||||
offset = (str3 > str1) ? str3 : str1;
|
||||
else
|
||||
offset = (str2 > str1) ? str2 : str1;
|
||||
return offset;
|
||||
}
|
||||
|
||||
static unsigned int encode_string (void *eeprom, int desc, int offset, char *s)
|
||||
{
|
||||
unsigned char c, *u8 = eeprom, slen = (strlen(s) + 1) * 2;
|
||||
|
||||
if (!s || !*s)
|
||||
return offset;
|
||||
u8[desc + 0] = offset | 0x80; /* offset of string */
|
||||
u8[desc + 1] = slen; /* length */
|
||||
|
||||
u8[offset++] = slen; /* length */
|
||||
u8[offset++] = 0x03; /* "type" == string */
|
||||
while ((c = *s++)) {
|
||||
u8[offset++] = c;
|
||||
u8[offset++] = 0;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void ft232r_eprom_build (struct eeprom_fields *ee, unsigned char *eeprom)
|
||||
{
|
||||
unsigned int len = ee->libftdi.size;
|
||||
int offset = 0x18;
|
||||
|
||||
memset(eeprom, 0, len);
|
||||
if (strlen(ee->libftdi.serial) > 16) {
|
||||
fprintf(stderr, "Serial number string exceeds limit of 16 chars, aborting.\n");
|
||||
exit(EINVAL);
|
||||
}
|
||||
if ((strlen(ee->libftdi.manufacturer) + strlen(ee->libftdi.product) + strlen(ee->libftdi.serial)) > 46) {
|
||||
fprintf(stderr, "Total string sizes exceed limit of 46 chars, aborting.\n");
|
||||
exit(EINVAL);
|
||||
}
|
||||
offset = encode_string(eeprom, 0x0e, offset, ee->libftdi.manufacturer);
|
||||
offset = encode_string(eeprom, 0x10, offset, ee->libftdi.product);
|
||||
offset = encode_string(eeprom, 0x12, offset, ee->libftdi.serial);
|
||||
eeprom[0x02] = ee->libftdi.vendor_id;
|
||||
eeprom[0x03] = ee->libftdi.vendor_id >> 8;
|
||||
eeprom[0x04] = ee->libftdi.product_id;
|
||||
eeprom[0x05] = ee->libftdi.product_id >> 8;
|
||||
eeprom[0x07] = ee->BM_type_chip;
|
||||
eeprom[0x08] = 0x80;
|
||||
if (ee->libftdi.remote_wakeup)
|
||||
eeprom[0x08] |= 0x20;
|
||||
if (ee->libftdi.self_powered)
|
||||
eeprom[0x08] |= 0x40;
|
||||
eeprom[0x09] = ee->libftdi.max_power;
|
||||
if (ee->libftdi.in_is_isochronous)
|
||||
eeprom[0x0a] |= 0x01;
|
||||
if (ee->libftdi.out_is_isochronous)
|
||||
eeprom[0x0a] |= 0x02;
|
||||
if (ee->libftdi.suspend_pull_downs)
|
||||
eeprom[0x0a] |= 0x04;
|
||||
if (ee->libftdi.use_serial)
|
||||
eeprom[0x0a] |= 0x08;
|
||||
if (ee->libftdi.change_usb_version)
|
||||
eeprom[0x0a] |= 0x10;
|
||||
eeprom[0x0c] = ee->libftdi.usb_version;
|
||||
eeprom[0x0d] = ee->libftdi.usb_version >> 8;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are some undefined "extra features" bytes after the strings.
|
||||
* So blindly preserve them from the original eeprom image.
|
||||
*/
|
||||
static void ee_encode_extras (unsigned char *eeprom, int len, struct eeprom_fields *ee)
|
||||
{
|
||||
unsigned int extras_offset = calc_extras_offset(eeprom);
|
||||
|
||||
memcpy(eeprom + extras_offset, ee->extras, len - extras_offset - 2);
|
||||
if (ee->pnp_enabled)
|
||||
eeprom[extras_offset + 2] |= 1;
|
||||
else
|
||||
eeprom[extras_offset + 2] &= ~1;
|
||||
}
|
||||
|
||||
static unsigned short ee_encode (unsigned char *eeprom, int len, struct eeprom_fields *ee)
|
||||
{
|
||||
int ret;
|
||||
|
||||
memset(eeprom, 0, len);
|
||||
ee->libftdi.size = len;
|
||||
|
||||
if (ee->new_vid)
|
||||
ee->libftdi.vendor_id = ee->new_vid;
|
||||
if (ee->new_pid)
|
||||
ee->libftdi.product_id = ee->new_pid;
|
||||
|
||||
/* Unfortunately, ftdi_eeprom_build() is buggy and puts things in the wrong places */
|
||||
if (0) {
|
||||
ret = ftdi_eeprom_build(&ee->libftdi, eeprom);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ftdi_eeprom_build() failed, ret=%d\n", ret);
|
||||
exit(EINVAL);
|
||||
}
|
||||
printf("ftdi_eeprom_build() ret=%d\n", ret);
|
||||
} else {
|
||||
ft232r_eprom_build(ee, eeprom);
|
||||
}
|
||||
eeprom[1] = ee->byte01;
|
||||
if (ee->high_current_io)
|
||||
eeprom[0x00] |= 0x04;
|
||||
if (ee->load_d2xx_driver)
|
||||
eeprom[0x00] |= 0x08;
|
||||
if (ee->txd_inverted)
|
||||
eeprom[0x0b] |= 0x01;
|
||||
if (ee->rxd_inverted)
|
||||
eeprom[0x0b] |= 0x02;
|
||||
if (ee->rts_inverted)
|
||||
eeprom[0x0b] |= 0x04;
|
||||
if (ee->cts_inverted)
|
||||
eeprom[0x0b] |= 0x08;
|
||||
if (ee->dtr_inverted)
|
||||
eeprom[0x0b] |= 0x10;
|
||||
if (ee->dsr_inverted)
|
||||
eeprom[0x0b] |= 0x20;
|
||||
if (ee->dcd_inverted)
|
||||
eeprom[0x0b] |= 0x40;
|
||||
if (ee->ri_inverted)
|
||||
eeprom[0x0b] |= 0x80;
|
||||
eeprom[0x14] = (ee->cbus[1] << 4) | ee->cbus[0];
|
||||
eeprom[0x15] = (ee->cbus[3] << 4) | ee->cbus[2];
|
||||
eeprom[0x16] = ee->cbus[4];
|
||||
ee_encode_extras(eeprom, len, ee);
|
||||
return update_crc(eeprom, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* There are some undefined "extra features" bytes after the strings.
|
||||
* So blindly preserve them from the original eeprom image.
|
||||
*/
|
||||
static void ee_decode_extras (unsigned char *eeprom, int len, struct eeprom_fields *ee)
|
||||
{
|
||||
unsigned int extras_offset = calc_extras_offset(eeprom);
|
||||
|
||||
memcpy(ee->extras, eeprom + extras_offset, len - extras_offset - 2);
|
||||
ee->pnp_enabled = eeprom[extras_offset + 2] & 0x01;
|
||||
}
|
||||
|
||||
static void ee_decode (unsigned char *eeprom, int len, struct eeprom_fields *ee)
|
||||
{
|
||||
memset(ee, 0, sizeof(*ee));
|
||||
if (eeprom[0] & 0x04)
|
||||
ee->high_current_io = 1;
|
||||
if (eeprom[0x00] & 0x08)
|
||||
ee->load_d2xx_driver = 1;
|
||||
ee->byte01 = eeprom[0x01];
|
||||
if (eeprom[0x0b] & 0x01)
|
||||
ee->txd_inverted = 1;
|
||||
if (eeprom[0x0b] & 0x02)
|
||||
ee->rxd_inverted = 1;
|
||||
if (eeprom[0x0b] & 0x04)
|
||||
ee->rts_inverted = 1;
|
||||
if (eeprom[0x0b] & 0x08)
|
||||
ee->cts_inverted = 1;
|
||||
if (eeprom[0x0b] & 0x10)
|
||||
ee->dtr_inverted = 1;
|
||||
if (eeprom[0x0b] & 0x20)
|
||||
ee->dsr_inverted = 1;
|
||||
if (eeprom[0x0b] & 0x40)
|
||||
ee->dcd_inverted = 1;
|
||||
if (eeprom[0x0b] & 0x80)
|
||||
ee->ri_inverted = 1;
|
||||
ee->cbus[0] = eeprom[0x14] & 0xf;
|
||||
ee->cbus[1] = eeprom[0x14] >> 4;
|
||||
ee->cbus[2] = eeprom[0x15] & 0xf;
|
||||
ee->cbus[3] = eeprom[0x15] >> 4;
|
||||
ee->cbus[4] = eeprom[0x16] & 0xf;
|
||||
ee_decode_extras(eeprom, len, ee);
|
||||
|
||||
/* Use libftdi to decode the remaining fields, which it knows about */
|
||||
if (ftdi_eeprom_decode(&ee->libftdi, eeprom, len)) {
|
||||
fprintf(stderr, "ftdi_eeprom_decode() failed\n");
|
||||
exit(EINVAL);
|
||||
}
|
||||
ee->BM_type_chip = eeprom[0x07]; /* buggy ftdi_eeprom_decode() */
|
||||
if (eeprom[0x0a] & 0x10) /* more buggy ftdi_eeprom_decode() */
|
||||
ee->libftdi.change_usb_version = 1;
|
||||
else
|
||||
ee->libftdi.change_usb_version = 0;
|
||||
ee->libftdi.usb_version = (eeprom[0x0d] << 8) | eeprom[0x0c];;
|
||||
}
|
||||
|
||||
static const char *myname;
|
||||
|
||||
static void show_help (FILE *fp)
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf(fp, "\nUsage: %s [<arg> <val>]..\n", myname);
|
||||
fprintf(fp, "\nwhere <arg> must be any of:\n");
|
||||
|
||||
for (i = 0; arg_type_strings[i]; ++i) {
|
||||
const char *val = arg_type_help[i];
|
||||
fprintf(fp, " %s", arg_type_strings[i]);
|
||||
if (val) {
|
||||
if (*val) {
|
||||
fprintf(fp, " %s", val);
|
||||
} else { /* cbus args */
|
||||
int j;
|
||||
fprintf(fp, " [");
|
||||
for (j = 0; cbus_mode_strings[j];) {
|
||||
fprintf(fp, "%s", cbus_mode_strings[j]);
|
||||
if (cbus_mode_strings[++j])
|
||||
fprintf(fp, "|");
|
||||
}
|
||||
fprintf(fp, "]");
|
||||
}
|
||||
}
|
||||
fputc('\n', fp);
|
||||
}
|
||||
fputc('\n', fp);
|
||||
}
|
||||
|
||||
static unsigned short ee_read_and_verify (void *eeprom, int len)
|
||||
{
|
||||
if (ftdi_read_eeprom(&ftdi, eeprom)) {
|
||||
fprintf(stderr, "ftdi_read_eeprom() failed: %s\n", ftdi_get_error_string(&ftdi));
|
||||
exit(EIO);
|
||||
}
|
||||
return verify_crc(eeprom, len);
|
||||
}
|
||||
|
||||
static void process_args (int argc, char *argv[], struct eeprom_fields *ee)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc;) {
|
||||
int arg;
|
||||
arg = match_arg(argv[i++], arg_type_strings);
|
||||
switch (arg) {
|
||||
case arg_help:
|
||||
show_help(stdout);
|
||||
exit(1);
|
||||
case arg_dump:
|
||||
continue;
|
||||
case arg_verbose:
|
||||
verbose = 1;
|
||||
continue;
|
||||
case arg_invert_txd:
|
||||
ee->txd_inverted = !ee->txd_inverted;
|
||||
continue;
|
||||
case arg_invert_rxd:
|
||||
ee->rxd_inverted = !ee->rxd_inverted;
|
||||
continue;
|
||||
case arg_invert_rts:
|
||||
ee->rts_inverted = !ee->rts_inverted;
|
||||
continue;
|
||||
case arg_invert_cts:
|
||||
ee->cts_inverted = !ee->cts_inverted;
|
||||
continue;
|
||||
case arg_invert_dtr:
|
||||
ee->dtr_inverted = !ee->dtr_inverted;
|
||||
continue;
|
||||
case arg_invert_dsr:
|
||||
ee->dsr_inverted = !ee->dsr_inverted;
|
||||
continue;
|
||||
case arg_invert_dcd:
|
||||
ee->dcd_inverted = !ee->dcd_inverted;
|
||||
continue;
|
||||
case arg_invert_ri:
|
||||
ee->ri_inverted = !ee->ri_inverted;
|
||||
continue;
|
||||
}
|
||||
if (i == argc) {
|
||||
fprintf(stderr, "%s: missing %s value\n", argv[i-2], argv[i-1]);
|
||||
exit(EINVAL);
|
||||
}
|
||||
switch (arg) {
|
||||
case arg_save:
|
||||
save_path = argv[i++];
|
||||
break;
|
||||
case arg_restore:
|
||||
restore_path = argv[i++];
|
||||
break;
|
||||
case arg_cbus0:
|
||||
case arg_cbus1:
|
||||
case arg_cbus2:
|
||||
case arg_cbus3:
|
||||
case arg_cbus4:
|
||||
ee->cbus[arg - arg_cbus0] = match_arg(argv[i++], cbus_mode_strings);
|
||||
break;
|
||||
case arg_manufacturer:
|
||||
ee->libftdi.manufacturer = argv[i++];
|
||||
break;
|
||||
case arg_product:
|
||||
ee->libftdi.product = argv[i++];
|
||||
break;
|
||||
case arg_new_serno:
|
||||
ee->libftdi.serial = argv[i++];
|
||||
break;
|
||||
case arg_high_current_io:
|
||||
ee->high_current_io = match_arg(argv[i++], bool_strings) & 1;
|
||||
break;
|
||||
case arg_self_powered:
|
||||
ee->libftdi.self_powered = match_arg(argv[i++], bool_strings) & 1;
|
||||
break;
|
||||
case arg_max_bus_power:
|
||||
ee->libftdi.max_power = unsigned_val(argv[i++], 0x1ff) / 2;
|
||||
break;
|
||||
case arg_suspend_pull_down:
|
||||
ee->libftdi.suspend_pull_downs = unsigned_val(argv[i++], 0xff);
|
||||
break;
|
||||
case arg_old_vid:
|
||||
ee->old_vid = unsigned_val(argv[i++], 0xffff);
|
||||
break;
|
||||
case arg_old_pid:
|
||||
ee->old_pid = unsigned_val(argv[i++], 0xffff);
|
||||
break;
|
||||
case arg_old_serno:
|
||||
ee->old_serno = argv[i++];
|
||||
break;
|
||||
case arg_new_vid:
|
||||
ee->new_vid = unsigned_val(argv[i++], 0xffff);
|
||||
break;
|
||||
case arg_new_pid:
|
||||
ee->new_pid = unsigned_val(argv[i++], 0xffff);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "bad args\n");
|
||||
exit(EINVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void save_eeprom_to_file (const char *path, void *eeprom, int len)
|
||||
{
|
||||
int count, fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0644);
|
||||
|
||||
if (fd == -1) {
|
||||
int err = errno;
|
||||
perror(path);
|
||||
exit(err);
|
||||
}
|
||||
count = write(fd, eeprom, len);
|
||||
if (count < 0) {
|
||||
int err = errno;
|
||||
perror(path);
|
||||
exit(err);
|
||||
}
|
||||
close(fd);
|
||||
if (count != len) {
|
||||
fprintf(stderr, "%s: wrong size, wrote %d/%d bytes\n", path, count, len);
|
||||
exit(EINVAL);
|
||||
}
|
||||
printf("%s: wrote %d bytes\n", path, count);
|
||||
}
|
||||
|
||||
static void restore_eeprom_from_file (const char *path, void *eeprom, int len, int max)
|
||||
{
|
||||
int count, fd = open(path, O_RDONLY);
|
||||
|
||||
if (fd == -1) {
|
||||
int err = errno;
|
||||
perror(path);
|
||||
exit(err);
|
||||
}
|
||||
count = read(fd, eeprom, max);
|
||||
if (count < 0) {
|
||||
int err = errno;
|
||||
perror(path);
|
||||
exit(err);
|
||||
}
|
||||
close(fd);
|
||||
if (count != len ) {
|
||||
fprintf(stderr, "%s: wrong size, read %d/%d bytes\n", path, count, len);
|
||||
exit(EINVAL);
|
||||
}
|
||||
printf("%s: read %d bytes\n", path, count);
|
||||
verify_crc(eeprom, len);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
const char *slash;
|
||||
unsigned char old[256] = {0,}, new[256] = {0,};
|
||||
unsigned short new_crc;
|
||||
struct eeprom_fields ee;
|
||||
unsigned int len = 128;
|
||||
|
||||
myname = argv[0];
|
||||
slash = strrchr(myname, '/');
|
||||
if (slash)
|
||||
myname = slash + 1;
|
||||
|
||||
printf("\n%s: version %s, by Mark Lord.\n", myname, MYVERSION);
|
||||
if (argc < 2) {
|
||||
show_help(stdout);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ftdi_init(&ftdi);
|
||||
atexit(&do_deinit);
|
||||
|
||||
memset(&ee, 0, sizeof(ee));
|
||||
ee.old_vid = 0x0403;; /* default; override with --old_vid arg */
|
||||
ee.old_pid = 0x6001; /* default; override with --old_pid arg */
|
||||
process_args(argc, argv, &ee); /* handle --help and --old-* args */
|
||||
|
||||
if (ftdi_usb_open_desc(&ftdi, ee.old_vid, ee.old_pid, NULL, ee.old_serno)) {
|
||||
fprintf(stderr, "ftdi_usb_open() failed for %04x:%04x:%s %s\n",
|
||||
ee.old_vid, ee.old_pid, ee.old_serno ? ee.old_serno : "", ftdi_get_error_string(&ftdi));
|
||||
exit(ENODEV);
|
||||
}
|
||||
atexit(&do_close);
|
||||
|
||||
/* First, read the original eeprom from the device */
|
||||
(void) ee_read_and_verify(old, len);
|
||||
if (verbose) dumpmem("existing eeprom", old, len);
|
||||
|
||||
/* Save old contents to a file, if requested (--save) */
|
||||
if (save_path)
|
||||
save_eeprom_to_file(save_path, old, len);
|
||||
|
||||
/* Restore contents from a file, if requested (--restore) */
|
||||
if (restore_path) {
|
||||
restore_eeprom_from_file(restore_path, new, len, sizeof(new));
|
||||
if (verbose) dumpmem(restore_path, new, len);
|
||||
/* Decode file contents into ee struct */
|
||||
ee_decode(new, len, &ee);
|
||||
} else {
|
||||
/* Decode eeprom contents into ee struct */
|
||||
ee_decode(old, len, &ee);
|
||||
|
||||
/* Reencode without any changes, to ensure we can reconstruct the original eeprom from ee */
|
||||
new_crc = ee_encode(new, len, &ee);
|
||||
if (memcmp(old, new, len)) {
|
||||
if (verbose) dumpmem("reconstructed eeprom", new, len);
|
||||
fprintf(stderr, "eeprom reconstruction self-test failed, aborting.\n");
|
||||
exit(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
/* process args, and dump new settings */
|
||||
process_args(argc, argv, &ee); /* Handle value-change args */
|
||||
ee_dump(&ee);
|
||||
|
||||
/* Build new eeprom image */
|
||||
new_crc = ee_encode(new, len, &ee);
|
||||
|
||||
/* If different from original, then write it back to the device */
|
||||
if (0 == memcmp(old, new, len)) {
|
||||
printf("No change from existing eeprom contents.\n");
|
||||
} else {
|
||||
if (verbose) dumpmem("new eeprom", new, len);
|
||||
printf("Rewriting eeprom with new contents.\n");
|
||||
if (ftdi_write_eeprom(&ftdi, new)) {
|
||||
fprintf(stderr, "ftdi_write_eeprom() failed: %s\n", ftdi_get_error_string(&ftdi));
|
||||
exit(EIO);
|
||||
}
|
||||
/* Read it back again, and check for differences */
|
||||
if (ee_read_and_verify(new, len) != new_crc) {
|
||||
fprintf(stderr, "Readback test failed, results may be botched\n");
|
||||
exit(EINVAL);
|
||||
}
|
||||
ftdi_usb_reset(&ftdi); /* reset the device to force it to load the new settings */
|
||||
}
|
||||
return 0;
|
||||
}
|
Binary file not shown.
16
Modem/afsk.c
16
Modem/afsk.c
|
@ -13,6 +13,10 @@
|
|||
#include <struct/fifobuf.h> // FIFO buffer implementation from BertOS
|
||||
#include <string.h> // String operations, primarily used for memset function
|
||||
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_KISS
|
||||
extern unsigned long kiss_preamble;
|
||||
extern unsigned long kiss_tail;
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Definitions and some useful macros //
|
||||
|
@ -449,14 +453,22 @@ static void afsk_txStart(Afsk *afsk) {
|
|||
LED_TX_ON();
|
||||
// We also need to calculate how many HDLC_FLAG
|
||||
// bytes we need to send in preamble
|
||||
afsk->preambleLength = DIV_ROUND(CONFIG_AFSK_PREAMBLE_LEN * BITRATE, 8000);
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_KISS
|
||||
afsk->preambleLength = DIV_ROUND(kiss_preamble * BITRATE, 8000);
|
||||
#else
|
||||
afsk->preambleLength = DIV_ROUND(CONFIG_AFSK_PREAMBLE_LEN * BITRATE, 8000);
|
||||
#endif
|
||||
AFSK_DAC_IRQ_START();
|
||||
}
|
||||
// We make the same calculation for the tail length,
|
||||
// but this needs to be atomic, since the txStart
|
||||
// function could potentially be called while we
|
||||
// are already transmitting.
|
||||
ATOMIC(afsk->tailLength = DIV_ROUND(CONFIG_AFSK_TRAILER_LEN * BITRATE, 8000));
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_KISS
|
||||
ATOMIC(afsk->tailLength = DIV_ROUND(kiss_tail * BITRATE, 8000));
|
||||
#else
|
||||
ATOMIC(afsk->tailLength = DIV_ROUND(CONFIG_AFSK_TRAILER_LEN * BITRATE, 8000));
|
||||
#endif
|
||||
}
|
||||
|
||||
// This is the DAC ISR, called at sampling rate whenever the DAC IRQ is on.
|
||||
|
|
|
@ -2,9 +2,16 @@
|
|||
#ifndef FSK_CFG
|
||||
#define FSK_CFG
|
||||
|
||||
// Serial options
|
||||
#define PROTOCOL_SIMPLE_SERIAL 0x01
|
||||
#define PROTOCOL_KISS 0x02
|
||||
|
||||
#define SERIAL_PROTOCOL PROTOCOL_SIMPLE_SERIAL
|
||||
//#define SERIAL_PROTOCOL PROTOCOL_KISS
|
||||
|
||||
// Debug & test options
|
||||
#define SERIAL_DEBUG false
|
||||
#define PASSALL false
|
||||
#define PASSALL true
|
||||
#define AUTOREPLY false
|
||||
|
||||
// Modem options
|
||||
|
|
193
Modem/main.c
193
Modem/main.c
|
@ -25,8 +25,6 @@
|
|||
#include "cfg/debug.h" // Debug configuration from BertOS
|
||||
#endif
|
||||
|
||||
#define SERIAL_PROTOCOL PROTOCOL_SIMPLE_SERIAL
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// A few definitions //
|
||||
//////////////////////////////////////////////////////
|
||||
|
@ -38,17 +36,21 @@ static Serial ser; // Declare a serial interface struct
|
|||
#define ADC_CH 0 // Define which channel (pin) we want
|
||||
// for the ADC (this is A0 on arduino)
|
||||
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_SIMPLE_SERIAL
|
||||
static uint8_t serialBuffer[CONFIG_AX25_FRAME_BUF_LEN+1]; // Buffer for holding incoming serial data
|
||||
static int sbyte; // For holding byte read from serial port
|
||||
static size_t serialLen = 0; // Counter for counting length of data from serial
|
||||
static bool sertx = false; // Flag signifying whether it's time to send data
|
||||
// received on the serial port.
|
||||
#endif
|
||||
|
||||
static uint8_t serialBuffer[CONFIG_AX25_FRAME_BUF_LEN+1]; // Buffer for holding incoming serial data
|
||||
static int sbyte; // For holding byte read from serial port
|
||||
static size_t serialLen = 0; // Counter for counting length of data from serial
|
||||
static bool sertx = false; // Flag signifying whether it's time to send data
|
||||
// received on the serial port.
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_KISS
|
||||
static uint8_t sbyte; // For holding byte read from serial port
|
||||
#endif
|
||||
|
||||
#define SER_BUFFER_FULL (serialLen < CONFIG_AX25_FRAME_BUF_LEN-1)
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// And here comes the actual program :) //
|
||||
//////////////////////////////////////////////////////
|
||||
|
@ -56,15 +58,19 @@ static bool sertx = false; // Flag signifying whether it's
|
|||
// This is a callback we register with the protocol,
|
||||
// so we can process each packet as they are decoded.
|
||||
// Right now it just prints the packet to the serial port.
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_SIMPLE_SERIAL
|
||||
static void message_callback(struct AX25Msg *msg)
|
||||
{
|
||||
if (SERIAL_PROTOCOL == PROTOCOL_SIMPLE_SERIAL) {
|
||||
ss_messageCallback(msg, &ser);
|
||||
}
|
||||
if (SERIAL_PROTOCOL == PROTOCOL_KISS) {
|
||||
// Not implemented yet
|
||||
}
|
||||
ss_messageCallback(msg, &ser);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_KISS
|
||||
static void message_callback(struct AX25Ctx *ctx)
|
||||
{
|
||||
kiss_messageCallback(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Simple initialization function.
|
||||
static void init(void)
|
||||
|
@ -90,8 +96,15 @@ static void init(void)
|
|||
// ... and a protocol context with the modem
|
||||
ax25_init(&ax25, &afsk.fd, message_callback);
|
||||
|
||||
// Init SimpleSerial
|
||||
ss_init(&ax25);
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_SIMPLE_SERIAL
|
||||
// Init SimpleSerial
|
||||
ss_init(&ax25);
|
||||
#endif
|
||||
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_KISS
|
||||
// Init KISS
|
||||
kiss_init(&ax25, &ser);
|
||||
#endif
|
||||
|
||||
// That's all!
|
||||
}
|
||||
|
@ -100,77 +113,93 @@ int main(void)
|
|||
{
|
||||
// Start by running the main initialization
|
||||
init();
|
||||
// Record the current tick count for time-keeping
|
||||
ticks_t start = timer_clock();
|
||||
|
||||
// Go into ye good ol' infinite loop
|
||||
while (1)
|
||||
{
|
||||
// First we instruct the protocol to check for
|
||||
// incoming data
|
||||
ax25_poll(&ax25);
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_KISS
|
||||
while (1) {
|
||||
// First we instruct the protocol to check for
|
||||
// incoming data
|
||||
ax25_poll(&ax25);
|
||||
|
||||
// Poll for incoming serial data
|
||||
if (!sertx && ser_available(&ser)) {
|
||||
// We then read a byte from the serial port.
|
||||
// Notice that we use "_nowait" since we can't
|
||||
// have this blocking execution until a byte
|
||||
// comes in.
|
||||
sbyte = ser_getchar_nowait(&ser);
|
||||
|
||||
// If SERIAL_DEBUG is specified we'll handle
|
||||
// serial data as direct human input and only
|
||||
// transmit when we get a LF character
|
||||
#if SERIAL_DEBUG
|
||||
// If we have not yet surpassed the maximum frame length
|
||||
// and the byte is not a "transmit" (newline) character,
|
||||
// we should store it for transmission.
|
||||
if ((serialLen < CONFIG_AX25_FRAME_BUF_LEN) && (sbyte != 10)) {
|
||||
// Put the read byte into the buffer;
|
||||
serialBuffer[serialLen] = sbyte;
|
||||
// Increment the read length counter
|
||||
serialLen++;
|
||||
} else {
|
||||
// If one of the above conditions were actually the
|
||||
// case, it means we have to transmit, se we set
|
||||
// transmission flag to true.
|
||||
sertx = true;
|
||||
}
|
||||
#else
|
||||
// Otherwise we assume the modem is running
|
||||
// in automated mode, and we push out data
|
||||
// as it becomes available. We either transmit
|
||||
// immediately when the max frame length has
|
||||
// been reached, or when we get no input for
|
||||
// a certain amount of time.
|
||||
|
||||
if (serialLen < CONFIG_AX25_FRAME_BUF_LEN-1) {
|
||||
// Put the read byte into the buffer;
|
||||
serialBuffer[serialLen] = sbyte;
|
||||
// Increment the read length counter
|
||||
serialLen++;
|
||||
} else {
|
||||
// If max frame length has been reached
|
||||
// we need to transmit.
|
||||
serialBuffer[serialLen] = sbyte;
|
||||
serialLen++;
|
||||
sertx = true;
|
||||
}
|
||||
|
||||
start = timer_clock();
|
||||
#endif
|
||||
} else {
|
||||
if (!SERIAL_DEBUG && serialLen > 0 && timer_clock() - start > ms_to_ticks(TX_MAXWAIT)) {
|
||||
sertx = true;
|
||||
if (ser_available(&ser)) {
|
||||
sbyte = ser_getchar_nowait(&ser);
|
||||
kiss_serialCallback(sbyte);
|
||||
}
|
||||
}
|
||||
|
||||
if (sertx) {
|
||||
ss_serialCallback(serialBuffer, serialLen, &ser, &ax25);
|
||||
sertx = false;
|
||||
serialLen = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_SIMPLE_SERIAL
|
||||
// Record the current tick count for time-keeping
|
||||
ticks_t start = timer_clock();
|
||||
// Go into ye good ol' infinite loop
|
||||
while (1) {
|
||||
// First we instruct the protocol to check for
|
||||
// incoming data
|
||||
ax25_poll(&ax25);
|
||||
|
||||
// Poll for incoming serial data
|
||||
if (!sertx && ser_available(&ser)) {
|
||||
// We then read a byte from the serial port.
|
||||
// Notice that we use "_nowait" since we can't
|
||||
// have this blocking execution until a byte
|
||||
// comes in.
|
||||
sbyte = ser_getchar_nowait(&ser);
|
||||
|
||||
// If SERIAL_DEBUG is specified we'll handle
|
||||
// serial data as direct human input and only
|
||||
// transmit when we get a LF character
|
||||
#if SERIAL_DEBUG
|
||||
// If we have not yet surpassed the maximum frame length
|
||||
// and the byte is not a "transmit" (newline) character,
|
||||
// we should store it for transmission.
|
||||
if ((serialLen < CONFIG_AX25_FRAME_BUF_LEN) && (sbyte != 10)) {
|
||||
// Put the read byte into the buffer;
|
||||
serialBuffer[serialLen] = sbyte;
|
||||
// Increment the read length counter
|
||||
serialLen++;
|
||||
} else {
|
||||
// If one of the above conditions were actually the
|
||||
// case, it means we have to transmit, se we set
|
||||
// transmission flag to true.
|
||||
sertx = true;
|
||||
}
|
||||
#else
|
||||
// Otherwise we assume the modem is running
|
||||
// in automated mode, and we push out data
|
||||
// as it becomes available. We either transmit
|
||||
// immediately when the max frame length has
|
||||
// been reached, or when we get no input for
|
||||
// a certain amount of time.
|
||||
|
||||
if (serialLen < CONFIG_AX25_FRAME_BUF_LEN-1) {
|
||||
// Put the read byte into the buffer;
|
||||
serialBuffer[serialLen] = sbyte;
|
||||
// Increment the read length counter
|
||||
serialLen++;
|
||||
} else {
|
||||
// If max frame length has been reached
|
||||
// we need to transmit.
|
||||
serialBuffer[serialLen] = sbyte;
|
||||
serialLen++;
|
||||
sertx = true;
|
||||
}
|
||||
|
||||
start = timer_clock();
|
||||
#endif
|
||||
} else {
|
||||
if (!SERIAL_DEBUG && serialLen > 0 && timer_clock() - start > ms_to_ticks(TX_MAXWAIT)) {
|
||||
sertx = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (sertx) {
|
||||
ss_serialCallback(serialBuffer, serialLen, &ser, &ax25);
|
||||
sertx = false;
|
||||
serialLen = 0;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <avr/eeprom.h>
|
||||
#define F_CPU 16000000UL
|
||||
#include <util/delay.h>
|
||||
#include <drv/timer.h> // Timer driver from BertOS
|
||||
#include "KISS.h"
|
||||
|
||||
static uint8_t serialBuffer[CONFIG_AX25_FRAME_BUF_LEN+1]; // Buffer for holding incoming serial data
|
||||
AX25Ctx *ax25ctx;
|
||||
Serial *serial;
|
||||
size_t frame_len;
|
||||
bool IN_FRAME;
|
||||
bool ESCAPE;
|
||||
uint8_t command = CMD_UNKNOWN;
|
||||
unsigned long kiss_preamble = CONFIG_AFSK_PREAMBLE_LEN;
|
||||
unsigned long kiss_tail = CONFIG_AFSK_TRAILER_LEN;
|
||||
|
||||
void kiss_init(AX25Ctx *ax25, Serial *ser) {
|
||||
ax25ctx = ax25;
|
||||
serial = ser;
|
||||
}
|
||||
|
||||
void kiss_messageCallback(AX25Ctx *ctx) {
|
||||
kfile_putc(FEND, &serial->fd);
|
||||
kfile_putc(0x00, &serial->fd);
|
||||
for (unsigned i = 0; i < ctx->frm_len; i++) {
|
||||
uint8_t b = ctx->buf[i];
|
||||
if (b == FEND) {
|
||||
kfile_putc(FESC, &serial->fd);
|
||||
kfile_putc(TFEND, &serial->fd);
|
||||
} else if (b == FESC) {
|
||||
kfile_putc(FESC, &serial->fd);
|
||||
kfile_putc(TFESC, &serial->fd);
|
||||
} else {
|
||||
kfile_putc(b, &serial->fd);
|
||||
}
|
||||
}
|
||||
kfile_putc(FEND, &serial->fd);
|
||||
}
|
||||
|
||||
void fon(void) {
|
||||
long ts = 300000;
|
||||
while (ts--) PORTB |= BV(2);
|
||||
}
|
||||
|
||||
|
||||
void kiss_serialCallback(uint8_t sbyte) {
|
||||
if (IN_FRAME && sbyte == FEND && command == CMD_DATA) {
|
||||
IN_FRAME = false;
|
||||
ax25_sendRaw(ax25ctx, serialBuffer, frame_len);
|
||||
} else if (sbyte == FEND) {
|
||||
IN_FRAME = true;
|
||||
command = CMD_UNKNOWN;
|
||||
frame_len = 0;
|
||||
} else if (IN_FRAME && frame_len < CONFIG_AX25_FRAME_BUF_LEN) {
|
||||
// Have a look at the command byte first
|
||||
if (frame_len == 0 && command == CMD_UNKNOWN) {
|
||||
// MicroModem supports only one HDLC port, so we
|
||||
// strip off the port nibble of the command byte
|
||||
sbyte = sbyte & 0x0F;
|
||||
command = sbyte;
|
||||
} else if (command == CMD_DATA) {
|
||||
if (sbyte == FESC) {
|
||||
ESCAPE = true;
|
||||
} else {
|
||||
if (ESCAPE) {
|
||||
if (sbyte == TFEND) sbyte = FEND;
|
||||
if (sbyte == TFESC) sbyte = FESC;
|
||||
ESCAPE = false;
|
||||
}
|
||||
serialBuffer[frame_len++] = sbyte;
|
||||
}
|
||||
} else if (command == CMD_TXDELAY) {
|
||||
kiss_preamble = sbyte * 10UL;
|
||||
} else if (command == CMD_TXTAIL) {
|
||||
kiss_tail = sbyte * 10;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,10 +1,27 @@
|
|||
#ifndef PROTOCOL_KISS
|
||||
#define PROTOCOL_KISS 0x02
|
||||
#ifndef _PROTOCOL_KISS
|
||||
#define _PROTOCOL_KISS 0x02
|
||||
|
||||
#define FEND 0xC0
|
||||
#define FESC 0xDB
|
||||
#define TFEND 0xDC
|
||||
#define TFESC 0xDD
|
||||
|
||||
#define CMD_UNKNOWN 0xFE
|
||||
#define CMD_DATA 0x00
|
||||
#define CMD_TXDELAY 0x01
|
||||
#define CMD_P 0x02
|
||||
#define CMD_SLOTTIME 0x03
|
||||
#define CMD_TXTAIL 0x04
|
||||
#define CMD_FULLDUPLEX 0x05
|
||||
#define CMD_SETHARDWARE 0x06
|
||||
#define CMD_RETURN 0xFF
|
||||
|
||||
#include <net/ax25.h>
|
||||
#include <drv/ser.h>
|
||||
|
||||
void kiss_init(AX25Ctx *ax25, Serial *ser);
|
||||
|
||||
void kiss_messageCallback(AX25Ctx *ctx);
|
||||
void kiss_serialCallback(uint8_t sbyte);
|
||||
void fon(void);
|
||||
#endif
|
|
@ -1,9 +1,8 @@
|
|||
#ifndef PROTOCOL_SIMPLE_SERIAL
|
||||
#ifndef _PROTOCOL_SIMPLE_SERIAL
|
||||
#define _PROTOCOL_SIMPLE_SERIAL 0x01
|
||||
#include <net/ax25.h>
|
||||
#include <drv/ser.h>
|
||||
|
||||
#define PROTOCOL_SIMPLE_SERIAL 0x01
|
||||
|
||||
#define DEFAULT_CALLSIGN "NOCALL"
|
||||
#define DEFAULT_DESTINATION_CALL "APZMDM"
|
||||
|
||||
|
|
|
@ -70,51 +70,56 @@
|
|||
|
||||
static void ax25_decode(AX25Ctx *ctx)
|
||||
{
|
||||
AX25Msg msg;
|
||||
uint8_t *buf = ctx->buf;
|
||||
|
||||
DECODE_CALL(buf, msg.dst.call);
|
||||
msg.dst.ssid = (*buf++ >> 1) & 0x0F;
|
||||
|
||||
DECODE_CALL(buf, msg.src.call);
|
||||
msg.src.ssid = (*buf >> 1) & 0x0F;
|
||||
|
||||
|
||||
/* Repeater addresses */
|
||||
#if CONFIG_AX25_RPT_LST
|
||||
for (msg.rpt_cnt = 0; !(*buf++ & 0x01) && (msg.rpt_cnt < countof(msg.rpt_lst)); msg.rpt_cnt++)
|
||||
{
|
||||
DECODE_CALL(buf, msg.rpt_lst[msg.rpt_cnt].call);
|
||||
msg.rpt_lst[msg.rpt_cnt].ssid = (*buf >> 1) & 0x0F;
|
||||
AX25_SET_REPEATED(&msg, msg.rpt_cnt, (*buf & 0x80));
|
||||
}
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_KISS
|
||||
if (ctx->hook)
|
||||
ctx->hook(ctx);
|
||||
#else
|
||||
while (!(*buf++ & 0x01))
|
||||
AX25Msg msg;
|
||||
uint8_t *buf = ctx->buf;
|
||||
DECODE_CALL(buf, msg.dst.call);
|
||||
msg.dst.ssid = (*buf++ >> 1) & 0x0F;
|
||||
|
||||
DECODE_CALL(buf, msg.src.call);
|
||||
msg.src.ssid = (*buf >> 1) & 0x0F;
|
||||
|
||||
|
||||
/* Repeater addresses */
|
||||
#if CONFIG_AX25_RPT_LST
|
||||
for (msg.rpt_cnt = 0; !(*buf++ & 0x01) && (msg.rpt_cnt < countof(msg.rpt_lst)); msg.rpt_cnt++)
|
||||
{
|
||||
DECODE_CALL(buf, msg.rpt_lst[msg.rpt_cnt].call);
|
||||
msg.rpt_lst[msg.rpt_cnt].ssid = (*buf >> 1) & 0x0F;
|
||||
AX25_SET_REPEATED(&msg, msg.rpt_cnt, (*buf & 0x80));
|
||||
}
|
||||
#else
|
||||
while (!(*buf++ & 0x01))
|
||||
{
|
||||
char rpt[6];
|
||||
uint8_t ssid;
|
||||
DECODE_CALL(buf, rpt);
|
||||
ssid = (*buf >> 1) & 0x0F;
|
||||
}
|
||||
#endif
|
||||
|
||||
msg.ctrl = *buf++;
|
||||
if (msg.ctrl != AX25_CTRL_UI)
|
||||
{
|
||||
char rpt[6];
|
||||
uint8_t ssid;
|
||||
DECODE_CALL(buf, rpt);
|
||||
ssid = (*buf >> 1) & 0x0F;
|
||||
return;
|
||||
}
|
||||
|
||||
msg.pid = *buf++;
|
||||
if (msg.pid != AX25_PID_NOLAYER3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
msg.len = ctx->frm_len - 2 - (buf - ctx->buf);
|
||||
msg.info = buf;
|
||||
|
||||
if (ctx->hook)
|
||||
ctx->hook(&msg);
|
||||
#endif
|
||||
|
||||
msg.ctrl = *buf++;
|
||||
if (msg.ctrl != AX25_CTRL_UI)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
msg.pid = *buf++;
|
||||
if (msg.pid != AX25_PID_NOLAYER3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
msg.len = ctx->frm_len - 2 - (buf - ctx->buf);
|
||||
msg.info = buf;
|
||||
|
||||
if (ctx->hook)
|
||||
ctx->hook(&msg);
|
||||
}
|
||||
|
||||
|
||||
|
@ -258,6 +263,20 @@ void ax25_sendVia(AX25Ctx *ctx, const AX25Call *path, size_t path_len, const voi
|
|||
kfile_putc(HDLC_FLAG, ctx->ch);
|
||||
}
|
||||
|
||||
void ax25_sendRaw(AX25Ctx *ctx, void *_buf, size_t len) {
|
||||
ctx->crc_out = CRC_CCITT_INIT_VAL;
|
||||
kfile_putc(HDLC_FLAG, ctx->ch);
|
||||
const uint8_t *buf = (const uint8_t *)_buf;
|
||||
while (len--) ax25_putchar(ctx, *buf++);
|
||||
|
||||
uint8_t crcl = (ctx->crc_out & 0xff) ^ 0xff;
|
||||
uint8_t crch = (ctx->crc_out >> 8) ^ 0xff;
|
||||
ax25_putchar(ctx, crcl);
|
||||
ax25_putchar(ctx, crch);
|
||||
|
||||
kfile_putc(HDLC_FLAG, ctx->ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init the AX25 protocol decoder.
|
||||
*
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#ifndef NET_AX25_H
|
||||
#define NET_AX25_H
|
||||
|
||||
#include "config.h" // Various configuration values
|
||||
#include "cfg/cfg_ax25.h"
|
||||
|
||||
#include <cfg/compiler.h>
|
||||
|
@ -62,11 +63,18 @@
|
|||
#define AX25_CRC_CORRECT 0xF0B8
|
||||
|
||||
struct AX25Msg; // fwd declaration
|
||||
struct AX25Ctx; // fwd declaration
|
||||
|
||||
/**
|
||||
* Type for AX25 messages callback.
|
||||
*/
|
||||
typedef void (*ax25_callback_t)(struct AX25Msg *msg);
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_SIMPLE_SERIAL
|
||||
typedef void (*ax25_callback_t)(struct AX25Msg *msg);
|
||||
#endif
|
||||
|
||||
#if SERIAL_PROTOCOL == PROTOCOL_KISS
|
||||
typedef void (*ax25_callback_t)(struct AX25Ctx *ctx);
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
|
@ -170,6 +178,7 @@ typedef struct AX25Msg
|
|||
|
||||
void ax25_poll(AX25Ctx *ctx);
|
||||
void ax25_sendVia(AX25Ctx *ctx, const AX25Call *path, size_t path_len, const void *_buf, size_t len);
|
||||
void ax25_sendRaw(AX25Ctx *ctx, void *_buf, size_t len);
|
||||
|
||||
/**
|
||||
* Send an AX25 frame on the channel.
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#define VERS_BUILD 2224
|
||||
#define VERS_BUILD 2341
|
||||
#define VERS_HOST "shard"
|
||||
|
|
BIN
images/Modem.elf
BIN
images/Modem.elf
Binary file not shown.
|
@ -194,7 +194,7 @@
|
|||
:100C100088E98093C10008951092C1000895FC01F5
|
||||
:100C20002285211105C021E0228788EB8093C10035
|
||||
:100C300008959A01AB01CA01B901969587957795F8
|
||||
:100C40006795605C7D4B804F9F4F0E9426352150F9
|
||||
:100C40006795605C7D4B804F9F4F0E9435352150EA
|
||||
:100C500031093093C5002093C4000895E2ECF0E020
|
||||
:100C60008081A4E0660F771FAA95E1F78F7C862B21
|
||||
:100C7000808308959FB7F89484B1886284B99FBF38
|
||||
|
@ -474,7 +474,7 @@
|
|||
:101D90001882C559D0406114710441F4CB56DF4F0D
|
||||
:101DA000F881C559D040FF2309F47CC0CD56DF4FE0
|
||||
:101DB0002881C359D0408E010A571F4F2130A9F006
|
||||
:101DC0002AE030E040E050E00E942635F701E60FBF
|
||||
:101DC0002AE030E040E050E00E943535F701E60FB0
|
||||
:101DD000F71F8081D8018E938D01B901CA01611569
|
||||
:101DE00071058105910561F715C0FB01EF70FF27B3
|
||||
:101DF000EE0DFF1D2081F80122938F0144E096959E
|
||||
|
@ -562,7 +562,7 @@
|
|||
:10231000C801029657FE07C02DE211962C935194E6
|
||||
:102320004194510803C02BE2F80121838C01065F20
|
||||
:102330001F4F20E030E02F5F3F4FF8013196C20180
|
||||
:102340006AE070E00E941235805DD8018C932B0109
|
||||
:102340006AE070E00E942135805DD8018C932B01FA
|
||||
:102350006115710511F08F01EECF22303105DCF3EC
|
||||
:10236000E21BF30B199781918E93215031091216BC
|
||||
:102370001306CCF309501109C256DF4FB881CE596C
|
||||
|
@ -686,8 +686,8 @@
|
|||
:102AD000CF92DF92EF92FF920F931F93CF93DF93EA
|
||||
:102AE000CDB7DEB72C970FB6F894DEBF0FBECDBFC3
|
||||
:102AF0009C878B877B015A01288739871D830C832C
|
||||
:102B00006115710541F446EE50E066EE72E081EE2B
|
||||
:102B100092E00E94B53222E0A216B10440F447EEE2
|
||||
:102B00006115710541F44BEE50E066EE72E081EE26
|
||||
:102B100092E00E94B53222E0A216B10440F44CEEDD
|
||||
:102B200050E06FEC72E081EC92E00E94B5324B8491
|
||||
:102B30005C8480EB481A8EEF580A8FEF9FEFF2010A
|
||||
:102B4000918380836B847C84F6EB6F1AFEEF7F0A9F
|
||||
|
@ -699,7 +699,7 @@
|
|||
:102BA0008E0D9F1D9B838A8317018A819B81281626
|
||||
:102BB000390601F1F10121911F01822E912CC401EE
|
||||
:102BC0002A870E94B1362A85892B51F4203241F0A0
|
||||
:102BD00049EC50E06CE772E085E692E00E94B53285
|
||||
:102BD0004EEC50E06CE772E085E692E00E94B53280
|
||||
:102BE000C4010E94C536682F660F8B859C850E94A4
|
||||
:102BF0007113DBCF0630110599F0812C912CE6E0A2
|
||||
:102C0000F0E0E01BF10B8F018016910648F460E4C0
|
||||
|
@ -712,14 +712,14 @@
|
|||
:102C70009C850E947113F5CFF201608111816095EE
|
||||
:102C80008B859C850E947113612F60958B859C8537
|
||||
:102C90000E947113F20180819181883B904F41F035
|
||||
:102CA00040E051E06FEA72E08EE892E00E94B532B7
|
||||
:102CA00045E051E06FEA72E08EE892E00E94B532B2
|
||||
:102CB000F301608171818EE790E02C960FB6F89455
|
||||
:102CC000DEBF0FBECDBFDF91CF911F910F91FF905F
|
||||
:102CD000EF90DF90CF90BF90AF909F908F907F90BC
|
||||
:102CE0006F905F904F903F902F900C944B0BEF9212
|
||||
:102CF000FF920F931F93CF93DF93EC018B017A0127
|
||||
:102D0000009741F44EE051E063E572E08FE492E019
|
||||
:102D10000E94B5320115110541F44FE051E06DE319
|
||||
:102D0000009741F441E251E063E572E08FE492E024
|
||||
:102D10000E94B5320115110541F442E251E06DE324
|
||||
:102D200072E085E392E00E94B53286E591E0FE0113
|
||||
:102D30009C01119221503040E1F7FE01E65BFE4F0D
|
||||
:102D400011830083FE01EE5AFE4FF182E082FE0104
|
||||
|
@ -1092,9 +1092,9 @@
|
|||
:104430002CF4909318068093170604C01092180667
|
||||
:1044400010921706FE01E00FF11F8BE783870091A2
|
||||
:104450001706109118069AE0892E912CC801B40114
|
||||
:104460000E9412359C0144E6A42EB12CC801B5016E
|
||||
:104470000E941235821B930BB4010E941235AB01CE
|
||||
:10448000C801861B970B821B930BB5010E94123546
|
||||
:104460000E9421359C0144E6A42EB12CC801B5015F
|
||||
:104470000E942135821B930BB4010E942135AB01B0
|
||||
:10448000C801861B970B821B930BB5010E94213537
|
||||
:10449000605D6487405D4587205D2687A601B70182
|
||||
:1044A000CE010E94DE1ECE01DF91CF911F910F91B0
|
||||
:1044B000FF90EF90DF90CF90BF90AF909F908F9044
|
||||
|
@ -1282,7 +1282,7 @@
|
|||
:1050100098E0E4C18836B9F58A8180538A3008F077
|
||||
:105020000BC280932B0190914B01992309F1A1E0D0
|
||||
:10503000B0E002C0AA0FBB1F8A95E2F728EE33E06A
|
||||
:105040000E940B3528E431E040E050E00E944835F2
|
||||
:105040000E941A3528E431E040E050E00E945735D4
|
||||
:105050005F934F933F932F938DE398E09F938F93AC
|
||||
:105060000E9433320F900F900F900F900F900F907F
|
||||
:1050700080914B018111E0C180911F068111DCC13B
|
||||
|
@ -1447,7 +1447,7 @@
|
|||
:105A6000CC56DF4F1882C459D0404114510441F440
|
||||
:105A7000CC56DF4FF881C459D040FF2309F476C0DB
|
||||
:105A8000CE56DF4F2881C259D0408E010A571F4F92
|
||||
:105A90002130A9F02AE030E040E050E00E942635B5
|
||||
:105A90002130A9F02AE030E040E050E00E943535A6
|
||||
:105AA000F701E60FF71F8081D8018E938D01B901B0
|
||||
:105AB000CA01611571058105910561F715C0FB01EA
|
||||
:105AC000EF70FF27EE0DFF1D2081F80122938F015B
|
||||
|
@ -1538,7 +1538,7 @@
|
|||
:10601000FC93C8010296B7FE07C02DE211962C939F
|
||||
:10602000B194A194B10804C02BE2D80111962C932D
|
||||
:106030008C01065F1F4F20E030E02F5F3F4FF801DB
|
||||
:106040003196C5016AE070E00E941235805DD8018A
|
||||
:106040003196C5016AE070E00E942135805DD8017B
|
||||
:106050008C935B016115710511F08F01EECF223039
|
||||
:106060003105DCF3E21BF30B199781918E932150DC
|
||||
:10607000310912161306CCF309501109C256DF4F2D
|
||||
|
@ -1613,10 +1613,10 @@
|
|||
:1064C0001093C100DF91CF911F910895AF92BF92B9
|
||||
:1064D000CF92DF92EF92FF920F931F93CF93DF93B0
|
||||
:1064E0006C0185E0E82EF12C00E117E2C0E0D0E07D
|
||||
:1064F0009AE0A92EB12CC601B8010E9412356C0198
|
||||
:1064F0009AE0A92EB12CC601B8010E9421356C0189
|
||||
:106500006115710529F4209719F40130110529F45A
|
||||
:1065100080E3860F0E941A322196C801B5010E94BD
|
||||
:1065200012358B0181E0E81AF108E114F10419F742
|
||||
:1065200021358B0181E0E81AF108E114F10419F733
|
||||
:10653000CE01DF91CF911F910F91FF90EF90DF90EF
|
||||
:10654000CF90BF90AF900895CF93DF93EB010E945F
|
||||
:1065500041328AE30E941A32CE010E94663288EBF1
|
||||
|
@ -1695,20 +1695,20 @@
|
|||
:1069E00091505040A9F79E3F510570F05CCFA6CF63
|
||||
:1069F0005F3FECF3983EDCF3869577956795B79506
|
||||
:106A0000F795E7959F5FC1F7FE2B880F911D96952F
|
||||
:106A1000879597F908950E946735B7FF0895821BFF
|
||||
:106A2000930B089597FB072E16F4009407D077FD7B
|
||||
:106A300009D00E94763507FC05D03EF490958195EB
|
||||
:106A40009F4F0895709561957F4F0895A1E21A2E8A
|
||||
:106A5000AA1BBB1BFD010DC0AA1FBB1FEE1FFF1F02
|
||||
:106A6000A217B307E407F50720F0A21BB30BE40B52
|
||||
:106A7000F50B661F771F881F991F1A9469F7609599
|
||||
:106A80007095809590959B01AC01BD01CF01089553
|
||||
:106A9000052E97FB1EF400940E945F3557FD07D02A
|
||||
:106AA0000E94263507FC03D04EF40C945F355095B8
|
||||
:106AB0004095309521953F4F4F4F5F4F08959095EA
|
||||
:106AC0008095709561957F4F8F4F9F4F0895A29F3E
|
||||
:106AD000B001B39FC001A39F700D811D1124911DB2
|
||||
:106AE000B29F700D811D1124911D0895AA1BBB1B1F
|
||||
:106A1000879597F90895A29FB001B39FC001A39FE6
|
||||
:106A2000700D811D1124911DB29F700D811D1124C7
|
||||
:106A3000911D08950E940B35B7FF0895821B930B9B
|
||||
:106A4000089597FB072E16F4009407D077FD09D020
|
||||
:106A50000E94763507FC05D03EF4909581959F4FB6
|
||||
:106A60000895709561957F4F0895A1E21A2EAA1B93
|
||||
:106A7000BB1BFD010DC0AA1FBB1FEE1FFF1FA217EE
|
||||
:106A8000B307E407F50720F0A21BB30BE40BF50BEB
|
||||
:106A9000661F771F881F991F1A9469F76095709574
|
||||
:106AA000809590959B01AC01BD01CF010895052E05
|
||||
:106AB00097FB1EF400940E946E3557FD07D00E948C
|
||||
:106AC000353507FC03D04EF40C946E355095409547
|
||||
:106AD000309521953F4F4F4F5F4F0895909580958A
|
||||
:106AE000709561957F4F8F4F9F4F0895AA1BBB1BD9
|
||||
:106AF00051E107C0AA1FBB1FA617B70710F0A61BBE
|
||||
:106B0000B70B881F991F5A95A9F780959095BC01DE
|
||||
:106B1000CD010895CF93DF938230910510F482E088
|
||||
|
|
Loading…
Reference in New Issue