diff --git a/Documentation/FT232R/ft232r_prog-1.24.tar.gz b/Documentation/FT232R/ft232r_prog-1.24.tar.gz new file mode 100644 index 0000000..1f1f0b9 Binary files /dev/null and b/Documentation/FT232R/ft232r_prog-1.24.tar.gz differ diff --git a/Documentation/FT232R/ft232r_prog-1.24/Changelog b/Documentation/FT232R/ft232r_prog-1.24/Changelog new file mode 100644 index 0000000..bdae93b --- /dev/null +++ b/Documentation/FT232R/ft232r_prog-1.24/Changelog @@ -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. diff --git a/Documentation/FT232R/ft232r_prog-1.24/LICENSE.txt b/Documentation/FT232R/ft232r_prog-1.24/LICENSE.txt new file mode 100644 index 0000000..10828e0 --- /dev/null +++ b/Documentation/FT232R/ft232r_prog-1.24/LICENSE.txt @@ -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. + + + Copyright (C) + + 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. + + , 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. diff --git a/Documentation/FT232R/ft232r_prog-1.24/Makefile b/Documentation/FT232R/ft232r_prog-1.24/Makefile new file mode 100644 index 0000000..28080a5 --- /dev/null +++ b/Documentation/FT232R/ft232r_prog-1.24/Makefile @@ -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) diff --git a/Documentation/FT232R/ft232r_prog-1.24/ft232r_prog b/Documentation/FT232R/ft232r_prog-1.24/ft232r_prog new file mode 100755 index 0000000..ee79603 Binary files /dev/null and b/Documentation/FT232R/ft232r_prog-1.24/ft232r_prog differ diff --git a/Documentation/FT232R/ft232r_prog-1.24/ft232r_prog.c b/Documentation/FT232R/ft232r_prog-1.24/ft232r_prog.c new file mode 100644 index 0000000..1d480d9 --- /dev/null +++ b/Documentation/FT232R/ft232r_prog-1.24/ft232r_prog.c @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#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)", + "", + "", + "", + "", + "", + " # (new USB manufacturer string)", + " # (new USB product name string)", + " # (current serial number of device to be reprogrammed)", + " # (new USB serial number string)", + " [on|off] # (self powered)", + " # (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)", + " # (current vendor id of device to be reprogrammed, eg. 0x0403)", + " # (current product id of device to be reprogrammed, eg. 0x6001)", + " # (new/custom vendor id to be programmed)", + " # (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 [ ]..\n", myname); + fprintf(fp, "\nwhere 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; +} diff --git a/Documentation/Usage.odt b/Documentation/Usage.odt new file mode 100644 index 0000000..25db245 Binary files /dev/null and b/Documentation/Usage.odt differ diff --git a/Modem/afsk.c b/Modem/afsk.c index e0da7ca..c709a31 100644 --- a/Modem/afsk.c +++ b/Modem/afsk.c @@ -13,6 +13,10 @@ #include // FIFO buffer implementation from BertOS #include // 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. diff --git a/Modem/config.h b/Modem/config.h index 470a7d8..3d83a1d 100644 --- a/Modem/config.h +++ b/Modem/config.h @@ -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 diff --git a/Modem/main.c b/Modem/main.c index 87d495a..0c19d35 100644 --- a/Modem/main.c +++ b/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,9 +96,16 @@ 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; } \ No newline at end of file diff --git a/Modem/protocol/KISS.c b/Modem/protocol/KISS.c index e69de29..58fbc0c 100644 --- a/Modem/protocol/KISS.c +++ b/Modem/protocol/KISS.c @@ -0,0 +1,81 @@ +#include +#include +#include +#define F_CPU 16000000UL +#include +#include // 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; + } + + } +} \ No newline at end of file diff --git a/Modem/protocol/KISS.h b/Modem/protocol/KISS.h index 00574f2..55ca40e 100644 --- a/Modem/protocol/KISS.h +++ b/Modem/protocol/KISS.h @@ -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 +#include + +void kiss_init(AX25Ctx *ax25, Serial *ser); + +void kiss_messageCallback(AX25Ctx *ctx); +void kiss_serialCallback(uint8_t sbyte); +void fon(void); #endif \ No newline at end of file diff --git a/Modem/protocol/SimpleSerial.h b/Modem/protocol/SimpleSerial.h index 5d78f1d..e77b55b 100644 --- a/Modem/protocol/SimpleSerial.h +++ b/Modem/protocol/SimpleSerial.h @@ -1,9 +1,8 @@ -#ifndef PROTOCOL_SIMPLE_SERIAL +#ifndef _PROTOCOL_SIMPLE_SERIAL +#define _PROTOCOL_SIMPLE_SERIAL 0x01 #include #include -#define PROTOCOL_SIMPLE_SERIAL 0x01 - #define DEFAULT_CALLSIGN "NOCALL" #define DEFAULT_DESTINATION_CALL "APZMDM" diff --git a/bertos/net/ax25.c b/bertos/net/ax25.c index b73f84e..5952a0b 100644 --- a/bertos/net/ax25.c +++ b/bertos/net/ax25.c @@ -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. * diff --git a/bertos/net/ax25.h b/bertos/net/ax25.h index dd43944..88ff202 100644 --- a/bertos/net/ax25.h +++ b/bertos/net/ax25.h @@ -45,6 +45,7 @@ #ifndef NET_AX25_H #define NET_AX25_H +#include "config.h" // Various configuration values #include "cfg/cfg_ax25.h" #include @@ -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. diff --git a/buildrev.h b/buildrev.h index 0aa220d..af44b59 100644 --- a/buildrev.h +++ b/buildrev.h @@ -1,2 +1,2 @@ -#define VERS_BUILD 2224 +#define VERS_BUILD 2341 #define VERS_HOST "shard" diff --git a/images/Modem.elf b/images/Modem.elf index f2d6f68..a3a2c1d 100755 Binary files a/images/Modem.elf and b/images/Modem.elf differ diff --git a/images/Modem.hex b/images/Modem.hex index 0a9d28c..da25a46 100644 --- a/images/Modem.hex +++ b/images/Modem.hex @@ -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