pax_global_header00006660000000000000000000000064132345557020014520gustar00rootroot0000000000000052 comment=90385aabe2b51f39fa130627d46b377569f82d4a picocom-3.1/000077500000000000000000000000001323455570200130145ustar00rootroot00000000000000picocom-3.1/.editorconfig000066400000000000000000000005311323455570200154700ustar00rootroot00000000000000# See: http://EditorConfig.org # top-most EditorConfig file root = true # Unix-style newlines with a newline ending every file [*] end_of_line = lf insert_final_newline = true # Matches multiple files with brace expansion notation # Set default indentation style [*.{c,h}] indent_style = space indent_size = 4 trim_trailing_whitespace = true picocom-3.1/.gitignore000066400000000000000000000000201323455570200147740ustar00rootroot00000000000000*.o *~ /picocom picocom-3.1/Android.mk000066400000000000000000000023241323455570200147260ustar00rootroot00000000000000# # 2017, Christopher N. Hesse # LOCAL_PATH := $(call my-dir) VERSION := 3.1 TTY_Q_SZ := 0 HISTFILE := .picocom_history ########################################################################## # linenoise include $(CLEAR_VARS) LOCAL_SRC_FILES := linenoise-1.0/linenoise.c LOCAL_MODULE := linenoise include $(BUILD_STATIC_LIBRARY) ########################################################################## # picocom include $(CLEAR_VARS) LOCAL_SRC_FILES := \ picocom.c \ term.c \ fdio.c \ split.c \ termios2.c LOCAL_CFLAGS += -DVERSION_STR=\"$(VERSION)\" LOCAL_CFLAGS += -DTTY_Q_SZ=$(TTY_Q_SZ) ## Comment this out to disable high-baudrate support LOCAL_CFLAGS += -DHIGH_BAUD ## Normally you should NOT enable both: UUCP-style and flock(2) ## locking. ## Comment this out to disable locking with flock LOCAL_CFLAGS += -DUSE_FLOCK ## Comment these out to disable UUCP-style lockdirs #UUCP_LOCK_DIR=/var/lock #LOCAL_CFLAGS += -DUUCP_LOCK_DIR=\"$(UUCP_LOCK_DIR)\" ## Comment these out to disable "linenoise"-library support LOCAL_CFLAGS += -DHISTFILE=\"$(HISTFILE)\" -DLINENOISE LOCAL_STATIC_LIBRARIES += linenoise LOCAL_MODULE := picocom include $(BUILD_EXECUTABLE) picocom-3.1/CHANGES.old000066400000000000000000000115321323455570200145660ustar00rootroot00000000000000------------------------------------------------------------------------ r35 | npat | 2004-08-13 14:18:38 +0300 (Fri, 13 Aug 2004) | 3 lines Changed paths: M /picocom/trunk/Makefile picocom version 1.4 ------------------------------------------------------------------------ r34 | npat | 2004-08-13 14:15:23 +0300 (Fri, 13 Aug 2004) | 4 lines Changed paths: M /picocom/trunk/Makefile Added the "changes" target that generates the CHANGES file from the svn (version control) commit logs. ------------------------------------------------------------------------ r33 | npat | 2004-08-13 05:48:26 +0300 (Fri, 13 Aug 2004) | 4 lines Changed paths: M /picocom/trunk/Makefile M /picocom/trunk/picocom.8.xml Converted the manpage sources to use the xmlmp-1.1 DTD, and hence the xmlmp tools (see http://npat.efault.net/hacks/xmlmp) ------------------------------------------------------------------------ r28 | npat | 2004-08-12 15:17:54 +0300 (Thu, 12 Aug 2004) | 2 lines Changed paths: M /picocom/trunk/TODO Removed stale tasks from TODO. (Now it's empty). ------------------------------------------------------------------------ r27 | npat | 2004-08-12 15:16:03 +0300 (Thu, 12 Aug 2004) | 5 lines Changed paths: M /picocom/trunk/CONTRIBUTORS M /picocom/trunk/picocom.8.xml Added Julius P. Malkiewicz in the contributors list Updated documentation to comply with the changes made since r13 ------------------------------------------------------------------------ r26 | npat | 2004-08-12 14:45:11 +0300 (Thu, 12 Aug 2004) | 9 lines Changed paths: M /picocom/trunk/Makefile M /picocom/trunk/picocom.c Added support for UUCP-style locks. Lock handling is compiled-in if the macro UUCP_LOCK_DIR is defined; if it is, it must contain the name of the lock directory. Locking can be disabled at runtime using the "--noock" option. UUCP-locks support is based on a patch submitted by Julius P. Malkiewicz ------------------------------------------------------------------------ r25 | npat | 2004-08-12 11:55:56 +0300 (Thu, 12 Aug 2004) | 4 lines Changed paths: M /picocom/trunk/picocom.c Implemented th C-\ command, which generates a break sequence. Patch submitted by Julius P. Malkiewicz ------------------------------------------------------------------------ r24 | npat | 2004-08-12 11:52:39 +0300 (Thu, 12 Aug 2004) | 5 lines Changed paths: M /picocom/trunk/picocom.c If two escape-characters are sent in a row, the second is passed-through, and picocom returns to transparrent mode. Patch submitteb by Julius P. Malkiewicz ------------------------------------------------------------------------ r23 | npat | 2004-08-12 11:45:57 +0300 (Thu, 12 Aug 2004) | 7 lines Changed paths: M /picocom/trunk/term.c Fixed "term.c" to compile under FreeBSD (and probably other BSDs also). "term.c" now includes "termios.h" instead of "termio.h" in non-linux system. Added a declaration for "tioold"---that was missing---in the non-linux part of the DTR toggling code. Patch submitted by Julius P. Malkiewicz ------------------------------------------------------------------------ r12 | npat | 2004-08-11 19:03:48 +0300 (Wed, 11 Aug 2004) | 2 lines Changed paths: M /picocom/trunk/CONTRIBUTORS M /picocom/trunk/Makefile M /picocom/trunk/README A /picocom/trunk/picocom.8.xml Added r1.3 ------------------------------------------------------------------------ r10 | npat | 2004-08-11 19:02:35 +0300 (Wed, 11 Aug 2004) | 3 lines Changed paths: A /picocom/trunk/CONTRIBUTORS M /picocom/trunk/Makefile A /picocom/trunk/TODO M /picocom/trunk/picocom.c Added r1.2 ------------------------------------------------------------------------ r8 | npat | 2004-08-11 19:01:25 +0300 (Wed, 11 Aug 2004) | 2 lines Changed paths: M /picocom/trunk/Makefile A /picocom/trunk/NEWS M /picocom/trunk/README A /picocom/trunk/pcasc A /picocom/trunk/pcxm A /picocom/trunk/pcym A /picocom/trunk/pczm M /picocom/trunk/picocom.c Added r1.1 ------------------------------------------------------------------------ r6 | npat | 2004-08-11 18:59:25 +0300 (Wed, 11 Aug 2004) | 2 lines Changed paths: A /picocom/trunk/LICENSE.txt A /picocom/trunk/Makefile A /picocom/trunk/README A /picocom/trunk/picocom.c A /picocom/trunk/term.c A /picocom/trunk/term.h Imported r1.0 sources ------------------------------------------------------------------------ r1 | svn | 2004-08-11 08:02:59 +0300 (Wed, 11 Aug 2004) | 2 lines Changed paths: A /mu0 A /mu0/branches A /mu0/tags A /mu0/trunk A /picocom A /picocom/branches A /picocom/tags A /picocom/trunk A /ppgplot A /ppgplot/branches A /ppgplot/tags A /ppgplot/trunk Imported initial projects directory structure. ------------------------------------------------------------------------ picocom-3.1/CONTRIBUTORS000066400000000000000000000051521323455570200146770ustar00rootroot00000000000000 The following people contributed improvements, fixes, suggestions, and comments: - Oliver Kurth (oku@debian.org) contributed bug fixes and the manual page for picocm. - Julius P. Malkiewicz (julius@sonartech.com.au) contributed FreeBSD portablity fixes, the C-\ command implementation, the UUCP locks implementation, and other minor fixes. - Pavel Vymetalek (pvymetalek@seznam.cz) contributed the higher baudrates support. - Niels Moller (nisse@lysator.liu.se) contributed support for non-alphabetic escape keys. - (lwithers@gmail.com) contributed fixes to select(2) and read(2) error handling. - (bob.dunlop@xyzzy.org.uk) suggested fix to prevent serial port form becoming controlling terminal. - Edgar Johansen (edgar@storteig.com) suggested conditionals to enable compilation without UUCP_LOCK_DIR - Scott Tsai (scott.tw@gmail.com) suggested better UUCP_LOCK_DIR definition - Josh Handley (https://github.com/jhandley) added support for line-editing, autocompletion and history when entering "send" and "receive" file names. Editing support uses the "linenoise" library. See: https://github.com/jhandley/picocom - Salvatore Sanfilippo (https://github.com/antirez) is the author of the linenoise line-editing library. See: https://github.com/antirez/linenoise - From Cody Schafer's (https://gitbub.com/jmesmon) fork originated the idea to add custom baudrate support to picocom. See: https://github.com/jmesmon/picocom - From Paul Chakravarti's (https://github.com/paulchakravarti) fork orignated the idea to add support for disabling the send- and rceive-file commands, and for not using the shell when executing external programs (to avoid shell escapes). See: https://github.com/paulchakravarti/picocom-noexec - Vicente Olivert Riera (Vincent.Riera@imgtec.com) contribiuted minor patches - Peter Bradstreet (peter.bradstreet@oracle.com) helped diagnose input performance problems on overloaded / slow systems. - Cody Planteen (https://github.com/planteen) contributed the implementation of the toggle-RTS command. - Joe Merten (https://github.com/JoeMerten) contributed the --lower-rts and --lower-dtr options, custom baudrate support for FreeBSD and macOS, the --logfile option implementation, and several bug-fixes. - Maciej Grela (https://github.com/mgrela) contributed the initial --initstring option implementation. - Baruch Siach (https://github.com/baruchsiach) contributed improvements to the Makefile - Christopher N. Hesse (https://github.com/raymanfx) contributed the initial Android makefile - Ben (https://github.com/the-dem) contributed backward compatibility fixes. picocom-3.1/LICENSE.txt000066400000000000000000000432061323455570200146440ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. picocom-3.1/Makefile000066400000000000000000000050371323455570200144610ustar00rootroot00000000000000 VERSION = 3.1 #CC ?= gcc CPPFLAGS += -DVERSION_STR=\"$(VERSION)\" CFLAGS += -Wall -g LD = $(CC) LDFLAGS ?= -g LDLIBS ?= all: picocom OBJS = ## This is the maximum size (in bytes) the output (e.g. copy-paste) ## queue is allowed to grow to. Zero means unlimitted. TTY_Q_SZ = 0 CPPFLAGS += -DTTY_Q_SZ=$(TTY_Q_SZ) ## Comment this out to disable high-baudrate support CPPFLAGS += -DHIGH_BAUD ## Normally you should NOT enable both: UUCP-style and flock(2) ## locking. ## Comment this out to disable locking with flock CPPFLAGS += -DUSE_FLOCK ## Comment these out to disable UUCP-style lockdirs #UUCP_LOCK_DIR=/var/lock #CPPFLAGS += -DUUCP_LOCK_DIR=\"$(UUCP_LOCK_DIR)\" ## Comment these out to disable "linenoise"-library support HISTFILE = .picocom_history CPPFLAGS += -DHISTFILE=\"$(HISTFILE)\" \ -DLINENOISE OBJS += linenoise-1.0/linenoise.o linenoise-1.0/linenoise.o : linenoise-1.0/linenoise.c linenoise-1.0/linenoise.h ## Comment this in to enable (force) custom baudrate support ## even on systems not enabled by default. #CPPFLAGS += -DUSE_CUSTOM_BAUD ## Comment this in to disable custom baudrate support ## on ALL systems (even on these enabled by default). #CPPFLAGS += -DNO_CUSTOM_BAUD ## Comment this IN to remove help strings (saves ~ 4-6 Kb). #CPPFLAGS += -DNO_HELP OBJS += picocom.o term.o fdio.o split.o termios2.o custbaud_bsd.o picocom : $(OBJS) $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) picocom.o : picocom.c term.h fdio.h split.h custbaud.h term.o : term.c term.h termios2.h custbaud_bsd.h custbaud.h split.o : split.c split.h fdio.o : fdio.c fdio.h termios2.o : termios2.c termios2.h termbits2.h custbaud.h custbaud_bsd.o : custbaud_bsd.c custbaud_bsd.h custbaud.h .c.o : $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< doc : picocom.1.html picocom.1 picocom.1.pdf picocom.1 : picocom.1.md sed 's/\*\*\[/\*\*/g;s/\]\*\*/\*\*/g' $? \ | pandoc -s -t man \ -Vfooter="Picocom $(VERSION)" -Vdate="`date -I`" \ -Vadjusting='l' \ -Vhyphenate='' \ -o $@ picocom.1.html : picocom.1.md pandoc -s -t html \ --template ~/.pandoc/tmpl/manpage.html \ -c ~/.pandoc/css/normalize-noforms.css \ -c ~/.pandoc/css/manpage.css \ --self-contained \ -Vversion="v$(VERSION)" -Vdate="`date -I`" \ -o $@ $? picocom.1.pdf : picocom.1 groff -man -Tpdf $? > $@ clean: rm -f picocom.o term.o fdio.o split.o rm -f linenoise-1.0/linenoise.o rm -f termios2.o custbaud_bsd.o rm -f *~ rm -f \#*\# distclean: clean rm -f picocom realclean: distclean rm -f picocom.1 rm -f picocom.1.html rm -f picocom.1.pdf rm -f CHANGES picocom-3.1/README.md000066400000000000000000000273751323455570200143110ustar00rootroot00000000000000# picocom Minimal dumb-terminal emulator by Nick Patavalis (npat@efault.net) The latest release can be downloaded from: > https://github.com/npat-efault/picocom/releases As its name suggests, *picocom* is a minimal dumb-terminal emulation program. It is, in principle, very much like minicom, only it's "pico" instead of "mini"! It was designed to serve as a simple, manual, modem configuration, testing, and debugging tool. It has also served (quite well) as a low-tech serial communications program to allow access to all types of devices that provide serial consoles. It could also prove useful in many other similar tasks. It is ideal for embedded systems since its memory footprint is small (approximately 40K, when stripped and minimally configured). Apart from being a handy little tool, *picocom's* source distribution includes a simple, easy to use, and thoroughly documented terminal-management library, which could serve other projects as well. This library hides the termios(3) calls, and provides a less complex and safer (though certainly less feature-rich) interface. *picocom* runs and is, primarily, tested on Linux. With no, or with minor, modifications it will run (and most of its features will work) on any Unix-like system with a reasonably POSIX-compatible termios(3) interface. Patches to support idiosyncrasies of specific Unix-like operating systems are very welcome. For a description of picocom's operation, its command line options, and usage examples, see the manual page included in the source distribution as "picocom.1", and also html-ized as "picocom.1.html". People who have contributed to picocom, by offering feature implementations, bug-fixes, corrections, and suggestions are listed in the "CONTRIBUTORS" file. Please feel free to send comments, requests for new features (no promises, though!), bug-fixes and rants, to the author's email address shown at the top of this file. ## Compilation / Installation Change into picocom's source directory and say: make This will be enough to compile picocom for most modern Unix-like systems. If you want, you can then strip the resulting binary like this: strip picocom Striping the binary is not required, it just reduces its size by a few kilobytes. Then you can copy the picocom binary, as well as the man-page, to wherever you put your binaries and man-pages. For example: cp picocom ~/bin cp picocom.1 ~/man/man1 Again, this is not strictly necessary. You can run picocom and read its man-page directly from the source directory. If something goes wrong and picocom can't compile cleanly, or if it's lacking a feature you need, take a look at the included Makefile. It's very simple and easy to understand. It allows you to select compile-time options and enable or disable some compile-time features by commenting in or out the respective lines. Once you edit the Makefile, to recompile say: make clean make If your system's default make(1) command is not GNU Make (or compatible enough), find out how you can run GNU Make on your system. For example: gmake clean gmake Alternatively, you might have to make some trivial edits to the Makefile for it to work with your system's make(1) command. ## Using picocom If your computer is a PC and has the standard on-board RS-233 ports (usually accessible as two male DB9 connectors at the back) then under Linux these are accessed through device nodes most likely named: `/dev/ttyS0` and `/dev/ttyS1`. If your computer has no on-board serial ports, then you will need a USB-to-Serial adapter (or something similar). Once inserted to a USB port and recognized by Linux, a device node is created for each serial port accessed through the adapter(s). These nodes are most likely named `/dev/ttyUSB0`, `/dev/ttyUSB1`, and so on. For other systems and other Unix-like OSes you will have to consult their documentation as to how the serial port device nodes are named. Lets assume your serial port is accessed through a device node named `/dev/ttyS0`. You can start picocom with its default option values (default serial port settings) like this: picocom /dev/ttyS0 If you have not installed the picocom binary to a suitable place, then you can run it directly from the source distribution directory like this: ./picocom /dev/ttyS0 If this fails with a message like: FATAL: cannot open /dev/ttyS0: Permission denied This means that you do not have permissions to access the serial port's device node. To overcome this you can run picocom as root: sudo picocom /dev/ttyS0 Alternatively, and preferably, you can add yourself to the user-group that your system has for allowing access to serial ports. For most Unix-like systems this group is called "dialout". Consult you system's documentation to find out how you can do this (as it differs form system to system). On most Linux systems you can do it like this: sudo usermod -a -G dialout username You will need to log-out and then log-in back again for this change to take effect. You can explicitly set one or more of the serial port settings to the desired values using picocom's command line options. For example, to set the baud-rate to 115200bps (the default is 9600bps), and enable hardware flow-control (RTS/CTS handshake) you can say: picocom -b 115200 -f h /dev/ttyS0 or: picocom --baud 115200 --flow h /dev/ttyS0 To see all available options run picocom like this: picocom --help Once picocom starts, it initializes the serial port and prints the message: Terminal is ready From now on, every character you type is sent to the serial port, and every character received from the serial port is sent ro your terminal. Including control and special characters. Assuming that there is nothing connected to the other end of your serial port, to respond to the characters you send to it (e.g. echo them back to you), then nothing that you type in picocom will appear on your terminal. This is normal. To exit picocom you have to type: C-a, C-x Which means you have to type [Control-A] followed by [Control-X]. You can do this by pressing and holding down the [Control] key, then pressing (and releasing) the [A] key and then pressing (and releasing) the [X] key (while you still keep [Control] held down). This `C-a` is called the "escape character". It is used to inform picocom that the next character typed is to be interpreted as a command to picocom itself (in this case the exit command) and not to be sent-down to the serial port. There are several other commands (other than `C-a`, `C-x`), all prefixed by `C-a`. Next you should take a look at the very detailed picocom manual page. It can be accessed like this (assuming you are inside the picocom distribution source directory): man ./picocom.1 or (assuming you have installed the manual page to a suitable place): man picocom Thanks for using picocom ## A low-tech terminal server You can use *picocom* to patch-together a very simple, *very low-tech*, terminal server. The situation is like this: You have, in your lab, a box with several serial ports on it, where you connect the console ports of embedded devices, development boards, etc. Let's call it "termbox". You want to access these console ports remotely. If you provide shell-access to termbox for your users, then it's as simple as having the users say (from their remote workstations): $ ssh -t user@termbox picocom -b 115200 /dev/ttyS0 Or make a convenient script/alias for this. Remember the `-t` switch which instructs ssh to create a pseudo-tty, otherwise picocom won't work. What if you *don't* want to give users shell-access to termbox? Then you can use picocom in a setup like the one described below. Just remember, there are countless variations to this theme, the one below is just one of them. Also, keep in mind that some of the commands shown may have small differences from system to system; more so if you go from Linux to other Unix-like systems. Login to termbox and create a user called _termbox_: $ sudo useradd -r -m termbox The `-r` means "system account", and the `-m` means *do* make the home-directory. Mostly we need this account's home-directory as a convenient place to keep stuff; so it doesn't need a login shell or a password. Switch to the _termbox_ account and create a `bin` directory in its home-dir. $ sudo su termbox $ cd ~ $ mkdir bin Copy the picocom binary in `~termbox/bin` (if you don't have it globally installed): $ cp /path/to/picocom ./bin For every serial port you want to provide access to, create a file named after the port and put it in `~termbox/bin`. It should look like this: $ cat ./bin/ttyS0 #!/bin/sh exec /home/termbox/bin/picocom \ --send-cmd '' \ --receive-cmd '' \ -b 115200 \ /dev/ttyS0 And make it executable: $ chmod +x ./bin/ttyS0 Repeat accordingly for every other port. Now the contents of `~termbox/bin` should look like this: $ ls -l ./bin -rwxrwxr-x 1 termbox termbox 102128 Aug 29 13:56 picocom* -rwxrwxr-x 1 termbox termbox 108 Aug 29 14:07 ttyS0* -rwxrwxr-x 1 termbox termbox 108 Aug 29 14:07 ttyS1* ... and so on ... Exit the _termbox_ account: $ exit Now, for every serial port, create a user account named after the port, like this: $ sudo useradd -r -g dialout -d ~termbox -M -s ~termbox/bin/ttyS0 ttyS0 Observe that we make `dialout` the default group for this account, so the account has access to the serial ports. Also observe that we make the script we just wrote (`~termbox/bin/ttyS0`) the login-shell for the account. The `-d` option instructs useradd to use `/home/termbox` as the user's home directory, and the `-M` switch instructs it *not* to create the home-directory. We don't really need a home directory for the _ttyS0_ account, since picocom will not read or write any files; but we provide one, regardless, because *some* systems need a valid home-directory to cd-into on login (else they choke). We could as well have used `/` as the home directory, or we could have let useradd create the usual `/home/ttyS0`. Then set a password for the newly created account: $ sudo passwd ttyS0 Enter new UNIX password: ****** Retype new UNIX password: ****** Repeat (create user account, set password) for every port you want to give access to. You 're set. All a user has to do to remotely access the console connected to termbox's `/dev/ttyS0` port, is: ssh ttyS0@termbox Some interesting points: - If the default port settings you specified as command-line arguments to picocom in `~termbox/bin/ttySx` do not match the settings of the device connected to the port, the user can easily change them from within picocom, using picocom commands. - If a second user tries to remotely access the same port, at the same time, picocom won't let him (picocom will find the port locked and exit). - In the example `~termbox/bin/ttySx` scripts we have completely disabled the send- and receive-file picocom commands. This guarantees that picocom won't execute any external commands. If you want, you can enable the commands by providing specific file-upload and file-download programs as the arguments to the `--send-cmd` and `--receive-cmd` picocom command-line options (provided, of-course, that you trust these programs). Picocom (starting with release 2.0) does not use `/bin/sh` to execute the file-upload and file-download programs and *will not* let the user inject shell-commands when supplying additional arguments to them. - If you allow send- and receive-file operations as described above, you will, most likely, also need a way for your users to put files on termbox, and get files back from it. There are many ways to arrange for this, but they are beyond the scope of this simple example. Again, this is only *one* possible setup. There are countless other variations and elaborations you can try. Be creative! picocom-3.1/TODO000066400000000000000000000000011323455570200134730ustar00rootroot00000000000000 picocom-3.1/bsd_notes.txt000066400000000000000000000073311323455570200155410ustar00rootroot00000000000000 Notes about running picocom on BSD-based OSes ============================================= by Joe Merten (https://github.com/JoeMerten) Test environment ================ - VirtualBox host Kubuntu 16.04 - FreeBsd 11.0 (VM) - OpenBsd 6.2 (VM) - NetBsd 7.1.1 (VM) - Dragonfly 5.0.2 (VM) - OSX 10.11.6 El Capitan (native on Macbook Pro) - macOS 10.12 Sierra (native on Macbook Pro) - Kubuntu 16.04 (native on Macbook Pro) - all above on Intel x86 64 Bit - Cygwin 5.1 on Windows XP 32 Bit host - Ftdi FT232R, max 1MBaud (chip can 3MBaud, but hw rs232 level shifter is specified for just 1MBaud) - Prolific PL2303, max 230kBaud (chip can 12MBaud, but hw rs232 level shifter is specified for just 230kBaud) - Unknown Asus onboard (16550 compatible?) uart chip, max 115kBaud. Just minor testing with this uart, because it seems that it don't supports non standard baudrates. For Cygwin, I'd just checked if it will build and ran `picocom -h`. I'd personally failed opening a serial port within Cygwin. Note that for Cygwin it needs to implement a `cfmakeraw()` replacement. See also: https://cygwin.com/ml/cygwin/2008-09/msg00295.html https://sourceforge.net/p/ser2net/patches/9/ https://sourceforge.net/p/ser2net/patches/_discuss/thread/8b87fdad/ed37/attachment/ser2net-2.2-cygwin.patch Accessing serial ports (examples) ================================= - Kubuntu: /dev/ttyS0 /dev/ttyUSB0 - FreeBsd: /dev/ttyu0 /dev/ttyU0 - OpenBsd: /dev/cuaU0 - NetBsd: /dev/ttyU0 - Dragonfly: /dev/ttyU0 - macOS /dev/tty.usbserial-FTGNI4B7 (Ftdi) /dev/tty.usbserial (Prolific) Manual controlling handshake lines ================================== All above listed Bsd variants (FreeBsd, OpenBsd, NetBsd, Dragonfly and even macOS) fail when trying to reset the handshake lines (RTS and DTR) using `tcsetattr()` and setting the baudrate to zero. They all basically work with the TIOCM[BIC|BIS|GET] `ioctl()`s. However, there are still some issues regarding RTS and DTR control for OpenBsd, NetBsd and Dragonfly (see details below). Custom Baudrates ================ Tested with 80000 baud. Most Bsd variants (except NetBsd) worked well with Ftdi, but not with the Prolific adapter (see details below). Linux and OSX / macOS still work with both adapters. Issues ====== FreeBsd ------- - Custom Baudrates work well with Ftdi adapter. But with Prolific adapter, baudrate switched silently to 9600 baud. OpenBsd ------- - `term_get_mctl()` sometimes reports wrong values for rts and dtr state (after port open). - `--lower-rts` works as expected, but `--lower-dtr` lowers both rts and dtr lines. Same for interactive toggle via `[C-t]` and `[C-g]`. Toggle rts via `[C-g]` works but toggle dtr via `[C-t]` also changes the state of rts (and `term_get_mctl()` reports wrong rts state afterwards). - Issues occurs with both Ftdi and Prolific adapters. - Custom baudrates with Prolific adapter has the same issue as in FreeBsd. NetBsd ------ - `term_get_mctl()` sometimes reports wrong values for rts and dtr state (after port open) - Issue occurs with both Ftdi and Prolific adapters. - Seems that there is no support for custom baudrates. - With Ftdi adapter: "Cannot set the device attributes: Invalid argument". - With Prolific adapter no error message but same behaviour as in FreeBsd. Dragonfly --------- - Got "FATAL: cannot lock /dev/ttyU0: Operation not supported" on startup. Need to pass `--nolock` or build with `#define USE_FLOCK` not set. - `term_get_mctl()` sometimes reports wrong state for dtr, e.g. when passing `--lower-dtr`. - When exit via `[C-x]`, got "term_exitfunc: reset failed for dev /dev/ttyU0: Invalid argument". - Custom baudrates with Prolific adapter has the same issue as in FreeBsd. picocom-3.1/custbaud.h000066400000000000000000000052471323455570200150070ustar00rootroot00000000000000/* vi: set sw=4 ts=4: * * custbaud.h * * Automatically enable custom baudrate support for systems (OS / * version / architecture combinations) we know it works. * * by Nick Patavalis (npat@efault.net) * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #ifndef CUSTBAUD_H #define CUSTBAUD_H #ifndef NO_CUSTOM_BAUD #if defined (__linux__) /* Enable by-default for kernels > 2.6.0 on x86 and x86_64 only */ #include #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) #if defined (__i386__) || defined (__x86_64__) || defined (USE_CUSTOM_BAUD) #ifndef USE_CUSTOM_BAUD #define USE_CUSTOM_BAUD #endif #define CUSTOM_BAUD_HEAD "termios2.h" #endif /* of arch */ #endif /* of version */ #elif defined (__APPLE__) && defined(__MACH__) #include #include #if TARGET_IPHONE_SIMULATOR /* Do not enable by default for iOS in Xcode simulator */ #elif TARGET_OS_IPHONE /* Do not enable by default for iOS until it has been tested */ #elif TARGET_OS_MAC #if defined (__i386__) || defined (__x86_64__) /* Enable by-default for Intel Mac, macOS / OSX >= 10.4 (Tiger) */ #ifndef USE_CUSTOM_BAUD #define USE_CUSTOM_BAUD #endif #endif /* of arch */ #endif /* of TARGET_OS_... */ #define CUSTOM_BAUD_HEAD "custbaud_bsd.h" #elif defined (__NetBSD__) /* Do not enable by default */ #define CUSTOM_BAUD_HEAD "custbaud_bsd.h" #elif defined (__FreeBSD__) || defined (__OpenBSD__) || \ defined (__DragonFly__) /* I believe it doesn't hurt to enable by-default for these */ #ifndef USE_CUSTOM_BAUD #define USE_CUSTOM_BAUD #endif #define CUSTOM_BAUD_HEAD "custbaud_bsd.h" #elif defined (USE_CUSTOM_BAUD) #error "USE_CUSTOM_BAUD not supported on this system!" #endif /* of platforms */ #else /* of ndef NO_CUSTOM_BAUD */ #ifdef USE_CUSTOM_BAUD #undef USE_CUSTOM_BAUD #endif #endif /* of ndef NO_CUSTOM_BAUD else */ #endif /* CUSTBAUD_H */ /**************************************************************************/ /* * Local Variables: * mode:c * tab-width: 4 * c-basic-offset: 4 * End: */ picocom-3.1/custbaud_bsd.c000066400000000000000000000134711323455570200156300ustar00rootroot00000000000000/* * custbaud_bsd.c * * Custom baud rate support for BSD and macOS. * * by Joe Merten (https://github.com/JoeMerten www.jme.de) * * ATTENTION: BSD and macOS specific stuff! * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ /***************************************************************************/ /* Known issues: * - FT232H 12MBaud not working * - using OSX El Capitan 10.11.6, FTDIUSBSerialDriver_v2_3.dmg * - tried with 2 different chips (FT232H and FT2232H) * Testing with Ftdi FT232H, which is capable to use up to 12MBaud, only * line speed up to 3MBaud were accepted. For higher baudrates we earn * a failure in the ioctl(IOSSIOSPEED) call. * But as `python -m serial.tools.miniterm` shows the same behaviour, it * looks that this is a bug or limitation in OSX and/or Ftdi driver. * Trying with PL2303 (driver version PL2303_MacOSX_1.6.1_20160309.zip), * baudrates up to 6MBaud were accepted. * - Have not tested with more recent macOS or Ftdi driver until now. */ #include "custbaud.h" /* Note that this code might also work with other BSD variants, but I have only * tested with those listed below. Also tested __NetBSD__ but won't work. */ #if (defined (__FreeBSD__) || defined (__NetBSD__) || \ defined (__OpenBSD__) || defined (__DragonFly__) || \ defined (__APPLE__)) && \ defined (USE_CUSTOM_BAUD) #include "custbaud_bsd.h" #include #include #include #include #ifdef __APPLE__ #include #endif #include "term.h" /***************************************************************************/ /* As we can see in BSD and macOS termios.h all the baudrate constants are * transparent, like B115200=115200. There is no need for any integer <-> code * translation. So we can pass any baudrate we want directly to / from * cfsetospeed() & co. */ int cfsetospeed_custom(struct termios *tiop, int speed) { return cfsetospeed(tiop, speed); } int cfsetispeed_custom(struct termios *tiop, int speed) { return cfsetispeed(tiop, speed); } int cfgetospeed_custom(struct termios *tiop) { return cfgetospeed(tiop); } int cfgetispeed_custom(struct termios *tiop) { return cfgetispeed(tiop); } #ifdef __APPLE__ /***************************************************************************/ /* Need to undef tcsetattr to get access to the original tcsetattr() * function inside our module. */ #undef tcsetattr /***************************************************************************/ /* The strategy of picocom's terminal handling library is to hold all the * terminal settings (including baudrate) using termios struct. * Problem on macOS is, that tcsetattr() will fail if termios contains an * unusual baudrate (like e.g. 12345 of 12M), The official macOS way to apply * those baudrates is to use ioctl(IOSSIOSPEED) instead. * Our workaround strategy is: * - set the baudrate stored in termios back to a standard value (e.g. 9600) * - call tcsetattr() to apply all the rest termios data to the fd * - and then applying the real desired baudrate to the fd by calling ioctl(IOSSIOSPEED) * Note, that in case of failed ioctl(IOSSIOSPEED), our 9600 staying * configured at the fd. */ int tcsetattr_custom(int fd, int optional_actions, const struct termios *tiop) { int r; int workaround = 0; int baudrate; struct termios tios = *tiop; struct termios tio0; int baudrate0; if ( fd >= 3 ) { /* don't apply this workaround for stdin/stdout/stderr */ baudrate = cfgetospeed(&tios); if (baudrate > 460800 || !term_baud_std(baudrate)) { /* save fd's current termios to recover in case of later falure */ r = tcgetattr(fd, &tio0); if ( r < 0 ) return -1; baudrate0 = cfgetospeed(&tio0); /* now temporarily switching baudrate back to 9600 */ r = cfsetspeed(&tios, B9600); if ( r < 0 ) return -1; workaround = 1; } } r = tcsetattr(fd, optional_actions, &tios); if ( r < 0 ) return -1; if ( workaround ) { r = ioctl(fd, IOSSIOSPEED, &baudrate); /*if ( r < 0 ) fprintf(stderr, "%s: ioctl(%d, %d) = %d, optional_actions = %d, %s\r\n", __FUNCTION__, fd, baudrate, r, optional_actions, strerror(errno));*/ if ( r < 0 ) { /* ioctl() failed, so we try to restore the fd to the old termios data */ r = cfsetspeed(&tio0, B9600); /*if ( r < 0 ) fprintf(stderr, "%s: cfsetspeed() = %d, %s\r\n", __FUNCTION__, r, strerror(errno));*/ if ( r < 0 ) return -1; r = tcsetattr(fd, optional_actions, &tio0); /*if ( r < 0 ) fprintf(stderr, "%s: tcsetattr() = %d, %s\r\n", __FUNCTION__, r, strerror(errno));*/ if ( r < 0 ) return -1; r = ioctl(fd, IOSSIOSPEED, &baudrate0); /*if ( r < 0 ) fprintf(stderr, "%s: ioctl(%d) = %d, %s\r\n", __FUNCTION__, baudrate0, r, strerror(errno));*/ return -1; } } return 0; } #endif /*__APPLE__ */ /***************************************************************************/ #endif /* __FreeBSD__ || ... || __APPLE__ && USE_CUSTOM_BAUD */ picocom-3.1/custbaud_bsd.h000066400000000000000000000055371323455570200156410ustar00rootroot00000000000000/* * custbaud_bsd.h * * Custom baud rate support for BSD and macOS. * * by Joe Merten (https://github.com/JoeMerten www.jme.de) * * ATTENTION: BSD and macOS specific stuff! * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #ifndef CUSTBAUD_BSD_H #define CUSTBAUD_BSD_H #include /***************************************************************************/ /* macOS termios.h unfortunately just provides constants for baudrates * up to 230k, so we add the missing constants here. Regardless, that * most of the high baudrates needs special handling (implementation in * tcsetattr_custom()), we want to provide the values here to have them * available for term_baud_up()/down(). * * FreeBSD 11.0 termios.h has 460k and 921k but misses e.g. 500k and >=1M. * OpenBSD 6.2 termios.h is missing all >230k (like macOS). * NetBSD 7.1.1 do same as FreeBSD 11.0. * DragonFly 5.0.2 looks same as OpenBSD 6.2. */ #if defined(HIGH_BAUD) #ifndef B460800 #define B460800 460800 #endif #ifndef B500000 #define B500000 500000 #endif #ifndef B576000 #define B576000 576000 #endif #ifndef B921600 #define B921600 921600 #endif #ifndef B1000000 #define B1000000 1000000 #endif #ifndef B1152000 #define B1152000 1152000 #endif #ifndef B1500000 #define B1500000 1500000 #endif #ifndef B2000000 #define B2000000 2000000 #endif #ifndef B2500000 #define B2500000 2500000 #endif #ifndef B3000000 #define B3000000 3000000 #endif #ifndef B3500000 #define B3500000 3500000 #endif #ifndef B4000000 #define B4000000 4000000 #endif #endif /* HIGH_BAUD */ /***************************************************************************/ int cfsetospeed_custom(struct termios *tiop, int speed); int cfsetispeed_custom(struct termios *tiop, int speed); int cfgetospeed_custom(struct termios *tiop); int cfgetispeed_custom(struct termios *tiop); /***************************************************************************/ #ifdef __APPLE__ /* Replace tcsetattr function with our macOS specific one */ #define tcsetattr tcsetattr_custom int tcsetattr_custom(int fd, int optional_actions, const struct termios *tiop); #endif /***************************************************************************/ #endif /* CUSTBAUD_BSD_H */ picocom-3.1/fdio.c000066400000000000000000000072361323455570200141110ustar00rootroot00000000000000/* vi: set sw=4 ts=4: * * fdio.c * * Functions for doing I/O on file descriptors. * * by Nick Patavalis (npat@efault.net) * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #include #include #include #include #include #include /**********************************************************************/ ssize_t writen_ni(int fd, const void *buff, size_t n) { size_t nl; ssize_t nw; const char *p; p = buff; nl = n; while (nl > 0) { do { nw = write(fd, p, nl); } while ( nw < 0 && errno == EINTR ); if ( nw <= 0 ) break; nl -= nw; p += nw; } return n - nl; } int fd_vprintf (int fd, const char *format, va_list ap) { char buf[256]; int len; len = vsnprintf(buf, sizeof(buf), format, ap); buf[sizeof(buf) - 1] = '\0'; return writen_ni(fd, buf, len); } int fd_printf (int fd, const char *format, ...) { va_list args; int len; va_start(args, format); len = fd_vprintf(fd, format, args); va_end(args); return len; } /**********************************************************************/ #ifndef LINENOISE static int cput(int fd, char c) { return write(fd, &c, 1); } static int cdel (int fd) { const char del[] = "\b \b"; return write(fd, del, sizeof(del) - 1); } static int xput (int fd, unsigned char c) { const char hex[] = "0123456789abcdef"; char b[4]; b[0] = '\\'; b[1] = 'x'; b[2] = hex[c >> 4]; b[3] = hex[c & 0x0f]; return write(fd, b, sizeof(b)); } static int xdel (int fd) { const char del[] = "\b\b\b\b \b\b\b\b"; return write(fd, del, sizeof(del) - 1); } int fd_readline (int fdi, int fdo, char *b, int bsz) { int r; unsigned char c; unsigned char *bp, *bpe; bp = (unsigned char *)b; bpe = (unsigned char *)b + bsz - 1; while (1) { r = read(fdi, &c, 1); if ( r <= 0 ) { r = -1; goto out; } switch (c) { case '\b': case '\x7f': if ( bp > (unsigned char *)b ) { bp--; if ( isprint(*bp) ) cdel(fdo); else xdel(fdo); } else { cput(fdo, '\x07'); } break; case '\x03': /* CTRL-c */ r = -1; errno = EINTR; goto out; case '\r': *bp = '\0'; r = bp - (unsigned char *)b; goto out; default: if ( bp < bpe ) { *bp++ = c; if ( isprint(c) ) cput(fdo, c); else xput(fdo, c); } else { cput(fdo, '\x07'); } break; } } out: return r; } #endif /* of LINENOISE */ /**********************************************************************/ /* * Local Variables: * mode:c * tab-width: 4 * c-basic-offset: 4 * indent-tabs-mode: nil * End: */ picocom-3.1/fdio.h000066400000000000000000000024451323455570200141130ustar00rootroot00000000000000/* vi: set sw=4 ts=4: * * fdio.h * * Functions for doing I/O on file descriptors. * * by Nick Patavalis (npat@efault.net) * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #ifndef FDIO_H ssize_t writen_ni(int fd, const void *buff, size_t n); int fd_vprintf (int fd, const char *format, va_list ap); int fd_printf (int fd, const char *format, ...); #ifndef LINENOISE int fd_readline (int fdi, int fdo, char *b, int bsz); #endif #endif /* of FDIO_H */ /**********************************************************************/ /* * Local Variables: * mode:c * tab-width: 4 * c-basic-offset: 4 * indent-tabs-mode: nil * End: */ picocom-3.1/linenoise-1.0/000077500000000000000000000000001323455570200152755ustar00rootroot00000000000000picocom-3.1/linenoise-1.0/.gitignore000066400000000000000000000000451323455570200172640ustar00rootroot00000000000000linenoise_example *.dSYM history.txt picocom-3.1/linenoise-1.0/LICENSE000066400000000000000000000026001323455570200163000ustar00rootroot00000000000000Copyright (c) 2010-2014, Salvatore Sanfilippo Copyright (c) 2010-2013, Pieter Noordhuis All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. picocom-3.1/linenoise-1.0/Makefile000066400000000000000000000002701323455570200167340ustar00rootroot00000000000000linenoise_example: linenoise.h linenoise.c linenoise_example: linenoise.c example.c $(CC) -Wall -W -Os -g -o linenoise_example linenoise.c example.c clean: rm -f linenoise_example picocom-3.1/linenoise-1.0/README.markdown000066400000000000000000000061211323455570200177760ustar00rootroot00000000000000# Linenoise A minimal, zero-config, BSD licensed, readline replacement used in Redis, MongoDB, and Android. * Single and multi line editing mode with the usual key bindings implemented. * History handling. * Completion. * About 1,100 lines of BSD license source code. * Only uses a subset of VT100 escapes (ANSI.SYS compatible). ## Can a line editing library be 20k lines of code? Line editing with some support for history is a really important feature for command line utilities. Instead of retyping almost the same stuff again and again it's just much better to hit the up arrow and edit on syntax errors, or in order to try a slightly different command. But apparently code dealing with terminals is some sort of Black Magic: readline is 30k lines of code, libedit 20k. Is it reasonable to link small utilities to huge libraries just to get a minimal support for line editing? So what usually happens is either: * Large programs with configure scripts disabling line editing if readline is not present in the system, or not supporting it at all since readline is GPL licensed and libedit (the BSD clone) is not as known and available as readline is (Real world example of this problem: Tclsh). * Smaller programs not using a configure script not supporting line editing at all (A problem we had with Redis-cli for instance). The result is a pollution of binaries without line editing support. So I spent more or less two hours doing a reality check resulting in this little library: is it *really* needed for a line editing library to be 20k lines of code? Apparently not, it is possibe to get a very small, zero configuration, trivial to embed library, that solves the problem. Smaller programs will just include this, supporing line editing out of the box. Larger programs may use this little library or just checking with configure if readline/libedit is available and resorting to linenoise if not. ## Terminals, in 2010. Apparently almost every terminal you can happen to use today has some kind of support for basic VT100 escape sequences. So I tried to write a lib using just very basic VT100 features. The resulting library appears to work everywhere I tried to use it, and now can work even on ANSI.SYS compatible terminals, since no VT220 specific sequences are used anymore. The library is currently about 1100 lines of code. In order to use it in your project just look at the *example.c* file in the source distribution, it is trivial. Linenoise is BSD code, so you can use both in free software and commercial software. ## Tested with... * Linux text only console ($TERM = linux) * Linux KDE terminal application ($TERM = xterm) * Linux xterm ($TERM = xterm) * Linux Buildroot ($TERM = vt100) * Mac OS X iTerm ($TERM = xterm) * Mac OS X default Terminal.app ($TERM = xterm) * OpenBSD 4.5 through an OSX Terminal.app ($TERM = screen) * IBM AIX 6.1 * FreeBSD xterm ($TERM = xterm) * ANSI.SYS Please test it everywhere you can and report back! ## Let's push this forward! Patches should be provided in the respect of linenoise sensibility for small easy to understand code. Send feedbacks to antirez at gmail picocom-3.1/linenoise-1.0/example.c000066400000000000000000000042361323455570200171010ustar00rootroot00000000000000#include #include #include #include "linenoise.h" void completion(const char *buf, linenoiseCompletions *lc) { if (buf[0] == 'h') { linenoiseAddCompletion(lc,"hello"); linenoiseAddCompletion(lc,"hello there"); } } int main(int argc, char **argv) { char *line; char *prgname = argv[0]; /* Parse options, with --multiline we enable multi line editing. */ while(argc > 1) { argc--; argv++; if (!strcmp(*argv,"--multiline")) { linenoiseSetMultiLine(1); printf("Multi-line mode enabled.\n"); } else if (!strcmp(*argv,"--keycodes")) { linenoisePrintKeyCodes(); exit(0); } else { fprintf(stderr, "Usage: %s [--multiline] [--keycodes]\n", prgname); exit(1); } } /* Set the completion callback. This will be called every time the * user uses the key. */ linenoiseSetCompletionCallback(completion); /* Load history from file. The history file is just a plain text file * where entries are separated by newlines. */ linenoiseHistoryLoad("history.txt"); /* Load the history at startup */ /* Now this is the main loop of the typical linenoise-based application. * The call to linenoise() will block as long as the user types something * and presses enter. * * The typed string is returned as a malloc() allocated string by * linenoise, so the user needs to free() it. */ while((line = linenoise("hello> ")) != NULL) { /* Do something with the string. */ if (line[0] != '\0' && line[0] != '/') { printf("echo: '%s'\n", line); linenoiseHistoryAdd(line); /* Add to the history. */ linenoiseHistorySave("history.txt"); /* Save the history on disk. */ } else if (!strncmp(line,"/historylen",11)) { /* The "/historylen" command will change the history len. */ int len = atoi(line+11); linenoiseHistorySetMaxLen(len); } else if (line[0] == '/') { printf("Unreconized command: %s\n", line); } free(line); } return 0; } picocom-3.1/linenoise-1.0/linenoise.c000066400000000000000000001062301323455570200174300ustar00rootroot00000000000000/* linenoise.c -- VERSION 1.0 * * Guerrilla line editing library against the idea that a line editing lib * needs to be 20,000 lines of C code. * * You can find the latest source code at: * * http://github.com/antirez/linenoise * * Does a number of crazy assumptions that happen to be true in 99.9999% of * the 2010 UNIX computers around. * * ------------------------------------------------------------------------ * * Copyright (c) 2010-2014, Salvatore Sanfilippo * Copyright (c) 2010-2013, Pieter Noordhuis * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * ------------------------------------------------------------------------ * * References: * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html * * Todo list: * - Filter bogus Ctrl+ combinations. * - Win32 support * * Bloat: * - History search like Ctrl+r in readline? * * List of escape sequences used by this program, we do everything just * with three sequences. In order to be so cheap we may have some * flickering effect with some slow terminal, but the lesser sequences * the more compatible. * * EL (Erase Line) * Sequence: ESC [ n K * Effect: if n is 0 or missing, clear from cursor to end of line * Effect: if n is 1, clear from beginning of line to cursor * Effect: if n is 2, clear entire line * * CUF (CUrsor Forward) * Sequence: ESC [ n C * Effect: moves cursor forward n chars * * CUB (CUrsor Backward) * Sequence: ESC [ n D * Effect: moves cursor backward n chars * * The following is used to get the terminal width if getting * the width with the TIOCGWINSZ ioctl fails * * DSR (Device Status Report) * Sequence: ESC [ 6 n * Effect: reports the current cusor position as ESC [ n ; m R * where n is the row and m is the column * * When multi line mode is enabled, we also use an additional escape * sequence. However multi line editing is disabled by default. * * CUU (Cursor Up) * Sequence: ESC [ n A * Effect: moves cursor up of n chars. * * CUD (Cursor Down) * Sequence: ESC [ n B * Effect: moves cursor down of n chars. * * When linenoiseClearScreen() is called, two additional escape sequences * are used in order to clear the screen and position the cursor at home * position. * * CUP (Cursor position) * Sequence: ESC [ H * Effect: moves the cursor to upper left corner * * ED (Erase display) * Sequence: ESC [ 2 J * Effect: clear the whole screen * */ #include #include #include #include #include #include #include #include #include #include #include #include "linenoise.h" #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 #define LINENOISE_MAX_LINE 4096 static char *unsupported_term[] = {"dumb","cons25","emacs",NULL}; static linenoiseCompletionCallback *completionCallback = NULL; static struct termios orig_termios; /* In order to restore at exit.*/ static int rawmode = 0; /* For atexit() function to check if restore is needed*/ static int mlmode = 0; /* Multi line mode. Default is single line. */ static int atexit_registered = 0; /* Register atexit just 1 time. */ static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN; static int history_len = 0; static char **history = NULL; /* The linenoiseState structure represents the state during line editing. * We pass this state to functions implementing specific editing * functionalities. */ struct linenoiseState { int ifd; /* Terminal stdin file descriptor. */ int ofd; /* Terminal stdout file descriptor. */ char *buf; /* Edited line buffer. */ size_t buflen; /* Edited line buffer size. */ const char *prompt; /* Prompt to display. */ size_t plen; /* Prompt length. */ size_t pos; /* Current cursor position. */ size_t oldpos; /* Previous refresh cursor position. */ size_t len; /* Current edited line length. */ size_t cols; /* Number of columns in terminal. */ size_t maxrows; /* Maximum num of rows used so far (multiline mode) */ int history_index; /* The history index we are currently editing. */ }; enum KEY_ACTION{ KEY_NULL = 0, /* NULL */ CTRL_A = 1, /* Ctrl+a */ CTRL_B = 2, /* Ctrl-b */ CTRL_C = 3, /* Ctrl-c */ CTRL_D = 4, /* Ctrl-d */ CTRL_E = 5, /* Ctrl-e */ CTRL_F = 6, /* Ctrl-f */ CTRL_H = 8, /* Ctrl-h */ TAB = 9, /* Tab */ CTRL_K = 11, /* Ctrl+k */ CTRL_L = 12, /* Ctrl+l */ ENTER = 13, /* Enter */ CTRL_N = 14, /* Ctrl-n */ CTRL_P = 16, /* Ctrl-p */ CTRL_T = 20, /* Ctrl-t */ CTRL_U = 21, /* Ctrl+u */ CTRL_W = 23, /* Ctrl+w */ ESC = 27, /* Escape */ BACKSPACE = 127 /* Backspace */ }; static void linenoiseAtExit(void); int linenoiseHistoryAdd(const char *line); static void refreshLine(struct linenoiseState *l); /* Debugging macro. */ #if 0 FILE *lndebug_fp = NULL; #define lndebug(...) \ do { \ if (lndebug_fp == NULL) { \ lndebug_fp = fopen("/tmp/lndebug.txt","a"); \ fprintf(lndebug_fp, \ "[%d %d %d] p: %d, rows: %d, rpos: %d, max: %d, oldmax: %d\n", \ (int)l->len,(int)l->pos,(int)l->oldpos,plen,rows,rpos, \ (int)l->maxrows,old_rows); \ } \ fprintf(lndebug_fp, ", " __VA_ARGS__); \ fflush(lndebug_fp); \ } while (0) #else #define lndebug(fmt, ...) #endif /* ======================= Low level terminal handling ====================== */ /* Set if to use or not the multi line mode. */ void linenoiseSetMultiLine(int ml) { mlmode = ml; } /* Return true if the terminal name is in the list of terminals we know are * not able to understand basic escape sequences. */ static int isUnsupportedTerm(void) { char *term = getenv("TERM"); int j; if (term == NULL) return 0; for (j = 0; unsupported_term[j]; j++) if (!strcasecmp(term,unsupported_term[j])) return 1; return 0; } /* Raw mode: 1960 magic shit. */ static int enableRawMode(int fd) { struct termios raw; if (!isatty(STDIN_FILENO)) goto fatal; if (!atexit_registered) { atexit(linenoiseAtExit); atexit_registered = 1; } if (tcgetattr(fd,&orig_termios) == -1) goto fatal; raw = orig_termios; /* modify the original mode */ /* input modes: no break, no CR to NL, no parity check, no strip char, * no start/stop output control. */ raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); /* output modes - disable post processing */ raw.c_oflag &= ~(OPOST); /* control modes - set 8 bit chars */ raw.c_cflag |= (CS8); /* local modes - choing off, canonical off, no extended functions, * no signal chars (^Z,^C) */ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); /* control chars - set return condition: min number of bytes and timer. * We want read to return every single byte, without timeout. */ raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */ /* put terminal in raw mode after flushing */ if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal; rawmode = 1; return 0; fatal: errno = ENOTTY; return -1; } static void disableRawMode(int fd) { /* Don't even check the return value as it's too late. */ if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1) rawmode = 0; } /* Use the ESC [6n escape sequence to query the horizontal cursor position * and return it. On error -1 is returned, on success the position of the * cursor. */ static int getCursorPosition(int ifd, int ofd) { char buf[32]; int cols, rows; unsigned int i = 0; /* Report cursor location */ if (write(ofd, "\x1b[6n", 4) != 4) return -1; /* Read the response: ESC [ rows ; cols R */ while (i < sizeof(buf)-1) { if (read(ifd,buf+i,1) != 1) break; if (buf[i] == 'R') break; i++; } buf[i] = '\0'; /* Parse it. */ if (buf[0] != ESC || buf[1] != '[') return -1; if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1; return cols; } /* Try to get the number of columns in the current terminal, or assume 80 * if it fails. */ static int getColumns(int ifd, int ofd) { struct winsize ws; if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { /* ioctl() failed. Try to query the terminal itself. */ int start, cols; /* Get the initial position so we can restore it later. */ start = getCursorPosition(ifd,ofd); if (start == -1) goto failed; /* Go to right margin and get position. */ if (write(ofd,"\x1b[999C",6) != 6) goto failed; cols = getCursorPosition(ifd,ofd); if (cols == -1) goto failed; /* Restore position. */ if (cols > start) { char seq[32]; snprintf(seq,32,"\x1b[%dD",cols-start); if (write(ofd,seq,strlen(seq)) == -1) { /* Can't recover... */ } } return cols; } else { return ws.ws_col; } failed: return 80; } /* Clear the screen. Used to handle ctrl+l */ void linenoiseClearScreen(void) { if (write(STDOUT_FILENO,"\x1b[H\x1b[2J",7) <= 0) { /* nothing to do, just to avoid warning. */ } } /* Beep, used for completion when there is nothing to complete or when all * the choices were already shown. */ static void linenoiseBeep(void) { fprintf(stderr, "\x7"); fflush(stderr); } /* ============================== Completion ================================ */ /* Free a list of completion option populated by linenoiseAddCompletion(). */ static void freeCompletions(linenoiseCompletions *lc) { size_t i; for (i = 0; i < lc->len; i++) free(lc->cvec[i]); if (lc->cvec != NULL) free(lc->cvec); } /* This is an helper function for linenoiseEdit() and is called when the * user types the key in order to complete the string currently in the * input. * * The state of the editing is encapsulated into the pointed linenoiseState * structure as described in the structure definition. */ static int completeLine(struct linenoiseState *ls) { linenoiseCompletions lc = { 0, NULL }; int nread, nwritten; char c = 0; completionCallback(ls->buf,&lc); if (lc.len == 0) { linenoiseBeep(); } else { size_t stop = 0, i = 0; while(!stop) { /* Show completion or original buffer */ if (i < lc.len) { struct linenoiseState saved = *ls; ls->len = ls->pos = strlen(lc.cvec[i]); ls->buf = lc.cvec[i]; refreshLine(ls); ls->len = saved.len; ls->pos = saved.pos; ls->buf = saved.buf; } else { refreshLine(ls); } nread = read(ls->ifd,&c,1); if (nread <= 0) { freeCompletions(&lc); return -1; } switch(c) { case 9: /* tab */ i = (i+1) % (lc.len+1); if (i == lc.len) linenoiseBeep(); break; case 27: /* escape */ /* Re-show original buffer */ if (i < lc.len) refreshLine(ls); stop = 1; break; default: /* Update buffer and return */ if (i < lc.len) { nwritten = snprintf(ls->buf,ls->buflen,"%s",lc.cvec[i]); ls->len = ls->pos = nwritten; } stop = 1; break; } } } freeCompletions(&lc); return c; /* Return last read character */ } /* Register a callback function to be called for tab-completion. */ void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) { completionCallback = fn; } /* This function is used by the callback function registered by the user * in order to add completion options given the input string when the * user typed . See the example.c source code for a very easy to * understand example. */ void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) { size_t len = strlen(str); char *copy, **cvec; copy = malloc(len+1); if (copy == NULL) return; memcpy(copy,str,len+1); cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1)); if (cvec == NULL) { free(copy); return; } lc->cvec = cvec; lc->cvec[lc->len++] = copy; } /* =========================== Line editing ================================= */ /* We define a very simple "append buffer" structure, that is an heap * allocated string where we can append to. This is useful in order to * write all the escape sequences in a buffer and flush them to the standard * output in a single call, to avoid flickering effects. */ struct abuf { char *b; int len; }; static void abInit(struct abuf *ab) { ab->b = NULL; ab->len = 0; } static void abAppend(struct abuf *ab, const char *s, int len) { char *new = realloc(ab->b,ab->len+len); if (new == NULL) return; memcpy(new+ab->len,s,len); ab->b = new; ab->len += len; } static void abFree(struct abuf *ab) { free(ab->b); } /* Single line low level line refresh. * * Rewrite the currently edited line accordingly to the buffer content, * cursor position, and number of columns of the terminal. */ static void refreshSingleLine(struct linenoiseState *l) { char seq[64]; size_t plen = strlen(l->prompt); int fd = l->ofd; char *buf = l->buf; size_t len = l->len; size_t pos = l->pos; struct abuf ab; while((plen+pos) >= l->cols) { buf++; len--; pos--; } while (plen+len > l->cols) { len--; } abInit(&ab); /* Cursor to left edge */ snprintf(seq,64,"\r"); abAppend(&ab,seq,strlen(seq)); /* Write the prompt and the current buffer content */ abAppend(&ab,l->prompt,strlen(l->prompt)); abAppend(&ab,buf,len); /* Erase to right */ snprintf(seq,64,"\x1b[0K"); abAppend(&ab,seq,strlen(seq)); /* Move cursor to original position. */ snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen)); abAppend(&ab,seq,strlen(seq)); if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */ abFree(&ab); } /* Multi line low level line refresh. * * Rewrite the currently edited line accordingly to the buffer content, * cursor position, and number of columns of the terminal. */ static void refreshMultiLine(struct linenoiseState *l) { char seq[64]; int plen = strlen(l->prompt); int rows = (plen+l->len+l->cols-1)/l->cols; /* rows used by current buf. */ int rpos = (plen+l->oldpos+l->cols)/l->cols; /* cursor relative row. */ int rpos2; /* rpos after refresh. */ int col; /* colum position, zero-based. */ int old_rows = l->maxrows; int fd = l->ofd, j; struct abuf ab; /* Update maxrows if needed. */ if (rows > (int)l->maxrows) l->maxrows = rows; /* First step: clear all the lines used before. To do so start by * going to the last row. */ abInit(&ab); if (old_rows-rpos > 0) { lndebug("go down %d", old_rows-rpos); snprintf(seq,64,"\x1b[%dB", old_rows-rpos); abAppend(&ab,seq,strlen(seq)); } /* Now for every row clear it, go up. */ for (j = 0; j < old_rows-1; j++) { lndebug("clear+up"); snprintf(seq,64,"\r\x1b[0K\x1b[1A"); abAppend(&ab,seq,strlen(seq)); } /* Clean the top line. */ lndebug("clear"); snprintf(seq,64,"\r\x1b[0K"); abAppend(&ab,seq,strlen(seq)); /* Write the prompt and the current buffer content */ abAppend(&ab,l->prompt,strlen(l->prompt)); abAppend(&ab,l->buf,l->len); /* If we are at the very end of the screen with our prompt, we need to * emit a newline and move the prompt to the first column. */ if (l->pos && l->pos == l->len && (l->pos+plen) % l->cols == 0) { lndebug(""); abAppend(&ab,"\n",1); snprintf(seq,64,"\r"); abAppend(&ab,seq,strlen(seq)); rows++; if (rows > (int)l->maxrows) l->maxrows = rows; } /* Move cursor to right position. */ rpos2 = (plen+l->pos+l->cols)/l->cols; /* current cursor relative row. */ lndebug("rpos2 %d", rpos2); /* Go up till we reach the expected positon. */ if (rows-rpos2 > 0) { lndebug("go-up %d", rows-rpos2); snprintf(seq,64,"\x1b[%dA", rows-rpos2); abAppend(&ab,seq,strlen(seq)); } /* Set column. */ col = (plen+(int)l->pos) % (int)l->cols; lndebug("set col %d", 1+col); if (col) snprintf(seq,64,"\r\x1b[%dC", col); else snprintf(seq,64,"\r"); abAppend(&ab,seq,strlen(seq)); lndebug("\n"); l->oldpos = l->pos; if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */ abFree(&ab); } /* Calls the two low level functions refreshSingleLine() or * refreshMultiLine() according to the selected mode. */ static void refreshLine(struct linenoiseState *l) { if (mlmode) refreshMultiLine(l); else refreshSingleLine(l); } /* Insert the character 'c' at cursor current position. * * On error writing to the terminal -1 is returned, otherwise 0. */ int linenoiseEditInsert(struct linenoiseState *l, char c) { if (l->len < l->buflen) { if (l->len == l->pos) { l->buf[l->pos] = c; l->pos++; l->len++; l->buf[l->len] = '\0'; if ((!mlmode && l->plen+l->len < l->cols) /* || mlmode */) { /* Avoid a full update of the line in the * trivial case. */ if (write(l->ofd,&c,1) == -1) return -1; } else { refreshLine(l); } } else { memmove(l->buf+l->pos+1,l->buf+l->pos,l->len-l->pos); l->buf[l->pos] = c; l->len++; l->pos++; l->buf[l->len] = '\0'; refreshLine(l); } } return 0; } /* Move cursor on the left. */ void linenoiseEditMoveLeft(struct linenoiseState *l) { if (l->pos > 0) { l->pos--; refreshLine(l); } } /* Move cursor on the right. */ void linenoiseEditMoveRight(struct linenoiseState *l) { if (l->pos != l->len) { l->pos++; refreshLine(l); } } /* Move cursor to the start of the line. */ void linenoiseEditMoveHome(struct linenoiseState *l) { if (l->pos != 0) { l->pos = 0; refreshLine(l); } } /* Move cursor to the end of the line. */ void linenoiseEditMoveEnd(struct linenoiseState *l) { if (l->pos != l->len) { l->pos = l->len; refreshLine(l); } } /* Substitute the currently edited line with the next or previous history * entry as specified by 'dir'. */ #define LINENOISE_HISTORY_NEXT 0 #define LINENOISE_HISTORY_PREV 1 void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) { if (history_len > 1) { /* Update the current history entry before to * overwrite it with the next one. */ free(history[history_len - 1 - l->history_index]); history[history_len - 1 - l->history_index] = strdup(l->buf); /* Show the new entry */ l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1; if (l->history_index < 0) { l->history_index = 0; return; } else if (l->history_index >= history_len) { l->history_index = history_len-1; return; } strncpy(l->buf,history[history_len - 1 - l->history_index],l->buflen); l->buf[l->buflen-1] = '\0'; l->len = l->pos = strlen(l->buf); refreshLine(l); } } /* Delete the character at the right of the cursor without altering the cursor * position. Basically this is what happens with the "Delete" keyboard key. */ void linenoiseEditDelete(struct linenoiseState *l) { if (l->len > 0 && l->pos < l->len) { memmove(l->buf+l->pos,l->buf+l->pos+1,l->len-l->pos-1); l->len--; l->buf[l->len] = '\0'; refreshLine(l); } } /* Backspace implementation. */ void linenoiseEditBackspace(struct linenoiseState *l) { if (l->pos > 0 && l->len > 0) { memmove(l->buf+l->pos-1,l->buf+l->pos,l->len-l->pos); l->pos--; l->len--; l->buf[l->len] = '\0'; refreshLine(l); } } /* Delete the previosu word, maintaining the cursor at the start of the * current word. */ void linenoiseEditDeletePrevWord(struct linenoiseState *l) { size_t old_pos = l->pos; size_t diff; while (l->pos > 0 && l->buf[l->pos-1] == ' ') l->pos--; while (l->pos > 0 && l->buf[l->pos-1] != ' ') l->pos--; diff = old_pos - l->pos; memmove(l->buf+l->pos,l->buf+old_pos,l->len-old_pos+1); l->len -= diff; refreshLine(l); } /* This function is the core of the line editing capability of linenoise. * It expects 'fd' to be already in "raw mode" so that every key pressed * will be returned ASAP to read(). * * The resulting string is put into 'buf' when the user type enter, or * when ctrl+d is typed. * * The function returns the length of the current buffer. */ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt) { struct linenoiseState l; /* Populate the linenoise state that we pass to functions implementing * specific editing functionalities. */ l.ifd = stdin_fd; l.ofd = stdout_fd; l.buf = buf; l.buflen = buflen; l.prompt = prompt; l.plen = strlen(prompt); l.oldpos = l.pos = 0; l.len = 0; l.cols = getColumns(stdin_fd, stdout_fd); l.maxrows = 0; l.history_index = 0; /* Buffer starts empty. */ l.buf[0] = '\0'; l.buflen--; /* Make sure there is always space for the nulterm */ /* The latest history entry is always our current buffer, that * initially is just an empty string. */ linenoiseHistoryAdd(""); if (write(l.ofd,prompt,l.plen) == -1) return -1; while(1) { char c; int nread; char seq[3]; nread = read(l.ifd,&c,1); if (nread < 0) { return nread; } else if (nread == 0) { errno = EAGAIN; return -1; } /* Only autocomplete when the callback is set. It returns < 0 when * there was an error reading from fd. Otherwise it will return the * character that should be handled next. */ if (c == 9 && completionCallback != NULL) { c = completeLine(&l); /* Return on errors */ if (c < 0) return l.len; /* Read next character when 0 */ if (c == 0) continue; } switch(c) { case ENTER: /* enter */ history_len--; free(history[history_len]); if (mlmode) linenoiseEditMoveEnd(&l); return (int)l.len; case CTRL_C: /* ctrl-c */ errno = EAGAIN; return -1; case BACKSPACE: /* backspace */ case 8: /* ctrl-h */ linenoiseEditBackspace(&l); break; case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the line is empty, act as end-of-file. */ if (l.len > 0) { linenoiseEditDelete(&l); } else { history_len--; free(history[history_len]); return -1; } break; case CTRL_T: /* ctrl-t, swaps current character with previous. */ if (l.pos > 0 && l.pos < l.len) { int aux = buf[l.pos-1]; buf[l.pos-1] = buf[l.pos]; buf[l.pos] = aux; if (l.pos != l.len-1) l.pos++; refreshLine(&l); } break; case CTRL_B: /* ctrl-b */ linenoiseEditMoveLeft(&l); break; case CTRL_F: /* ctrl-f */ linenoiseEditMoveRight(&l); break; case CTRL_P: /* ctrl-p */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); break; case CTRL_N: /* ctrl-n */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); break; case ESC: /* escape sequence */ /* Read the next two bytes representing the escape sequence. * Use two calls to handle slow terminals returning the two * chars at different times. */ if (read(l.ifd,seq,1) == -1) break; if (read(l.ifd,seq+1,1) == -1) break; /* ESC [ sequences. */ if (seq[0] == '[') { if (seq[1] >= '0' && seq[1] <= '9') { /* Extended escape, read additional byte. */ if (read(l.ifd,seq+2,1) == -1) break; if (seq[2] == '~') { switch(seq[1]) { case '3': /* Delete key. */ linenoiseEditDelete(&l); break; } } } else { switch(seq[1]) { case 'A': /* Up */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); break; case 'B': /* Down */ linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); break; case 'C': /* Right */ linenoiseEditMoveRight(&l); break; case 'D': /* Left */ linenoiseEditMoveLeft(&l); break; case 'H': /* Home */ linenoiseEditMoveHome(&l); break; case 'F': /* End*/ linenoiseEditMoveEnd(&l); break; } } } /* ESC O sequences. */ else if (seq[0] == 'O') { switch(seq[1]) { case 'H': /* Home */ linenoiseEditMoveHome(&l); break; case 'F': /* End*/ linenoiseEditMoveEnd(&l); break; } } break; default: if (linenoiseEditInsert(&l,c)) return -1; break; case CTRL_U: /* Ctrl+u, delete the whole line. */ buf[0] = '\0'; l.pos = l.len = 0; refreshLine(&l); break; case CTRL_K: /* Ctrl+k, delete from current to end of line. */ buf[l.pos] = '\0'; l.len = l.pos; refreshLine(&l); break; case CTRL_A: /* Ctrl+a, go to the start of the line */ linenoiseEditMoveHome(&l); break; case CTRL_E: /* ctrl+e, go to the end of the line */ linenoiseEditMoveEnd(&l); break; case CTRL_L: /* ctrl+l, clear screen */ linenoiseClearScreen(); refreshLine(&l); break; case CTRL_W: /* ctrl+w, delete previous word */ linenoiseEditDeletePrevWord(&l); break; } } return l.len; } /* This special mode is used by linenoise in order to print scan codes * on screen for debugging / development purposes. It is implemented * by the linenoise_example program using the --keycodes option. */ void linenoisePrintKeyCodes(void) { char quit[4]; printf("Linenoise key codes debugging mode.\n" "Press keys to see scan codes. Type 'quit' at any time to exit.\n"); if (enableRawMode(STDIN_FILENO) == -1) return; memset(quit,' ',4); while(1) { char c; int nread; nread = read(STDIN_FILENO,&c,1); if (nread <= 0) continue; memmove(quit,quit+1,sizeof(quit)-1); /* shift string to left. */ quit[sizeof(quit)-1] = c; /* Insert current char on the right. */ if (memcmp(quit,"quit",sizeof(quit)) == 0) break; printf("'%c' %02x (%d) (type quit to exit)\n", isprint(c) ? c : '?', (int)c, (int)c); printf("\r"); /* Go left edge manually, we are in raw mode. */ fflush(stdout); } disableRawMode(STDIN_FILENO); } /* This function calls the line editing function linenoiseEdit() using * the STDIN file descriptor set in raw mode. */ static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) { int count; if (buflen == 0) { errno = EINVAL; return -1; } if (!isatty(STDIN_FILENO)) { /* Not a tty: read from file / pipe. */ if (fgets(buf, buflen, stdin) == NULL) return -1; count = strlen(buf); if (count && buf[count-1] == '\n') { count--; buf[count] = '\0'; } } else { /* Interactive editing. */ if (enableRawMode(STDIN_FILENO) == -1) return -1; count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt); disableRawMode(STDIN_FILENO); printf("\n"); } return count; } /* The high level function that is the main API of the linenoise library. * This function checks if the terminal has basic capabilities, just checking * for a blacklist of stupid terminals, and later either calls the line * editing function or uses dummy fgets() so that you will be able to type * something even in the most desperate of the conditions. */ char *linenoise(const char *prompt) { char buf[LINENOISE_MAX_LINE]; int count; if (isUnsupportedTerm()) { size_t len; printf("%s",prompt); fflush(stdout); if (fgets(buf,LINENOISE_MAX_LINE,stdin) == NULL) return NULL; len = strlen(buf); while(len && (buf[len-1] == '\n' || buf[len-1] == '\r')) { len--; buf[len] = '\0'; } return strdup(buf); } else { count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt); if (count == -1) return NULL; return strdup(buf); } } /* ================================ History ================================= */ /* Free the history, but does not reset it. Only used when we have to * exit() to avoid memory leaks are reported by valgrind & co. */ static void freeHistory(void) { if (history) { int j; for (j = 0; j < history_len; j++) free(history[j]); free(history); } } /* At exit we'll try to fix the terminal to the initial conditions. */ static void linenoiseAtExit(void) { disableRawMode(STDIN_FILENO); freeHistory(); } /* This is the API call to add a new entry in the linenoise history. * It uses a fixed array of char pointers that are shifted (memmoved) * when the history max length is reached in order to remove the older * entry and make room for the new one, so it is not exactly suitable for huge * histories, but will work well for a few hundred of entries. * * Using a circular buffer is smarter, but a bit more complex to handle. */ int linenoiseHistoryAdd(const char *line) { char *linecopy; if (history_max_len == 0) return 0; /* Initialization on first call. */ if (history == NULL) { history = malloc(sizeof(char*)*history_max_len); if (history == NULL) return 0; memset(history,0,(sizeof(char*)*history_max_len)); } /* Don't add duplicated lines. */ if (history_len && !strcmp(history[history_len-1], line)) return 0; /* Add an heap allocated copy of the line in the history. * If we reached the max length, remove the older line. */ linecopy = strdup(line); if (!linecopy) return 0; if (history_len == history_max_len) { free(history[0]); memmove(history,history+1,sizeof(char*)*(history_max_len-1)); history_len--; } history[history_len] = linecopy; history_len++; return 1; } /* Set the maximum length for the history. This function can be called even * if there is already some history, the function will make sure to retain * just the latest 'len' elements if the new history length value is smaller * than the amount of items already inside the history. */ int linenoiseHistorySetMaxLen(int len) { char **new; if (len < 1) return 0; if (history) { int tocopy = history_len; new = malloc(sizeof(char*)*len); if (new == NULL) return 0; /* If we can't copy everything, free the elements we'll not use. */ if (len < tocopy) { int j; for (j = 0; j < tocopy-len; j++) free(history[j]); tocopy = len; } memset(new,0,sizeof(char*)*len); memcpy(new,history+(history_len-tocopy), sizeof(char*)*tocopy); free(history); history = new; } history_max_len = len; if (history_len > history_max_len) history_len = history_max_len; return 1; } /* Save the history in the specified file. On success 0 is returned * otherwise -1 is returned. */ int linenoiseHistorySave(const char *filename) { FILE *fp = fopen(filename,"w"); int j; if (fp == NULL) return -1; for (j = 0; j < history_len; j++) fprintf(fp,"%s\n",history[j]); fclose(fp); return 0; } /* Load the history from the specified file. If the file does not exist * zero is returned and no operation is performed. * * If the file exists and the operation succeeded 0 is returned, otherwise * on error -1 is returned. */ int linenoiseHistoryLoad(const char *filename) { FILE *fp = fopen(filename,"r"); char buf[LINENOISE_MAX_LINE]; if (fp == NULL) return -1; while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) { char *p; p = strchr(buf,'\r'); if (!p) p = strchr(buf,'\n'); if (p) *p = '\0'; linenoiseHistoryAdd(buf); } fclose(fp); return 0; } picocom-3.1/linenoise-1.0/linenoise.h000066400000000000000000000047601323455570200174420ustar00rootroot00000000000000/* linenoise.h -- VERSION 1.0 * * Guerrilla line editing library against the idea that a line editing lib * needs to be 20,000 lines of C code. * * See linenoise.c for more information. * * ------------------------------------------------------------------------ * * Copyright (c) 2010-2014, Salvatore Sanfilippo * Copyright (c) 2010-2013, Pieter Noordhuis * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __LINENOISE_H #define __LINENOISE_H #ifdef __cplusplus extern "C" { #endif typedef struct linenoiseCompletions { size_t len; char **cvec; } linenoiseCompletions; typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); void linenoiseAddCompletion(linenoiseCompletions *, const char *); char *linenoise(const char *prompt); int linenoiseHistoryAdd(const char *line); int linenoiseHistorySetMaxLen(int len); int linenoiseHistorySave(const char *filename); int linenoiseHistoryLoad(const char *filename); void linenoiseClearScreen(void); void linenoiseSetMultiLine(int ml); void linenoisePrintKeyCodes(void); #ifdef __cplusplus } #endif #endif /* __LINENOISE_H */ picocom-3.1/lowerrts.md000066400000000000000000000112711323455570200152210ustar00rootroot00000000000000Using RTS/DTR lines to control microcontroller reset signals ============================================================ Introduction ------------ In bare-metal software development, it's common practice to "misuse" the UART handshake lines to control the reset signals of the target microcontroller. For example, we often use RTS to drive the microcontroller's reset input pin and DTR to switch between bootloader and normal operation mode. If the microcontroller's reset input uses negative logic (low = reset, high = running), just connect the RTS TTL-level output (which is itself inverted) to the microcontroller's reset input pin. Problem at open --------------- In both Linux and macOS, we observe that the RTS handshake line will be driven high (TTL-level output low) when `open()` is called, even when the port is used without hardware handshake. This behavior cannot be avoided without patching the linux kernel driver (see also http://stackoverflow.com/a/21753723/2880699). Note, that in FreeBSD the RTS handshake line is not been changed upon `open()` but staying left in the state whatever it was before. Tested with FreeBSD 11, both Ftdi and Prolific adapters, picocom 3.1. Work-around using the user-space API ------------------------------------ All we can do in our terminal software, is to reset the RTS signal back to low, immediately after the `open()` call. But even if we do this quite fast, directly after `open()`, the RTS signal will still transition to high for a short time. This may reset the microcontroller. Using the picocom `--lower-rts` command line option, I measured about 50µs-70µs on my Linux machine and 250µs-450µs on my old Macbook Pro running macOS (both tested with an FTDI FT2232H USB-to-Serial adapter). But note that there is no hard guarantee for these times; the OS may preempt picocom between the `open()` and the "lower-rts" calls. If the possibility of a microcontroller-reset is not acceptable, you could guard against it by adding some hardware between the RTS line and the microcontroller's reset input pin. Most likely, a simple low pass RC filter will do the job. Using python3 ------------- Python's serial communication example tool `python3 -m serial.tools.miniterm` provides a command line option `--rts 0` which also lowers the RTS line after opening the port. On the same linux machine mentioned above, I measured an RTS transition duration of about 150µs-170µs. When using something like `python3 -c "import serial; ser = serial.Serial('/dev/ttyUSB0'); ser.setRTS(False); ... "`, I measured a duration of about 180µs-260µs. Deeper analysis --------------- Analyzed using: - Macbook Pro - Ft2232H based Usb serial adapter - Kubuntu 16.04 64 bit - picocom 2.3a, with `--lower-rts` command line option CRTSCTS=0x80000000. This bit is set in tty->termios->c_cflag when the uart is used with Rts/Cts handshake. When calling open() / ftdi_open(), I observed that this flag seems to be undefined. I found it either set or unset, depending on if the last session was with or without hardware handshake. So user space API open() calls the following functions of the `ftdi_sio` kernel driver module: ftdi_open(c_cflag=000008BD) // CRTSCTS is undefined here ftdi_set_termios(c_cflag=000008BD) // called by ftdi_open ftdi_dtr_rts(on=1, c_cflag=000008BD) // regardless if using hw-flow update_mctrl(set=0006, clear=0000) // CRTSCTS still undefined here Hacking the ftdi_sio kernel driver module ----------------------------------------- see also http://stackoverflow.com/a/40811405/2880699 static void ftdi_dtr_rts(struct usb_serial_port *port, int on) { ... /* drop RTS and DTR */ if (on) set_mctrl(port, TIOCM_DTR /*| TIOCM_RTS*/); // <<-- HERE else clear_mctrl(port, TIOCM_DTR /*| TIOCM_RTS*/); // <<-- and maybe even HERE } Steps to perform on e.g. Kubuntu 16.04: ``` $ sudo apt-get install build-essential ;# etc. $ apt-get source linux-image-$(uname -r) ;# of course, neets to have deb-src in /etc/apt/sources.list activated -> this creates a ~/linux-4.4.0 with about 760 MiB source code including linux-4.4.0/drivers/usb/serial/ftdi_sio.c $ cd ~/linux-4.4.0 $ chmod +x debian/scripts/misc/splitconfig.pl $ chmod +x debian/scripts/config-check $ debian/rules genconfigs $ cp CONFIGS/amd64-config.flavour.generic .config and then after each change in drivers/usb/serial/ftdi_sio.c: $ make -C /lib/modules/$(uname -r)/build M=${PWD} drivers/usb/serial/ftdi_sio.ko $ sudo rmmod ftdi_sio.ko $ sudo insmod drivers/usb/serial/ftdi_sio.ko ergo: $ make -C /lib/modules/$(uname -r)/build M=${PWD} drivers/usb/serial/ftdi_sio.ko && sudo rmmod ftdi_sio.ko && sudo insmod drivers/usb/serial/ftdi_sio.ko ``` picocom-3.1/pcasc000077500000000000000000000001501323455570200140270ustar00rootroot00000000000000#!/bin/sh exec picocom \ --send-cmd="ascii-xfr -senv -l5" \ --receive-cmd="ascii-xfr -rnv" "$@" picocom-3.1/pcxm000077500000000000000000000001311323455570200137040ustar00rootroot00000000000000#!/bin/sh exec picocom \ --send-cmd="sx -b -vv" \ --receive-cmd="rx -b -vv" "$@" picocom-3.1/pcym000077500000000000000000000001341323455570200137100ustar00rootroot00000000000000#!/bin/sh exec picocom \ --send-cmd="sb -b -vv" \ --receive-cmd="rb -b -E -vv" "$@" picocom-3.1/pczm000077500000000000000000000001341323455570200137110ustar00rootroot00000000000000#!/bin/sh exec picocom \ --send-cmd="sz -b -vv" \ --receive-cmd="rz -b -E -vv" "$@" picocom-3.1/picocom.1000066400000000000000000000730111323455570200145310ustar00rootroot00000000000000.\" Automatically generated by Pandoc 1.16.0.2 .\" .ad l .TH "PICOCOM" "1" "2018-02-01" "Picocom 3.1" "User Commands" .nh \" Turn off hyphenation by default. .SH NAME .PP picocom \- minimal dumb\-terminal emulation program .SH SYNOPSIS .PP \f[B]picocom\f[] [ \f[I]options\f[] ] \f[I]device\f[] .SH DESCRIPTION .PP As its name suggests, \f[B]picocom(1)\f[] is a minimal dumb\-terminal emulation program. It is, in principle, very much like \f[B]minicom(1)\f[], only it\[aq]s "pico" instead of "mini"! It was designed to serve as a simple, manual, modem configuration, testing, and debugging tool. It has also served (quite well) as a low\-tech serial communications program to allow access to all types of devices that provide serial consoles. It could also prove useful in many other similar tasks. .PP In effect, picocom is not an "emulator" per\-se. It is a simple program that opens, configures, manages a serial port (tty device) and its settings, and connects to it the terminal emulator you are, most likely, already using (the terminal window application, xterm, rxvt, system console, etc). .PP When picocom starts it opens the tty (serial port) given as its non\-option argument. Unless the \f[B]\-\-noinit\f[] option is given, it configures the port to the settings specified by the option\-arguments (or to some default settings), and sets it to "raw" mode. If \f[B]\-\-noinit\f[] is given, the initialization and configuration is skipped; the port is just opened. Following this, if standard input is a tty, picocom sets the tty to raw mode. Then it goes in a loop where it listens for input from stdin, or from the serial port. Input from the serial port is copied to the standard output while input from the standard input is copied to the serial port. Picocom also scans its input stream for a user\-specified control character, called the \f[I]escape character\f[] (being by default \f[B]C\-a\f[]). If the escape character is seen, then instead of sending it to the serial\-device, the program enters "command mode" and waits for the next character (which is called the "function character"). Depending on the value of the function character, picocom performs one of the operations described in the \f[B]COMMANDS\f[] section below. .SH COMMANDS .PP Commands are given to picocom by first keying the \f[I]espace character\f[] which by default is \f[B]C\-a\f[] (see \f[B]OPTIONS\f[] below for how to change it), and then keying one of the function (command) characters shown here. .TP .B \f[I]escape character\f[] Send the escape character to the serial port and return to "transparent" mode. This means that if the escape character (\f[B]C\-a\f[], by default) is typed twice, the program sends the escape character to the serial port, and remains in transparent mode. .RS .RE .TP .B \f[B]C\-x\f[] Exit the program. If the \f[B]\-\-noreset\f[] option is \f[I]not\f[] given, then the serial port is reset to its original settings before exiting, and the modem control lines (typically DTR and RTS) are cleared (lowered) signaling a modem hangup. If \f[B]\-\-noreset\f[] is given (and \f[B]\-\-hangup\f[] is not), then the serial port settings are not reset, and the modem control lines remain unaffected. If both \f[B]\-\-noreset\f[] and \f[B]\-\-hangup\f[] are given, then the serial port settings are not reset, but the modem\-control lines \f[I]are\f[] cleared. .RS .RE .TP .B \f[B]C\-q\f[] Quit the program \f[I]without\f[] resetting the serial port to its original settings. Terminating with the Quit command, picocom behaves \f[I]exactly\f[] as if the \f[B]\-\-noreset\f[] option was given. The serial port is \f[I]not\f[] reset to its original settings, and the modem control lines remain unaffected or are cleared, subject to the \f[B]\-\-hangup\f[] option. .RS .RE .TP .B \f[B]C\-p\f[] Pulse the DTR line. Lower it for 1 sec, and then raise it again. .RS .RE .TP .B \f[B]C\-t\f[] Toggle the DTR line. If DTR is up, then lower it. If it is down, then raise it. May not be supported on some systems. .RS .RE .TP .B \f[B]C\-g\f[] Toggle the RTS line. If RTS is up, then lower it. If it is down, then raise it. Not supported if the flow control mode is RTS/CTS. May not be supported on some systems. .RS .RE .TP .B \f[B]C\-backslash\f[] Generate a break sequence on the serial line. A break sequence is usually generated by marking (driving to logical one) the serial Tx line for an amount of time coresponding to several character durations. .RS .RE .TP .B \f[B]C\-b\f[] Set baudrate. Prompts you to enter a baudrate numerically (in bps) and configures the serial port accordingly. .RS .RE .TP .B \f[B]C\-u\f[] Baud up. Increase the baud\-rate. The list of baud\-rates stepped\-through by this command is: 50, 75, 110, 134, 150, 200, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200. If \f[C]HIGH_BAUD\f[] support is compiled\-in, then the following baud\-rates are also added to the list: 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000. Depending on you system, any of the higher baud rates may be missing. .RS .RE .TP .B \f[B]C\-d\f[] Baud down. Decrease the baud\-rate. The list of baud\-rates stepped\-through by this command is the same as for the "baud\-up" command. .RS .RE .TP .B \f[B]C\-f\f[] Cycle through flow\-control settings (RTS/CTS, XON/XOFF, none). .RS .RE .TP .B \f[B]C\-y\f[] Cycle through parity settings (even, odd, none). .RS .RE .TP .B \f[B]C\-i\f[] Cycle through databits\-number settings (5, 6, 7, 8). .RS .RE .TP .B \f[B]C\-j\f[] Cycle through stopbits\-number settings (1, 2). .RS .RE .TP .B \f[B]C\-c\f[] Toggle local\-echo mode. .RS .RE .TP .B \f[B]C\-w\f[] Write hex. Picococm prompts the user for a string of hexadecimal values. Values can be entered with or without delimeters (separators). The hexadecimal values are translated to binary and sent to the port, exactly as if input at the terminal (i.e. the \f[B]\-\-omap\f[], \f[B]\-\-echo\f[] and \f[B]\-\-emap\f[] options are observed). Example: The following sends the characters "ABCD" to the port. .RS .IP .nf \f[C] C\-a\ C\-w ***\ hex:\ 41\ 4243:44 ***\ wrote\ 4\ bytes\ *** \f[] .fi .RE .TP .B \f[B]C\-s\f[] Send (upload) a file. See \f[B]SENDING AND RECEIVING FILES\f[] below. .RS .RE .TP .B \f[B]C\-r\f[] Receive (download) a file. See \f[B]SENDING AND RECEIVING FILES\f[] below. .RS .RE .TP .B \f[B]C\-v\f[] Show program options (like baud rate, data bits, etc) as well as the actual serial port settings. Only the options and port settings that can be modified online (through commands) are shown, not those that can only be set at the command\-line. See \f[B]DISPLAY OF OPTIONS AND PORT SETTINGS\f[] for details. .RS .RE .TP .B \f[B]C\-h\f[] or \f[B]C\-k\f[] Show help, or show keys. Prints a short description of all available function (command) keys. .RS .RE .PP After performing one of the above operations, the program leaves the command mode and enters transparent mode. Example: To increase the baud\-rate by two steps, you have to type: .RS .PP \f[B]C\-a\f[], \f[B]C\-u\f[], \f[B]C\-a\f[], \f[B]C\-u\f[] .RE .PP assuming of\-course that \f[B]C\-a\f[] is the escape character. .SH OPTIONS .PP Picocom accepts the following command\-line options. .TP .B \f[B]\-\-baud\f[] | \f[B]\-b\f[] Defines the baud\-rate to set the serial\-port (terminal) to. .RS .RE .TP .B \f[B]\-\-flow\f[] | \f[B]\-f\f[] Defines the flow\-control mode to set the serial\-port to. Must be one of: \f[B]x\f[] for xon/xoff (software) mode, \f[B]h\f[] for hardware flow control (RTS/CTS), \f[B]n\f[] for no flow control. (Default: \f[B]n\f[]) .RS .RE .TP .B \f[B]\-\-parity\f[] | \f[B]\-y\f[] Defines the parity mode to set the serial\-port to. Must be one of: \f[B]o\f[] for odd parity mode, \f[B]e\f[] for even parity mode, \f[B]n\f[] for no parity mode. (Default: \f[B]n\f[]) .RS .RE .TP .B \f[B]\-\-databits\f[] | \f[B]\-d\f[] Defines the number of data bits in every character. Must be one of: \f[B]5\f[], \f[B]6\f[], \f[B]7\f[], \f[B]8\f[]. (Default: \f[B]8\f[]) .RS .RE .TP .B \f[B]\-\-stopbits\f[] | \f[B]\-p\f[] Defines the number of stop bits in every character. Must be one of: \f[B]1\f[], or \f[B]2\f[]. (Default: \f[B]1\f[]) .RS .RE .TP .B \f[B]\-\-escape\f[] | \f[B]\-e\f[] Defines the character that will make picocom enter command\-mode (see description above). If \f[B]x\f[] is given, then \f[B]C\-x\f[] will make picocom enter command mode. See also the \f[B]\-\-no\-escape\f[] option. (Default: \f[B]a\f[]) .RS .RE .TP .B \f[B]\-\-no\-escape\f[] | \f[B]\-n\f[] Disables the escape character. Picocom will never enter command\-mode if this option is given. To exit picocom, in this case, you must either close its standard input, or send it the TERM or INT signal. (Default: Disabled). .RS .RE .TP .B \f[B]\-\-echo\f[] | \f[B]\-c\f[] Enable local echo. Every character being read from the terminal (standard input) is echoed to the terminal (standard output) subject to the echo\-mapping configuration (see \f[B]\-\-emap\f[] option). (Default: Disabled) .RS .RE .TP .B \f[B]\-\-noinit\f[] | \f[B]\-i\f[] If given, picocom will not initialize, configure, or otherwise mess with the serial port at start\-up. It will just open it. This is useful, for example, for connecting picocom to already\-connected modems, or already configured ports without terminating the connection, or altering their settings. If required, serial port parameters can then be adjusted at run\-time by commands. See also the \f[B]\-\-noreset\f[] and \f[B]\-\-hangup\f[] options. (Default: Disabled) .RS .RE .TP .B \f[B]\-\-noreset\f[] | \f[B]\-r\f[] If given, picocom will not reset the serial port when exiting. It will just close the respective file descriptor and do nothing more. The serial port settings will \f[I]not\f[] be restored to their original values and, unless the \f[B]\-\-hangup\f[] option is also given, the modem\-control lines will \f[I]not\f[] be affected. This is useful, for example, for leaving modems connected when exiting picocom. Regardless whether the \f[B]\-\-noreset\f[] option is given, the user can exit picocom using the "Quit" command (instead of "Exit"), which makes picocom behave \f[I]exactly\f[] as if \f[B]\-\-noreset\f[] was given. See also the \f[B]\-\-hangup\f[] option. (Default: Disabled) .RS .PP NOTICE: Picocom clears the modem control lines on exit by setting the \f[I]HUPCL\f[] control bit of the respective port. Picocom always sets HUPCL according to the \f[B]\-\-noreset\f[] and \f[B]\-\-hangup\f[] options. If \f[B]\-\-noreset\f[] is given and \f[B]\-\-hangup\f[] is not, then HUPCL for the port is cleared and will remain so after exiting picocom. If \f[B]\-\-noreset\f[] is \f[I]not\f[] given, or if both \f[B]\-\-noreset\f[] and \f[B]\-\-hangup\f[] are given, then HUPCL is set for the port and will remain so after exiting picocom. This is true, regardless of the way picocom terminates (command, read zero\-bytes from standard input, killed by signal, fatal error, etc), and regardless of the \f[B]\-\-noinit\f[] option. .RE .TP .B \f[B]\-\-hangup\f[] | \f[B]\-u\f[] If given together with \f[B]\-\-noreset\f[], picocom will not reset the serial port to it\[aq]s original settings on exit, but it \f[I]will\f[] clear the modem control lines (typically DTR and RTS) to signal a modem hangup. Without the \f[B]\-\-noreset\f[] option (explicitly given, or implied by extiting with the "Quit" command) \f[B]\-\-hangup\f[] has no effect (without \f[B]\-\-noreset\f[] picocom always clears the modem control lines on exit, anyway). .RS .RE .TP .B \f[B]\-\-nolock\f[] | \f[B]\-l\f[] If given, picocom will \f[I]not\f[] attempt to lock the serial port before opening it. Normally, depending on how it\[aq]s compiled, picocom attempts to get a UUCP\-style lock\-file (e.g. \[aq]/var/lock/LCK..ttyS0\[aq]) before opening the port, or attempts to lock the port device\-node using \f[B]flock(2)\f[]. Failing to do so, results in the program exiting after emitting an error\-message. It is possible that your picocom binary is compiled without support for locking. In this case the \f[B]\-\-nolock\f[] option is accepted, but has no effect. (Default: Disabled) .RS .RE .TP .B \f[B]\-\-send\-cmd\f[] | \f[B]\-s\f[] Specifies the external program (and any arguments to it) that will be used for transmitting files. If the argument to \f[B]\-\-send\-cmd\f[] is the empty string (\[aq]\[aq]), the send\-file command is disabled. See \f[B]SENDING AND RECEIVING FILES\f[]. (Default: \f[B]sz \-vv\f[]) .RS .RE .TP .B \f[B]\-\-receive\-cmd\f[] | \f[B]\-v\f[] Specifies the external program (and any arguments to it) that will be used for receiving files. If the argument to \f[B]\-\-receive\-cmd\f[] is the empty string (\[aq]\[aq]), the receive\-file command is disabled. See \f[B]SENDING AND RECEIVING FILES\f[]. (Default: \f[B]rz \-vv\f[]) .RS .RE .TP .B \f[B]\-\-imap\f[] Specifies the input character map (i.e. special characters to be replaced when read from the serial port). See \f[B]INPUT, OUTPUT, AND ECHO MAPPING\f[]. (Defaul: Empty) .RS .RE .TP .B \f[B]\-\-omap\f[] Specifies the output character map (i.e. special characters to be replaced before being written to serial port). See \f[B]INPUT, OUTPUT, AND ECHO MAPPING\f[]. (Defaul: Empty) .RS .RE .TP .B \f[B]\-\-emap\f[] Specifies the local\-echo character map (i.e. special characters to be replaced before being echoed\-back to the terminal, if local\-echo is enabled). See \f[B]INPUT, OUTPUT, AND ECHO MAPPING\f[]. (Defaul: \f[B]delbs,crcrlf\f[]) .RS .RE .TP .B \f[B]\-\-logfile\f[] | \f[B]\-g\f[] Use specified file for logging (recording) serial input, and possibly serial output. If the file exists, it is appended to. Every character read from the serial port is written to the specified file (before input mapping is performed). If local\-echo mode is is enabled (see \f[B]\-\-echo\f[] option and \f[B]C\-c\f[] command), then every character written to the serial port (after output mapping is performed) is also logged to the same file. (Default: no logging) .RS .RE .TP .B \f[B]\-\-initstring\f[] | \f[B]\-t\f[] Send the provided string after opening and configuring the serial port. The init string is sent exactly as if it was input at the terminal. Sending the init string, picocom observes the \f[B]\-\-omap\f[] output mapping, the \f[B]\-\-echo\f[] local\-echo setting, and the \f[B]\-\-emap\f[] local\-echo mapping. This feature is useful, for example, if the serial device needs some special magic strings to start responding. Use \f[B]echo(1)\f[] or \f[B]xxd(1)\f[] to generate special characters like a CR or binary data. Example: .RS .IP .nf \f[C] picocom\ \-t\ "$(echo\ \-ne\ \[aq]AAATZ\\r\\n\[aq])"\ /dev/ttyS0 \f[] .fi .PP Note, that the init string is not sent if \f[B]\-\-noinit\f[] is given. (Default: empty). .RE .TP .B \f[B]\-\-lower\-rts\f[] Lower the RTS modem control signal after opening the serial port. Only supported when flow\-control mode is not set to RTS/CTS, ignored otherwise. Only supported on some systems. .RS .PP If neither \f[B]\-\-lower\-rts\f[] nor \f[B]\-\-raise\-rts\f[] are given, the state of the RTS signal, after opening and configuring the port, is system dependent. On most systems the signal is raised. .RE .TP .B \f[B]\-\-raise\-rts\f[] Raise the RTS modem control signal after opening the serial port. Only supported when flow\-control mode is not set to RTS/CTS, ignored otherwise. Only supported on some systems. .RS .PP If neither \f[B]\-\-raise\-rts\f[] nor \f[B]\-\-lower\-rts\f[] are given, the state of the RTS signal, after opening and configuring the port, is system dependent. On most systems the signal is raised. .RE .TP .B \f[B]\-\-lower\-dtr\f[] Lower the DTR control signal after opening the serial port. Only supported on some systems. .RS .PP If neither \f[B]\-\-lower\-dtr\f[] nor \f[B]\-\-raise\-dtr\f[] are given, the state of the DTR signal, after opening and configuring the port, is system dependent. On most systems the signal is raised. .RE .TP .B \f[B]\-\-raise\-dtr\f[] Raise the DTR control signal after opening the serial port. Only supported on some systems. .RS .PP If neither \f[B]\-\-raise\-dtr\f[] nor \f[B]\-\-lower\-dtr\f[] are given, the state of the DTR signal, after opening and configuring the port, is system dependent. On most systems the signal is raised. .RE .TP .B \f[B]\-\-exit\-aftrer\f[] | \f[B]\-x\f[] Exit picocom if it remains idle for the specified time (in milliseconds). Picocom is considered idle if: Nothing is read (received) from the serial port, AND there is nothing to write (send) to the serial port, AND nothing is read from the standard input (terminal). If \f[B]\-\-exit\-after\f[] is set to zero, then picocom exits after opening and configuring the serial port, after sending the init string (if any, see option \f[B]\-\-initstring\f[]) and imediatelly when it becomes idle. When exiting after being idle, picocom drains the O/S serial port ouput buffer (i.e. waits for data already written to the port to be transmitted) and observes the \f[B]\-\-noreset\f[] and \f[B]\-\-hangup\f[] options as usual. (Default: not set). .RS .PP NOTICE: If \f[B]\-\-exit\-after\f[] is set, reading zero bytes from the standard input (which usually means that whatever was connected there has been closed), will \f[I]not\f[] cause picocom to exit. Instead, picocom will keep running, \f[I]without\f[] reading from stdin, and will exit only when it becomes idle for the specified time, or if it is killed by a signal. If \f[B]\-\-exit\-after\f[] is \f[I]not\f[] set, then reading zero bytes from the standard input causes picocom to exit, after the contents of its output queue have been transmitted. .RE .TP .B \f[B]\-\-exit\f[] | \f[B]\-X\f[] Exit picocom immediatelly after opening and configuring the serial port. Do \f[I]not\f[] read \f[I]anything\f[] from the standard input or from the serial port. When exiting the \f[B]\-\-noreset\f[] and \f[B]\-\-hangup\f[] options are observed as usual. With \f[B]\-\-exit\f[] and \f[B]\-\-noreset\f[] (and possibly \f[B]\-\-hangup\f[]) picocom can be used as a very crude replacement of \f[B]stty(1)\f[]. If an init string is also given (see \f[B]\-\-initstring\f[] option), picocom exits imediatelly after sending (writing) the init string to the serial port and draining the O/S serial port output buffer (i.e. waiting for data written to the port to be transmitted). Again, nothing is read from the standard input, or from the serial port. The \f[B]\-\-exit\f[] option, overrides the \f[B]\-\-exit\-after\f[] option. (Default: Disabled) .RS .RE .TP .B \f[B]\-\-quiet\f[] | \f[B]\-q\f[] Forces picocom to be quiet. Suppresses the output of the initial status and options information, as well as any other information or messages not explicitly requested by the user. Responses to user commands and any error or warning messages are still printed. .RS .RE .TP .B \f[B]\-\-help\f[] | \f[B]\-h\f[] Print a short help message describing the command\-line options. Picocom\[aq]s version, compile\-time options, and enabled features are also shown. .RS .RE .SH DISPLAY OF OPTIONS AND PORT SETTINGS .PP The "show program options" command (\f[B]C\-v\f[]), as well as the commands that change program options (\f[B]C\-b\f[], \f[B]C\-u\f[], \f[B]C\-d\f[], \f[B]C\-f\f[], etc) print messages showing the current values (or the new values, if they were changed) for the respective options. If picocom determines that an actual serial\-port setting differs from the current value of the respective option (for whatever reason), then the value of the option is shown followed by the value of the actual serial\-port setting in parenthesis. Example: .IP .nf \f[C] ***\ baud:\ 115200\ (9600) \f[] .fi .PP This means that a baud rate of 115200bps has been selected (from the command line, or using commands that change the baudrate) but the serial\-port is actually operating at 9600bps (the driver may not support the higher setting, and has silently replaced it with a safe default, or the setting may have been changed from outside picocom). If the option and the corresponding serial\-port setting are the same, only a single value is shown. Example: .IP .nf \f[C] ***\ baud:\ 9600 \f[] .fi .PP This behavior was introduced in picocom 2.0. Older releases displayed only the option values, not the actual serial\-port settings corresponding to them. .PP On startup, after the serial port is opened and configured (and assuming that neither the \f[B]\-\-noinit\f[], nor the \f[B]\-\-quiet\f[] command line options have been given), the port settings are silently checked. If any mismatch is detected between the requested and the actual port settings, a warning message is displayed. You may then use the \f[B]C\-v\f[] command to determine the exact mismatch or mismatches. .SH SENDING AND RECEIVING FILES .PP Picocom can send and receive files over the serial port using external programs that implement the respective protocols. In Linux typical programs for this purpose are: .IP \[bu] 2 \f[B]rx(1)\f[] \- receive using the X\-MODEM protocol .IP \[bu] 2 \f[B]rb(1)\f[] \- receive using the Y\-MODEM protocol .IP \[bu] 2 \f[B]rz(1)\f[] \- receive using the Z\-MODEM protocol .IP \[bu] 2 \f[B]sx(1)\f[] \- send using the X\-MODEM protocol .IP \[bu] 2 \f[B]sb(1)\f[] \- send using the Y\-MODEM protocol .IP \[bu] 2 \f[B]sz(1)\f[] \- send using the Z\-MODEM protocol .IP \[bu] 2 \f[B]ascii\-xfr(1)\f[] \- receive or transmit ASCII files .PP The name of, and the command\-line options to, the program to be used for transmitting files are given by the \f[B]\-\-send\-cmd\f[] option. Similarly the program to receive files, and its arguments, are given by the \f[B]\-\-receive\-cmd\f[] option. For example, in order to start a picocom session that uses \f[B]sz(1)\f[] to transmit files, and \f[B]rz(1)\f[] to receive files, you have to say something like this: .IP .nf \f[C] picocom\ \-\-send\-cmd\ "sz\ \-vv"\ \-\-receive\-cmd\ "rz\ \-vv"\ ... \f[] .fi .PP If the argument to the \f[B]\-send\-cmd\f[] option, or the argument to the \f[B]\-\-receive\-cmd\f[] option is the empty string, then the respective command is disabled. For example, in order to disable both the "send" and the "receive" commands you can invoke picocom like this: .IP .nf \f[C] picocom\ \-\-send\-cmd\ \[aq]\[aq]\ \-\-receive\-cmd\ \[aq]\[aq]\ ... \f[] .fi .PP A picocom session with both, the send\- and the receive\-file commands disabled does not \f[B]fork(2)\f[] and does not run any external programs. .PP During the picocom session, if you key the "send" or "receive" commands (e.g. by pressing \f[B]C\-a\f[], \f[B]C\-s\f[], or \f[B]C\-a\f[], \f[B]C\-r\f[]) you will be prompted for a filename. At this prompt you can enter one or more file\-names, and any additional arguments to the transmission or reception program. Command\-line editing and rudimentary pathname completion are available at this prompt, if you have compiled picocom with support for the linenoise library. Pressing \f[B]C\-c\f[] at this prompt will cancel the file transfer command and return to normal picocom operation. After entering a filename (and / or additional transmission or reception program arguments) and assuming you have not canceled the operation by pressing \f[B]C\-c\f[], picocom will start the external program as specified by the \f[B]\-\-send\-cmd\f[], or \f[B]\-\-receive\-cmd\f[] option, and with any filenames and additional arguments you may have supplied. The standard input and output of the external program will be connected to the serial port. The standard error of the external program will be connected to the terminal which\-\-\-while the program is running\-\-\-will revert to canonical mode. Pressing \f[B]C\-c\f[] while the external program is running will prematurely terminate it (assuming that the program itself does not ignore SIGINT), and return control to picocom. Pressing \f[B]C\-c\f[] at any other time, has no special effect; the character is normally passed to the serial port. .SH INPUT, OUTPUT, AND ECHO MAPPING .PP Using the \f[B]\-\-imap\f[], \f[B]\-\-omap\f[], and \f[B]\-\-emap\f[] options you can make picocom map (translate, replace) certain special characters after being read from the serial port (with \f[B]\-\-imap\f[]), before being written to the serial port (with \f[B]\-\-omap\f[]), and before being locally echoed to the terminal (standard output) if local echo is enabled (with \f[B]\-\-emap\f[]). These mapping options take, each, a single argument which is a comma\-separated list of one or more of the following identifiers: .IP \[bu] 2 \f[B]crlf\f[] (map CR to LF), .IP \[bu] 2 \f[B]crcrlf\f[] (map CR to CR + LF), .IP \[bu] 2 \f[B]igncr\f[] (ignore CR), .IP \[bu] 2 \f[B]lfcr\f[] (map LF to CR), .IP \[bu] 2 \f[B]lfcrlf\f[] (map LF to CR + LF), .IP \[bu] 2 \f[B]ignlf\f[] (ignore LF), .IP \[bu] 2 \f[B]bsdel\f[] (map BS to DEL), .IP \[bu] 2 \f[B]delbs\f[] (map DEL to BS) .IP \[bu] 2 \f[B]spchex\f[] (map special chars (< 0x20 || 0x7f), excl. CR, LF, and TAB to hex) .IP \[bu] 2 \f[B]tabhex\f[] (map TAB to hex) .IP \[bu] 2 \f[B]crhex\f[] (map CR to hex) .IP \[bu] 2 \f[B]lfhex\f[] (map LF to hex) .IP \[bu] 2 \f[B]8bithex\f[] (map chars with 8th\-bit set to hex) .IP \[bu] 2 \f[B]nrmhex\f[] (map normal ascii chars (0x20 <= c < 0x7f) to hex) .PP The "to hex" mappings (\f[B]???hex\f[]) replace the respective characters with their hexadecimal representation (in square brackets), like this: .IP .nf \f[C] CR\ \-\->\ [0d] \f[] .fi .PP If more than one mappings are provided that apply to the same character, then only the first mapping, in the order listed above, is applied. .PP For example the command: .IP .nf \f[C] picocom\ \-\-omap\ crlf,delbs\ \-\-imap\ ignlf,bsdel\ \-\-emap\ crcrlf\ ... \f[] .fi .PP will: .IP \[bu] 2 Replace every CR (carriage return, 0x0d) character with LF (line feed, 0x0a) and every DEL (delete, 0x7f) character with BS (backspace, 0x08) before writing it to the serial port. .IP \[bu] 2 Ignore (not write to the terminal) every LF character read from the serial port, and replace every BS character read from the serial port with DEL. .IP \[bu] 2 Replace every CR character with CR and LF when echoing to the terminal (if local\-echo is enabled). .SH EXITING PICOCOM .PP This section summarizes the conditions in which picocom terminates its operation and what happens in each such condition: .IP \[bu] 2 The exit command is seen in the standard input. That is, the escape character is seen (default \f[B]C\-a\f[]), followed by the exit command character (default \f[B]C\-x\f[]). In this case: The contents of the output queue (data read from the standard input, but not yet written to the port) as well as the contents of the O/S serial port output buffer (data already written to the port, but not yet transmitted) are discarded (flushed). Then the serial port is reset to it\[aq]s original settings, and the modem\-control lines are cleared signaling a modem reset, subject to the \f[B]\-\-noreset\f[] and the \f[B]\-\-hangup\f[] options. After that picocom exits with a success status. .IP \[bu] 2 The quit command is seen in the standard input. That is, the escape character is seen (default \f[B]C\-a\f[]), followed by the quit command character (default \f[B]C\-q\f[]). The behavior in this case is similar to that of the exit command, with one difference: Picocom behaves as if the \f[B]\-\-noreset\f[] option is given (regardless if it actualy is, or not). .IP \[bu] 2 The \f[B]\-\-exit\f[] option is given. See the documentation of this option for a description of what exactly happens in this case. Picocom exits with a success exit status. .IP \[bu] 2 The \f[B]\-\-exit\-after\f[] option is given. See the documentation of this option for a description of what exactly happens in this case. Picocom exits with a success exit status. .IP \[bu] 2 Zero bytes are read from the standard input. This usually means that whatever was connected to picocom\[aq]s standard input has been closed or, if a file was connected, then picocom has read up to the end of the file. In this case, if the \f[B]\-\-exit\-after\f[] option is \f[I]not\f[] given, picocom stops reading from the standard input, and keeps operating normally (i.e. writing to, and reading from, the serial port) until its output queue empties. When this happens, picocom waits for the O/S serial port output buffer to drain and then (subject to the \f[B]\-\-noreset\f[] and \f[B]\-\-hangup\f[] options) resets the serial port to it\[aq]s initial settings, clears the modem\-control lines, and exits. If the \f[B]\-\-exit\-after\f[] option is given then, again, picocom stops reading from the standard input and continues operating normally but, in this case, it does so until it becomes idle for the specified amount of time, before exiting. Picocom exits with a success exit status. .IP \[bu] 2 Picocom is killed by the TERM or INT signal, or an unrecoverable error occurs. In this case picocom behaves as if it had received the exit command, that is: The contents of the output queue and the contents of the O/S serial port output buffer are discarded (flushed). Then, subject to the \f[B]\-\-noreset\f[] and \f[B]\-\-hangup\f[] options, the serial port is reset to its original settings, the modem control lines are cleared, and picocom exits with a failure status. .SH AUTHOR .PP Written by Nick Patavalis .SH AVAILABILITY .PP Download the latest release from: .SH COPYRIGHT .PP Copyright (c) 2003\-2018 Nick Patavalis .PP This file is part of Picocom. .PP Picocom 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. .PP Picocom 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. .PP 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., 59 Temple Place, Suite 330, Boston, MA 02111\-1307 USA picocom-3.1/picocom.1.html000066400000000000000000001132351323455570200154770ustar00rootroot00000000000000 PICOCOM(1)

NAME

picocom - minimal dumb-terminal emulation program

SYNOPSIS

picocom [ options ] device

DESCRIPTION

As its name suggests, picocom(1) is a minimal dumb-terminal emulation program. It is, in principle, very much like minicom(1), only it's "pico" instead of "mini"! It was designed to serve as a simple, manual, modem configuration, testing, and debugging tool. It has also served (quite well) as a low-tech serial communications program to allow access to all types of devices that provide serial consoles. It could also prove useful in many other similar tasks.

In effect, picocom is not an "emulator" per-se. It is a simple program that opens, configures, manages a serial port (tty device) and its settings, and connects to it the terminal emulator you are, most likely, already using (the terminal window application, xterm, rxvt, system console, etc).

When picocom starts it opens the tty (serial port) given as its non-option argument. Unless the --noinit option is given, it configures the port to the settings specified by the option-arguments (or to some default settings), and sets it to "raw" mode. If --noinit is given, the initialization and configuration is skipped; the port is just opened. Following this, if standard input is a tty, picocom sets the tty to raw mode. Then it goes in a loop where it listens for input from stdin, or from the serial port. Input from the serial port is copied to the standard output while input from the standard input is copied to the serial port. Picocom also scans its input stream for a user-specified control character, called the escape character (being by default C-a). If the escape character is seen, then instead of sending it to the serial-device, the program enters "command mode" and waits for the next character (which is called the "function character"). Depending on the value of the function character, picocom performs one of the operations described in the COMMANDS section below.

COMMANDS

Commands are given to picocom by first keying the espace character which by default is C-a (see OPTIONS below for how to change it), and then keying one of the function (command) characters shown here.

escape character

Send the escape character to the serial port and return to "transparent" mode. This means that if the escape character (C-a, by default) is typed twice, the program sends the escape character to the serial port, and remains in transparent mode.

C-x

Exit the program. If the --noreset option is not given, then the serial port is reset to its original settings before exiting, and the modem control lines (typically DTR and RTS) are cleared (lowered) signaling a modem hangup. If --noreset is given (and --hangup is not), then the serial port settings are not reset, and the modem control lines remain unaffected. If both --noreset and --hangup are given, then the serial port settings are not reset, but the modem-control lines are cleared.

C-q

Quit the program without resetting the serial port to its original settings. Terminating with the Quit command, picocom behaves exactly as if the --noreset option was given. The serial port is not reset to its original settings, and the modem control lines remain unaffected or are cleared, subject to the --hangup option.

C-p

Pulse the DTR line. Lower it for 1 sec, and then raise it again.

C-t

Toggle the DTR line. If DTR is up, then lower it. If it is down, then raise it. May not be supported on some systems.

C-g

Toggle the RTS line. If RTS is up, then lower it. If it is down, then raise it. Not supported if the flow control mode is RTS/CTS. May not be supported on some systems.

C-backslash

Generate a break sequence on the serial line. A break sequence is usually generated by marking (driving to logical one) the serial Tx line for an amount of time coresponding to several character durations.

C-b

Set baudrate. Prompts you to enter a baudrate numerically (in bps) and configures the serial port accordingly.

C-u

Baud up. Increase the baud-rate. The list of baud-rates stepped-through by this command is: 50, 75, 110, 134, 150, 200, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200. If HIGH_BAUD support is compiled-in, then the following baud-rates are also added to the list: 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000. Depending on you system, any of the higher baud rates may be missing.

C-d

Baud down. Decrease the baud-rate. The list of baud-rates stepped-through by this command is the same as for the "baud-up" command.

C-f

Cycle through flow-control settings (RTS/CTS, XON/XOFF, none).

C-y

Cycle through parity settings (even, odd, none).

C-i

Cycle through databits-number settings (5, 6, 7, 8).

C-j

Cycle through stopbits-number settings (1, 2).

C-c

Toggle local-echo mode.

C-w

Write hex. Picococm prompts the user for a string of hexadecimal values. Values can be entered with or without delimeters (separators). The hexadecimal values are translated to binary and sent to the port, exactly as if input at the terminal (i.e. the --omap, --echo and --emap options are observed). Example: The following sends the characters "ABCD" to the port.

C-a C-w
*** hex: 41 4243:44
*** wrote 4 bytes ***
C-s

Send (upload) a file. See SENDING AND RECEIVING FILES below.

C-r

Receive (download) a file. See SENDING AND RECEIVING FILES below.

C-v

Show program options (like baud rate, data bits, etc) as well as the actual serial port settings. Only the options and port settings that can be modified online (through commands) are shown, not those that can only be set at the command-line. See DISPLAY OF OPTIONS AND PORT SETTINGS for details.

C-h or C-k

Show help, or show keys. Prints a short description of all available function (command) keys.

After performing one of the above operations, the program leaves the command mode and enters transparent mode. Example: To increase the baud-rate by two steps, you have to type:

C-a, C-u, C-a, C-u

assuming of-course that C-a is the escape character.

OPTIONS

Picocom accepts the following command-line options.

--baud | -b

Defines the baud-rate to set the serial-port (terminal) to.

--flow | -f

Defines the flow-control mode to set the serial-port to. Must be one of: x for xon/xoff (software) mode, h for hardware flow control (RTS/CTS), n for no flow control. (Default: n)

--parity | -y

Defines the parity mode to set the serial-port to. Must be one of: o for odd parity mode, e for even parity mode, n for no parity mode. (Default: n)

--databits | -d

Defines the number of data bits in every character. Must be one of: 5, 6, 7, 8. (Default: 8)

--stopbits | -p

Defines the number of stop bits in every character. Must be one of: 1, or 2. (Default: 1)

--escape | -e

Defines the character that will make picocom enter command-mode (see description above). If x is given, then C-x will make picocom enter command mode. See also the --no-escape option. (Default: a)

--no-escape | -n

Disables the escape character. Picocom will never enter command-mode if this option is given. To exit picocom, in this case, you must either close its standard input, or send it the TERM or INT signal. (Default: Disabled).

--echo | -c

Enable local echo. Every character being read from the terminal (standard input) is echoed to the terminal (standard output) subject to the echo-mapping configuration (see --emap option). (Default: Disabled)

--noinit | -i

If given, picocom will not initialize, configure, or otherwise mess with the serial port at start-up. It will just open it. This is useful, for example, for connecting picocom to already-connected modems, or already configured ports without terminating the connection, or altering their settings. If required, serial port parameters can then be adjusted at run-time by commands. See also the --noreset and --hangup options. (Default: Disabled)

--noreset | -r

If given, picocom will not reset the serial port when exiting. It will just close the respective file descriptor and do nothing more. The serial port settings will not be restored to their original values and, unless the --hangup option is also given, the modem-control lines will not be affected. This is useful, for example, for leaving modems connected when exiting picocom. Regardless whether the --noreset option is given, the user can exit picocom using the "Quit" command (instead of "Exit"), which makes picocom behave exactly as if --noreset was given. See also the --hangup option. (Default: Disabled)

NOTICE: Picocom clears the modem control lines on exit by setting the HUPCL control bit of the respective port. Picocom always sets HUPCL according to the --noreset and --hangup options. If --noreset is given and --hangup is not, then HUPCL for the port is cleared and will remain so after exiting picocom. If --noreset is not given, or if both --noreset and --hangup are given, then HUPCL is set for the port and will remain so after exiting picocom. This is true, regardless of the way picocom terminates (command, read zero-bytes from standard input, killed by signal, fatal error, etc), and regardless of the --noinit option.

--hangup | -u

If given together with --noreset, picocom will not reset the serial port to it's original settings on exit, but it will clear the modem control lines (typically DTR and RTS) to signal a modem hangup. Without the --noreset option (explicitly given, or implied by extiting with the "Quit" command) --hangup has no effect (without --noreset picocom always clears the modem control lines on exit, anyway).

--nolock | -l

If given, picocom will not attempt to lock the serial port before opening it. Normally, depending on how it's compiled, picocom attempts to get a UUCP-style lock-file (e.g. '/var/lock/LCK..ttyS0') before opening the port, or attempts to lock the port device-node using flock(2). Failing to do so, results in the program exiting after emitting an error-message. It is possible that your picocom binary is compiled without support for locking. In this case the --nolock option is accepted, but has no effect. (Default: Disabled)

--send-cmd | -s

Specifies the external program (and any arguments to it) that will be used for transmitting files. If the argument to --send-cmd is the empty string (''), the send-file command is disabled. See SENDING AND RECEIVING FILES. (Default: sz -vv)

--receive-cmd | -v

Specifies the external program (and any arguments to it) that will be used for receiving files. If the argument to --receive-cmd is the empty string (''), the receive-file command is disabled. See SENDING AND RECEIVING FILES. (Default: rz -vv)

--imap

Specifies the input character map (i.e. special characters to be replaced when read from the serial port). See INPUT, OUTPUT, AND ECHO MAPPING. (Defaul: Empty)

--omap

Specifies the output character map (i.e. special characters to be replaced before being written to serial port). See INPUT, OUTPUT, AND ECHO MAPPING. (Defaul: Empty)

--emap

Specifies the local-echo character map (i.e. special characters to be replaced before being echoed-back to the terminal, if local-echo is enabled). See INPUT, OUTPUT, AND ECHO MAPPING. (Defaul: delbs,crcrlf)

--logfile | -g

Use specified file for logging (recording) serial input, and possibly serial output. If the file exists, it is appended to. Every character read from the serial port is written to the specified file (before input mapping is performed). If local-echo mode is is enabled (see --echo option and C-c command), then every character written to the serial port (after output mapping is performed) is also logged to the same file. (Default: no logging)

--initstring | -t

Send the provided string after opening and configuring the serial port. The init string is sent exactly as if it was input at the terminal. Sending the init string, picocom observes the --omap output mapping, the --echo local-echo setting, and the --emap local-echo mapping. This feature is useful, for example, if the serial device needs some special magic strings to start responding. Use echo(1) or xxd(1) to generate special characters like a CR or binary data. Example:

picocom -t "$(echo -ne 'AAATZ\r\n')" /dev/ttyS0

Note, that the init string is not sent if --noinit is given. (Default: empty).

--lower-rts

Lower the RTS modem control signal after opening the serial port. Only supported when flow-control mode is not set to RTS/CTS, ignored otherwise. Only supported on some systems.

If neither --lower-rts nor --raise-rts are given, the state of the RTS signal, after opening and configuring the port, is system dependent. On most systems the signal is raised.

--raise-rts

Raise the RTS modem control signal after opening the serial port. Only supported when flow-control mode is not set to RTS/CTS, ignored otherwise. Only supported on some systems.

If neither --raise-rts nor --lower-rts are given, the state of the RTS signal, after opening and configuring the port, is system dependent. On most systems the signal is raised.

--lower-dtr

Lower the DTR control signal after opening the serial port. Only supported on some systems.

If neither --lower-dtr nor --raise-dtr are given, the state of the DTR signal, after opening and configuring the port, is system dependent. On most systems the signal is raised.

--raise-dtr

Raise the DTR control signal after opening the serial port. Only supported on some systems.

If neither --raise-dtr nor --lower-dtr are given, the state of the DTR signal, after opening and configuring the port, is system dependent. On most systems the signal is raised.

--exit-aftrer | -x

Exit picocom if it remains idle for the specified time (in milliseconds). Picocom is considered idle if: Nothing is read (received) from the serial port, AND there is nothing to write (send) to the serial port, AND nothing is read from the standard input (terminal). If --exit-after is set to zero, then picocom exits after opening and configuring the serial port, after sending the init string (if any, see option --initstring) and imediatelly when it becomes idle. When exiting after being idle, picocom drains the O/S serial port ouput buffer (i.e. waits for data already written to the port to be transmitted) and observes the --noreset and --hangup options as usual. (Default: not set).

NOTICE: If --exit-after is set, reading zero bytes from the standard input (which usually means that whatever was connected there has been closed), will not cause picocom to exit. Instead, picocom will keep running, without reading from stdin, and will exit only when it becomes idle for the specified time, or if it is killed by a signal. If --exit-after is not set, then reading zero bytes from the standard input causes picocom to exit, after the contents of its output queue have been transmitted.

--exit | -X

Exit picocom immediatelly after opening and configuring the serial port. Do not read anything from the standard input or from the serial port. When exiting the --noreset and --hangup options are observed as usual. With --exit and --noreset (and possibly --hangup) picocom can be used as a very crude replacement of stty(1). If an init string is also given (see --initstring option), picocom exits imediatelly after sending (writing) the init string to the serial port and draining the O/S serial port output buffer (i.e. waiting for data written to the port to be transmitted). Again, nothing is read from the standard input, or from the serial port. The --exit option, overrides the --exit-after option. (Default: Disabled)

--quiet | -q

Forces picocom to be quiet. Suppresses the output of the initial status and options information, as well as any other information or messages not explicitly requested by the user. Responses to user commands and any error or warning messages are still printed.

--help | -h

Print a short help message describing the command-line options. Picocom's version, compile-time options, and enabled features are also shown.

DISPLAY OF OPTIONS AND PORT SETTINGS

The "show program options" command (C-v), as well as the commands that change program options (C-b, C-u, C-d, C-f, etc) print messages showing the current values (or the new values, if they were changed) for the respective options. If picocom determines that an actual serial-port setting differs from the current value of the respective option (for whatever reason), then the value of the option is shown followed by the value of the actual serial-port setting in parenthesis. Example:

*** baud: 115200 (9600)

This means that a baud rate of 115200bps has been selected (from the command line, or using commands that change the baudrate) but the serial-port is actually operating at 9600bps (the driver may not support the higher setting, and has silently replaced it with a safe default, or the setting may have been changed from outside picocom). If the option and the corresponding serial-port setting are the same, only a single value is shown. Example:

*** baud: 9600

This behavior was introduced in picocom 2.0. Older releases displayed only the option values, not the actual serial-port settings corresponding to them.

On startup, after the serial port is opened and configured (and assuming that neither the --noinit, nor the --quiet command line options have been given), the port settings are silently checked. If any mismatch is detected between the requested and the actual port settings, a warning message is displayed. You may then use the [C-v] command to determine the exact mismatch or mismatches.

SENDING AND RECEIVING FILES

Picocom can send and receive files over the serial port using external programs that implement the respective protocols. In Linux typical programs for this purpose are:

  • rx(1) - receive using the X-MODEM protocol
  • rb(1) - receive using the Y-MODEM protocol
  • rz(1) - receive using the Z-MODEM protocol
  • sx(1) - send using the X-MODEM protocol
  • sb(1) - send using the Y-MODEM protocol
  • sz(1) - send using the Z-MODEM protocol
  • ascii-xfr(1) - receive or transmit ASCII files

The name of, and the command-line options to, the program to be used for transmitting files are given by the --send-cmd option. Similarly the program to receive files, and its arguments, are given by the --receive-cmd option. For example, in order to start a picocom session that uses sz(1) to transmit files, and rz(1) to receive files, you have to say something like this:

picocom --send-cmd "sz -vv" --receive-cmd "rz -vv" ...

If the argument to the -send-cmd option, or the argument to the --receive-cmd option is the empty string, then the respective command is disabled. For example, in order to disable both the "send" and the "receive" commands you can invoke picocom like this:

picocom --send-cmd '' --receive-cmd '' ...

A picocom session with both, the send- and the receive-file commands disabled does not fork(2) and does not run any external programs.

During the picocom session, if you key the "send" or "receive" commands (e.g. by pressing C-a, C-s, or C-a, C-r) you will be prompted for a filename. At this prompt you can enter one or more file-names, and any additional arguments to the transmission or reception program. Command-line editing and rudimentary pathname completion are available at this prompt, if you have compiled picocom with support for the linenoise library. Pressing C-c at this prompt will cancel the file transfer command and return to normal picocom operation. After entering a filename (and / or additional transmission or reception program arguments) and assuming you have not canceled the operation by pressing C-c, picocom will start the external program as specified by the --send-cmd, or --receive-cmd option, and with any filenames and additional arguments you may have supplied. The standard input and output of the external program will be connected to the serial port. The standard error of the external program will be connected to the terminal which---while the program is running---will revert to canonical mode. Pressing C-c while the external program is running will prematurely terminate it (assuming that the program itself does not ignore SIGINT), and return control to picocom. Pressing C-c at any other time, has no special effect; the character is normally passed to the serial port.

INPUT, OUTPUT, AND ECHO MAPPING

Using the --imap, --omap, and --emap options you can make picocom map (translate, replace) certain special characters after being read from the serial port (with --imap), before being written to the serial port (with --omap), and before being locally echoed to the terminal (standard output) if local echo is enabled (with --emap). These mapping options take, each, a single argument which is a comma-separated list of one or more of the following identifiers:

  • crlf (map CR to LF),
  • crcrlf (map CR to CR + LF),
  • igncr (ignore CR),
  • lfcr (map LF to CR),
  • lfcrlf (map LF to CR + LF),
  • ignlf (ignore LF),
  • bsdel (map BS to DEL),
  • delbs (map DEL to BS)
  • spchex (map special chars (< 0x20 || 0x7f), excl. CR, LF, and TAB to hex)
  • tabhex (map TAB to hex)
  • crhex (map CR to hex)
  • lfhex (map LF to hex)
  • 8bithex (map chars with 8th-bit set to hex)
  • nrmhex (map normal ascii chars (0x20 <= c < 0x7f) to hex)

The "to hex" mappings (???hex) replace the respective characters with their hexadecimal representation (in square brackets), like this:

CR --> [0d]

If more than one mappings are provided that apply to the same character, then only the first mapping, in the order listed above, is applied.

For example the command:

picocom --omap crlf,delbs --imap ignlf,bsdel --emap crcrlf ...

will:

  • Replace every CR (carriage return, 0x0d) character with LF (line feed, 0x0a) and every DEL (delete, 0x7f) character with BS (backspace, 0x08) before writing it to the serial port.

  • Ignore (not write to the terminal) every LF character read from the serial port, and replace every BS character read from the serial port with DEL.

  • Replace every CR character with CR and LF when echoing to the terminal (if local-echo is enabled).

EXITING PICOCOM

This section summarizes the conditions in which picocom terminates its operation and what happens in each such condition:

  • The exit command is seen in the standard input. That is, the escape character is seen (default C-a), followed by the exit command character (default C-x). In this case: The contents of the output queue (data read from the standard input, but not yet written to the port) as well as the contents of the O/S serial port output buffer (data already written to the port, but not yet transmitted) are discarded (flushed). Then the serial port is reset to it's original settings, and the modem-control lines are cleared signaling a modem reset, subject to the --noreset and the --hangup options. After that picocom exits with a success status.

  • The quit command is seen in the standard input. That is, the escape character is seen (default C-a), followed by the quit command character (default C-q). The behavior in this case is similar to that of the exit command, with one difference: Picocom behaves as if the --noreset option is given (regardless if it actualy is, or not).

  • The --exit option is given. See the documentation of this option for a description of what exactly happens in this case. Picocom exits with a success exit status.

  • The --exit-after option is given. See the documentation of this option for a description of what exactly happens in this case. Picocom exits with a success exit status.

  • Zero bytes are read from the standard input. This usually means that whatever was connected to picocom's standard input has been closed or, if a file was connected, then picocom has read up to the end of the file. In this case, if the --exit-after option is not given, picocom stops reading from the standard input, and keeps operating normally (i.e. writing to, and reading from, the serial port) until its output queue empties. When this happens, picocom waits for the O/S serial port output buffer to drain and then (subject to the --noreset and --hangup options) resets the serial port to it's initial settings, clears the modem-control lines, and exits. If the --exit-after option is given then, again, picocom stops reading from the standard input and continues operating normally but, in this case, it does so until it becomes idle for the specified amount of time, before exiting. Picocom exits with a success exit status.

  • Picocom is killed by the TERM or INT signal, or an unrecoverable error occurs. In this case picocom behaves as if it had received the exit command, that is: The contents of the output queue and the contents of the O/S serial port output buffer are discarded (flushed). Then, subject to the --noreset and --hangup options, the serial port is reset to its original settings, the modem control lines are cleared, and picocom exits with a failure status.

AUTHOR

Written by Nick Patavalis

AVAILABILITY

Download the latest release from: https://github.com/npat-efault/picocom/releases

COPYRIGHT

Copyright (c) 2003-2018 Nick Patavalis

This file is part of Picocom.

Picocom 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.

Picocom 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

picocom-3.1/picocom.1.md000066400000000000000000000666301323455570200151410ustar00rootroot00000000000000% PICOCOM(1) --- header: User Commands --- # NAME picocom - minimal dumb-terminal emulation program # SYNOPSIS **picocom** [ _options_ ] _device_ # DESCRIPTION As its name suggests, **picocom(1)** is a minimal dumb-terminal emulation program. It is, in principle, very much like **minicom(1)**, only it's "pico" instead of "mini"! It was designed to serve as a simple, manual, modem configuration, testing, and debugging tool. It has also served (quite well) as a low-tech serial communications program to allow access to all types of devices that provide serial consoles. It could also prove useful in many other similar tasks. In effect, picocom is not an "emulator" per-se. It is a simple program that opens, configures, manages a serial port (tty device) and its settings, and connects to it the terminal emulator you are, most likely, already using (the terminal window application, xterm, rxvt, system console, etc). When picocom starts it opens the tty (serial port) given as its non-option argument. Unless the **--noinit** option is given, it configures the port to the settings specified by the option-arguments (or to some default settings), and sets it to "raw" mode. If **--noinit** is given, the initialization and configuration is skipped; the port is just opened. Following this, if standard input is a tty, picocom sets the tty to raw mode. Then it goes in a loop where it listens for input from stdin, or from the serial port. Input from the serial port is copied to the standard output while input from the standard input is copied to the serial port. Picocom also scans its input stream for a user-specified control character, called the _escape character_ (being by default **C-a**). If the escape character is seen, then instead of sending it to the serial-device, the program enters "command mode" and waits for the next character (which is called the "function character"). Depending on the value of the function character, picocom performs one of the operations described in the **[COMMANDS]** section below. # COMMANDS Commands are given to picocom by first keying the *espace character* which by default is **C-a** (see **[OPTIONS]** below for how to change it), and then keying one of the function (command) characters shown here. *escape character* : Send the escape character to the serial port and return to "transparent" mode. This means that if the escape character (**C-a**, by default) is typed twice, the program sends the escape character to the serial port, and remains in transparent mode. **C-x** : Exit the program. If the **--noreset** option is *not* given, then the serial port is reset to its original settings before exiting, and the modem control lines (typically DTR and RTS) are cleared (lowered) signaling a modem hangup. If **--noreset** is given (and **--hangup** is not), then the serial port settings are not reset, and the modem control lines remain unaffected. If both **--noreset** and **--hangup** are given, then the serial port settings are not reset, but the modem-control lines *are* cleared. **C-q** : Quit the program *without* resetting the serial port to its original settings. Terminating with the Quit command, picocom behaves *exactly* as if the **--noreset** option was given. The serial port is *not* reset to its original settings, and the modem control lines remain unaffected or are cleared, subject to the **--hangup** option. **C-p** : Pulse the DTR line. Lower it for 1 sec, and then raise it again. **C-t** : Toggle the DTR line. If DTR is up, then lower it. If it is down, then raise it. May not be supported on some systems. **C-g** : Toggle the RTS line. If RTS is up, then lower it. If it is down, then raise it. Not supported if the flow control mode is RTS/CTS. May not be supported on some systems. **C-backslash** : Generate a break sequence on the serial line. A break sequence is usually generated by marking (driving to logical one) the serial Tx line for an amount of time coresponding to several character durations. **C-b** : Set baudrate. Prompts you to enter a baudrate numerically (in bps) and configures the serial port accordingly. **C-u** : Baud up. Increase the baud-rate. The list of baud-rates stepped-through by this command is: 50, 75, 110, 134, 150, 200, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200. If `HIGH_BAUD` support is compiled-in, then the following baud-rates are also added to the list: 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000. Depending on you system, any of the higher baud rates may be missing. **C-d** : Baud down. Decrease the baud-rate. The list of baud-rates stepped-through by this command is the same as for the "baud-up" command. **C-f** : Cycle through flow-control settings (RTS/CTS, XON/XOFF, none). **C-y** : Cycle through parity settings (even, odd, none). **C-i** : Cycle through databits-number settings (5, 6, 7, 8). **C-j** : Cycle through stopbits-number settings (1, 2). **C-c** : Toggle local-echo mode. **C-w** : Write hex. Picococm prompts the user for a string of hexadecimal values. Values can be entered with or without delimeters (separators). The hexadecimal values are translated to binary and sent to the port, exactly as if input at the terminal (i.e. the **--omap**, **--echo** and **--emap** options are observed). Example: The following sends the characters "ABCD" to the port. C-a C-w *** hex: 41 4243:44 *** wrote 4 bytes *** **C-s** : Send (upload) a file. See **[SENDING AND RECEIVING FILES]** below. **C-r** : Receive (download) a file. See **[SENDING AND RECEIVING FILES]** below. **C-v** : Show program options (like baud rate, data bits, etc) as well as the actual serial port settings. Only the options and port settings that can be modified online (through commands) are shown, not those that can only be set at the command-line. See **[DISPLAY OF OPTIONS AND PORT SETTINGS]** for details. **C-h** or **C-k** : Show help, or show keys. Prints a short description of all available function (command) keys. After performing one of the above operations, the program leaves the command mode and enters transparent mode. Example: To increase the baud-rate by two steps, you have to type: > **C-a**, **C-u**, **C-a**, **C-u** assuming of-course that **C-a** is the escape character. # OPTIONS Picocom accepts the following command-line options. **--baud** | **-b** : Defines the baud-rate to set the serial-port (terminal) to. **--flow** | **-f** : Defines the flow-control mode to set the serial-port to. Must be one of: **x** for xon/xoff (software) mode, **h** for hardware flow control (RTS/CTS), **n** for no flow control. (Default: **n**) **--parity** | **-y** : Defines the parity mode to set the serial-port to. Must be one of: **o** for odd parity mode, **e** for even parity mode, **n** for no parity mode. (Default: **n**) **--databits** | **-d** : Defines the number of data bits in every character. Must be one of: **5**, **6**, **7**, **8**. (Default: **8**) **--stopbits** | **-p** : Defines the number of stop bits in every character. Must be one of: **1**, or **2**. (Default: **1**) **--escape** | **-e** : Defines the character that will make picocom enter command-mode (see description above). If **x** is given, then **C-x** will make picocom enter command mode. See also the **--no-escape** option. (Default: **a**) **--no-escape** | **-n** : Disables the escape character. Picocom will never enter command-mode if this option is given. To exit picocom, in this case, you must either close its standard input, or send it the TERM or INT signal. (Default: Disabled). **--echo** | **-c** : Enable local echo. Every character being read from the terminal (standard input) is echoed to the terminal (standard output) subject to the echo-mapping configuration (see **--emap** option). (Default: Disabled) **--noinit** | **-i** : If given, picocom will not initialize, configure, or otherwise mess with the serial port at start-up. It will just open it. This is useful, for example, for connecting picocom to already-connected modems, or already configured ports without terminating the connection, or altering their settings. If required, serial port parameters can then be adjusted at run-time by commands. See also the **--noreset** and **--hangup** options. (Default: Disabled) **--noreset** | **-r** : If given, picocom will not reset the serial port when exiting. It will just close the respective file descriptor and do nothing more. The serial port settings will *not* be restored to their original values and, unless the **--hangup** option is also given, the modem-control lines will *not* be affected. This is useful, for example, for leaving modems connected when exiting picocom. Regardless whether the **--noreset** option is given, the user can exit picocom using the "Quit" command (instead of "Exit"), which makes picocom behave *exactly* as if **--noreset** was given. See also the **--hangup** option. (Default: Disabled) NOTICE: Picocom clears the modem control lines on exit by setting the *HUPCL* control bit of the respective port. Picocom always sets HUPCL according to the **--noreset** and **--hangup** options. If **--noreset** is given and **--hangup** is not, then HUPCL for the port is cleared and will remain so after exiting picocom. If **--noreset** is *not* given, or if both **--noreset** and **--hangup** are given, then HUPCL is set for the port and will remain so after exiting picocom. This is true, regardless of the way picocom terminates (command, read zero-bytes from standard input, killed by signal, fatal error, etc), and regardless of the **--noinit** option. **--hangup** | **-u** : If given together with **--noreset**, picocom will not reset the serial port to it's original settings on exit, but it *will* clear the modem control lines (typically DTR and RTS) to signal a modem hangup. Without the **--noreset** option (explicitly given, or implied by extiting with the "Quit" command) **--hangup** has no effect (without **--noreset** picocom always clears the modem control lines on exit, anyway). **--nolock** | **-l** : If given, picocom will _not_ attempt to lock the serial port before opening it. Normally, depending on how it's compiled, picocom attempts to get a UUCP-style lock-file (e.g. '/var/lock/LCK..ttyS0') before opening the port, or attempts to lock the port device-node using **flock(2)**. Failing to do so, results in the program exiting after emitting an error-message. It is possible that your picocom binary is compiled without support for locking. In this case the **--nolock** option is accepted, but has no effect. (Default: Disabled) **--send-cmd** | **-s** : Specifies the external program (and any arguments to it) that will be used for transmitting files. If the argument to **--send-cmd** is the empty string (''), the send-file command is disabled. See **[SENDING AND RECEIVING FILES]**. (Default: **sz -vv**) **--receive-cmd** | **-v** : Specifies the external program (and any arguments to it) that will be used for receiving files. If the argument to **--receive-cmd** is the empty string (''), the receive-file command is disabled. See **[SENDING AND RECEIVING FILES]**. (Default: **rz -vv**) **--imap** : Specifies the input character map (i.e. special characters to be replaced when read from the serial port). See **[INPUT, OUTPUT, AND ECHO MAPPING]**. (Defaul: Empty) **--omap** : Specifies the output character map (i.e. special characters to be replaced before being written to serial port). See **[INPUT, OUTPUT, AND ECHO MAPPING]**. (Defaul: Empty) **--emap** : Specifies the local-echo character map (i.e. special characters to be replaced before being echoed-back to the terminal, if local-echo is enabled). See **[INPUT, OUTPUT, AND ECHO MAPPING]**. (Defaul: **delbs,crcrlf**) **--logfile** | **-g** : Use specified file for logging (recording) serial input, and possibly serial output. If the file exists, it is appended to. Every character read from the serial port is written to the specified file (before input mapping is performed). If local-echo mode is is enabled (see **--echo** option and **C-c** command), then every character written to the serial port (after output mapping is performed) is also logged to the same file. (Default: no logging) **--initstring** | **-t** : Send the provided string after opening and configuring the serial port. The init string is sent exactly as if it was input at the terminal. Sending the init string, picocom observes the **--omap** output mapping, the **--echo** local-echo setting, and the **--emap** local-echo mapping. This feature is useful, for example, if the serial device needs some special magic strings to start responding. Use **echo(1)** or **xxd(1)** to generate special characters like a CR or binary data. Example: picocom -t "$(echo -ne 'AAATZ\r\n')" /dev/ttyS0 Note, that the init string is not sent if **--noinit** is given. (Default: empty). **--lower-rts** : Lower the RTS modem control signal after opening the serial port. Only supported when flow-control mode is not set to RTS/CTS, ignored otherwise. Only supported on some systems. If neither **--lower-rts** nor **--raise-rts** are given, the state of the RTS signal, after opening and configuring the port, is system dependent. On most systems the signal is raised. **--raise-rts** : Raise the RTS modem control signal after opening the serial port. Only supported when flow-control mode is not set to RTS/CTS, ignored otherwise. Only supported on some systems. If neither **--raise-rts** nor **--lower-rts** are given, the state of the RTS signal, after opening and configuring the port, is system dependent. On most systems the signal is raised. **--lower-dtr** : Lower the DTR control signal after opening the serial port. Only supported on some systems. If neither **--lower-dtr** nor **--raise-dtr** are given, the state of the DTR signal, after opening and configuring the port, is system dependent. On most systems the signal is raised. **--raise-dtr** : Raise the DTR control signal after opening the serial port. Only supported on some systems. If neither **--raise-dtr** nor **--lower-dtr** are given, the state of the DTR signal, after opening and configuring the port, is system dependent. On most systems the signal is raised. **--exit-aftrer** | **-x** : Exit picocom if it remains idle for the specified time (in milliseconds). Picocom is considered idle if: Nothing is read (received) from the serial port, AND there is nothing to write (send) to the serial port, AND nothing is read from the standard input (terminal). If **--exit-after** is set to zero, then picocom exits after opening and configuring the serial port, after sending the init string (if any, see option **--initstring**) and imediatelly when it becomes idle. When exiting after being idle, picocom drains the O/S serial port ouput buffer (i.e. waits for data already written to the port to be transmitted) and observes the **--noreset** and **--hangup** options as usual. (Default: not set). NOTICE: If **--exit-after** is set, reading zero bytes from the standard input (which usually means that whatever was connected there has been closed), will *not* cause picocom to exit. Instead, picocom will keep running, *without* reading from stdin, and will exit only when it becomes idle for the specified time, or if it is killed by a signal. If **--exit-after** is *not* set, then reading zero bytes from the standard input causes picocom to exit, after the contents of its output queue have been transmitted. **--exit** | **-X** : Exit picocom immediatelly after opening and configuring the serial port. Do *not* read *anything* from the standard input or from the serial port. When exiting the **--noreset** and **--hangup** options are observed as usual. With **--exit** and **--noreset** (and possibly **--hangup**) picocom can be used as a very crude replacement of **stty(1)**. If an init string is also given (see **--initstring** option), picocom exits imediatelly after sending (writing) the init string to the serial port and draining the O/S serial port output buffer (i.e. waiting for data written to the port to be transmitted). Again, nothing is read from the standard input, or from the serial port. The **--exit** option, overrides the **--exit-after** option. (Default: Disabled) **--quiet** | **-q** : Forces picocom to be quiet. Suppresses the output of the initial status and options information, as well as any other information or messages not explicitly requested by the user. Responses to user commands and any error or warning messages are still printed. **--help** | **-h** : Print a short help message describing the command-line options. Picocom's version, compile-time options, and enabled features are also shown. # DISPLAY OF OPTIONS AND PORT SETTINGS The "show program options" command (**C-v**), as well as the commands that change program options (**C-b**, **C-u**, **C-d**, **C-f**, etc) print messages showing the current values (or the new values, if they were changed) for the respective options. If picocom determines that an actual serial-port setting differs from the current value of the respective option (for whatever reason), then the value of the option is shown followed by the value of the actual serial-port setting in parenthesis. Example: *** baud: 115200 (9600) This means that a baud rate of 115200bps has been selected (from the command line, or using commands that change the baudrate) but the serial-port is actually operating at 9600bps (the driver may not support the higher setting, and has silently replaced it with a safe default, or the setting may have been changed from outside picocom). If the option and the corresponding serial-port setting are the same, only a single value is shown. Example: *** baud: 9600 This behavior was introduced in picocom 2.0. Older releases displayed only the option values, not the actual serial-port settings corresponding to them. On startup, after the serial port is opened and configured (and assuming that neither the **--noinit**, nor the **--quiet** command line options have been given), the port settings are silently checked. If any mismatch is detected between the requested and the actual port settings, a warning message is displayed. You may then use the **[C-v]** command to determine the exact mismatch or mismatches. # SENDING AND RECEIVING FILES Picocom can send and receive files over the serial port using external programs that implement the respective protocols. In Linux typical programs for this purpose are: - **rx(1)** - receive using the X-MODEM protocol - **rb(1)** - receive using the Y-MODEM protocol - **rz(1)** - receive using the Z-MODEM protocol - **sx(1)** - send using the X-MODEM protocol - **sb(1)** - send using the Y-MODEM protocol - **sz(1)** - send using the Z-MODEM protocol - **ascii-xfr(1)** - receive or transmit ASCII files The name of, and the command-line options to, the program to be used for transmitting files are given by the **--send-cmd** option. Similarly the program to receive files, and its arguments, are given by the **--receive-cmd** option. For example, in order to start a picocom session that uses **sz(1)** to transmit files, and **rz(1)** to receive files, you have to say something like this: picocom --send-cmd "sz -vv" --receive-cmd "rz -vv" ... If the argument to the **-send-cmd** option, or the argument to the **--receive-cmd** option is the empty string, then the respective command is disabled. For example, in order to disable both the "send" and the "receive" commands you can invoke picocom like this: picocom --send-cmd '' --receive-cmd '' ... A picocom session with both, the send- and the receive-file commands disabled does not **fork(2)** and does not run any external programs. During the picocom session, if you key the "send" or "receive" commands (e.g. by pressing **C-a**, **C-s**, or **C-a**, **C-r**) you will be prompted for a filename. At this prompt you can enter one or more file-names, and any additional arguments to the transmission or reception program. Command-line editing and rudimentary pathname completion are available at this prompt, if you have compiled picocom with support for the linenoise library. Pressing **C-c** at this prompt will cancel the file transfer command and return to normal picocom operation. After entering a filename (and / or additional transmission or reception program arguments) and assuming you have not canceled the operation by pressing **C-c**, picocom will start the external program as specified by the **--send-cmd**, or **--receive-cmd** option, and with any filenames and additional arguments you may have supplied. The standard input and output of the external program will be connected to the serial port. The standard error of the external program will be connected to the terminal which---while the program is running---will revert to canonical mode. Pressing **C-c** while the external program is running will prematurely terminate it (assuming that the program itself does not ignore SIGINT), and return control to picocom. Pressing **C-c** at any other time, has no special effect; the character is normally passed to the serial port. # INPUT, OUTPUT, AND ECHO MAPPING Using the **--imap**, **--omap**, and **--emap** options you can make picocom map (translate, replace) certain special characters after being read from the serial port (with **--imap**), before being written to the serial port (with **--omap**), and before being locally echoed to the terminal (standard output) if local echo is enabled (with **--emap**). These mapping options take, each, a single argument which is a comma-separated list of one or more of the following identifiers: - **crlf** (map CR to LF), - **crcrlf** (map CR to CR + LF), - **igncr** (ignore CR), - **lfcr** (map LF to CR), - **lfcrlf** (map LF to CR + LF), - **ignlf** (ignore LF), - **bsdel** (map BS to DEL), - **delbs** (map DEL to BS) - **spchex** (map special chars (< 0x20 || 0x7f), excl. CR, LF, and TAB to hex) - **tabhex** (map TAB to hex) - **crhex** (map CR to hex) - **lfhex** (map LF to hex) - **8bithex** (map chars with 8th-bit set to hex) - **nrmhex** (map normal ascii chars (0x20 <= c < 0x7f) to hex) The "to hex" mappings (**???hex**) replace the respective characters with their hexadecimal representation (in square brackets), like this: CR --> [0d] If more than one mappings are provided that apply to the same character, then only the first mapping, in the order listed above, is applied. For example the command: picocom --omap crlf,delbs --imap ignlf,bsdel --emap crcrlf ... will: - Replace every CR (carriage return, 0x0d) character with LF (line feed, 0x0a) and every DEL (delete, 0x7f) character with BS (backspace, 0x08) before writing it to the serial port. - Ignore (not write to the terminal) every LF character read from the serial port, and replace every BS character read from the serial port with DEL. - Replace every CR character with CR and LF when echoing to the terminal (if local-echo is enabled). # EXITING PICOCOM This section summarizes the conditions in which picocom terminates its operation and what happens in each such condition: - The exit command is seen in the standard input. That is, the escape character is seen (default **C-a**), followed by the exit command character (default **C-x**). In this case: The contents of the output queue (data read from the standard input, but not yet written to the port) as well as the contents of the O/S serial port output buffer (data already written to the port, but not yet transmitted) are discarded (flushed). Then the serial port is reset to it's original settings, and the modem-control lines are cleared signaling a modem reset, subject to the **--noreset** and the **--hangup** options. After that picocom exits with a success status. - The quit command is seen in the standard input. That is, the escape character is seen (default **C-a**), followed by the quit command character (default **C-q**). The behavior in this case is similar to that of the exit command, with one difference: Picocom behaves as if the **--noreset** option is given (regardless if it actualy is, or not). - The **--exit** option is given. See the documentation of this option for a description of what exactly happens in this case. Picocom exits with a success exit status. - The **--exit-after** option is given. See the documentation of this option for a description of what exactly happens in this case. Picocom exits with a success exit status. - Zero bytes are read from the standard input. This usually means that whatever was connected to picocom's standard input has been closed or, if a file was connected, then picocom has read up to the end of the file. In this case, if the **--exit-after** option is *not* given, picocom stops reading from the standard input, and keeps operating normally (i.e. writing to, and reading from, the serial port) until its output queue empties. When this happens, picocom waits for the O/S serial port output buffer to drain and then (subject to the **--noreset** and **--hangup** options) resets the serial port to it's initial settings, clears the modem-control lines, and exits. If the **--exit-after** option is given then, again, picocom stops reading from the standard input and continues operating normally but, in this case, it does so until it becomes idle for the specified amount of time, before exiting. Picocom exits with a success exit status. - Picocom is killed by the TERM or INT signal, or an unrecoverable error occurs. In this case picocom behaves as if it had received the exit command, that is: The contents of the output queue and the contents of the O/S serial port output buffer are discarded (flushed). Then, subject to the **--noreset** and **--hangup** options, the serial port is reset to its original settings, the modem control lines are cleared, and picocom exits with a failure status. # AUTHOR Written by Nick Patavalis # AVAILABILITY Download the latest release from: # COPYRIGHT Copyright (c) 2003-2018 Nick Patavalis This file is part of Picocom. Picocom 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. Picocom 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA picocom-3.1/picocom.1.pdf000066400000000000000000001004111323455570200152740ustar00rootroot00000000000000%PDF-1.4 %âãÏÓ 3 0 obj << /Contents [4 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 4 0 obj << /Filter [/FlateDecode ] /Length 3206 >> stream xœ­ZYsÛF~ׯ˜åU¥ ¸Ú'¯ì¤´µ>1µµeæ‡$, q˜âþ†ìOÑÜî9€0€¤ÄIÙ&È9z¾îþú|%1áþwr¼²È?áÏ—+“ü öW_É?VWrL`“ rÉêxõãO±L²ÚÁ Ure¦ ÎäóòÓÝíÇÛï×Kk}Mþì×ä‡Ðbk.«hIn‹ã1ηÕ÷XPðúw²úgïx^ˆÇc‡úñ'ˇÈç‰ñ €å‡k²úr~À ÕöJàòæý;Âö*×ó}Û2á߀ô°ÌÀˆFRxÝÎìÝ”®ßâóò”&ERùŽdù$?Ó<=Æ™|Ü6ÇÍSMKøºû’›,®Ó"—_œÊb_ưØ-;2ì×áÕ›!„½ÿχŸîïîŸÇÇ ;t¦÷í¡bã­ú¸°Å{¦Œc>÷µÂþÏÅ ±©f—ø}n‰å–2‰S1’å·4á?©ˆ™¦á¾ãÞ !ÑÛw÷·¿Þ}ZÝ}üð<Ìðkæ;ÜúYCôÃp¼ó Õ2­Ûy|¤òsÕì÷´ª«›h~S¡:î·sà§í.ñ÷0{ž=$Ž»º=H+ë2U†§y’ž2ÚþöMxŒk¹†ã÷4MËKOÑ ½ÀWÑë(õØ$’¥œ­ϰB³Ç-t9vø8ØTA¬Ûä†yv!i½6-³" „{AÒ¼ªi¼%ÅŽ,pÅßÈ]MÎ\Û² ·µàn©¸"[Z¥ûœnI] ðo|Bà~0O ̈I•=LßÄÙÍõ€ ߨØÒ#IŠü}S2ÞL*Í÷7∳Ëy0óX0A Ò™Aðˆ)«Té-8ndjÄß’õòk“Ö”œi–AØcÇÉ >-ô ËÏ:ƒ‚Zaùlp|VÏÖŸ4yl@¡ì˜FŠ8Ç™ÜÒr`‚nO' ­*1šÔ—­P·ÀH|¢é–FCHL0ë׸! HŽnè–ŠS¡Fª"£‡4)šlË@Õ×qú÷g`ðèXð½k„㣤©è®ÉÀtÑ’øV¾eØY/¤¨^€å¥Y\’:®*C# V£SÆ]NèNŒ G#ÎŽ&õ ÜEÒŠäE &IœnŠrAN´|ª(Ç(í¡S-Â^œh^ÝH§s“x“Äy-K/¯ÐË©(k°Ùº¾´š÷õâ£âÑ Á‡€½A¯5:UŽ „ÉáxÌœÒä¤D’*‘Ç#—¢!q‰n]TµÂb–g¸NŸ3Á‰–áilöÌJà¢Ëø¼^éÏÛTèÕpRU´sšo¥ š¶j\åtÊ„“ÝGœ{CÊÇo Ëê”x”¶}Ch¬¯5Fã…°¶N¨hÞZDUÇ% ˜ sA/kUW }*8×ô Ϲ7äHF¨º¼ÈŸxêêàkE[bŽmxrξ9Ò¼6Èo9¸n%³Œ€ œúx­7OOy¡¢Äš6©ÇFHn ìºFðšóÞ –­›0<™¹ƒâgiÁ¤:Ñ$ý¸{sa?ðŸ$6¶o–5Þ€ƒS~À¶1¸G N$H ”ILظÉêQ¤÷¼P|)Ýúš{<3Û€¥ttÓ1œã òÈŽèUóYÑÍ‹(P‚H Mȼ£W©AÅ­ÀˆÓÿÆÜð8i´Qõ\=¤§ÝþÇkœÈõõH1Âô/MÅ]‡náä?µ!׳{™<ÃѨõÌ¢ÿ;’îÐ)óm\çå§F28¥ ®¾6¸v,Ï´&T×iÎÓ§Rq+dP÷¾ • ÇÕc‘ÓâDÎÍ(®¥@R@';°R~ˆ]ÉØf›‚jàKöÈ¢¥4nìàGD!)N)Ëé4ÂÙlÇ–‘xMëŸiFU¹zƒZÐÛí4‚~Xó-‰sÆr¹¬ ¦á»T5„”#ƒ)ÆÄ"±ä0Ôº, ‰9Äeœ@ Å‘«S)Š ²¶î7¨)Hzj ŸD8Wh–Ù3WØR¦>Ý^"¹f¢Ì¹ïz¹¡`Îr—Í¥-{€¦ø¨4ì`°.#ª™2âö)0º3 íŒáw£ ¦C”8ÀŒ¨àŽ\­=*šoÑCÓºo O2}±ƒÈp#}þ©HfSÀÞ´„ú&á-%Èáå “.‡‰úRôÐïc¸E‹Âms! ç*a»ûX+Ç_/Á1 &@Óïli±kò„±e;rp“·ô$`ßp¤¨SlȆ‚ …²†Ž¢Lð ŽË÷mƒœ?ËÐÂñPY䔈ŀ¢KQ²@m˜”醢§÷½e¬n?¾ÿæÃÛûk‡ˆ™ðš}x8¿ÇGlì†Ê àQ 3ûÞWOöµ1ìÆ¸J«í%½wÜšëŸj® ãBï:ƒ=Ÿm¸Ψ#Û§m_¤¤£™c¾"À£#J…C õG qXäö‘«OíÅR¶ÆE/<ôΑæ)NF¤éGl‰ïEšÌóf)b·ÎÙ6Ña'mø)ž3_Ló© UmÓµG=̬‹7ë­¥cÇDÓî83~:ˆ8î@u«©ŽÏ¨bðý|)…LI5?È„fGž×´Â -Á¬—‚¡ÐiÉbІ”78¬ÆåžÃc6dHtC ºNä¨=bžEh¹/¶5ijúÒÇu‰Zú-ï)GwÇ ÓDIë¦d~¸¨KH€NàÖy½è’I0Ë#sѸI‡á…ñ#½0Z9ÖSß85èÅ…Í¥«,ÀÒÕúhDƦqEnLª)„4gó‚é³)XÞ0qŠI$ÚɱçŽ;Ñ”Ÿ$‘zœ³þŒNäw¢¿"{Ò¬È›Ž¬Îj{J¹(­›ÎW€¼îÚÝó7"y1· 1x%B4{m™ëÊåçM'È1ÊtÏÚøc°C=šm`CÁœD €Ò°@ßö‘Q˜¶Ù̪ƒ,Í)vÀjSLÚ.äíêW6öWÁ]Že˜šÀ±ºÇ¾ìždþ&¢(¿åìg½”)Œ©Í=ÏÀxÈ¢Ø}‡ºø6#7§¹î€j4@RVôJ£Ñ´ ï•IÅz‰ÐMw/ø)^(Ø%D-ù„Ö¤|¾&[¸9q¿ Ú_k<¨;læ2kœ7N.¤ÉãLÑ•€¦”QØ-ÆF”RJŸmSÔ‡$ªàvd,¥S¦ AÚ~¥.±2š½{‘*ty&¶¯"û¯óÀ”äEOèŽî¢§Ö4šÂp‚z™>ŸúúÔgªK‘D¾²³8Å? 0F í«×Q¦?HF™¯3Qf0£;ê/M?ÊLfäç´>ͼ1uÔJ¢máOíÅ)¨³Th.‹[Šo§sÕ·7³+a[6–¦šä‚wþqAÑ',À›¸4a°ˆµ+r7ô Ûz6”NÏE6éw³/PÙ¢4ûÒœì2ïkÝ5ûn ùs„úƒ.û«“„³Ð^ jü.î:úxSöLG_¡DšØUùP5þMgBü9­F¦ÛSµ }æ¹,FôŸ²Ó6u¬ªzc˜¶¼åD#ßÈFä‹&Òîmíý&'ØîUáÅ:âa÷…Íæ ¬!+¿—…µhH®× "¹~WÜiŽä¦ú¾Ÿš¬¢ì4˜¨!¾ý«h;&±7Y³šÙ‚À“(•p§ë¸Ç{+æðƒî[ª9·=[@¨Cä™'oÕàÌãñ+6ZåQì÷ÙHñ ’ìæ$oûR(·*CpøÜ”åçòvÕ÷ _“PŸeH—ØÁÜ÷ñ…ñ†˜­P[ÆUÍ Ýí;ç×püfVwoAnÿì cýAðýàš/ƒ\®gxšq«{Eb(D'ÝË'0T§,ÌÓAÿ=tõôÔŸîôáß´bó¿¶vÑÞÁµY32" 'Ž©Y‹’V÷?Þ®î ´•û[És?tH¹Õ/eCŠcJϪ¦lÇ×j·O›8y¨²¸:ÌÙ=QtüLsl™S¨à6%€x¾64O¨l÷‹lXXÊ›á(4‹ªa%é^,Å.»qù€iÙXcÖ¸ŠX/·%/ß-W©Õ öÚÞë_lïAù©ˆ·zdò+¶œÄÇ¢ÉkÖLÁe¨¿«SÁ¯1Ø»bòõ׈^qß\Æ£‹:õH-Àò Ñ1¬?ý^q÷z1°#3Û´ÂLûó//:»Õ?¤ù'à"OùnE~¹úåêÿ<Œ³ endstream endobj 12 0 obj << /Contents [13 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 13 0 obj << /Filter [/FlateDecode ] /Length 2539 >> stream xœÅZër›Hþï§èÊ/9¥`î ÿKd;ã©™ØkfgËÞÚBÐ²È š[UûÉ£ðŽ{ú†hÑ '›ª+2 ¾œóõ¹|çà¿‘…LøáŸñæÄB?ÃÿO'&zò7z·8‘ß6 f.Zlà«Ç“³+Y&Z¬ànŸ˜†iÂźŸÜ^Ïoæ7¿>L¬‡Sô½ÿNÑ›ÐbkN~¯p‰æd³‰ò¤ú v<ýZüܪh¹. ¼ëHµ¢M’mÕ)É+ã->í›! \˰ÛágW–/@Äל7K¶ØFEuÆÛ;\£e´M@ l t[’MQWhG¶¨&ç5@µ#P¾Ýà2£,Û¡‡Iš£eQÁ¡(&ù—Çm‰+T¯1ˆÓ(C)k "ö¬'ǤLÒü1Û1=\ßð|:e‘ˆ°,Ûp‚¥ ’`mÇÀRgìÁz0 m8]çq‰£ 3]):p÷YZÕˆ¬öÏ+TÕ¸(pÒÔë’l×h¹ƒ™i 1+DiuŽ•ÏÖ¼s-/W$ËÈ)ßÀ6}#œI Ùó6Ô…>*1вР(IpB­ºgtÞ‡Û|=ܶcr }“Aé™ôŸ€Bk[GS|Á5ÙÑð'¶üÊO4Ûû®~{GÎuäj.'v œSÏA$gŽ[íÀÜ6SðJ¾˜€1óúHí¨‘R0Öéãüœ‚†8h›h‡–X# ×w¦MZU°{ß=}Ç3ücî©’¸çÁŒ÷L—Úq GÆÛðZëÈ Œ;/·*Â[#ã·—^¨ßPÃéÞ“•v^Õ}zàýÊ„*EªLá¡ûôOÅvôˆ°HmÀ*´"%;ìWLÆmñJã`Az(Ô·Žžœ2HžÜjìäÔ{9ç»8£±”ǯâý™hÌö©TS—$ƒ$S×`y¤¢|Jè–fÊâîl¾¸›¢?o>œýysuÕžiÈå$ǧ\<~•î‰Éneü"ET¦õ®«¯ôMÛ3BOI“Ÿyúì<Þ¯Šó)"I2¦aàçê ©e:¦¥:cHÏ$ª£eZW ðŒ%D¤ŽÂîü) ¦(ÔËíùÇ©€:HÊýiLno ¨rW5)ä¶ Þë%vfÇ££:HJI¬™±`ã=ñú&AA‘Œ§kp¼&hC¬×¶‡u÷iL\uÆ^®€ÅCfvî¸{6؉æÏºMc?›nŒ,8‹‰ï[à§Ý{ŽÝÛHÞ%œåpÌ—2Z3Ó€ôßCø9Jpœn€ æÝÐp¼¾2Q¶Å•þh5¶üþblŠ#`Þ˜Ósœô‚g™zTŸÒz Ðßd[£géÃ*ÔT+ q&ªI ”^PÙ®nNðºõĦT¬.£¼Ê C2*¶Ló¨Ü±ú¡múš¸³P¯‰àq”RN‘NÄÕ@\C½90]¡4/@ï¨f³Añ HÑZÆ ô>”ü·µpnÇMC6Qq`Ê2e¨ÌWyS©g²ã6ˬÁ¶Yƒ¬¨”dÐTY4ìgm²wàyƲËêÛ&N¨I\>G›"Ãç]ë? Gœ¡³]g ñs8섊ñl.føêí»ùÅ+Ô9Yc° Mäæa%2o¨çúTvTíéœÃZü~òúõk9gŸÏåµkµW¶ëœ»®n5×Yí©$5n‘Ë'‡ì†î…ZW)B­«©¡çM5jft{à~“m‘‘(¡Õ<ú’Qg¸ÃCÎs.?\\x/mííYüM>^Î/¯ÿè|wuýËå݈áN–˜uÔøBǘµ9Š}Çse <îîKz®¶Pަ™ñǘ“H^P彘}Ȳ<±á¹­qŽüÿ~>DzóûÎÀ™½ àSÉ3ø‘µwäÎÑ$ðr¾íé+!$Ño›ûî¬ó«ÛØ8="{þRÙsÙ¥™|•Î9ðJ¡•Žÿ¬JØ¢ïA Êm³ú|4žçº$0'7ä2Þ@G½iÄÛpݨƒ ýM@ÇEÄR?ÌÆ›`ƒ ‰ì‡M¸ òî–Š_º‰ì9!Iǧyß›†Ú*즃€|‡eöñ€ú†R÷ 7D‘T|ËðÜjŠÝ?ÜÑ2 ‘ýcXßýw5û?¯ñ^$ئ¾1í7æÿ¼èø6*3¦Øyû@y¹@¿üvò_·ìaendstream endobj 16 0 obj << /Contents [17 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 17 0 obj << /Filter [/FlateDecode ] /Length 2899 >> stream xœÕZÉ’ÛH½×Wdø¤Šiî¤|œrõLõ´w9æ`Í¢R*Ú\d.®RG‚çSôäB%Å$%•1n»C”˜ xüF,bÂüÿqve‘ßáß—+“üýêùÛüJþØ$˜¹džÁO›«¿yÄ2É| WóøÊ4L><Ï“ww7ooÞ¾^L¬Å5yêŸkò<´˜ÌɧЖä¦È²(_U¿B ªàõ¿ÉüwØŒå‹ÝÈÝZfH/äÛínp¿_Eu´LêŠüEö+)Â;–àº$p}„WôGN+RßS’7ÙöW¬ %Lj’Ê¥Z®mØÊ›¯®ØâÉ÷k2ÿrå¡'¿>È¥åŽÄ÷QÅ5-¹Ï2_Üiž¼Ó ¯›ª£Ø_?YRõªÈ»—ë—êeÏj\5©ÖA>kÊ—ý"ÿ)‹‚§, u̱§¬…ÑÇÕèŸ'Q“Ö//’ο„ñ¯õ³g†­‡XU[ ±í(Ĭ@/C 2«™ûÿ2ëØÎͦ¤(ÉÀ2û\çۮᛗ:¿§Ô9Î7MÃÕ;ŸVq´¥èz:æz? õ×·ž‚«¨&Iš’,ú*‘>3¼™ÆÅd›ÄE\d„æ¸4æÙwŸ+ ƪ(%+бL¶uRä$Z\žmùLÈ’ÃÓŵAîÖg8ýñȾ+¾Þ IE6‰Ø¨o'ôR·ŸOÑvù–>Onö]8å!´²¸a‚Ææ·…3#ðÏ66Ac„|cGiU0o)´ßç…@͈b“‚ùË`[ï˜ÐwUrð²˜`w††m_Ñ"ÂwC[/•íaPä£Aáxz!¯’*Z¦",„°£Ê7ÍXPQ &$Ï1™Ë¸üÔ×¢ÿ¢Ðu}Ï8sãJ|Áæ1¨Ë± v=GßzýÚ°.™2Çñú€‘A5³ Óíó(ÏOàØõqùrÔ¤±J­~ÀR.AŸ-Æ„ìû´† ³£ïFKçc±Á™1ÖQaR?4fãí ,‘5ÿÙû&©ŸõÍëÌÒ½ìØ“$‡b „¼X“g· ýÙâz VLâ{eèͶ¥Ó½juYÒ{ "ßpO5“bùQ-îÛD À2¬°»ìš‰t7^ç[¯$ëÑžÿ€…@©GçAaòÀ˱g:®®4Àái@ ö¿N8PfΜ²œjõtçêéLGoÍ€æÍ[¾=W1õAæüîæö¥[@óM£²:¤iÒMÓE(¶¦œ)@;EqíZé(­ÿãÓ»›?FM$.QµLê¶Š®•âª)¥Žg÷ìÐÒ´†cÃ`œŒ e!íõ›Ïp<Ãêœx†¥Cç®BËT„mDq\”+f¦1<©©Ó·”Ñàÿ~+ìû8R\óØÒÈkÏŒÇ3œðÂýh’?Š1/HþŒ"þTô”v2UÀØÖ(Þš d2APõK‹Á<¸¯3..i%íÃõƒÀûGkœ ÉHk¦_G$‚èUÎ(íŽÂH.õçÓè߆400ï‚î‚·éÉš,¡K8½±Ð¼§¿¦í(ô‰7˜yvŠx‹Ú6íG¬5pÂf <5%,Q1žŠ‰‰~ fOçÐ#P»@²m…é!IN}ê².\¶lÖ3ÜnŸC=‹µ¦ šîàɃ<‚2B²Ñî0J#¨{ Iݦ|Žú'-‹ýr‡?±‘êñ¤ú+˜ È:B6nžöu´gý Å;G9ÉW«qü[–…˜4@Ê›i:Œ)¡uŒd½%Mëªcâ ,{ò( ‰çž# L]ì`àFFNWš±éŠí;z ?1]мá- ›žÌÀø«y,= Ÿ@Ÿ9½fÔ Ó2Ábrp˜\¹WžÕ;¹¡b¯¶¾µ™’¥$u e>ÜÒÔxä2D㔢4Àâ°žiª#˜mÑëR=F7åÅbRïÀ\QÚö“WóšúøAäGÛu O³‘ùÇÅ5Z”%‰Çå8Óôɶ3ëÙò_ÜßÚL'gÃçP9hØ‚K+J· ^L$óõÀµ¡ÆµÛ4‰èÚÚ0»8ÁÅE29<›ÑëÕÐÛÇšgúöØ€7Èr=6~EcÛÁ±±Ï,‘÷‘BÆä§¶™‚NN×ÒãÄòºœçŸÃ,óBmÕÃ`¢ÉY…møÝÖôT×p²/Ó€×ò.O‘d÷˜ÄŽ«hÙŠŽ|®¶“'mÞš…C'£y‘ñWÌðéX†·B_/á×ÍÏŸ:ÿêšfۖņ¾¸1MÒã¹]×,)°­ö><#ƒXj»ƒº¼)ÊŒ§BÎðÔRÃß§dEA¶—}lXÁÀa54ø÷òõõ„Ãm=Ûm“ϧ¤%…1*̱P>!Á~útón_Õ;~€ýuÿ#Å÷‚¨±Ñd[Ë·û‡³ð¤ßEÊut´¨|‚_üqóOèëÝG—@šçæ$ÂŽ-‹å§sŠž €-Ç]‰ 瘢šÇ}Ob ¨]Q>Mh–gööóxÚbb·¯·hß2ûM$kȲº'©¬ ’ÈH«&å/ê±}”ŦŒ²Ã9ª¯å“‚• Ÿ%|^ƒ“Pä˜{<ÿ6xnrÕ¿ÒxˈêmQU ¾±ÀÞ#ÛMyW})wHý%vÚóÔªÙ2°É8‰G‘;åM‘“Ç––íÛûcžvêÇt[ÂÛ• äG]pÀF #í»%þÁ‰Gç ÝwPL…@ž;ñÃ7­µ}ŽSA7þä¡ïCû?ܰM+|nÚÏÍŸ:ú§»Iˆ˜ZîòvNÞ_½¿ú/‘£Í2endstream endobj 18 0 obj << /Contents [19 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 19 0 obj << /Filter [/FlateDecode ] /Length 2110 >> stream xœÕZÙrÛ6}÷W`:}g„û’7×QSgZÛµ™>´êMB2n!!/~‚û)úÇ^,”H¤”8m“dìˆqq—sî‚øÒ‘Å÷(;ÒÑ[øúãHCoŽ> ï‚£fÝ5ë[(È`iyôò{é ðDGÖ4øp~›\ž^œ^ü4Ÿèócô©ŽÑ Oç2'ïjR¡Ó"ËÂ<®?‡À¶‚Ç¿£à-£;ÒšÆZ]ók{ÂÜ®ëuMòxe1ú ­ëF„½+Á²k9* ×%‰’'R#zKl;ÛÄíW(©ò0EeU,«0Có ¸…¹Øä;ØÐû›QX‰tk~ÿ…å*#9…ó ”P½ )ºOÒÝ´ªIŒE…hæu–PšäKô”’#t¶‚ÛVš–ÊJf\£‡a`S¡¨Ðƒ©Ñ DÏÙAÃÖÐŽ·åkI-—Ù©ÍG’•ô±y¨if4OóÉ\Ó5þuÞߨ+úœ`Þȇþaé6‚K‹~(màR{ÔD”…t(»mãè.éýK£íjØëÅ‘ì‰#$se‹Û‰cZDaº&ÑmñYb© å¨Õ`g’x}Fï™D¦ HÏ(ÎS”,ÚšAZ&9Ïʇ‡Úp ¬?Ÿ³ ƒ š»ÁhÑÆ\[~/µföILÒ›zÉ2­µ´æËQ•.vN?$ÙÛúÀ”KV¡![Ž5d¶¦ä&Lu7O&‡5? rÉØ>g庨bø ’¤1/ SÄjpYÔur“>6K"ÓlÚ!.OÖe“`»ãˆ‡¤¦õTt,-E-_Yžʰ–%L *-à˜™lA=ÈùŠ^ŠT-¦¨êÏILî6¯‰Õ¶GæA›>¾,OÙSˆâ Ì,™AzI*INœu“1aïl‰Öƒ´agûF›¶¢¤I‘7íÅv^Rãõtä&ËÕT6Ê6 š<æ°¼ ³ UÌ;¼£ëh7­Aç¿`¯ÈR¦v-<*B¤¾;Óºà0çPç…G,Dh§ xž² ÐW(/®ì) –¥«ûOè×ò„Ššq˜ŽqØ2†ºX 7F%9RA—§¨cw #×ÝÞÐC$ T<}€øC kVK@þ½éèØvž¯ew c[»ñj“Çî-M§¨L¢‹Š0I& ¦CQPdµ¿öôdVwßÊíbw:rÈAߦí] ¿!šöyßÀ†äf}ÔҔ͕Kp˦ÅÌ¡«€ éªâÙæîÅ š V}d*nÒT] „Y™Þv´ ËM¾ÞÅÚ°Ê ‰²EF6R.“H¢„7K5 +¢ÍÎßj*R—FPJ÷O*¢™wž£)¼ØÃC¼_Ý„jIrR…t{¯&°¹VÛtŒÍOÒä½ ¥•­JÞ(D§WvôƒL‡4Ä ßuGo΢™ˆâ+É£^Æ„„kö‡[ AIÖ¤O [ÊOß|;ŸHhŠ•œ4Ù]ÄÉÉIðë|^Í繸šø¦Y}“»—”>^k½¼c„i«g›ó‚’©¸C¢ýü˜”çH†Öa®çÛvà5̲¹=1 ÑhÎx­m!•äÆìÑUÉ•—5"àžTëŠÖ#™ÓÔœžÀ¥8ªÚ‚Lîõ+i“‡ E©®y“•±êF«"Eu²d׊Ýòׯw9ëlW%{”—}t~Äø{£´ê®ý~ÝèÑ´~%üÒOZ¢öy,¸~y\Cò[æÐƨ­«û¤&}u‹\¦ºÇš’¬VÓp•­´§9I˜àá(£ c«­·£üÛ6Ì#`Î÷%·õº Á¨½‚Šôh¡6ö¬qZ´³X.*1$~JP±hã ’¾£ àI hÚï ^v”yc§ÓbA›òŽŠ‡ êŸsrC@JM›H u„a÷TÍS_Ãî¥ßáôØÃ³V¶6œÖÌáDVñr‚¡}9ôÓ}Gíçÿ”€ºë+nwGkeL«^êŽÛxX­|\=“‹ûÁ XR_$>¿¶p·|ŽÚ²Oº¶øXÿˆë ¸™ÿ?¿æÀÕð¿ƒßö/™(is)'iëŸü; Û_óYÉÐtï…f¼Ðž-tô«k¤ m„­±r Ÿ~>ú}:Íendstream endobj 20 0 obj << /Contents [21 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 21 0 obj << /Filter [/FlateDecode ] /Length 2968 >> stream xœ­ZÛ’Û6}Ÿ¯@åIã’ÞIùÍ;c§&µ™™x´µ»í%BФ rdmí'äWæ· H5—Ø);¢DèƒîÓ§üJ,bÂâßÍáÂ"?Ãßß/LòÓÅWò·å…ü=°I°pÉò?í.~üìË$Ë-\-7¦ašðáH~›Ýß\Ý]Ýý²šY«KòÖ?—ä}hñ1gÿ`´$Wùáe1ûª ¼üYþ ÆX~c´Ö2Cx¡0 DãfOOe”0úWå%Yþ® Ð>çº$pý/ø(©ö”\/¿MžUež–ì²(%Ѷ3ó‚fI¶ã7Ù üPäeer—¥'Âê/iLòŒ°ü7XEÌvôa/ [·Œ›-Éh3”dd}sKÏÌ÷¶g’æF¯_–~ïã¤9Çɲ#´qqËX>|¤å³D%m~Ÿí’Kq“·0Â@jöÈçpГ_wÖÒl.Ь¢Š’|Ûâ/pŸ€Ó@iz(aÿÜÕ¥Ü1Ü›9IX³+$¦0jL3±ä³Jn˜X“Øzx€Ãç½Ñ4 wäô[R= ÂÝÐð %ùyúv9YµÑCuôîÙO0)’M¾É$Ù¸*é!J2F’8¥d›—˜‚n’?Á5«ür5KÀà$MÁ.@)f«Ká^ÃÐýYÓÀaÆ û¯_P²ý@nój¨#t4Šaº’nh"FY„†é¿ÜAb ©m «Ýœ|¼½Æ/KŠódÍ”UNŽeR¡‰ v†oà.¾«·`4I60§[N•€QVÔL ¾zHÀi8œÉÓ,ƒž°„Éc´’«\~ú/-óyx=Û<[o¬:kÝ¥Å7…yX ‡U,q7â.N2pHVñÛÁé¶šmpÇqeÜ#€!=G95Žâh–;‡yAŠ*òÕã°ãzÄr B | …8‰`¥˜ýˆ°%kˆ–¡;üOüºAÑ^؆ãhaäÐqhÖ”û<=× aOĸܯ¸äq¸Þýø BOòpÝ ê/ Ïê!Wo¹½záx‰[XlŽ&Å®eئŠÐ'R⨊H”b8œxÀU€„ˆ4± ø¼Ö5AUeì€ãÄ þù |l8Ã5lÍ©cr·y³=Ë‚~z£]ÊvuqvámGí§šÕQjÀ•‡šg5»¦[Ç¥ø½‚}V‹`ã+ ˜1¸ÞbaøƒPº½Þ5Lw<æòæêÓ‡ïOTsùýƒÇZGWòóúTÑödÔ–Ýö­¨ü*¯9ÍÊ‹Õì¸O6û éI^h„°1 C+ÿª}TAœCÀ·`9/OS¥Œ#Žn÷xNÍèå¡ÈZ{ønM!n6iÎÐíçä)¹Û‹p(çÎ{ì&ªY ]Ãã”APl/0LI¶á)|e› dPkHÊ <=~’¤¸ \J-¸05`Ñ‚”u†)e>ií4p^Ÿ·xà^ª± ~iý° æ®o„…é–†îP[åÙÿ#jðñ)ÿˆ°9Š „Ű,øa}"Q#<¿·‚x£W©áŒêáå¡=ÆxX‹Í” âÍZ½9E¦PŸ¶¥Ý0©Bp8,â@ß3,,0s?á°_kZcøÉ±%bŸt³šwÆä«$5£ÑÚÚÁ³m#Ô#v«ƒ« ÙëŸïWEѼFØ'^ço¦%t”s.ÁyâúúLÉîBÑ 5pÊs ´tEÃP³îæ´f{‘¶ð}#¿¯¶P¤Å4"¡¯G¤Qjóž„ ôœiH¨§­ÜA;Øø99„®úÍ– †d^+ØV*Ë9cɺ•¯‚¹_ ÈèÙDš wW¿ k ˜ l#Òì€çi•-OdSÖ1…â²H£ =e!cM¸«ª“hŽõ—­äpHà[a¹h©E™z…5z-ë!åÖ{:e¹z½k yÛqnòL«‡×ägBj²8ëAîOp¥p|TQƒú‹ekƒœõм~õ ò²ä4€-„A%Û:j¦íL¹Þ/óJNR̸–«ÔbÎ…ÚÇí¡üýŠ9\B[ν¢Œs•Ïë•qù¸k%äÓŽWÍ_Ú]™Ÿáôå9¢´4íOöY"…iÅÈŽg¸Ö˽,“ølyú 'V¢/AR¹:dy±x°hâVœm]¢]ZññµN(W_Ï©g1ìÃU·˜k¹éK: J>ìãC]%e¬® „¦+Œˆ{Ž­âš‰A“ë’ œø‰ý‚{ä¯N¨ÕGˆ{NÑ µƒ„ 5Uò‰ä¼¯LƒÎ…‹v”÷[a ¿Ð ñ­H“MRË”ä'«„ÖG» OÈ:‚zIfˆ¡¬Ci—«++è†ÚnËFž× ŠÒúÀV³ªõàÌ`nÞ–¸.”¸æ‰JNi-,¨@X…å`¬Y=×@w¼‰6>¤išè†û³nèzúçïqv,«öÈh|¬fBtS&kÉÄ ,Oi’ÉV"ëúâ+(—™LæŽå(ͽž– Pô[Ô…9ÎÔùÄ¡HRúÄ[òÍts¾%4ãqK¶|½l°Ä<ŒFHí:Ê ÇÌèMØÄéõÛ䛯ÂSq=!¾¾y¸ÿûG>6„ˆé-º½·„)ÿ&wŸÉÝýòæîö÷Ìïï¾4Þh/ŒÀ GO,Éçåòæö§Òw[Ç Ç­ÜëV«ÙôÓ.féšI? tDry IˆGpÔ|WF¹?H€Œ:‘_®žÏÉG¤#"iFq1¼ˆ ÀEJ‡ÓÂlÃæòpS`Iƒ’R®h=\QÓ!?+†¯žê·=¿í±í4lsB« Jo¸-Ÿ´®o…jR˱ãº,QD?¶ÄèZr)1ìlsB–ÉãK+r4 ÜL§¦p´96tÚÓ&×7lMuy‡(‡¢ 794õ½qá%ü ¬Y+PBA7Uw¢†/—& ³ÝlÛLSqxE׌2mª.×ZO\BÆEc,rì Tú¤=ʸ\ÓØéOœsh¶²›¶`K]ÐÇľ÷ŠÓEy`´š!´Jû7ð/xIû´+å?cÕ56„Ž>cC³ŠDqò轟ZJoLÖÛ<•Çú¡ák´È±ÓeK»‡ê ÏøB’‘"ÂMÛS– W}úŠ”~”9Êöíq»ì·Ù»wï€5|”3먎?È ËòlÓ”W«Ùþõï”@d¦ZjË= ÌO?'8)›÷ÄTë‚uíyFSѶ_uí&™P)ðʤf…dwÓOµèÔ<€#ãjp1í²„„hi4>Hã®[¦‰¡™ÆáÝ½Š bhÔŠY\Ê’³÷ªSŽCtgPâ]—±¡ÖT«'Þ'»=¯±¹ç­ƒ83A™PǼcWOP¶E[j’o\[[öbÁÃ7B@"<Û¶yMÇð_Ã’âhFP¯ÆÌ©þw¨\ðõ I®òu%ÔÑráHeÉÅ=o:è ¥7*âgxGÙnôZ.«ßê™hÌä!®ÒŽk ™Ý”¤å‹ÂÚ¾“5Ôè’gCØÂ¾Åd¯©ÜY'4šºå1é*ŸŽà°t¬Ê<®¹ËuoF€áKAỉ=j‡´' œóÄ_ïJOêf>ÊW,}a$¤†ÍøM4tê]°iÒeÇ=›ÃðP·&^¹Ë°”.«ºPLÔF ŒØÆìÎ8ò²‘±ú Œ|g홞¹è=N ¿LDpß |µQk‚|aÉ1¬7¿yؽ€è¢’¶M+|oÚïÍ¿<èÙi¼¾‘djPiå§%ùõâ׋ÿ5/ endstream endobj 22 0 obj << /Contents [23 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 23 0 obj << /Filter [/FlateDecode ] /Length 2854 >> stream xœ½ZÉ–Û6Ý×WàÔJuZf8ÉÊ].»•ã¡Ë}âX½@QPc2I¹¬l³Í¯èû= DPC%Ýöq"‰ðÆûîð…XÄ„¿â¿qva‘áßo&yuñ…üs~¡ž6 "—Ì3xtñÝKX&™¯àÛ<¾0 Ó„äÓävvýîúÝ›ÅÄZ\‘§þ¹"ÏB‹Ï9ùP±’\YFóeõwLØðê?dþ#(cùR¥­e†$ðB¡.*(”Ûí¾lVÃl¶g9¸c |'²Êw&i’3õ¹X×I‘Wêë½sXŽoØ&®<_Ši&_¯Èü· ×=õskbFîËÉ}"Äw¼Î[Çç‹«)©YeM*V×I~_Z2R%)ËëtKâ³[žk˜®œÇ6¼fž¥Af+¡Š0,Íyœh¸ð–dI•Ñ:~ I%çîZÛõ[k·£–¬fqÍ– rýˆZ£ä%û²aþ †æ¿Ð¸Þд¯Ò”Pò(²=Çp5Æ eo’ŒU½g Y&Õ:¥[ÔŽ|”RÚžái’Ñ-.ŸkÔq\:›Šqy'Ÿ_゙\u¡>¡Ê¬k°ŠúÈT˜ù®ák<ó ¬×:§(›Ï¬2úš!Xa7ªu4Èë&Ò`®k‰ußß¼}1{ûŠ<û‚ü|s}3û7~{9{}óžô×µ=Ëp°¸×.ØšªçÓë®-!*‰ 0¤2O +?V¬µmÇÌ%‹Y¢Œ+†Î¹úgÊ*RÈÔiýÓÇ–É’”–éVoÒCšÚu¥ ¼º%å'2)ფFë ý}0œ†ÔÞoìàû+û–aÁÝÐÈ-]i=ÇԥݮäóZý¢!ôÇG>_H#JÔûÄ8×3/¥ýÈpÝ¡Z‹Šz†¥#¹â”$9¤ÏYhAªšý¤d-¸3Òª‚5·„¯F[šSÀ¬ •%ê;÷¹§lMqo)ûˆ,§T}°ölyr¬n¡G„._h‹Ï‰v4:´—U‘1`È€i"[ò00üP;˜ô÷ʃXu]â™@^7ͱÓÃþËeõ{óðë×ËöEnž¯¬÷n©}×0Œ«}kwé†Ñ^‡(…›­Dw/SÝÁ.p,ÕÑ`‡Zës@nÚìØ”tqd@„Oœ"PƒcXÿ7ŒP*$•F/–­ë­&×Ü`¿W©]—˜¼ê©Ù1ŠþÔ9«¤©ª*·aè]Êwa^J¬2]ÃÖàü“ÐLNOîŠú ~‰Áq©êû°°ºþ`‚½q” ÍóÍÁ¥RµâÓ¤“6 ËÒÏÔ„â3ÿ=ê„B¯ý–8Ý€†çަœ®)êQØX˜–‰ÿâÅþKG@»Mø|P˜p-úw*7Q@¼†¿ Ï bAþì;@öÖ}*Nɲ€˜õX¶¯DB?³­~êåçÅÄ>R”:›Q¸’.I­HoªÜäDmϺ¦ájBfÛ¤‘eºM½]%C“$¦­çÐ/6¥j†÷Üi¹â9 v›Ý ³y,ÐPzC—üÛnò\vB½Õƒç±œ\L˜qÈäo]¢œ ûˆ[¯wT¶@{›""0¬ÚÖŠ2M2N0Ѐq>Yr\ÅwÍc’¦ØÉ€ç¡@Èn†"ÃÁ¾ìô¼–{xü…Ò Ú9o²¢ä¤h‡c‹„Åps–ãœÞÿt¹L°°Ad*–à†7Þ¨ª,‰¦ #‡—Há Øu·Íc¸D‚^rßׇ~¹Y&¸.-!˜hýÀ[Iˆ4(I|1ìN¨ª_Ñ84èÎ. ûÂF{ÖoJÑN<½8· ¯„4•ªI«Í7 5š{®^s±µË//’ ?Ý•`‡†x*=;ÇJ¹•)×=Z?.‰ÃfÝÒœ–òK©oÞ£€˜¥j‘ÛëPV¬!†{G2½cƒzS6” ûŠ¡õÜÈÌ‹2C´•>(Ö¬¤¼Éƒt[a^ñìâñ¨2p ëÛwÍ´ t/S/ÚÒP)æ:F4JÄ+À „VÕ&C ûáètš—ÂË—p µ»1ÅiøÚ6Äâx‹«1Š5²3„¨š¦u´f‚EòãäO<ÏÜnZ>u¨Nk.l;êâÿuw1Õ$¢Gû³J3l•{x.cY³Cç˜#ËcmXüÀ0ñ2°•Ç·*0Cû¼ó-Ä4á nBðäKZBó’¯75ÿbSãÇBô°2RlÓìl †ÊP};ÁYUžã"ÏÅQ¹¬psÃ}!YYBììIæÙ'ñØz‘ÃpGÕ0çãC?ìv;øÊz›§PЀ´âé<>Æ%K%§ãuêqO•¼)r~ö˜K$-·‡‘ãxmá2÷JÅÐÁ¨¢³û¦n ¬h—Q¨),ð6¬IjD~¶|C®gɺbéªmP’{¨-:o퀿Ÿ½š½ã­ŒjQÔÐûuY¤hZ ¢‡MÛzÝ@… 2Ðäñ–@o‡Ý<Ы)d1*'Ð ÈVª—‰´÷>V¸?Œ­;3ñ-iŒ¥7Áµ°<§ÈéªJŸrƒ›6hqν‰îû"vfoo?ÌÅi¼cØžßêe©’ðîÃßQG–6Ì:| /\Ü\ÿëyóüöï\ìݶ€A[ÞžÀGïZØÖ`Cöƒþúhyk$ÔÍ呌~V1ëùÚ¤maAHZNÍRÈá)¤Õ:¥1êbÑDÃÎlSÛß«˜oâ³"”3Ä;†©X2 0ÞÁ]’¯Íã Bçns8…VØÖ‰…ˤ®qp CU¬h°¡´è2…§¹YATO¬´ˆy¢²ø¡hµ©@‹ISE½@ÅGñ1˜í@Ip“G£G88–>I6Ô£Ó-® ,×ë¶@0b½×õ¢RüTSµ‘9¬Û …Pc4~À»q˜›i»¹8ÚS¹—Í+5Ú‚Š}à§kˆ7,ÿiR!ËÑX'0uÛÝdU¤©¼"…ç òˆ¾L– °ç²Òܲ> /Parent 2 0 R /Type /Page >> endobj 25 0 obj << /Filter [/FlateDecode ] /Length 2351 >> stream xœíZ[oÛÈ~÷¯ì*\Þ/ƶÁÚM^d›ÝX Èû0¢FÖ¤)“T,ûÖ×îOÑÜ33’Ce*I>4Ar朙sýÎ9Œ‘,ø-þN¶6úþ|¼°Ðèz~!÷C…±‡æ[Øz¸øö­l Í×ð6O.,Ó²àá -ŒŸooÞß¼ÿéÞ°ï/ÑçþºD¯"›Ÿiü½$ºÉ·[œ­Ê¯q`WÀË_ÑüÇFEÛŠPèGBGÐjlkjüûÍ?‚!ì ¶DCnkÈ}È’äp| ñk2Š{F“¤&2n>Ü_Î.ÑPFÏ6½”ÊÎ9‡ #]¿(è樂ïÞʧ*QrÇ3=½äÊÎɇ Bòtý¥²Ë§?µd#êX¡èÕQv¦¨3dà!ó¢6jÈŒIÄ–©lug‚¤†…±,W$n÷뻡ÝÿúæÝˆì¡>dºëSäî“/ yYN—$Š}}0¢ÚGrTÝ™"øaa”»dCÓe/w$¡XºÈH6¸šáwòÑ:8–|þí·v5\s߈W"õ c3t™ óÕ…cú²’ÔD7jzºiœÇ‹ÌX²tªÆ ¼£¹ qBÓv†4ß_£*G"ˆ\ߌIÄx`Ž3*Æö¬ÀQw¦¸aȰ0*¼<Ë óÚt~l_KEÇ!ugŠŠC†…‘giØÂg›#1‘gFÞËYÁX);S42°*q–Fº"ÑjAa½¨‘[Z}ºë´/ŒhI«³´Q2ÿ ˜åsTmŽpX¤:¡¶øførlú¡;‚‚êÎ݇ #+¶g)¥rÛ‚ .JG± „ßý¹!j–ThîqAÐDø§`ƒRÚA«jJiMæÄf¬103 -¯¤e!êyÈw4=ÇÀ•Àãñ/òqa­~½ì¬¢–­4Y­·k´…~„ÁÊ3Òzi»+òÚDndÚ¯|¢+²b̾ô™•æêo;«Ïða6ÐÖjà`—3vàýOQVRŒ¢[:Ê‹#½Fy±‚ /¥e’áe­@à˜V0=ØàÞ’kDÉÊÔ\õ±æ-?Í7=MDä’ øÚN䀷»TäH"&Ó“qáX kG“˜ÛàÈNñ76ÅÌdwZïÓÎ> f²é® ˆr@=ñ7Ó4OF›]Y¿z¢iz5€)ϵGš u§ è]ïQµ&ýPãŽl}¢N¾ìþâúM@ˆÅ ºª}‘Íu°V€jMd $z÷hS Ù³&dÅ©0P±´¾ß‰ oˆÎ¦8Ñù6Élºž¦þÕ˜Å\I FEÿÊ qëÙn_™ÍYÏCKÞ¼ R&x×ixnàë:\È·›@ ïSiZ}‡}sÄýöš¯ó¯'}Å­á'Ïuž¦¹ °Ô¨üMÒRô]¤ik]ݱM«gG?’ÀöÎÖ¯?>t¾û@²£Û¬ûÕ§jrF¼'¸$WÝ…¹Ì“z?Ï*høž|­ž¨0äû ÜÛ]yÜ“}¿ýc;±£2°®pĕ虡e} àB ™ öbõ*Hˆde€u0‘4eÿЦQ¨‰ò5ÿí]]74‚G–^p^a„þR>hØ=uBÛ¯¹»"ÓŠ†b¯E@0õqÊ ð¬¿£}Ü™ùµÚWÎÊ-;‚u]l"YQHµ‚ ÷ÆïûrÃKËFÒ昮A¤×µ_X!]ÙhÈ»ZÝ[¶¶,è¯F°Îš£R´Œu›¯ÈöȬ^ä)bŸ—’”À?+TB?SVÙ°F¨±ÉœŸ*ä˜L.?BQ†ÀGh—DzCyözèBÚo.úoo Œö¦\âÃ~wòÀ|Ç L¯X߯Ùô×\ÑÖ‘^mj>nÀ€h" À§úuÙ÷IBÊ’e_µ/5M“ãŒý‹3½5¥¦G¥–šÇýµš@¢_¹špW|A5QÔ׌À6}çlOŒ^X’M2‘kú‘?QϹ[ÀʬžpkÓ-Mq!²<#pUzÖð‹8©»b'>YDg"žÙ'—•±|Ó×+Ér…~iƒZ­Ø8qÆ\Y²’A×Ó0%´MÇ>R4ýaÓ)>Ð:Å×tÏø¾h»¶(VXjÖXà 镲ìmi5t|9€8Ýãô™g#„”¢ÁÐÁ½‘XÝà բm_ÆQ˜èz:çtrŠd&º#äDÏ´Ê“ýV~V=Õi©½[WN±²Î‹î+V.P,è€E½¢TÄ»ŒdOM’x9}:%ù.QÏ= PlË|”ÐàÄœåDùB²(Õ,‘¥ ^£eËöôE«»>v}šÉAwÄbþ™¡ðÈúìibÏÕ61ÿ3‘Ç~`K+¡Å5íÏþyªöǪ‚PØÏ±ìè•å¼²¾øÐ“ׄª’¬C£H-ßÌÑ/¿\ü€Ôe#endstream endobj 26 0 obj << /Contents [27 0 R ] /Group << /CS /DeviceRGB /S /Transparency >> /Parent 2 0 R /Type /Page >> endobj 27 0 obj << /Filter [/FlateDecode ] /Length 2150 >> stream xœµYËrÛ8Ýû+°”«ˆoRIW×8;QWb»m¹S™ö,( ’P¤B€íñz¶=Ÿâœ”H¶£ôLR±E îãÜ{Îe¾›Xø[ÿLÖG6ùÿ¾YäÝÑ7òvzÔ|:${dºÆWˣѹOl‹L¸š&Gµ,|¸'¿®&§—§—ïöÝ1ùÑ?ÇäUdW{n+Èi¾^ÇÙ\ü/6lxüO2ýeë¢mE$ô£ÚGxõÔýÊÓÁ¿ÉôËn½·f‘°"'³É‰ F ÏÉ¢È×D®~ÅÅœðlSJJÈtÅ)E§éY³8XKr¬¶×µlêêÜé\óGeŒG#¿¹½;ñ»×ކÔ÷Ä‚$y–±D²9‘ù^P”c^`rlÓ<É×w–m‰=GÈ ›ÎËH’æÛæEc‚O oÃð‰ÉŸ)kŒõ:6xÓ6v¨B˜mGufÝr7ªð²lnpÇõLîä‹ê˜€4L2\ I,Xe›úªÞjtn;ð«'Ù¿¸|Œ’@š³õJ¿»0ßHžgzÉ€‹îb˜ÖYåò™ÝK^%Ýq‘öèûÑ ·2ßÔ!ãÙ²ICäǹ*åC‚§ÈW¼z–áp†óò +b©NÌòb]áünÀ©Šú}Á«/d^ïÖ6mXÛÆ §d“ý¥Ì$O —Ø´”°Á`±ŠXßâo%+Ž5òÁþ¤pT%|o6,» 5µ3¶¨m£:}‘•u—£›¶…Ú*2Ó[¸wë¶\T©Š¨õ·^ rãyó¬ ‡B{ßÅ`ll;wQξ NšZ0£àEj+|êv€„„ öá> ¬ â^m¬âlYn¾£.².BÜ”ÇÖ7ëè6W*ÈÛEù¶®dÕ’¶—@µ{+Œ‰as#IY\tÏêÇ82vÀu>gëGô#Yä)IyÆD \Ý©mÛ¦~Óqê7Ï¡[u“E}hÍK['ëËÿW¯©ÚFmœPçÆQáþ-u»Ô7ÄSÆÝÐØ‰Ÿ`Ç*²*Ø<+™±èBsÜÐhšjR¼ÛØ%™çØKäÛ^Ú‚å¸Çç)3˜[`ÓĆ%üO^¼Î±#Q¤Â×8iư„m ÖB#0à%WuüÚ€ÐO† ܾk QäžËHT”I„hΊ,#‘â _Y Ú—Aš6 ¡î7OI¡½U-y¨ |åiŠ@ͪÀMÏ®?B%ÉÅ”¾Ìât¨.ã ‰)‘&³µ‘>ñ Š‚¶Ê“¤,Ä·7H5$Úu{ŽÎØ*®}hp@é@ù %"¸FŠÖÆu:=êù߿ѼV5|2±I-˜‡µväâ5t%«j‡eŠ-k=£é©&CM0ÛE†ˆ8¶9©z»ØÏSÇ;Œý”^žs‘ Àõ»ÁJ±bó»ãJ'«^t(Å90"<ŒãjŠÃ³­m;Q±Æû89Œõ†ÑÜ®‘-Ã;ì·]‘|ɳg¨¯ubEe[J¬­¹¬ˆ­¹@N:Ì n Lš±¢`Ö°ƒÆ±šŸoi‹geeÌÓ²`æn†¹ÕGÜñL+ú#ª¨ÔÞ5 N*`‚”׆ÏíôýåuÓ¨=ü`[øîÅÄq¨ã÷LñwÇïàÑn·~í[òûàd2j´IÃì¡ùtÁ“¯Íç+ÆØê”],u³©g‰×S´ÌŸ²M,ÿÆt:ü€Únwë2•4còç#¨ˆú6 ËAç‰vêÚí ~Ó·=§›š“ɇ“·““éç—óã»Ô†Þ·óå¹ãž™Ï›øŽ ¸¾ÏÒ<®{mŠ™^Hð \¤tÏkòÓJÊx=-ý²éž‘K£n÷¤(¡‘ÊÇ+V÷Q8:½tŒtµô)¢Ÿ`3:,7'´_§—WŸ¯'ïÞO_6f{'{¿l|¿ÿæ4ßÔÔ7Dû=p%Á æEDzÜGÇzT¥«†™|êE?\"õ©jÌms½±QÞV¯xÔ›üÚÄE%µ.2H1/|¢“¶¤Ô¢`hùBêa5 hd‰hÖoÈC^Bùd˜U\,ò*Ú—ÌL©tí$H‚/Ô2›³ZñbYoÅ»‹[òŽeÐ]©Á“à)QXÎRž<ÁäÍ”VÚ¨;Šëyx®<¼ÙyhcXµ ï‘”b8×Z»Ó_Y>ñ¾! /þÐRÌ7¿³(§qQ[Y©Ó;E´08ë»Oˆ¥ŠõÆXÏòžÕÒ’-àVÝak Ýß-îÚ0ÚGP#îZ€é¤ aÐRª×Õ¸ÄÈ Ã–Ö’œœ¦˜gH)Ø¢„LoZèÀ3¤ðÓ$y;%'ŸÉ§zõØnA´nî××'ªU«úÑÛý­ÞTzº²‘h$¾k¬Ï¨[ŸŠ-÷ãäxæ8)‡ùz“rø¯áæ{-m£­ˆ3ù  ññìúô=ì×Þ™ P³‘‚ÎùdzqvsCÎ/¯Éɶ¹6õ£½¨Ô†M†W·ÓÉé퇓kru{}uys]|ÃT¢öWå®í˜ÝmÕ,Ù«ÄEUóJ„3 ‘ešݱßã¿ÏšÍåG2˜Î1 騢çÛ/ä°UŽíéÉiŸñ=ÓSŒñf£ 5Ø÷`heûa‰Ó<[ÖÒ´$7E¾,âõ5âe¹Vï1 )pAâÆ÷Hz|ÙorÁ˜Z­Ç 1ì&t9N42a‚mè6 xgä*t¶›æ×µ†äm.¤Úæã ±Û¶!øBr{sÒSÙæW9MÏÁ©?üŸ7»ÿà Âú]ˆ¢ðW–óÊúË›>{LÔuÒ‡þ¬/Ϧä×£_þ ”µâ€endstream endobj 1 0 obj << /Pages 2 0 R /Type /Catalog >> endobj 28 0 obj << /CreationDate (D:20180201091827+00'00') /Creator (groff version 1.22.3) /ModDate (D:20180201091827+00'00') /Producer (gropdf version 1.22.3) >> endobj 5 0 obj << /BaseFont /Times-Roman /Encoding 6 0 R /Subtype /Type1 /ToUnicode 7 0 R /Type /Font >> endobj 6 0 obj << /Differences [0 /asciicircum /asciitilde /Scaron /Zcaron /scaron /zcaron /Ydieresis /trademark /quotesingle /Euro /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /circumflex /underscore /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /tilde /.notdef /quotesinglbase /guillemotleft /guillemotright /bullet /florin /fraction /perthousand /dagger /daggerdbl /endash /emdash /.notdef /fi /fl /.notdef /.notdef /dotlessi /.notdef /grave /hungarumlaut /dotaccent /breve /caron /ring /ogonek /quotedblleft /quotedblright /oe /lslash /quotedblbase /OE /Lslash /.notdef /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guilsinglleft /logicalnot /minus /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guilsinglright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis /ellipsis ] /Type /Encoding >> endobj 7 0 obj << /Filter [/FlateDecode ] /Length 252 >> stream xœ]PKkÃ0 ¾ûWèØŠÛÊÁ029ìÁ²ÆŽ-CcÇ9äßOv»*õøôÉ’xÓ>·Î&àÑ«ëtÄÉÏQ!ô8XÇNh«Ò-*¯e`œÈÝ2%[g<«kàŸN).°{Ò¾Ç=ãïQc´n€ÝwÓQÜÍ!\pD—àÈ„†½Êð&G^h‡VnÓr ÎVñµ„ªÄ§ë0Êkœ‚T¥ÕGõ ‰`èô^]Y½YËz*'cü=Ÿ³–Tq7Wmî’µ¿¹Ô%}3•.Cü—çÉg[—UsŒ´g¹mY0¯f®ç>dVÑ?à+‚÷endstream endobj 8 0 obj << /BaseFont /Times-Bold /Encoding 9 0 R /Subtype /Type1 /ToUnicode 7 0 R /Type /Font >> endobj 9 0 obj << /Differences [0 /asciicircum /asciitilde /Scaron /Zcaron /scaron /zcaron /Ydieresis /trademark /quotesingle /Euro /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /circumflex /underscore /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /tilde /.notdef /quotesinglbase /guillemotleft /guillemotright /bullet /florin /fraction /perthousand /dagger /daggerdbl /endash /emdash /.notdef /fi /fl /.notdef /.notdef /dotlessi /.notdef /grave /hungarumlaut /dotaccent /breve /caron /ring /ogonek /quotedblleft /quotedblright /oe /lslash /quotedblbase /OE /Lslash /.notdef /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guilsinglleft /logicalnot /minus /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guilsinglright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis /ellipsis ] /Type /Encoding >> endobj 10 0 obj << /BaseFont /Times-Italic /Encoding 11 0 R /Subtype /Type1 /ToUnicode 7 0 R /Type /Font >> endobj 11 0 obj << /Differences [0 /asciicircum /asciitilde /Scaron /Zcaron /scaron /zcaron /Ydieresis /trademark /quotesingle /Euro /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /circumflex /underscore /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /tilde /.notdef /quotesinglbase /guillemotleft /guillemotright /bullet /florin /fraction /perthousand /dagger /daggerdbl /endash /emdash /.notdef /fi /fl /.notdef /.notdef /dotlessi /.notdef /grave /hungarumlaut /dotaccent /breve /caron /ring /ogonek /quotedblleft /quotedblright /oe /lslash /quotedblbase /OE /Lslash /.notdef /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guilsinglleft /logicalnot /minus /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guilsinglright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis /ellipsis ] /Type /Encoding >> endobj 14 0 obj << /BaseFont /Courier /Encoding 15 0 R /Subtype /Type1 /ToUnicode 7 0 R /Type /Font >> endobj 15 0 obj << /Differences [0 /asciicircum /asciitilde /Scaron /Zcaron /scaron /zcaron /Ydieresis /trademark /quotesingle /Euro /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /circumflex /underscore /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /tilde /.notdef /quotesinglbase /guillemotleft /guillemotright /bullet /florin /fraction /perthousand /dagger /daggerdbl /endash /emdash /.notdef /fi /fl /.notdef /.notdef /dotlessi /.notdef /grave /hungarumlaut /dotaccent /breve /caron /ring /ogonek /quotedblleft /quotedblright /oe /lslash /quotedblbase /OE /Lslash /.notdef /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guilsinglleft /logicalnot /minus /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guilsinglright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis /ellipsis ] /Type /Encoding >> endobj 2 0 obj << /Count 8 /Kids [3 0 R 12 0 R 16 0 R 18 0 R 20 0 R 22 0 R 24 0 R 26 0 R ] /MediaBox [0 0 595 842 ] /Resources << /Font << /F16 8 0 R /F18 10 0 R /F5 5 0 R /F6 14 0 R >> /ProcSet [/PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Type /Pages >> endobj xref 0 29 0000000000 65535 f 0000022609 00000 n 0000032098 00000 n 0000000015 00000 n 0000000127 00000 n 0000022822 00000 n 0000022929 00000 n 0000025059 00000 n 0000025385 00000 n 0000025491 00000 n 0000027621 00000 n 0000027731 00000 n 0000003408 00000 n 0000003522 00000 n 0000029862 00000 n 0000029967 00000 n 0000006137 00000 n 0000006251 00000 n 0000009226 00000 n 0000009340 00000 n 0000011526 00000 n 0000011640 00000 n 0000014684 00000 n 0000014798 00000 n 0000017728 00000 n 0000017842 00000 n 0000020269 00000 n 0000020383 00000 n 0000022659 00000 n trailer << /Info 28 0 R /Root 1 0 R /Size 29 >> startxref 32372 %%EOF picocom-3.1/picocom.c000066400000000000000000001673561323455570200146330ustar00rootroot00000000000000/* vi: set sw=4 ts=4: * * picocom.c * * simple dumb-terminal program. Helps you manually configure and test * stuff like modems, devices w. serial ports, etc. * * by Nick Patavalis (npat@efault.net) * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef USE_FLOCK #include #endif #ifdef LINENOISE #include #include #endif #define _GNU_SOURCE #include #include "fdio.h" #include "split.h" #include "term.h" #ifdef LINENOISE #include "linenoise-1.0/linenoise.h" #endif #include "custbaud.h" /**********************************************************************/ /* parity modes names */ const char *parity_str[] = { [P_NONE] = "none", [P_EVEN] = "even", [P_ODD] = "odd", [P_MARK] = "mark", [P_SPACE] = "space", }; /* flow control modes names */ const char *flow_str[] = { [FC_NONE] = "none", [FC_RTSCTS] = "RTS/CTS", [FC_XONXOFF] = "xon/xoff", [FC_OTHER] = "other", }; /**********************************************************************/ /* control-key to printable character (lowcase) */ #define KEYC(k) ((k) | 0x60) /* printable character to control-key */ #define CKEY(c) ((c) & 0x1f) #define KEY_EXIT CKEY('x') /* exit picocom */ #define KEY_QUIT CKEY('q') /* exit picocom without reseting port */ #define KEY_PULSE CKEY('p') /* pulse DTR */ #define KEY_TOG_DTR CKEY('t') /* toggle DTR */ #define KEY_TOG_RTS CKEY('g') /* toggle RTS */ #define KEY_BAUD CKEY('b') /* set baudrate */ #define KEY_BAUD_UP CKEY('u') /* increase baudrate (up) */ #define KEY_BAUD_DN CKEY('d') /* decrase baudrate (down) */ #define KEY_FLOW CKEY('f') /* change flowcntrl mode */ #define KEY_PARITY CKEY('y') /* change parity mode */ #define KEY_BITS CKEY('i') /* change number of databits */ #define KEY_STOP CKEY('j') /* change number of stopbits */ #define KEY_LECHO CKEY('c') /* toggle local echo */ #define KEY_STATUS CKEY('v') /* show program options */ #define KEY_HELP CKEY('h') /* show help (same as [C-k]) */ #define KEY_KEYS CKEY('k') /* show available command keys */ #define KEY_SEND CKEY('s') /* send file */ #define KEY_RECEIVE CKEY('r') /* receive file */ #define KEY_HEX CKEY('w') /* write hex */ #define KEY_BREAK CKEY('\\') /* break */ /**********************************************************************/ /* implemented caracter mappings */ #define M_CRLF (1 << 0) /* map CR --> LF */ #define M_CRCRLF (1 << 1) /* map CR --> CR + LF */ #define M_IGNCR (1 << 2) /* map CR --> */ #define M_LFCR (1 << 3) /* map LF --> CR */ #define M_LFCRLF (1 << 4) /* map LF --> CR + LF */ #define M_IGNLF (1 << 5) /* map LF --> */ #define M_DELBS (1 << 6) /* map DEL --> BS */ #define M_BSDEL (1 << 7) /* map BS --> DEL */ #define M_SPCHEX (1 << 8) /* map special chars --> hex */ #define M_TABHEX (1 << 9) /* map TAB --> hex */ #define M_CRHEX (1 << 10) /* map CR --> hex */ #define M_LFHEX (1 << 11) /* map LF --> hex */ #define M_8BITHEX (1 << 12) /* map 8-bit chars --> hex */ #define M_NRMHEX (1 << 13) /* map normal ascii chars --> hex */ #define M_NFLAGS 14 /* default character mappings */ #define M_I_DFL 0 #define M_O_DFL 0 #define M_E_DFL (M_DELBS | M_CRCRLF) /* character mapping names */ struct map_names_s { char *name; int flag; } map_names[] = { { "crlf", M_CRLF }, { "crcrlf", M_CRCRLF }, { "igncr", M_IGNCR }, { "lfcr", M_LFCR }, { "lfcrlf", M_LFCRLF }, { "ignlf", M_IGNLF }, { "delbs", M_DELBS }, { "bsdel", M_BSDEL }, { "spchex", M_SPCHEX }, { "tabhex", M_TABHEX }, { "crhex", M_CRHEX }, { "lfhex", M_LFHEX }, { "8bithex", M_8BITHEX }, { "nrmhex", M_NRMHEX }, /* Sentinel */ { NULL, 0 } }; int parse_map (char *s) { char *m, *t; int f, flags, i; flags = 0; while ( (t = strtok(s, ", \t")) ) { for (i=0; (m = map_names[i].name); i++) { if ( ! strcmp(t, m) ) { f = map_names[i].flag; break; } } if ( m ) flags |= f; else { flags = -1; break; } s = NULL; } return flags; } void print_map (int flags) { int i; for (i = 0; i < M_NFLAGS; i++) if ( flags & (1 << i) ) printf("%s,", map_names[i].name); printf("\n"); } /**********************************************************************/ struct { char *port; int baud; enum flowcntrl_e flow; enum parity_e parity; int databits; int stopbits; int lecho; int noinit; int noreset; int hangup; #if defined (UUCP_LOCK_DIR) || defined (USE_FLOCK) int nolock; #endif unsigned char escape; int noescape; char send_cmd[128]; char receive_cmd[128]; int imap; int omap; int emap; char *log_filename; char *initstring; int exit_after; int exit; int lower_rts; int lower_dtr; int raise_rts; int raise_dtr; int quiet; } opts = { .port = NULL, .baud = 9600, .flow = FC_NONE, .parity = P_NONE, .databits = 8, .stopbits = 1, .lecho = 0, .noinit = 0, .noreset = 0, .hangup = 0, #if defined (UUCP_LOCK_DIR) || defined (USE_FLOCK) .nolock = 0, #endif .escape = CKEY('a'), .noescape = 0, .send_cmd = "sz -vv", .receive_cmd = "rz -vv -E", .imap = M_I_DFL, .omap = M_O_DFL, .emap = M_E_DFL, .log_filename = NULL, .initstring = NULL, .exit_after = -1, .exit = 0, .lower_rts = 0, .lower_dtr = 0, .raise_rts = 0, .raise_dtr = 0, .quiet = 0 }; int sig_exit = 0; #define STI STDIN_FILENO #define STO STDOUT_FILENO #define STE STDERR_FILENO int tty_fd = -1; int log_fd = -1; /* RTS and DTR are usually raised upon opening the serial port (at least as tested on Linux, OpenBSD and macOS, but FreeBSD behave different) */ int rts_up = 1; int dtr_up = 1; #define TTY_Q_SZ_MIN 256 #ifndef TTY_Q_SZ #define TTY_Q_SZ 32768 #endif struct tty_q { int sz; int len; unsigned char *buff; } tty_q = { .sz = 0, .len = 0, .buff = NULL }; #define STI_RD_SZ 16 #define TTY_RD_SZ 128 int tty_write_sz; #define TTY_WRITE_SZ_DIV 10 #define TTY_WRITE_SZ_MIN 8 #define set_tty_write_sz(baud) \ do { \ tty_write_sz = (baud) / TTY_WRITE_SZ_DIV; \ if ( tty_write_sz < TTY_WRITE_SZ_MIN ) \ tty_write_sz = TTY_WRITE_SZ_MIN; \ } while (0) /**********************************************************************/ #ifdef UUCP_LOCK_DIR /* use HDB UUCP locks .. see * for details */ char lockname[_POSIX_PATH_MAX] = ""; int uucp_lockname(const char *dir, const char *file) { char *p, *cp; struct stat sb; if ( ! dir || *dir == '\0' || stat(dir, &sb) != 0 ) return -1; /* cut-off initial "/dev/" from file-name */ p = strchr(file + 1, '/'); p = p ? p + 1 : (char *)file; /* replace '/'s with '_'s in what remains (after making a copy) */ p = cp = strdup(p); do { if ( *p == '/' ) *p = '_'; } while(*p++); /* build lockname */ snprintf(lockname, sizeof(lockname), "%s/LCK..%s", dir, cp); /* destroy the copy */ free(cp); return 0; } int uucp_lock(void) { int r, fd, pid; char buf[16]; mode_t m; if ( lockname[0] == '\0' ) return 0; fd = open(lockname, O_RDONLY); if ( fd >= 0 ) { r = read(fd, buf, sizeof(buf)); close(fd); /* if r == 4, lock file is binary (old-style) */ pid = (r == 4) ? *(int *)buf : strtol(buf, NULL, 10); if ( pid > 0 && kill((pid_t)pid, 0) < 0 && errno == ESRCH ) { /* stale lock file */ pinfo("\r\nRemoving stale lock: %s\r\n", lockname); sleep(1); unlink(lockname); } else { lockname[0] = '\0'; errno = EEXIST; return -1; } } /* lock it */ m = umask(022); fd = open(lockname, O_WRONLY|O_CREAT|O_EXCL, 0666); if ( fd < 0 ) { lockname[0] = '\0'; return -1; } umask(m); snprintf(buf, sizeof(buf), "%04d\n", getpid()); write(fd, buf, strlen(buf)); close(fd); return 0; } int uucp_unlock(void) { if ( lockname[0] ) unlink(lockname); return 0; } #endif /* of UUCP_LOCK_DIR */ /**********************************************************************/ #define HEXBUF_SZ 128 #define HEXDELIM " \r;:-_.,/" #define hexisdelim(c) ( strchr(HEXDELIM, (c)) != NULL ) static inline int hex2byte (char c) { int r; if ( c >= '0' && c <= '9' ) r = c - '0'; else if ( c >= 'A' && c <= 'F') r = c - 'A' + 10; else if ( c >= 'a' && c <= 'f' ) r = c - 'a' + 10; else r = -1; return r; } int hex2bin(unsigned char *buf, int sz, const char *str) { char c; int b0, b1; int i; i = 0; while (i < sz) { /* delimiter, end of string, or high nibble */ c = *str++; if ( c == '\0' ) break; if ( hexisdelim(c) ) continue; b0 = hex2byte(c); if ( b0 < 0 ) return -1; /* low nibble */ c = *str++; if ( c == '\0' ) return -1; b1 = hex2byte(c); if ( b1 < 0 ) return -1; /* pack byte */ buf[i++] = (unsigned char)b0 << 4 | (unsigned char)b1; } return i; } /**********************************************************************/ #ifndef LINENOISE char * read_filename (void) { char fname[_POSIX_PATH_MAX]; int r; fd_printf(STO, "\r\n*** file: "); r = fd_readline(STI, STO, fname, sizeof(fname)); fd_printf(STO, "\r\n"); if ( r < 0 ) return NULL; else return strdup(fname); } int read_baud (void) { char baudstr[9], *ep; int baud = -1, r; do { fd_printf(STO, "\r\n*** baud: "); r = fd_readline(STI, STO, baudstr, sizeof(baudstr)); fd_printf(STO, "\r\n"); if ( r < 0 ) break; baud = strtol(baudstr, &ep, 0); if ( ! ep || *ep != '\0' || ! term_baud_ok(baud) || baud == 0 ) { fd_printf(STO, "*** Invalid baudrate!"); baud = -1; } } while (baud < 0); return baud; } int read_hex (unsigned char *buff, int sz) { char hexstr[256]; int r, n; do { fd_printf(STO, "\r\n*** hex: "); r = fd_readline(STI, STO, hexstr, sizeof(hexstr)); fd_printf(STO, "\r\n"); if ( r < 0 ) { n = 0; break; } n = hex2bin(buff, sz, hexstr); if ( n < 0 ) fd_printf(STO, "*** Invalid hex!"); } while (n < 0); return n; } #else /* LINENOISE defined */ void file_completion_cb (const char *buf, linenoiseCompletions *lc) { DIR *dirp; struct dirent *dp; char *basec, *basen, *dirc, *dirn; int baselen, dirlen, namelen; char *fullpath; struct stat filestat; basec = strdup(buf); dirc = strdup(buf); dirn = dirname(dirc); dirlen = strlen(dirn); basen = basename(basec); baselen = strlen(basen); dirp = opendir(dirn); if (dirp) { while ((dp = readdir(dirp)) != NULL) { namelen = strlen(dp->d_name); if (strncmp(basen, dp->d_name, baselen) == 0) { /* add 2 extra bytes for possible / in middle & at end */ fullpath = (char *) malloc(namelen + dirlen + 3); memcpy(fullpath, dirn, dirlen + 1); if (fullpath[dirlen-1] != '/') strcat(fullpath, "/"); strncat(fullpath, dp->d_name, namelen); if (stat(fullpath, &filestat) == 0) { if (S_ISDIR(filestat.st_mode)) { strcat(fullpath, "/"); } linenoiseAddCompletion(lc,fullpath); } free(fullpath); } } closedir(dirp); } free(basec); free(dirc); } static char *history_file_path = NULL; void init_history (void) { char *home_directory; int home_directory_len; home_directory = getenv("HOME"); if (home_directory) { home_directory_len = strlen(home_directory); history_file_path = malloc(home_directory_len + 2 + strlen(HISTFILE)); memcpy(history_file_path, home_directory, home_directory_len + 1); if (home_directory[home_directory_len - 1] != '/') { strcat(history_file_path, "/"); } strcat(history_file_path, HISTFILE); linenoiseHistoryLoad(history_file_path); } } void cleanup_history (void) { if (history_file_path) free(history_file_path); } void add_history (char *fname) { linenoiseHistoryAdd(fname); if (history_file_path) linenoiseHistorySave(history_file_path); } char * read_filename (void) { char *fname; linenoiseSetCompletionCallback(file_completion_cb); fd_printf(STO, "\r\n"); fname = linenoise("*** file: "); fd_printf(STO, "\r"); linenoiseSetCompletionCallback(NULL); if (fname != NULL) add_history(fname); return fname; } int read_baud (void) { char *baudstr, *ep; int baud = -1; do { fd_printf(STO, "\r\n"); baudstr = linenoise("*** baud: "); fd_printf(STO, "\r"); if ( baudstr == NULL ) break; baud = strtol(baudstr, &ep, 0); if ( ! ep || *ep != '\0' || ! term_baud_ok(baud) || baud == 0 ) { fd_printf(STO, "*** Invalid baudrate!"); baud = -1; } free(baudstr); } while (baud < 0); if (baudstr != NULL) add_history(baudstr); return baud; } int read_hex (unsigned char *buff, int sz) { char *hexstr; int n; do { fd_printf(STO, "\r\n"); hexstr = linenoise("*** hex: "); fd_printf(STO, "\r"); if ( hexstr == NULL ) { n = 0; break; } n = hex2bin(buff, sz, hexstr); if ( n < 0 ) fd_printf(STO, "*** Invalid hex!"); free(hexstr); } while (n < 0); return n; } #endif /* of ifndef LINENOISE */ /**********************************************************************/ int pinfo(const char *format, ...) { va_list args; int len; if ( opts.quiet ) { return 0; } va_start(args, format); len = fd_vprintf(STO, format, args); va_end(args); return len; } void cleanup (int drain, int noreset, int hup) { if ( tty_fd >= 0 ) { /* Print msg if they fail? Can't do anything, anyway... */ if ( drain ) term_drain(tty_fd); term_flush(tty_fd); /* term_flush does not work with some drivers. If we try to drain or even close the port while there are still data in it's output buffers *and* flow-control is enabled we may block forever. So we "fake" a flush, by temporarily setting f/c to none, waiting for any data in the output buffer to drain, and then reseting f/c to it's original setting. If the real flush above does works, then the fake one should amount to instantaneously switching f/c to none and then back to its propper setting. */ if ( opts.flow != FC_NONE ) term_fake_flush(tty_fd); term_set_hupcl(tty_fd, !noreset || hup); term_apply(tty_fd, 1); if ( noreset ) { pinfo("Skipping tty reset...\r\n"); term_erase(tty_fd); #ifdef USE_FLOCK /* Explicitly unlock tty_fd before exiting. See comments in term.c/term_exitfunc() for more. */ flock(tty_fd, LOCK_UN); #endif close(tty_fd); tty_fd = -1; } } #ifdef LINENOISE cleanup_history(); #endif #ifdef UUCP_LOCK_DIR uucp_unlock(); #endif if ( opts.initstring ) { free(opts.initstring); opts.initstring = NULL; } if ( tty_q.buff ) { free(tty_q.buff); tty_q.buff = NULL; } free(opts.port); if (opts.log_filename) { free(opts.log_filename); close(log_fd); } } void fatal (const char *format, ...) { va_list args; fd_printf(STE, "\r\nFATAL: "); va_start(args, format); fd_vprintf(STE, format, args); va_end(args); fd_printf(STE, "\r\n"); cleanup(0 /* drain */, opts.noreset, opts.hangup); exit(EXIT_FAILURE); } /**********************************************************************/ /* maximum number of chars that can replace a single characted due to mapping */ #define M_MAXMAP 4 int map2hex (char *b, char c) { const char *hexd = "0123456789abcdef"; b[0] = '['; b[1] = hexd[(unsigned char)c >> 4]; b[2] = hexd[(unsigned char)c & 0x0f]; b[3] = ']'; return 4; } int do_map (char *b, int map, char c) { int n = -1; switch (c) { case '\x7f': /* DEL mapings */ if ( map & M_DELBS ) { b[0] = '\x08'; n = 1; } break; case '\x08': /* BS mapings */ if ( map & M_BSDEL ) { b[0] = '\x7f'; n = 1; } break; case '\x0d': /* CR mappings */ if ( map & M_CRLF ) { b[0] = '\x0a'; n = 1; } else if ( map & M_CRCRLF ) { b[0] = '\x0d'; b[1] = '\x0a'; n = 2; } else if ( map & M_IGNCR ) { n = 0; } else if ( map & M_CRHEX ) { n = map2hex(b, c); } break; case '\x0a': /* LF mappings */ if ( map & M_LFCR ) { b[0] = '\x0d'; n = 1; } else if ( map & M_LFCRLF ) { b[0] = '\x0d'; b[1] = '\x0a'; n = 2; } else if ( map & M_IGNLF ) { n = 0; } else if ( map & M_LFHEX ) { n = map2hex(b, c); } break; case '\x09': /* TAB mappings */ if ( map & M_TABHEX ) { n = map2hex(b,c); } break; default: break; } if ( n < 0 && map & M_SPCHEX ) { if ( c == '\x7f' || ( (unsigned char)c < 0x20 && c != '\x09' && c != '\x0a' && c != '\x0d') ) { n = map2hex(b,c); } } if ( n < 0 && map & M_8BITHEX ) { if ( c & 0x80 ) { n = map2hex(b,c); } } if ( n < 0 && map & M_NRMHEX ) { if ( (unsigned char)c >= 0x20 && (unsigned char)c < 0x7f ) { n = map2hex(b,c); } } if ( n < 0 ) { b[0] = c; n = 1; } assert(n > 0 && n <= M_MAXMAP); return n; } void map_and_write (int fd, int map, char c) { char b[M_MAXMAP]; int n; n = do_map(b, map, c); if ( n ) if ( writen_ni(fd, b, n) < n ) fatal("write to stdout failed: %s", strerror(errno)); } /**********************************************************************/ int baud_up (int baud) { return term_baud_up(baud); } int baud_down (int baud) { int nb; nb = term_baud_down(baud); if (nb == 0) nb = baud; return nb; } int flow_next (int flow) { switch(flow) { case FC_NONE: flow = FC_RTSCTS; break; case FC_RTSCTS: flow = FC_XONXOFF; break; case FC_XONXOFF: flow = FC_NONE; break; default: flow = FC_NONE; break; } return flow; } int parity_next (int parity) { switch(parity) { case P_NONE: parity = P_EVEN; break; case P_EVEN: parity = P_ODD; break; case P_ODD: parity = P_NONE; break; default: parity = P_NONE; break; } return parity; } int bits_next (int bits) { bits++; if (bits > 8) bits = 5; return bits; } int stopbits_next (int bits) { bits++; if (bits > 2) bits = 1; return bits; } /**********************************************************************/ #define statpf(...) \ do { if (! quiet) fd_printf(__VA_ARGS__); } while(0) int show_status (int quiet) { int baud, bits, stopbits, mctl; enum flowcntrl_e flow; enum parity_e parity; int mismatch = 0; term_refresh(tty_fd); baud = term_get_baudrate(tty_fd, NULL); flow = term_get_flowcntrl(tty_fd); parity = term_get_parity(tty_fd); bits = term_get_databits(tty_fd); stopbits = term_get_stopbits(tty_fd); statpf(STO, "\r\n"); if ( baud != opts.baud ) { mismatch++; statpf(STO, "*** baud: %d (%d)\r\n", opts.baud, baud); } else { statpf(STO, "*** baud: %d\r\n", opts.baud); } if ( flow != opts.flow ) { mismatch++; statpf(STO, "*** flow: %s (%s)\r\n", flow_str[opts.flow], flow_str[flow]); } else { statpf(STO, "*** flow: %s\r\n", flow_str[opts.flow]); } if ( parity != opts.parity ) { mismatch++; statpf(STO, "*** parity: %s (%s)\r\n", parity_str[opts.parity], parity_str[parity]); } else { statpf(STO, "*** parity: %s\r\n", parity_str[opts.parity]); } if ( bits != opts.databits ) { mismatch++; statpf(STO, "*** databits: %d (%d)\r\n", opts.databits, bits); } else { statpf(STO, "*** databits: %d\r\n", opts.databits); } if ( stopbits != opts.stopbits ) { mismatch++; statpf(STO, "*** stopbits: %d (%d)\r\n", opts.stopbits, stopbits); } else { statpf(STO, "*** stopbits: %d\r\n", opts.stopbits); } mctl = term_get_mctl(tty_fd); if (mctl >= 0 && mctl != MCTL_UNAVAIL) { if ( ((mctl & MCTL_DTR) ? 1 : 0) == dtr_up ) { statpf(STO, "*** dtr: %s\r\n", dtr_up ? "up" : "down"); } else { mismatch++; statpf(STO, "*** dtr: %s (%s)\r\n", dtr_up ? "up" : "down", (mctl & MCTL_DTR) ? "up" : "down"); } if ( ((mctl & MCTL_RTS) ? 1 : 0) == rts_up ) { statpf(STO, "*** rts: %s\r\n", rts_up ? "up" : "down"); } else { mismatch++; statpf(STO, "*** rts: %s (%s)\r\n", rts_up ? "up" : "down", (mctl & MCTL_RTS) ? "up" : "down"); } statpf(STO, "*** mctl: "); statpf(STO, "DTR:%c DSR:%c DCD:%c RTS:%c CTS:%c RI:%c\r\n", (mctl & MCTL_DTR) ? '1' : '0', (mctl & MCTL_DSR) ? '1' : '0', (mctl & MCTL_DCD) ? '1' : '0', (mctl & MCTL_RTS) ? '1' : '0', (mctl & MCTL_CTS) ? '1' : '0', (mctl & MCTL_RI) ? '1' : '0'); } else { statpf(STO, "*** dtr: %s\r\n", dtr_up ? "up" : "down"); statpf(STO, "*** rts: %s\r\n", rts_up ? "up" : "down"); } return mismatch; } #undef statpf /**********************************************************************/ void show_keys() { #ifndef NO_HELP fd_printf(STO, "\r\n"); fd_printf(STO, "*** Picocom commands (all prefixed by [C-%c])\r\n", KEYC(opts.escape)); fd_printf(STO, "\r\n"); fd_printf(STO, "*** [C-%c] : Exit picocom\r\n", KEYC(KEY_EXIT)); fd_printf(STO, "*** [C-%c] : Exit without reseting serial port\r\n", KEYC(KEY_QUIT)); fd_printf(STO, "*** [C-%c] : Set baudrate\r\n", KEYC(KEY_BAUD)); fd_printf(STO, "*** [C-%c] : Increase baudrate (baud-up)\r\n", KEYC(KEY_BAUD_UP)); fd_printf(STO, "*** [C-%c] : Decrease baudrate (baud-down)\r\n", KEYC(KEY_BAUD_DN));; fd_printf(STO, "*** [C-%c] : Change number of databits\r\n", KEYC(KEY_BITS)); fd_printf(STO, "*** [C-%c] : Change number of stopbits\r\n", KEYC(KEY_STOP)); fd_printf(STO, "*** [C-%c] : Change flow-control mode\r\n", KEYC(KEY_FLOW)); fd_printf(STO, "*** [C-%c] : Change parity mode\r\n", KEYC(KEY_PARITY)); fd_printf(STO, "*** [C-%c] : Pulse DTR\r\n", KEYC(KEY_PULSE)); fd_printf(STO, "*** [C-%c] : Toggle DTR\r\n", KEYC(KEY_TOG_DTR)); fd_printf(STO, "*** [C-%c] : Toggle RTS\r\n", KEYC(KEY_TOG_RTS)); fd_printf(STO, "*** [C-%c] : Send break\r\n", KEYC(KEY_BREAK)); fd_printf(STO, "*** [C-%c] : Toggle local echo\r\n", KEYC(KEY_LECHO)); fd_printf(STO, "*** [C-%c] : Write hex\r\n", KEYC(KEY_HEX)); fd_printf(STO, "*** [C-%c] : Send file\r\n", KEYC(KEY_SEND)); fd_printf(STO, "*** [C-%c] : Receive file\r\n", KEYC(KEY_RECEIVE)); fd_printf(STO, "*** [C-%c] : Show port settings\r\n", KEYC(KEY_STATUS)); fd_printf(STO, "*** [C-%c] : Show this message\r\n", KEYC(KEY_HELP)); fd_printf(STO, "\r\n"); #else /* defined NO_HELP */ fd_printf(STO, "*** Help is disabled.\r\n"); #endif /* of NO_HELP */ } /**********************************************************************/ #define RUNCMD_ARGS_MAX 32 #define RUNCMD_EXEC_FAIL 126 void establish_child_signal_handlers (void) { struct sigaction dfl_action; /* Set up the structure to specify the default action. */ dfl_action.sa_handler = SIG_DFL; sigemptyset (&dfl_action.sa_mask); dfl_action.sa_flags = 0; sigaction (SIGINT, &dfl_action, NULL); sigaction (SIGTERM, &dfl_action, NULL); } int run_cmd(int fd, const char *cmd, const char *args_extra) { pid_t pid; sigset_t sigm, sigm_old; struct sigaction ign_action, old_action; /* Picocom ignores SIGINT while the command is running */ ign_action.sa_handler = SIG_IGN; sigemptyset (&ign_action.sa_mask); ign_action.sa_flags = 0; sigaction (SIGINT, &ign_action, &old_action); /* block signals, let child establish its own handlers */ sigemptyset(&sigm); sigaddset(&sigm, SIGTERM); sigaddset(&sigm, SIGINT); sigprocmask(SIG_BLOCK, &sigm, &sigm_old); pid = fork(); if ( pid < 0 ) { sigprocmask(SIG_SETMASK, &sigm_old, NULL); fd_printf(STO, "*** cannot fork: %s ***\r\n", strerror(errno)); return -1; } else if ( pid ) { /* father: picocom */ int status, r; /* reset the mask */ sigprocmask(SIG_SETMASK, &sigm_old, NULL); /* wait for child to finish */ do { r = waitpid(pid, &status, 0); } while ( r < 0 && errno == EINTR ); /* reset terminal (back to raw mode) */ term_apply(STI, 0); /* re-enable SIGINT */ sigaction(SIGINT, &old_action, NULL); /* check and report child return status */ if ( WIFEXITED(status) ) { fd_printf(STO, "\r\n*** exit status: %d ***\r\n", WEXITSTATUS(status)); return WEXITSTATUS(status); } else if ( WIFSIGNALED(status) ) { fd_printf(STO, "\r\n*** killed by signal: %d ***\r\n", WTERMSIG(status)); return -1; } else { fd_printf(STO, "\r\n*** abnormal termination: 0x%x ***\r\n", r); return -1; } } else { /* child: external program */ long fl; int argc; char *argv[RUNCMD_ARGS_MAX + 1]; int r; /* unmanage terminal, and reset it to canonical mode */ term_drain(STI); term_remove(STI); /* unmanage serial port fd, without reset */ term_erase(fd); /* set serial port fd to blocking mode */ fl = fcntl(fd, F_GETFL); fl &= ~O_NONBLOCK; fcntl(fd, F_SETFL, fl); /* connect stdin and stdout to serial port */ close(STI); close(STO); dup2(fd, STI); dup2(fd, STO); /* build command arguments vector */ argc = 0; r = split_quoted(cmd, &argc, argv, RUNCMD_ARGS_MAX); if ( r < 0 ) { fd_printf(STE, "Cannot parse command\n"); exit(RUNCMD_EXEC_FAIL); } r = split_quoted(args_extra, &argc, argv, RUNCMD_ARGS_MAX); if ( r < 0 ) { fd_printf(STE, "Cannot parse extra args\n"); exit(RUNCMD_EXEC_FAIL); } if ( argc < 1 ) { fd_printf(STE, "No command given\n"); exit(RUNCMD_EXEC_FAIL); } argv[argc] = NULL; /* run extenral command */ fd_printf(STE, "$ %s %s\n", cmd, args_extra); establish_child_signal_handlers(); sigprocmask(SIG_SETMASK, &sigm_old, NULL); execvp(argv[0], argv); fd_printf(STE, "exec: %s\n", strerror(errno)); exit(RUNCMD_EXEC_FAIL); } } /**********************************************************************/ int tty_q_push(const char *s, int len) { int i, sz, n; unsigned char *b; for (i = 0; i < len; i++) { while (tty_q.len + M_MAXMAP > tty_q.sz) { sz = tty_q.sz * 2; if ( TTY_Q_SZ && sz > TTY_Q_SZ ) return i; b = realloc(tty_q.buff, sz); if ( ! b ) return i; tty_q.buff = b; tty_q.sz = sz; #if 0 fd_printf(STO, "New tty_q size: %d\r\n", sz); #endif } n = do_map((char *)tty_q.buff + tty_q.len, opts.omap, s[i]); tty_q.len += n; /* write to STO if local-echo is enabled */ if ( opts.lecho ) map_and_write(STO, opts.emap, s[i]); } return i; } /* Process command key. Returns non-zero if command results in picocom exit, zero otherwise. */ int do_command (unsigned char c) { int newbaud, newflow, newparity, newbits, newstopbits; const char *xfr_cmd; char *fname; unsigned char hexbuf[HEXBUF_SZ]; int n, r; switch (c) { case KEY_EXIT: return 1; case KEY_QUIT: opts.noreset = 1; return 1; case KEY_STATUS: show_status(0); break; case KEY_HELP: case KEY_KEYS: show_keys(); break; case KEY_PULSE: fd_printf(STO, "\r\n*** pulse DTR ***\r\n"); if ( term_pulse_dtr(tty_fd) < 0 ) fd_printf(STO, "*** FAILED\r\n"); else dtr_up = 1; break; case KEY_TOG_DTR: if ( dtr_up ) r = term_lower_dtr(tty_fd); else r = term_raise_dtr(tty_fd); if ( r >= 0 ) dtr_up = ! dtr_up; fd_printf(STO, "\r\n*** DTR: %s ***\r\n", dtr_up ? "up" : "down"); break; case KEY_TOG_RTS: if ( rts_up ) r = term_lower_rts(tty_fd); else r = term_raise_rts(tty_fd); if ( r >= 0 ) rts_up = ! rts_up; fd_printf(STO, "\r\n*** RTS: %s ***\r\n", rts_up ? "up" : "down"); break; case KEY_BAUD: case KEY_BAUD_UP: case KEY_BAUD_DN: if ( c== KEY_BAUD) { newbaud = read_baud(); if ( newbaud < 0 ) { fd_printf(STO, "*** cannot read baudrate ***\r\n"); break; } opts.baud = newbaud; } else if (c == KEY_BAUD_UP) { opts.baud = baud_up(opts.baud); } else { opts.baud = baud_down(opts.baud); } term_set_baudrate(tty_fd, opts.baud); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newbaud = term_get_baudrate(tty_fd, NULL); if ( opts.baud != newbaud ) { fd_printf(STO, "\r\n*** baud: %d (%d) ***\r\n", opts.baud, newbaud); } else { fd_printf(STO, "\r\n*** baud: %d ***\r\n", opts.baud); } set_tty_write_sz(newbaud); break; case KEY_FLOW: opts.flow = flow_next(opts.flow); term_set_flowcntrl(tty_fd, opts.flow); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newflow = term_get_flowcntrl(tty_fd); if ( opts.flow != newflow ) { fd_printf(STO, "\r\n*** flow: %s (%s) ***\r\n", flow_str[opts.flow], flow_str[newflow]); } else { fd_printf(STO, "\r\n*** flow: %s ***\r\n", flow_str[opts.flow]); } break; case KEY_PARITY: opts.parity = parity_next(opts.parity); term_set_parity(tty_fd, opts.parity); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newparity = term_get_parity(tty_fd); if (opts.parity != newparity ) { fd_printf(STO, "\r\n*** parity: %s (%s) ***\r\n", parity_str[opts.parity], parity_str[newparity]); } else { fd_printf(STO, "\r\n*** parity: %s ***\r\n", parity_str[opts.parity]); } break; case KEY_BITS: opts.databits = bits_next(opts.databits); term_set_databits(tty_fd, opts.databits); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newbits = term_get_databits(tty_fd); if (opts.databits != newbits ) { fd_printf(STO, "\r\n*** databits: %d (%d) ***\r\n", opts.databits, newbits); } else { fd_printf(STO, "\r\n*** databits: %d ***\r\n", opts.databits); } break; case KEY_STOP: opts.stopbits = stopbits_next(opts.stopbits); term_set_stopbits(tty_fd, opts.stopbits); tty_q.len = 0; term_flush(tty_fd); term_apply(tty_fd, 1); newstopbits = term_get_stopbits(tty_fd); if (opts.stopbits != newstopbits ) { fd_printf(STO, "\r\n*** stopbits: %d (%d) ***\r\n", opts.stopbits, newstopbits); } else { fd_printf(STO, "\r\n*** stopbits: %d ***\r\n", opts.stopbits); } break; case KEY_LECHO: opts.lecho = ! opts.lecho; fd_printf(STO, "\r\n*** local echo: %s ***\r\n", opts.lecho ? "yes" : "no"); break; case KEY_SEND: case KEY_RECEIVE: xfr_cmd = (c == KEY_SEND) ? opts.send_cmd : opts.receive_cmd; if ( xfr_cmd[0] == '\0' ) { fd_printf(STO, "\r\n*** command disabled ***\r\n"); break; } fname = read_filename(); if (fname == NULL) { fd_printf(STO, "*** cannot read filename ***\r\n"); break; } run_cmd(tty_fd, xfr_cmd, fname); free(fname); break; case KEY_HEX: n = read_hex(hexbuf, sizeof(hexbuf)); if ( n < 0 ) { fd_printf(STO, "*** cannot read hex ***\r\n"); break; } if ( tty_q_push((char *)hexbuf, n) != n ) fd_printf(STO, "*** output buffer full ***\r\n"); fd_printf(STO, "*** wrote %d bytes ***\r\n", n); break; case KEY_BREAK: term_break(tty_fd); fd_printf(STO, "\r\n*** break sent ***\r\n"); break; default: break; } return 0; } /**********************************************************************/ static struct timeval * msec2tv (struct timeval *tv, long ms) { tv->tv_sec = ms / 1000; tv->tv_usec = (ms % 1000) * 1000; return tv; } /* loop-exit reason */ enum le_reason { LE_CMD, LE_IDLE, LE_STDIN, LE_SIGNAL }; enum le_reason loop(void) { enum { ST_COMMAND, ST_TRANSPARENT } state; fd_set rdset, wrset; int r, n; int stdin_closed; state = ST_TRANSPARENT; if ( ! opts.exit ) stdin_closed = 0; else stdin_closed = 1; while ( ! sig_exit ) { struct timeval tv, *ptv; ptv = NULL; FD_ZERO(&rdset); FD_ZERO(&wrset); if ( ! stdin_closed ) FD_SET(STI, &rdset); if ( ! opts.exit ) FD_SET(tty_fd, &rdset); if ( tty_q.len ) { FD_SET(tty_fd, &wrset); } else { if ( opts.exit_after >= 0 ) { msec2tv(&tv, opts.exit_after); ptv = &tv; } else if ( stdin_closed ) { /* stdin closed, output queue empty, and no idle timeout: Exit. */ return LE_STDIN; } } r = select(tty_fd + 1, &rdset, &wrset, NULL, ptv); if ( r < 0 ) { if ( errno == EINTR ) continue; else fatal("select failed: %d : %s", errno, strerror(errno)); } if ( r == 0 ) { /* Idle timeout expired */ return LE_IDLE; } if ( FD_ISSET(STI, &rdset) ) { /* read from terminal */ char buff_rd[STI_RD_SZ]; int i; unsigned char c; do { n = read(STI, buff_rd, sizeof(buff_rd)); } while (n < 0 && errno == EINTR); if (n == 0) { stdin_closed = 1; pinfo("\r\n** read zero bytes from stdin **\r\n"); goto skip_proc_STI; } else if (n < 0) { /* is this really necessary? better safe than sory! */ if ( errno != EAGAIN && errno != EWOULDBLOCK ) fatal("read from stdin failed: %s", strerror(errno)); else goto skip_proc_STI; } for ( i = 0; i < n; i++ ) { c = buff_rd[i]; switch (state) { case ST_COMMAND: if ( c == opts.escape ) { /* pass the escape character down */ if ( tty_q_push((char *)&c, 1) != 1 ) fd_printf(STO, "\x07"); } else { /* process command key */ if ( do_command(c) ) /* picocom exit */ return LE_CMD; } state = ST_TRANSPARENT; break; case ST_TRANSPARENT: if ( ! opts.noescape && c == opts.escape ) state = ST_COMMAND; else if ( tty_q_push((char *)&c, 1) != 1 ) fd_printf(STO, "\x07"); break; default: assert(0); break; } } } skip_proc_STI: if ( FD_ISSET(tty_fd, &rdset) ) { char buff_rd[TTY_RD_SZ]; char buff_map[TTY_RD_SZ * M_MAXMAP]; /* read from port */ do { n = read(tty_fd, &buff_rd, sizeof(buff_rd)); } while (n < 0 && errno == EINTR); if (n == 0) { fatal("read zero bytes from port"); } else if ( n < 0 ) { if ( errno != EAGAIN && errno != EWOULDBLOCK ) fatal("read from port failed: %s", strerror(errno)); } else { int i; char *bmp = &buff_map[0]; if ( opts.log_filename ) if ( writen_ni(log_fd, buff_rd, n) < n ) fatal("write to logfile failed: %s", strerror(errno)); for (i = 0; i < n; i++) { bmp += do_map(bmp, opts.imap, buff_rd[i]); } n = bmp - buff_map; if ( writen_ni(STO, buff_map, n) < n ) fatal("write to stdout failed: %s", strerror(errno)); } } if ( FD_ISSET(tty_fd, &wrset) ) { /* write to port */ int sz; sz = (tty_q.len < tty_write_sz) ? tty_q.len : tty_write_sz; do { n = write(tty_fd, tty_q.buff, sz); } while ( n < 0 && errno == EINTR ); if ( n <= 0 ) fatal("write to port failed: %s", strerror(errno)); if ( opts.lecho && opts.log_filename ) if ( writen_ni(log_fd, tty_q.buff, n) < n ) fatal("write to logfile failed: %s", strerror(errno)); memmove(tty_q.buff, tty_q.buff + n, tty_q.len - n); tty_q.len -= n; } } return LE_SIGNAL; } /**********************************************************************/ void deadly_handler(int signum) { if ( ! sig_exit ) { sig_exit = 1; kill(0, SIGTERM); } } void establish_signal_handlers (void) { struct sigaction exit_action, ign_action; /* Set up the structure to specify the exit action. */ exit_action.sa_handler = deadly_handler; sigemptyset (&exit_action.sa_mask); exit_action.sa_flags = 0; /* Set up the structure to specify the ignore action. */ ign_action.sa_handler = SIG_IGN; sigemptyset (&ign_action.sa_mask); ign_action.sa_flags = 0; sigaction (SIGTERM, &exit_action, NULL); sigaction (SIGINT, &exit_action, NULL); sigaction (SIGHUP, &ign_action, NULL); sigaction (SIGQUIT, &ign_action, NULL); sigaction (SIGALRM, &ign_action, NULL); sigaction (SIGUSR1, &ign_action, NULL); sigaction (SIGUSR2, &ign_action, NULL); sigaction (SIGPIPE, &ign_action, NULL); } /**********************************************************************/ void show_usage(char *name) { #ifndef NO_HELP char *s; s = strrchr(name, '/'); s = s ? s+1 : name; printf("picocom v%s\n", VERSION_STR); printf("\nCompiled-in options:\n"); printf(" TTY_Q_SZ is %d\n", TTY_Q_SZ); #ifdef HIGH_BAUD printf(" HIGH_BAUD is enabled\n"); #endif #ifdef USE_FLOCK printf(" USE_FLOCK is enabled\n"); #endif #ifdef UUCP_LOCK_DIR printf(" UUCP_LOCK_DIR is: %s\n", UUCP_LOCK_DIR); #endif #ifdef LINENOISE printf(" LINENOISE is enabled\n"); printf(" HISTFILE is: %s\n", HISTFILE); #endif #ifdef USE_CUSTOM_BAUD printf(" USE_CUSTOM_BAUD is enabled\n"); #endif printf("\nUsage is: %s [options] \n", s); printf("Options are:\n"); printf(" --aud \n"); printf(" --low x (=soft,xon/xoff) | h (=hard) | n (=none)\n"); printf(" --parit o (=odd) | e (=even) | n (=none)\n"); printf(" --atabits 5 | 6 | 7 | 8\n"); printf(" --sto

bits 1 | 2\n"); printf(" --scape \n"); printf(" --o-escape\n"); printf(" --eho\n"); printf(" --nonit\n"); printf(" --noeset\n"); printf(" --hangp\n"); printf(" --noock\n"); printf(" --end-cmd \n"); printf(" --receie-cmd \n"); printf(" --imap (input mappings)\n"); printf(" --omap (output mappings)\n"); printf(" --emap (local-echo mappings)\n"); printf(" --lofile \n"); printf(" --initsring \n"); printf(" --eit-after \n"); printf(" --eit\n"); printf(" --lower-rts\n"); printf(" --raise-rts\n"); printf(" --lower-dtr\n"); printf(" --raise-dtr\n"); printf(" --uiet\n"); printf(" --elp\n"); printf(" is a comma-separated list of one or more of:\n"); printf(" crlf : map CR --> LF\n"); printf(" crcrlf : map CR --> CR + LF\n"); printf(" igncr : ignore CR\n"); printf(" lfcr : map LF --> CR\n"); printf(" lfcrlf : map LF --> CR + LF\n"); printf(" ignlf : ignore LF\n"); printf(" bsdel : map BS --> DEL\n"); printf(" delbs : map DEL --> BS\n"); printf(" spchex : map special chars (excl. CR, LF & TAB) --> hex\n"); printf(" tabhex : map TAB --> hex\n"); printf(" crhex : map CR --> hex\n"); printf(" lfhex : map LF --> hex\n"); printf(" 8bithex : map 8-bit chars --> hex\n"); printf(" nrmhex : map normal ascii chars --> hex\n"); printf(" indicates the equivalent short option.\n"); printf("Short options are prefixed by \"-\" instead of by \"--\".\n"); #else /* defined NO_HELP */ printf("Help disabled.\n"); #endif /* of NO_HELP */ fflush(stdout); } /**********************************************************************/ void parse_args(int argc, char *argv[]) { int r; static struct option longOptions[] = { {"receive-cmd", required_argument, 0, 'v'}, {"send-cmd", required_argument, 0, 's'}, {"imap", required_argument, 0, 'I' }, {"omap", required_argument, 0, 'O' }, {"emap", required_argument, 0, 'E' }, {"escape", required_argument, 0, 'e'}, {"no-escape", no_argument, 0, 'n'}, {"echo", no_argument, 0, 'c'}, {"noinit", no_argument, 0, 'i'}, {"noreset", no_argument, 0, 'r'}, {"hangup", no_argument, 0, 'u'}, {"nolock", no_argument, 0, 'l'}, {"flow", required_argument, 0, 'f'}, {"baud", required_argument, 0, 'b'}, {"parity", required_argument, 0, 'y'}, {"databits", required_argument, 0, 'd'}, {"stopbits", required_argument, 0, 'p'}, {"logfile", required_argument, 0, 'g'}, {"initstring", required_argument, 0, 't'}, {"exit-after", required_argument, 0, 'x'}, {"exit", no_argument, 0, 'X'}, {"lower-rts", no_argument, 0, 1}, {"lower-dtr", no_argument, 0, 2}, {"raise-rts", no_argument, 0, 3}, {"raise-dtr", no_argument, 0, 4}, {"quiet", no_argument, 0, 'q'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; r = 0; while (1) { int optionIndex = 0; int c; int map; char *ep; /* no default error messages printed. */ opterr = 0; c = getopt_long(argc, argv, "hirulcqXnv:s:r:e:f:b:y:d:p:g:t:x:", longOptions, &optionIndex); if (c < 0) break; switch (c) { case 's': strncpy(opts.send_cmd, optarg, sizeof(opts.send_cmd)); opts.send_cmd[sizeof(opts.send_cmd) - 1] = '\0'; break; case 'v': strncpy(opts.receive_cmd, optarg, sizeof(opts.receive_cmd)); opts.receive_cmd[sizeof(opts.receive_cmd) - 1] = '\0'; break; case 'I': map = parse_map(optarg); if (map >= 0) opts.imap = map; else { fprintf(stderr, "Invalid --imap\n"); r = -1; } break; case 'O': map = parse_map(optarg); if (map >= 0) opts.omap = map; else { fprintf(stderr, "Invalid --omap\n"); r = -1; } break; case 'E': map = parse_map(optarg); if (map >= 0) opts.emap = map; else { fprintf(stderr, "Invalid --emap\n"); r = -1; } break; case 'c': opts.lecho = 1; break; case 'i': opts.noinit = 1; break; case 'r': opts.noreset = 1; break; case 'u': opts.hangup = 1; break; case 'l': #if defined (UUCP_LOCK_DIR) || defined (USE_FLOCK) opts.nolock = 1; #endif break; case 'e': opts.escape = CKEY(optarg[0]); break; case 'n': opts.noescape = 1; break; case 'f': switch (optarg[0]) { case 'X': case 'x': case 'S': case 's': opts.flow = FC_XONXOFF; break; case 'H': case 'h': opts.flow = FC_RTSCTS; break; case 'N': case 'n': opts.flow = FC_NONE; break; default: fprintf(stderr, "Invalid --flow: %c\n", optarg[0]); r = -1; break; } break; case 'b': opts.baud = atoi(optarg); if ( opts.baud == 0 || ! term_baud_ok(opts.baud) ) { fprintf(stderr, "Invalid --baud: %d\n", opts.baud); r = -1; } break; case 'y': switch (optarg[0]) { case 'e': opts.parity = P_EVEN; break; case 'o': opts.parity = P_ODD; break; case 'n': opts.parity = P_NONE; break; default: fprintf(stderr, "Invalid --parity: %c\n", optarg[0]); r = -1; break; } break; case 'd': switch (optarg[0]) { case '5': opts.databits = 5; break; case '6': opts.databits = 6; break; case '7': opts.databits = 7; break; case '8': opts.databits = 8; break; default: fprintf(stderr, "Invalid --databits: %c\n", optarg[0]); r = -1; break; } break; case 'p': opts.stopbits = 1; switch (optarg[0]) { case '1': break; case '2': opts.stopbits = 2; break; /* For backwards compatibility, you can use 'p' to set the parity as well */ case 'e': opts.parity = P_EVEN; break; case 'o': opts.parity = P_ODD; break; case 'n': opts.parity = P_NONE; break; default: fprintf(stderr, "Invalid --stopbits: %c\n", optarg[0]); r = -1; break; } break; case 'g': opts.log_filename = strdup(optarg); break; case 't': opts.initstring = strdup(optarg); break; case 1: opts.lower_rts = 1; break; case 2: opts.lower_dtr = 1; break; case 3: opts.raise_rts = 1; break; case 4: opts.raise_dtr = 1; break; case 'x': opts.exit_after = strtol(optarg, &ep, 10); if ( ! ep || *ep != '\0' || opts.exit_after < 0 ) { fprintf(stderr, "Inavild --exit-after: %s\n", optarg); r = -1; break; } break; case 'X': opts.exit = 1; break; case 'q': opts.quiet = 1; break; case 'h': show_usage(argv[0]); exit(EXIT_SUCCESS); case '?': default: fprintf(stderr, "Unrecognized option(s)\n"); r = -1; break; } if ( r < 0 ) { fprintf(stderr, "Run with '--help'.\n"); exit(EXIT_FAILURE); } } /* while */ if ( opts.raise_rts && opts.lower_rts ) { fprintf(stderr, "Both --raise-rts and --lower-rts given\n"); exit(EXIT_FAILURE); } if ( opts.raise_dtr && opts.lower_dtr ) { fprintf(stderr, "Both --raise-dtr and --lower-dtr given\n"); exit(EXIT_FAILURE); } /* --exit overrides --exit-after */ if ( opts.exit ) opts.exit_after = -1; if ( (argc - optind) < 1) { fprintf(stderr, "No port given\n"); fprintf(stderr, "Run with '--help'.\n"); exit(EXIT_FAILURE); } opts.port = strdup(argv[optind++]); if ( ! opts.port ) { fprintf(stderr, "Out of memory\n"); exit(EXIT_FAILURE); } if ( argc != optind ) { fprintf(stderr, "Unexpected non-option arguments: "); while (argc != optind) fprintf(stderr, "%s ", argv[optind++]); fprintf(stderr, "\n"); exit(EXIT_FAILURE); } if ( opts.quiet ) return; #ifndef NO_HELP printf("picocom v%s\n", VERSION_STR); printf("\n"); printf("port is : %s\n", opts.port); printf("flowcontrol : %s\n", flow_str[opts.flow]); printf("baudrate is : %d\n", opts.baud); printf("parity is : %s\n", parity_str[opts.parity]); printf("databits are : %d\n", opts.databits); printf("stopbits are : %d\n", opts.stopbits); if ( opts.noescape ) { printf("escape is : none\n"); } else { printf("escape is : C-%c\n", KEYC(opts.escape)); } printf("local echo is : %s\n", opts.lecho ? "yes" : "no"); printf("noinit is : %s\n", opts.noinit ? "yes" : "no"); printf("noreset is : %s\n", opts.noreset ? "yes" : "no"); printf("hangup is : %s\n", opts.hangup ? "yes" : "no"); #if defined (UUCP_LOCK_DIR) || defined (USE_FLOCK) printf("nolock is : %s\n", opts.nolock ? "yes" : "no"); #endif printf("send_cmd is : %s\n", (opts.send_cmd[0] == '\0') ? "disabled" : opts.send_cmd); printf("receive_cmd is : %s\n", (opts.receive_cmd[0] == '\0') ? "disabled" : opts.receive_cmd); printf("imap is : "); print_map(opts.imap); printf("omap is : "); print_map(opts.omap); printf("emap is : "); print_map(opts.emap); printf("logfile is : %s\n", opts.log_filename ? opts.log_filename : "none"); if ( opts.initstring ) { printf("initstring len : %lu bytes\n", (unsigned long)strlen(opts.initstring)); } else { printf("initstring : none\n"); } if (opts.exit_after < 0) { printf("exit_after is : not set\n"); } else { printf("exit_after is : %d ms\n", opts.exit_after); } printf("exit is : %s\n", opts.exit ? "yes" : "no"); printf("\n"); fflush(stdout); #endif /* of NO_HELP */ } /**********************************************************************/ void set_dtr_rts (void) { int r; if ( opts.lower_rts ) { r = term_lower_rts(tty_fd); if ( r < 0 ) fatal("failed to lower RTS of port: %s", term_strerror(term_errno, errno)); rts_up = 0; } else if ( opts.raise_rts ) { r = term_raise_rts(tty_fd); if ( r < 0 ) fatal("failed to raise RTS of port: %s", term_strerror(term_errno, errno)); rts_up = 1; } if ( opts.lower_dtr ) { r = term_lower_dtr(tty_fd); if ( r < 0 ) fatal("failed to lower DTR of port: %s", term_strerror(term_errno, errno)); dtr_up = 0; } else if ( opts.raise_dtr ) { r = term_raise_dtr(tty_fd); if ( r < 0 ) fatal("failed to raise DTR of port: %s", term_strerror(term_errno, errno)); dtr_up = 1; } /* Try to read the status of the modem-conrtol lines from the port. */ r = term_get_mctl(tty_fd); if ( r >= 0 && r != MCTL_UNAVAIL ) { rts_up = (r & MCTL_RTS) != 0; dtr_up = (r & MCTL_DTR) != 0; } } int main (int argc, char *argv[]) { int xcode = EXIT_SUCCESS; int ler; int r; parse_args(argc, argv); establish_signal_handlers(); r = term_lib_init(); if ( r < 0 ) fatal("term_lib_init failed: %s", term_strerror(term_errno, errno)); #ifdef UUCP_LOCK_DIR if ( ! opts.nolock ) uucp_lockname(UUCP_LOCK_DIR, opts.port); if ( uucp_lock() < 0 ) fatal("cannot lock %s: %s", opts.port, strerror(errno)); #endif if (opts.log_filename) { log_fd = open(opts.log_filename, O_CREAT | O_RDWR | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); if (log_fd < 0) fatal("cannot open %s: %s", opts.log_filename, strerror(errno)); } tty_fd = open(opts.port, O_RDWR | O_NONBLOCK | O_NOCTTY); if (tty_fd < 0) fatal("cannot open %s: %s", opts.port, strerror(errno)); #ifdef USE_FLOCK if ( ! opts.nolock ) { r = flock(tty_fd, LOCK_EX | LOCK_NB); if ( r < 0 ) fatal("cannot lock %s: %s", opts.port, strerror(errno)); } #endif if ( opts.noinit ) { r = term_add(tty_fd); } else { r = term_set(tty_fd, 1, /* raw mode. */ opts.baud, /* baud rate. */ opts.parity, /* parity. */ opts.databits, /* data bits. */ opts.stopbits, /* stop bits. */ opts.flow, /* flow control. */ 1, /* local or modem */ !opts.noreset); /* hup-on-close. */ } if ( r < 0 ) fatal("failed to add port: %s", term_strerror(term_errno, errno)); /* Set DTR and RTS status, as quickly as possible after opening the serial port (i.e. before configuring it) */ set_dtr_rts(); r = term_apply(tty_fd, 0); if ( r < 0 ) fatal("failed to config port: %s", term_strerror(term_errno, errno)); /* Set DTR and RTS status *again* after configuring the port. On some systems term_apply() resets the status of DTR and / or RTS */ set_dtr_rts(); set_tty_write_sz(term_get_baudrate(tty_fd, NULL)); /* Check for settings mismatch and print warning */ if ( !opts.quiet && !opts.noinit && show_status(1) != 0 ) { pinfo("!! Settings mismatch !!"); if ( ! opts.noescape ) pinfo(" Type [C-%c] [C-%c] to see actual port settings", KEYC(opts.escape), KEYC(KEY_STATUS)); pinfo("\r\n"); } if ( ! opts.exit ) { if ( isatty(STI) ) { r = term_add(STI); if ( r < 0 ) fatal("failed to add I/O device: %s", term_strerror(term_errno, errno)); term_set_raw(STI); r = term_apply(STI, 0); if ( r < 0 ) fatal("failed to set I/O device to raw mode: %s", term_strerror(term_errno, errno)); } else { pinfo("!! STDIN is not a TTY !! Continue anyway...\r\n"); } } else { close(STI); } #ifdef LINENOISE init_history(); #endif /* Allocate output buffer with initial size */ tty_q.buff = calloc(TTY_Q_SZ_MIN, sizeof(*tty_q.buff)); if ( ! tty_q.buff ) fatal("out of memory"); tty_q.sz = TTY_Q_SZ_MIN; tty_q.len = 0; /* Prime output buffer with initstring */ if ( opts.initstring ) { if ( opts.noinit ) { pinfo("Ignoring init-string (--noinit)\r\n"); } else { int l; l = strlen(opts.initstring); if ( tty_q_push(opts.initstring, l) != l ) { fatal("initstring too long!"); } } } /* Free initstirng, no longer needed */ if ( opts.initstring ) { free(opts.initstring); opts.initstring = NULL; } #ifndef NO_HELP if ( ! opts.noescape ) { pinfo("Type [C-%c] [C-%c] to see available commands\r\n", KEYC(opts.escape), KEYC(KEY_HELP)); } #endif pinfo("Terminal ready\r\n"); /* Enter main processing loop */ ler = loop(); /* Terminating picocom */ pinfo("\r\n"); pinfo("Terminating...\r\n"); if ( ler == LE_CMD || ler == LE_SIGNAL ) cleanup(0 /* drain */, opts.noreset, opts.hangup); else cleanup(1 /* drain */, opts.noreset, opts.hangup); if ( ler == LE_SIGNAL ) { pinfo("Picocom was killed\r\n"); xcode = EXIT_FAILURE; } else pinfo("Thanks for using picocom\r\n"); return xcode; } /**********************************************************************/ /* * Local Variables: * mode:c * tab-width: 4 * c-basic-offset: 4 * End: */ picocom-3.1/split.c000066400000000000000000000152261323455570200143210ustar00rootroot00000000000000/* vi: set sw=4 ts=4: * * split.c * * Function that splits a string intro arguments with quoting. * * by Nick Patavalis (npat@efault.net) * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #include #include #include #include "split.h" /* Lexer error end-codes */ enum err_codes { ERR_OK = 0, /* no error, string lexed ok */ ERR_BS_AT_EOS, /* backslash at the end of string */ ERR_SQ_OPEN_AT_EOS, /* single-quote left open */ ERR_DQ_OPEN_AT_EOS /* double-quote left open */ }; /* Lexer states */ enum states { ST_DELIM, ST_QUOTE, ST_ARG, ST_END }; /* Special characters */ #define BS '\\' #define SQ '\'' #define DQ '\"' #define NL '\n' #define EOS '\0' #define is_delim(c) \ ( (c) == ' ' || (c) == '\t' || (c) == '\n' ) #define is_dq_escapable(c) \ ( (c) == '\\' || (c) == '\"' || (c) == '`' || (c) == '$' ) /* Short-hands used in split_quoted() */ #define push() \ do { \ char *arg; \ if ( *argc < argv_sz ) { \ *ap = '\0'; \ arg = strdup(arg_buff); \ /* !! out of mem !! */ \ if ( ! arg ) return -1; \ argv[*argc] = arg; \ (*argc)++; \ } else { \ flags |= SPLIT_DROP; \ } \ ap = &arg_buff[0]; \ } while(0) #define save() \ do { \ if (ap != ae) { \ *ap++ = *c; \ } else { \ flags |= SPLIT_TRUNC; \ } \ } while (0) int split_quoted (const char *s, int *argc, char *argv[], int argv_sz) { char arg_buff[MAX_ARG_LEN]; /* current argument buffer */ char *ap, *ae; /* arg_buff current ptr & end-guard */ const char *c; /* current input charcter ptr */ char qc; /* current quote character */ enum states state; /* current state */ enum err_codes err; /* error end-code */ int flags; /* warning flags */ ap = &arg_buff[0]; ae = &arg_buff[MAX_ARG_LEN - 1]; c = &s[0]; state = ST_DELIM; err = ERR_OK; flags = 0; qc = SQ; /* silence compiler waring */ while ( state != ST_END ) { switch (state) { case ST_DELIM: while ( is_delim(*c) ) c++; if ( *c == SQ || *c == DQ ) { qc = *c; c++; state = ST_QUOTE; break; } if ( *c == EOS ) { state = ST_END; break; } if ( *c == BS ) { c++; if ( *c == NL ) { c++; break; } if ( *c == EOS ) { state = ST_END; err = ERR_BS_AT_EOS; break; } } /* All other cases incl. character after BS */ save(); c++; state = ST_ARG; break; case ST_QUOTE: while ( *c != qc && ( *c != BS || qc == SQ ) && *c != EOS ) { save(); c++; } if ( *c == qc ) { c++; state = ST_ARG; break; } if ( *c == BS ) { assert (qc == DQ); c++; if ( *c == NL) { c++; break; } if (*c == EOS) { state = ST_END; err = ERR_BS_AT_EOS; break; } if ( ! is_dq_escapable(*c) ) { c--; save(); c++; } save(); c++; break; } if ( *c == EOS ) { state = ST_END; err = ERR_SQ_OPEN_AT_EOS; break; } assert(0); case ST_ARG: if ( *c == SQ || *c == DQ ) { qc = *c; c++; state = ST_QUOTE; break; } if ( is_delim(*c) || *c == EOS ) { push(); state = (*c == EOS) ? ST_END : ST_DELIM; c++; break; } if ( *c == BS ) { c++; if ( *c == NL ) { c++; break; } if ( *c == EOS ) { state = ST_END; err = ERR_BS_AT_EOS; break; } } /* All other cases, incl. character after BS */ save(); c++; break; default: assert(0); } } return ( err != ERR_OK ) ? -1 : flags; } /**********************************************************************/ #if 0 int main (int argc, char *argv[]) { char *my_argv[12]; int my_argc, i, r; if ( argc != 2 ) { printf("Usage is: %s: \n", argv[0]); exit(EXIT_FAILURE); } printf("String to split is: [%s]\n", argv[1]); r = split_quoted(argv[1], &my_argc, my_argv, 12); if ( r < 0 ) { printf("Spliting failed!\n"); exit(EXIT_FAILURE); } printf("Split ok. SPLIT_DROP is %s, SPLIT_TRUNC is %s\n", (r & SPLIT_DROP) ? "ON" : "off", (r & SPLIT_TRUNC) ? "ON" : "off"); for (i = 0; i < my_argc; i++) printf("%02d : [%s]\n", i, my_argv[i]); return EXIT_SUCCESS; } #endif /**********************************************************************/ /* * Local Variables: * mode:c * tab-width: 4 * c-basic-offset: 4 * indent-tabs-mode: nil * End: */ picocom-3.1/split.h000066400000000000000000000120261323455570200143210ustar00rootroot00000000000000/* vi: set sw=4 ts=4: * * split.h * * Function that splits a string intro arguments with quoting. * * by Nick Patavalis (npat@efault.net) * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #ifndef SPLIT_H #define SPLIT_H /* Maximum single-argument length that can be dealt-with by function * split_quoted(). Longer arguments are truncated. See below. */ #define MAX_ARG_LEN 512 /* Warning flags, set by split_quoted() to its return value. */ #define SPLIT_DROP (1 << 0) /* argument had to be dropped */ #define SPLIT_TRUNC (1 << 1) /* argument had to be truncated */ /* F split_quoted * * Splits string "s" into arguments and places them in "argv". Every * argument is a heap-allocated null-terminated string that must be * freed with free(3) when no longer needed. The first argument is * placed in "argv[*argc]", the following at subsequent "argv" slots, * and "*argc" is incremented accordingly. As a result, this function * can be called multiple times to add arguments to the same argument * vector. The argument "argv_sz" is the allocated size (in number of * slots) of the supplied argument vector ("argv"). The function takes * care not to overrun it. If more arguments are present in the * input string "s", they are dropped. * * When spliting the input string intro arguments, quoting rules * very similar to the ones used by the Unix shell are used. * * The following caracters are considered special: ' ' (space), '\t' * (tab), '\n' (newline), '\' (backslash), ''' (single quote), and '"' * (double quote). All other caracters are considered normal and can * become part of an argument without escaping. * * Arguments are separated by runs of the characters: ' ' (space), * '\t', and '\n', which are considered delimiters. * * All characters beetween single quotes (')---without * exceptions---are considered normal and become part of the current * argument (but not the single quotes themselves). * * All characters between double quotes (") are considered normal and * become part of the current argument (but not the double quotes * themselves). Exception to this is the backslash character, when * followed by one of the characters '"', '\', '$', and '`'. In this * case, the backslash is removed, and the next caracter is considered * normal and becomes part of the current argument. When the backslash * is followed by newline, both the backslash and the newline are * removed. In all other cases a backslash, within double quotes, is * considered a normal character (and becomes part of the current * argument). We treat the sequences '\$' and '\`' specially (while * there is no real reason), for better unix-shell compatibility. * * Outside of single or double quotes, every backslash caracter is * removed, and the following character (with the exception of * , see below) is considered normal and becomes part of the * current argument. If, outside of quotes, a backslash precedes a * , then both the backslash and the newline are removed. * * Examples: * * a b c d --> [a] [b] [c] [d] * 'a b' c d --> [a b] [c] [d] * 'a "b"' c d --> [a "b"] [c] [d] * "a 'b'" c d --> [a 'b'] [c] [d] * a"b c" d --> [ab c] [d] * a\ b c d --> [a b] [c] [d] * \a\b c d --> [ab] [c] [d] * \a\\b \\ c d --> [a\b] [\] [c] [d] * "a\$\b" c d --> [a$\b] [c] [d] * "\a\`\"\b" c d --> [\a`"\b] [c] [d] * * Limitation: This function cannot deal with individual arguments * longer than MAX_ARG_LEN. If such an argument is encountered, it is * truncated accordingly. * * This function returns a non-negative on success, and a negative on * failure. The only causes for failure is a malformed command string * (e.g. un-balanced quotes), or the inability to allocate an argument * string. On success the value returned can be checked against the * warning flags SPLIT_DROP, and SPLIT_TRUNC. If SPLIT_DROP is set, * then a least one argument was dropped as there was no available * slot in "argv" to store it in. If SPLIT_TRUNC is set, then at least * one argument was truncated (see limitation, above). */ int split_quoted(const char *s, int *argc, char *argv[], int argv_sz); #endif /* of SPLIT_H */ /**********************************************************************/ /* * Local Variables: * mode:c * tab-width: 4 * c-basic-offset: 4 * indent-tabs-mode: nil * End: */ picocom-3.1/term.c000066400000000000000000001077001323455570200141340ustar00rootroot00000000000000/* vi: set sw=4 ts=4: * * term.c * * General purpose terminal handling library. * * by Nick Patavalis (npat@efault.net) * * originaly by Pantelis Antoniou (https://github.com/pantoniou), * Nick Patavalis * * Documentation can be found in the header file "term.h". * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * * $Id$ */ #include #include #include #include #include #include #ifdef USE_FLOCK #include #endif /* glibc for MIPS has its own bits/termios.h which does not define * CMSPAR, so we use the value from the generic bits/termios.h */ #ifdef __linux__ #ifndef CMSPAR #define CMSPAR 010000000000 #endif #endif /* Some BSDs (and possibly other systems too) have no mark / space * parity support, and they don't define CMSPAR. Use a zero CMSPAR in * these cases. If the user tries to set P_MARK or P_SPACE he will get * P_EVEN or P_ODD instead. */ #ifndef CMSPAR #define CMSPAR 0 #endif /* On these systems, use the TIOCM[BIS|BIC|GET] ioctls to manipulate * the modem control lines (DTR / RTS) */ #if defined(__linux__) || \ defined(__FreeBSD__) || defined(__OpenBSD__) || \ defined(__NetBSD__) || defined(__DragonFly__) || \ defined(__APPLE__) #define USE_IOCTL #endif #ifdef USE_IOCTL #include #endif #include "custbaud.h" #ifdef USE_CUSTOM_BAUD #include CUSTOM_BAUD_HEAD #endif /* Time to wait for UART to clear after a drain (in usec). */ #define DRAIN_DELAY 200000 #include "term.h" /***************************************************************************/ static struct term_s { int init; int fd[MAX_TERMS]; struct termios origtermios[MAX_TERMS]; struct termios currtermios[MAX_TERMS]; struct termios nexttermios[MAX_TERMS]; } term; /***************************************************************************/ int term_errno; static const char * const term_err_str[] = { [TERM_EOK] = "No error", [TERM_ENOINIT] = "Framework is uninitialized", [TERM_EFULL] = "Framework is full", [TERM_ENOTFOUND] = "Filedes not in the framework", [TERM_EEXISTS] = "Filedes already in the framework", [TERM_EATEXIT] = "Cannot install atexit handler", [TERM_EISATTY] = "Filedes is not a tty", [TERM_EFLUSH] = "Cannot flush the device", [TERM_EGETATTR] = "Cannot get the device attributes", [TERM_ESETATTR] = "Cannot set the device attributes", [TERM_EBAUD] = "Invalid baud rate", [TERM_ESETOSPEED] = "Cannot set the output speed", [TERM_ESETISPEED] = "Cannot set the input speed", [TERM_EGETSPEED] = "Cannot decode speed", [TERM_EPARITY] = "Invalid parity mode", [TERM_EDATABITS] = "Invalid number of databits", [TERM_ESTOPBITS] = "Invalid number of stopbits", [TERM_EFLOW] = "Invalid flowcontrol mode", [TERM_EDTRDOWN] = "Cannot lower DTR", [TERM_EDTRUP] = "Cannot raise DTR", [TERM_EMCTL] = "Cannot get mctl status", [TERM_EDRAIN] = "Cannot drain the device", [TERM_EBREAK] = "Cannot send break sequence", [TERM_ERTSDOWN] = "Cannot lower RTS", [TERM_ERTSUP] = "Cannot raise RTS" }; static char term_err_buff[1024]; const char * term_strerror (int terrnum, int errnum) { const char *rval; switch(terrnum) { case TERM_EFLUSH: case TERM_EGETATTR: case TERM_ESETATTR: case TERM_ESETOSPEED: case TERM_ESETISPEED: case TERM_EDRAIN: case TERM_EBREAK: snprintf(term_err_buff, sizeof(term_err_buff), "%s: %s", term_err_str[terrnum], strerror(errnum)); rval = term_err_buff; break; case TERM_EOK: case TERM_ENOINIT: case TERM_EFULL: case TERM_ENOTFOUND: case TERM_EEXISTS: case TERM_EATEXIT: case TERM_EISATTY: case TERM_EBAUD: case TERM_EPARITY: case TERM_EDATABITS: case TERM_ESTOPBITS: case TERM_EFLOW: case TERM_EDTRDOWN: case TERM_EDTRUP: case TERM_EMCTL: case TERM_ERTSDOWN: case TERM_ERTSUP: snprintf(term_err_buff, sizeof(term_err_buff), "%s", term_err_str[terrnum]); rval = term_err_buff; break; default: rval = NULL; break; } return rval; } int term_perror (const char *prefix) { return fprintf(stderr, "%s %s\n", prefix, term_strerror(term_errno, errno)); } /***************************************************************************/ #define BNONE 0xFFFFFFFF struct baud_codes { int speed; speed_t code; } baud_table[] = { { 0, B0 }, { 50, B50 }, { 75, B75 }, { 110, B110 }, { 134, B134 }, { 150, B150 }, { 200, B200 }, { 300, B300 }, { 600, B600 }, { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, { 4800, B4800 }, { 9600, B9600 }, { 19200, B19200 }, { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 }, #ifdef HIGH_BAUD #ifdef B230400 { 230400, B230400 }, #endif #ifdef B460800 { 460800, B460800 }, #endif #ifdef B500000 { 500000, B500000 }, #endif #ifdef B576000 { 576000, B576000 }, #endif #ifdef B921600 { 921600, B921600 }, #endif #ifdef B1000000 { 1000000, B1000000 }, #endif #ifdef B1152000 { 1152000, B1152000 }, #endif #ifdef B1500000 { 1500000, B1500000 }, #endif #ifdef B2000000 { 2000000, B2000000 }, #endif #ifdef B2500000 { 2500000, B2500000 }, #endif #ifdef B3000000 { 3000000, B3000000 }, #endif #ifdef B3500000 { 3500000, B3500000 }, #endif #ifdef B4000000 { 4000000, B4000000 }, #endif #endif /* of HIGH_BAUD */ }; #define BAUD_TABLE_SZ (sizeof(baud_table) / sizeof(baud_table[0])) int term_baud_up (int baud) { int i; for (i = 0; i < BAUD_TABLE_SZ; i++) { if ( baud >= baud_table[i].speed ) continue; else { baud = baud_table[i].speed; break; } } return baud; } int term_baud_down (int baud) { int i; for (i = BAUD_TABLE_SZ - 1; i >= 0; i--) { if ( baud <= baud_table[i].speed ) continue; else { baud = baud_table[i].speed; break; } } return baud; } static speed_t Bcode(int speed) { speed_t code = BNONE; int i; for (i = 0; i < BAUD_TABLE_SZ; i++) { if ( baud_table[i].speed == speed ) { code = baud_table[i].code; break; } } return code; } static int Bspeed(speed_t code) { int speed = -1, i; for (i = 0; i < BAUD_TABLE_SZ; i++) { if ( baud_table[i].code == code ) { speed = baud_table[i].speed; break; } } return speed; } int term_baud_ok(int baud) { #ifndef USE_CUSTOM_BAUD return (Bcode(baud) != BNONE) ? 1 : 0; #else return (baud >= 0); #endif } int term_baud_std(int baud) { return (Bcode(baud) != BNONE) ? 1 : 0; } /**************************************************************************/ static int term_find_next_free (void) { int rval, i; do { /* dummy */ if ( ! term.init ) { term_errno = TERM_ENOINIT; rval = -1; break; } for (i = 0; i < MAX_TERMS; i++) if ( term.fd[i] == -1 ) break; if ( i == MAX_TERMS ) { term_errno = TERM_EFULL; rval = -1; break; } rval = i; } while (0); return rval; } /***************************************************************************/ static int term_find (int fd) { int rval, i; do { /* dummy */ if ( ! term.init ) { term_errno = TERM_ENOINIT; rval = -1; break; } for (i = 0; i < MAX_TERMS; i++) if (term.fd[i] == fd) break; if ( i == MAX_TERMS ) { term_errno = TERM_ENOTFOUND; rval = -1; break; } rval = i; } while (0); return rval; } /***************************************************************************/ static void term_exitfunc (void) { int r, i; do { /* dummy */ if ( ! term.init ) break; for (i = 0; i < MAX_TERMS; i++) { if (term.fd[i] == -1) continue; term_drain(term.fd[i]); tcflush(term.fd[i], TCIFLUSH); do { r = tcsetattr(term.fd[i], TCSANOW, &term.origtermios[i]); } while ( r < 0 && errno == EINTR ); if ( r < 0 ) { char *tname; tname = ttyname(term.fd[i]); if ( ! tname ) tname = "UNKNOWN"; fprintf(stderr, "%s: reset failed for dev %s: %s\r\n", __FUNCTION__, tname, strerror(errno)); } #ifdef USE_FLOCK /* Explicitly unlock the file. If the file is not in fact flock(2)'ed, no harm is done. This should normally not be necessary. Normally, exiting the program should take care of unlocking the file. Unfortuntelly, it has been observed that, on some systems, exiting or closing an flock(2)'ed tty fd has peculiar side effects (like not reseting the modem-control lines, even if HUPCL is set). */ flock(term.fd[i], LOCK_UN); #endif close(term.fd[i]); term.fd[i] = -1; } } while (0); } /***************************************************************************/ int term_lib_init (void) { int rval, r, i; rval = 0; do { /* dummy */ if ( term.init ) { /* reset all terms back to their original settings */ for (i = 0; i < MAX_TERMS; i++) { if (term.fd[i] == -1) continue; tcflush(term.fd[i], TCIOFLUSH); do { r = tcsetattr(term.fd[i], TCSANOW, &term.origtermios[i]); } while ( r < 0 && errno == EINTR ); if ( r < 0 ) { char *tname; tname = ttyname(term.fd[i]); if ( ! tname ) tname = "UNKNOWN"; fprintf(stderr, "%s: reset failed for dev %s: %s\n", __FUNCTION__, tname, strerror(errno)); } term.fd[i] = -1; } } else { /* initialize term structure. */ for (i = 0; i < MAX_TERMS; i++) term.fd[i] = -1; if ( atexit(term_exitfunc) != 0 ) { term_errno = TERM_EATEXIT; rval = -1; break; } /* ok. term struct is now initialized. */ term.init = 1; } } while(0); return rval; } /***************************************************************************/ int term_add (int fd) { int rval, r, i; rval = 0; do { /* dummy */ i = term_find(fd); if ( i >= 0 ) { term_errno = TERM_EEXISTS; rval = -1; break; } if ( ! isatty(fd) ) { term_errno = TERM_EISATTY; rval = -1; break; } i = term_find_next_free(); if ( i < 0 ) { rval = -1; break; } r = tcgetattr(fd, &term.origtermios[i]); if ( r < 0 ) { term_errno = TERM_EGETATTR; rval = -1; break; } term.currtermios[i] = term.origtermios[i]; term.nexttermios[i] = term.origtermios[i]; term.fd[i] = fd; } while (0); return rval; } /***************************************************************************/ int term_remove(int fd) { int rval, r, i; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } do { /* dummy */ r = tcflush(term.fd[i], TCIOFLUSH); if ( r < 0 ) { term_errno = TERM_EFLUSH; rval = -1; break; } r = tcsetattr(term.fd[i], TCSANOW, &term.origtermios[i]); if ( r < 0 ) { term_errno = TERM_ESETATTR; rval = -1; break; } } while (0); term.fd[i] = -1; } while (0); return rval; } /***************************************************************************/ int term_erase(int fd) { int rval, i; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } term.fd[i] = -1; } while (0); return rval; } /***************************************************************************/ int term_replace (int oldfd, int newfd) { int rval, r, i; rval = 0; do { /* dummy */ i = term_find(oldfd); if ( i < 0 ) { rval = -1; break; } r = tcsetattr(newfd, TCSANOW, &term.currtermios[i]); if ( r < 0 ) { term_errno = TERM_ESETATTR; rval = -1; break; } r = tcgetattr(newfd, &term.currtermios[i]); if ( r < 0 ) { term_errno = TERM_EGETATTR; rval = -1; break; } term.fd[i] = newfd; } while (0); return rval; } /***************************************************************************/ int term_reset (int fd) { int rval, r, i; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } r = tcflush(term.fd[i], TCIOFLUSH); if ( r < 0 ) { term_errno = TERM_EFLUSH; rval = -1; break; } r = tcsetattr(term.fd[i], TCSANOW, &term.origtermios[i]); if ( r < 0 ) { term_errno = TERM_ESETATTR; rval = -1; break; } r = tcgetattr(term.fd[i], &term.currtermios[i]); if ( r < 0 ) { term_errno = TERM_EGETATTR; rval = -1; break; } term.nexttermios[i] = term.currtermios[i]; } while (0); return rval; } /***************************************************************************/ int term_revert (int fd) { int rval, i; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } term.nexttermios[i] = term.currtermios[i]; } while (0); return rval; } /***************************************************************************/ int term_refresh (int fd) { int rval, r, i; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } r = tcgetattr(fd, &term.currtermios[i]); if ( r < 0 ) { term_errno = TERM_EGETATTR; rval = -1; break; } } while (0); return rval; } /***************************************************************************/ int term_apply (int fd, int now) { int when, rval, r, i; when = now ? TCSANOW : TCSAFLUSH; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } r = tcsetattr(term.fd[i], when, &term.nexttermios[i]); if ( r < 0 ) { term_errno = TERM_ESETATTR; rval = -1; break; } r = tcgetattr(term.fd[i], &term.nexttermios[i]); if ( r < 0 ) { term_errno = TERM_EGETATTR; rval = -1; break; } term.currtermios[i] = term.nexttermios[i]; /* Set HUPCL to origtermios as well. Since setting HUPCL affects the behavior on close(2), we most likely want it to also apply when the filedes is implicitly closed by exit(3)ing the program. Since, uppon exiting, we restore the original settings, this wouldn't happen unless we also set HUPCL to origtermios. */ if ( term.currtermios[i].c_cflag & HUPCL ) term.origtermios[i].c_cflag |= HUPCL; else term.origtermios[i].c_cflag &= ~HUPCL; } while (0); return rval; } /***************************************************************************/ int term_set_raw (int fd) { int rval, i; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } /* BSD raw mode */ cfmakeraw(&term.nexttermios[i]); /* one byte at a time, no timer */ term.nexttermios[i].c_cc[VMIN] = 1; term.nexttermios[i].c_cc[VTIME] = 0; } while (0); return rval; } /***************************************************************************/ int term_set_baudrate (int fd, int baudrate) { int rval, r, i; speed_t spd; struct termios tio; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } tio = term.nexttermios[i]; spd = Bcode(baudrate); if ( spd != BNONE ) { r = cfsetospeed(&tio, spd); if ( r < 0 ) { term_errno = TERM_ESETOSPEED; rval = -1; break; } /* ispeed = 0, means same as ospeed (see POSIX) */ cfsetispeed(&tio, B0); } else { #ifdef USE_CUSTOM_BAUD r = cfsetospeed_custom(&tio, baudrate); if ( r < 0 ) { term_errno = TERM_ESETOSPEED; rval = -1; break; } /* ispeed = 0, means same as ospeed (see POSIX) */ cfsetispeed(&tio, B0); #else /* ! defined USE_CUSTOM_BAUD */ term_errno = TERM_EBAUD; rval = -1; break; #endif /* of USE_CUSTOM_BAUD */ } term.nexttermios[i] = tio; } while (0); return rval; } int term_get_baudrate (int fd, int *ispeed) { speed_t code; int i, ospeed; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { ospeed = -1; break; } if ( ispeed ) { code = cfgetispeed(&term.currtermios[i]); *ispeed = Bspeed(code); #ifdef USE_CUSTOM_BAUD if ( *ispeed < 0 ) { *ispeed = cfgetispeed_custom(&term.currtermios[i]); } #endif } code = cfgetospeed(&term.currtermios[i]); ospeed = Bspeed(code); if ( ospeed < 0 ) { #ifdef USE_CUSTOM_BAUD ospeed = cfgetospeed_custom(&term.currtermios[i]); if ( ospeed < 0 ) { term_errno = TERM_EGETSPEED; } #else term_errno = TERM_EGETSPEED; #endif } } while (0); return ospeed; } /***************************************************************************/ int term_set_parity (int fd, enum parity_e parity) { int rval, i; struct termios *tiop; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } tiop = &term.nexttermios[i]; switch (parity) { case P_EVEN: tiop->c_cflag &= ~(PARODD | CMSPAR); tiop->c_cflag |= PARENB; break; case P_ODD: tiop->c_cflag &= ~CMSPAR; tiop->c_cflag |= PARENB | PARODD; break; case P_MARK: tiop->c_cflag |= PARENB | PARODD | CMSPAR; break; case P_SPACE: tiop->c_cflag &= ~PARODD; tiop->c_cflag |= PARENB | CMSPAR; break; case P_NONE: tiop->c_cflag &= ~(PARENB | PARODD | CMSPAR); break; default: term_errno = TERM_EPARITY; rval = -1; break; } if ( rval < 0 ) break; } while (0); return rval; } enum parity_e term_get_parity (int fd) { tcflag_t flg; int i, parity; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { parity = -1; break; } flg = term.currtermios[i].c_cflag; if ( ! (flg & PARENB) ) { parity = P_NONE; } else if ( flg & CMSPAR ) { parity = (flg & PARODD) ? P_MARK : P_SPACE; } else { parity = (flg & PARODD) ? P_ODD : P_EVEN; } } while (0); return parity; } /***************************************************************************/ int term_set_databits (int fd, int databits) { int rval, i; struct termios *tiop; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } tiop = &term.nexttermios[i]; switch (databits) { case 5: tiop->c_cflag = (tiop->c_cflag & ~CSIZE) | CS5; break; case 6: tiop->c_cflag = (tiop->c_cflag & ~CSIZE) | CS6; break; case 7: tiop->c_cflag = (tiop->c_cflag & ~CSIZE) | CS7; break; case 8: tiop->c_cflag = (tiop->c_cflag & ~CSIZE) | CS8; break; default: term_errno = TERM_EDATABITS; rval = -1; break; } if ( rval < 0 ) break; } while (0); return rval; } int term_get_databits (int fd) { tcflag_t flg; int i, bits; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { bits = -1; break; } flg = term.currtermios[i].c_cflag & CSIZE; switch (flg) { case CS5: bits = 5; break; case CS6: bits = 6; break; case CS7: bits = 7; break; case CS8: default: bits = 8; break; } } while (0); return bits; } /***************************************************************************/ int term_set_stopbits (int fd, int stopbits) { int rval, i; struct termios *tiop; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } tiop = &term.nexttermios[i]; switch (stopbits) { case 1: tiop->c_cflag &= ~CSTOPB; break; case 2: tiop->c_cflag |= CSTOPB; break; default: term_errno = TERM_ESTOPBITS; rval = -1; break; } if ( rval < 0 ) break; } while (0); return rval; } int term_get_stopbits (int fd) { int i, bits; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { bits = -1; break; } bits = (term.currtermios[i].c_cflag & CSTOPB) ? 2 : 1; } while (0); return bits; } /***************************************************************************/ int term_set_flowcntrl (int fd, enum flowcntrl_e flowcntl) { int rval, i; struct termios *tiop; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } tiop = &term.nexttermios[i]; switch (flowcntl) { case FC_RTSCTS: tiop->c_cflag |= CRTSCTS; tiop->c_iflag &= ~(IXON | IXOFF | IXANY); break; case FC_XONXOFF: tiop->c_cflag &= ~(CRTSCTS); tiop->c_iflag |= IXON | IXOFF; break; case FC_NONE: tiop->c_cflag &= ~(CRTSCTS); tiop->c_iflag &= ~(IXON | IXOFF | IXANY); break; default: term_errno = TERM_EFLOW; rval = -1; break; } if ( rval < 0 ) break; } while (0); return rval; } enum flowcntrl_e term_get_flowcntrl (int fd) { int i, flow; int rtscts, xoff, xon; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { flow = -1; break; } rtscts = (term.currtermios[i].c_cflag & CRTSCTS) ? 1 : 0; xoff = (term.currtermios[i].c_iflag & IXOFF) ? 1 : 0; xon = (term.currtermios[i].c_iflag & (IXON | IXANY)) ? 1 : 0; if ( rtscts && ! xoff && ! xon ) { flow = FC_RTSCTS; } else if ( ! rtscts && xoff && xon ) { flow = FC_XONXOFF; } else if ( ! rtscts && ! xoff && ! xon ) { flow = FC_NONE; } else { flow = FC_OTHER; } } while (0); return flow; } /***************************************************************************/ int term_set_local(int fd, int local) { int rval, i; struct termios *tiop; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } tiop = &term.nexttermios[i]; if ( local ) tiop->c_cflag |= CLOCAL; else tiop->c_cflag &= ~CLOCAL; } while (0); return rval; } /***************************************************************************/ int term_set_hupcl (int fd, int on) { int rval, i; struct termios *tiop; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } tiop = &term.nexttermios[i]; if ( on ) tiop->c_cflag |= HUPCL; else tiop->c_cflag &= ~HUPCL; } while (0); return rval; } /***************************************************************************/ int term_set(int fd, int raw, int baud, enum parity_e parity, int databits, int stopbits, enum flowcntrl_e fc, int local, int hup_close) { int rval, r, i, ni; struct termios tio; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { ni = term_add(fd); if ( ni < 0 ) { rval = -1; break; } } else { ni = i; } tio = term.nexttermios[ni]; do { /* dummy */ if (raw) { r = term_set_raw(fd); if ( r < 0 ) { rval = -1; break; } } r = term_set_baudrate(fd, baud); if ( r < 0 ) { rval = -1; break; } r = term_set_parity(fd, parity); if ( r < 0 ) { rval = -1; break; } r = term_set_databits(fd, databits); if ( r < 0 ) { rval = -1; break; } r = term_set_stopbits(fd, stopbits); if ( r < 0 ) { rval = -1; break; } r = term_set_flowcntrl(fd, fc); if ( r < 0 ) { rval = -1; break; } r = term_set_local(fd, local); if ( r < 0 ) { rval = -1; break; } r = term_set_hupcl(fd, hup_close); if ( r < 0 ) { rval = -1; break; } } while (0); if ( rval < 0 ) { if ( i < 0 ) /* new addition. must be removed */ term.fd[ni] = -1; else /* just revert to previous settings */ term.nexttermios[ni] = tio; } } while (0); return rval; } /***************************************************************************/ int term_pulse_dtr (int fd) { int rval, r, i; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } #ifdef USE_IOCTL { int opins = TIOCM_DTR; r = ioctl(fd, TIOCMBIC, &opins); if ( r < 0 ) { term_errno = TERM_EDTRDOWN; rval = -1; break; } sleep(1); r = ioctl(fd, TIOCMBIS, &opins); if ( r < 0 ) { term_errno = TERM_EDTRUP; rval = -1; break; } } #else { struct termios tio, tioold; r = tcgetattr(fd, &tio); if ( r < 0 ) { term_errno = TERM_EGETATTR; rval = -1; break; } tioold = tio; /* ospeed = 0, means hangup (see POSIX) */ cfsetospeed(&tio, B0); r = tcsetattr(fd, TCSANOW, &tio); if ( r < 0 ) { term_errno = TERM_ESETATTR; rval = -1; break; } sleep(1); r = tcsetattr(fd, TCSANOW, &tioold); if ( r < 0 ) { term.currtermios[i] = tio; term_errno = TERM_ESETATTR; rval = -1; break; } } #endif /* of USE_IOCTL */ } while (0); return rval; } /***************************************************************************/ int term_raise_dtr(int fd) { int rval, i; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } #ifdef USE_IOCTL { int r, opins = TIOCM_DTR; r = ioctl(fd, TIOCMBIS, &opins); if ( r < 0 ) { term_errno = TERM_EDTRUP; rval = -1; break; } } #else term_errno = TERM_EDTRUP; rval = -1; #endif /* of USE_IOCTL */ } while (0); return rval; } /***************************************************************************/ int term_lower_dtr(int fd) { int rval, i; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } #ifdef USE_IOCTL { int r, opins = TIOCM_DTR; r = ioctl(fd, TIOCMBIC, &opins); if ( r < 0 ) { term_errno = TERM_EDTRDOWN; rval = -1; break; } } #else term_errno = TERM_EDTRDOWN; rval = -1; #endif /* of USE_IOCTL */ } while (0); return rval; } /***************************************************************************/ int term_raise_rts(int fd) { int rval, i; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } #ifdef USE_IOCTL { int r; int opins = TIOCM_RTS; r = ioctl(fd, TIOCMBIS, &opins); if ( r < 0 ) { term_errno = TERM_ERTSUP; rval = -1; break; } } #else term_errno = TERM_ERTSUP; rval = -1; #endif /* of USE_IOCTL */ } while (0); return rval; } /***************************************************************************/ int term_lower_rts(int fd) { int rval, i; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } #ifdef USE_IOCTL { int r; int opins = TIOCM_RTS; r = ioctl(fd, TIOCMBIC, &opins); if ( r < 0 ) { term_errno = TERM_ERTSDOWN; rval = -1; break; } } #else term_errno = TERM_ERTSDOWN; rval = -1; #endif /* of USE_IOCTL */ } while (0); return rval; } /***************************************************************************/ int term_get_mctl (int fd) { int mctl, i; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { mctl = -1; break; } #ifdef USE_IOCTL { int r, pmctl; r = ioctl(fd, TIOCMGET, &pmctl); if (r < 0) { mctl = -1; break; } mctl = 0; if (pmctl & TIOCM_DTR) mctl |= MCTL_DTR; if (pmctl & TIOCM_DSR) mctl |= MCTL_DSR; if (pmctl & TIOCM_CD) mctl |= MCTL_DCD; if (pmctl & TIOCM_RTS) mctl |= MCTL_RTS; if (pmctl & TIOCM_CTS) mctl |= MCTL_CTS; if (pmctl & TIOCM_RI) mctl |= MCTL_RI; } #else mctl = MCTL_UNAVAIL; #endif /* of USE_IOCTL */ } while(0); return mctl; } int term_drain(int fd) { int rval, r; rval = 0; do { /* dummy */ r = term_find(fd); if ( r < 0 ) { rval = -1; break; } do { #ifdef __BIONIC__ /* See: http://dan.drown.org/android/src/gdb/no-tcdrain */ r = ioctl(fd, TCSBRK, 1); #else r = tcdrain(fd); #endif } while ( r < 0 && errno == EINTR); if ( r < 0 ) { term_errno = TERM_EDRAIN; rval = -1; break; } /* Give some time to the UART to transmit everything. Some systems and / or drivers corrupt the last character(s) if the port is immediately reconfigured, even after a drain. (I guess, drain does not wait for everything to actually be transitted on the wire). */ if ( DRAIN_DELAY ) usleep(DRAIN_DELAY); } while (0); return rval; } /***************************************************************************/ int term_fake_flush(int fd) { struct termios tio; int rval, i, r; rval = 0; do { /* dummy */ i = term_find(fd); if ( i < 0 ) { rval = -1; break; } /* Get current termios */ r = tcgetattr(fd, &tio); if ( r < 0 ) { term_errno = TERM_EGETATTR; rval = -1; break; } term.currtermios[i] = tio; /* Set flow-control to none */ tio.c_cflag &= ~(CRTSCTS); tio.c_iflag &= ~(IXON | IXOFF | IXANY); /* Apply termios */ r = tcsetattr(fd, TCSANOW, &tio); if ( r < 0 ) { term_errno = TERM_ESETATTR; rval = -1; break; } /* Wait for output to drain. Without flow-control this should complete in finite time. */ r = tcdrain(fd); if ( r < 0 ) { term_errno = TERM_EDRAIN; rval = -1; break; } /* see comment in term_drain */ if ( DRAIN_DELAY ) usleep(DRAIN_DELAY); /* Reset flow-control to original setting. */ r = tcsetattr(fd, TCSANOW, &term.currtermios[i]); if ( r < 0 ) { term_errno = TERM_ESETATTR; rval = -1; break; } } while (0); return rval; } int term_flush(int fd) { int rval, r; rval = 0; do { /* dummy */ r = term_find(fd); if ( r < 0 ) { rval = -1; break; } r = tcflush(fd, TCIOFLUSH); if ( r < 0 ) { term_errno = TERM_EFLUSH; rval = -1; break; } } while (0); return rval; } /***************************************************************************/ int term_break(int fd) { int rval, r; rval = 0; do { /* dummy */ r = term_find(fd); if ( r < 0 ) { rval = -1; break; } r = tcsendbreak(fd, 0); if ( r < 0 ) { term_errno = TERM_EBREAK; rval = -1; break; } } while (0); return rval; } /**************************************************************************/ /* * Local Variables: * mode:c * tab-width: 4 * c-basic-offset: 4 * End: */ picocom-3.1/term.h000066400000000000000000000605541323455570200141460ustar00rootroot00000000000000/* vi: set sw=4 ts=4: * * term.h * * Simple terminal management library. Wraps termios(3), and * simplifies the logistics required for the reliable management and * control of terminals. * * Principles of operation: * * After the library is initialized, one or more file-descriptors can * be added to (and latter removed from) the list managed by the * it. These file descriptors must be opened on terminal devices. For * every fd, the original settings of the associated terminal device * are saved by the library. These settings are restored when the fd * is removed from the framework, or at program termination [by means * of an atexit(3) handler installed by the library], or at user * request. The library maintains three structures for every fd in the * framework: The original settings structure ("origtermios"), keeping * the settings of the terminal device when the respective filedes was * added to the framework. The current settings structure * ("currtermios"), keeping the current settings of the associated * terminal device; and the next settings structure ("nexttermios") * which keeps settings to be applied to the associated terminal * device at a latter time, upon user request. The "term_set_*" * functions can be used to modify the device settings stored in the * nexttermios structure. Using functions provided by the library the * user can: Apply the nexttermios settings to the device. Revert all * changes made on nexttermios by copying the currtermios structure to * nexttermios. Reset the device, by configuring it to the original * settings, and copying origtermios to currtermios and * nexttermios. Refresh the device by rereading the current settings * from it and updating currtermios (to catch up with changes made to * the device by means outside of this framework). * * Interface summary: * * F term_lib_init - library initialization * F term_add - add a filedes to the framework * F term_remove - remove a filedes from the framework * F term_erase - remove a filedes from the framework without reset * F term_replace - replace a fd w/o affecting the settings stuctures * F term_reset - revert a device to the settings in "origtermios" * F term_apply - configure a device to the settings in "nexttermios" * F term_revert - discard "nexttermios" by copying-over "currtermios" * F term_refresh - update "currtermios" from the device * F term_set_raw - set "nexttermios" to raw mode * F term_set_baudrate - set the baudrate in "nexttermios" * F term_set_parity - set the parity mode in "nexttermios" * F term_set_databits - set the databits in "nexttermios" * F term_set_stopbits - set the stopbits in "nexttermios" * F term_set_flowcntrl - set the flowcntl mode in "nexttermios" * F term_set_hupcl - enable or disable hupcl in "nexttermios" * F term_set_local - set "nexttermios" to local or non-local mode * F term_set - set all params of "nexttermios" in a single stroke * F term_get_baudrate - return the baudrate set in "currtermios" * F term_get_parity - return the parity setting in "currtermios" * F term_get_databits - return the data-bits setting in "currtermios" * F term_get_flowcntrl - return the flow-control setting in "currtermios" * F term_pulse_dtr - pulse the DTR line a device * F term_lower_dtr - lower the DTR line of a device * F term_raise_dtr - raise the DTR line of a device * F term_lower_rts - lower the RTS line of a device * F term_raise_rts - raise the RTS line of a device * F term_get_mctl - Get modem control signals status * F term_drain - drain the output from the terminal buffer * F term_flush - discard terminal input and output queue contents * F term_fake_flush - discard terminal input and output queue contents * F term_break - generate a break condition on a device * F term_baud_up - return next higher baudrate * F term_baud_down - return next lower baudrate * F term_baud_ok - check if baudrate is valid * F term_baud_std - check if baudrate is on of our listed standard baudrates * F term_strerror - return a string describing current error condition * F term_perror - print a string describing the current error condition * G term_errno - current error condition of the library * E term_errno_e - error condition codes * E parity_t - library supported parity types * E flocntrl_t - library supported folw-control modes * M MAX_TERM - maximum number of fds that can be managed * * by Nick Patavalis (npat@efault.net) * * originaly by Pantelis Antoniou (https://github.com/pantoniou), * Nick Patavalis * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * * $Id: term.h,v 1.1 2003/05/07 18:00:05 npat Exp $ */ #ifndef TERM_H #define TERM_H /* M MAX_TERMS * * Maximum nuber of terminals that can be managed by the library. Keep * relatively low, since linear searches are used. Reasonable values * would be: 16, 32, 64, etc. */ #define MAX_TERMS 16 /* * E term_errno_e * * Library error-condition codes. These marked with "see errno" * correspond to system errors, so it makes sense to also check the * system's error-condition code (errno) in order to fully determine * what went wrong. * * See the error strings in "term.c" for a description of each. */ enum term_errno_e { TERM_EOK = 0, TERM_ENOINIT, TERM_EFULL, TERM_ENOTFOUND, TERM_EEXISTS, TERM_EATEXIT, TERM_EISATTY, TERM_EFLUSH, /* see errno */ TERM_EGETATTR, /* see errno */ TERM_ESETATTR, /* see errno */ TERM_EBAUD, TERM_ESETOSPEED, TERM_ESETISPEED, TERM_EGETSPEED, TERM_EPARITY, TERM_EDATABITS, TERM_ESTOPBITS, TERM_EFLOW, TERM_EDTRDOWN, TERM_EDTRUP, TERM_EMCTL, TERM_EDRAIN, /* see errno */ TERM_EBREAK, TERM_ERTSDOWN, TERM_ERTSUP }; /* E parity_e * * Parity modes supported by the library: * * P_NONE - no patiry * P_EVEN - even parity * P_ODD - odd parity * P_MARK - mark parity (parity bit always 1) * P_SPACE - space parity (parity bit always 0) */ enum parity_e { P_NONE = 0, P_EVEN, P_ODD, P_MARK, P_SPACE }; /* * E flowcntrl_e * * Flow control modes, supported by the library. * * FC_NONE - no flow control * FC_RTSCTS - RTS/CTS handshaking, also known as hardware * flow-control. * FC_XONXOFF - xon/xoff flow control. */ enum flowcntrl_e { FC_NONE = 0, FC_RTSCTS, FC_XONXOFF, FC_OTHER }; /* * C MCTL_xxx * * Modem control line bits. Used against the return value of * term_get_mctl(). */ #define MCTL_DTR (1<<1) /* O: Data Terminal Ready */ #define MCTL_DSR (1<<2) /* I: Data Set Ready */ #define MCTL_DCD (1<<3) /* I: Data Carrier Detect */ #define MCTL_RTS (1<<4) /* O: Request To Send */ #define MCTL_CTS (1<<5) /* I: Clear To Send */ #define MCTL_RI (1<<6) /* I: Ring Indicator */ #define MCTL_UNAVAIL (1<<0) /* MCTL lines (status) not available */ /***************************************************************************/ /* * G term_errno * * Keeps the current library error-condtion code */ extern int term_errno; /***************************************************************************/ /* * F term_strerror * * Return a string descibing the current library error condition. If * the error condition reflects a system error, then the respective * system-error description is appended at the end of the returned * string. The returned string points to a statically allocated buffer * that is overwritten with every call to term_strerror() * * Returns a string describing the current library (and possibly * system) error condition. */ const char *term_strerror (int terrnum, int errnum); /* * F term_perror * * Emit a description of the current library (and possibly system) * error condition to the standard-error stream. The description is * prefixed by a user-supplied string. What is actually emmited is: * * \n * * The description emitted is the string returned by term_strerror(). * * Returns the number of characters emmited to the standard-error * stream or a neagative on failure. */ int term_perror (const char *prefix); /* F term_lib_init * * Initialize the library * * Initialize the library. This function must be called before any * attemt to use the library. If this function is called and the * library is already initialized, all terminals associated with the * file-descriptors in the framework will be reset to their original * settings, and the file-descriptors will be removed from the * framework. An atexit(3) handler is installed by the library which * resets and removes all managed terminals. * * Returns negative on failure, non-negative on success. This function * will only fail if the atexit(3) handler cannot be * installed. Failure to reset a terminal to the original settings is * not considered an error. */ int term_lib_init (void); /* F term_add * * Add the filedes "fd" to the framework. The filedes must be opened * on a terminal device or else the addition will fail. The settings * of the terminal device associated with the filedes are read and * stored in the origtermios structure. * * Returns negative on failure, non-negative on success. */ int term_add (int fd); /* F term_remove * * Remove the filedes "fd" from the framework. The device associated * with the filedes is reset to its original settings (those it had * when it was added to the framework) * * Return negative on failure, non-negative on success. The filedes is * always removed form the framework even if this function returns * failure, indicating that the device reset failed. */ int term_remove (int fd); /* F term_erase * * Remove the filedes "fd" from the framework. The device associated * with the filedes is *not* reset to its original settings. * * Return negative on failure, non-negative on success. The only * reason for failure is the filedes not to be found. */ int term_erase (int fd); /* F term_replace * * Replace a managed filedes without affecting the associated settings * structures. The "newfd" takes the place of "oldfd". "oldfd" is * removed from the framework without the associated device beign * reset (it is most-likely no longer connected to a device anyway, * and reset would fail). The device associated with "newfd" is * configured with "oldfd"s current settings (stored in the * "currtermios" structure). After applying the settings to "newfd", * the "currtermios" structure is re-read from the device, so that it * corresponds to the actual device settings. * * Returns negative on failure, non-negative on success. In case of * failure "oldfd" is not removed from the framework, and no * replacement takes place. * * The usual reason to replace the filedes of a managed terminal is * because the device was closed and re-opened. This function gives * you a way to do transparent "open"s and "close"s: Before you close * a device, it has certain settings managed by the library. When you * close it and then re-open it many of these settings are lost, since * the device reverts to system-default settings. By calling * term_replace, you conceptually _maintain_ the old (pre-close) * settings to the new (post-open) filedes. */ int term_replace (int oldfd, int newfd); /* * F term_apply * * Applies the settings stored in the "nexttermios" structure * associated with the managed filedes "fd", to the respective * terminal device. It then re-reads the settings form the device and * stores them in "nexttermios". Finally it copies "nexttermios" to * "currtermios". If "now" is not zero, settings are applied * immediatelly, otherwise setting are applied after the output * buffers are drained and the input buffers are discarder. In this * sense, term_apply(fd, 0) is equivalent to: term_drain(fd); * term_flush(fd); term_apply(fd, 1); * * Returns negative on failure, non negative on success. In case of * failure the "nexttermios" and "currtermios" structures are not * affected. */ int term_apply (int fd, int now); /* * F term_revert * * Discards all the changes made to the nexttermios structure * associated with the managed filedes "fd" that have not been applied * to the device. It does this by copying currtermios to nexttermios. * * Returns negative on failure, non negative on success. Returns * failure only to indicate invalid arguments, so the return value can * be safely ignored. */ int term_revert (int fd); /* F term_reset * * Reset the terminal device associated with the managed filedes "fd" * to its "original" settings. This function applies the settings in * the "origtermios" structure to the actual device. It then reads the * settings from the device and stores them in both the "currtermios" * and "nexttermios" stuctures. * * Returns negative on failure, non-negative of success. On failure * the the "origtermios", "currtermios", and "nexttermios" stuctures * associated with the filedes remain unaffected. */ int term_reset (int fd); /* * F term_refresh * * Updates the contents of the currtermios structure associated with * the managed filedes "fd", by reading the settings from the * respective terminal device. * * Returns negative on failure, non negative on success. On failure * the currtermios structure remains unaffected. */ int term_refresh (int fd); /* F term_set_raw * * Sets the "nexttermios" structure associated with the managed * filedes "fd" to raw mode. The effective settings of the device are * not affected by this function. * * Returns negative on failure, non-negative on success. Returns * failure only to indicate invalid arguments, so the return value can * be safely ignored. * * When in raw mode, no characters are processed by the terminal * driver and there is no line-discipline or buffering. More * technically setting to raw mode means, affecting the following * terminal settings as indicated: * * -ignbrk -brkint -parmrk -istrip -inlcr -igncr -icrnl -ixon * -opost -echo -echonl -icannon -isig -iexten -csize -parenb * cs8 min=1 time=0 */ int term_set_raw (int fd); /* F term_set_baudrate * * Sets the baudrate in the "nexttermios" structure associated with * the managed filedes "fd" to "baudrate". The effective settings of * the device are not affected by this function. * * Supported baudrates: 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, * 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400 * * Returns negative on failure, non negative on success. Returns * failure only to indicate invalid arguments, so the return value can * be safely ignored. */ int term_set_baudrate (int fd, int baudrate); /* F term_set_parity * * Sets the parity mode in the "nexttermios" structure associated with * the managed filedes "fd" to "parity". The effective settings of the * device are not affected by this function. * * Supported parity modes are: p_even, p_odd, p_none. * * Returns negative on failure, non negative on success. Returns * failure only to indicate invalid arguments, so the return value can * be safely ignored. */ int term_set_parity (int fd, enum parity_e parity); /* F term_set_databits * * Sets the databits number in the "nexttermios" structure associated * with the managed filedes "fd" to "databits". The effective settings * of the device are not affected by this function. * * 5, 6, 7, and 8 databits are supported by the library. * * Returns negative on failure, non negative on success. Returns * failure only to indicate invalid arguments, so the return value can * be safely ignored. */ int term_set_databits (int fd, int databits); /* F term_set_stopbits * * Sets the stopbits number in the "nexttermios" structure associated * with the managed filedes "fd" to "stopbits". The effective settings * of the device are not affected by this function. * * 1 and 2 stopbits are supported by the library. * * Returns negative on failure, non negative on success. Returns * failure only to indicate invalid arguments, so the return value can * be safely ignored. */ int term_set_stopbits (int fd, int stopbits); /* F term_set_flowcntrl * * Sets the folwcontrol mode in the "nexttermios" structure associated * with the managed filedes "fd" to "flowcntl". The effective settings * of the device are not affected by this function. * * The following flow control modes are supportd by the library: * FC_NONE, FC_RTSCTS, FC_XONXOFF. * * Returns negative on failure, non negative on success. Returns * failure only to indicate invalid arguments, so the return value can * be safely ignored. */ int term_set_flowcntrl (int fd, enum flowcntrl_e flowcntl); /* F term_set_hupcl * * Enables ("on" = nonzero) or disables ("on" = zero) the * "HUP-on-close" setting in the "nexttermios" structure associated * with the managed filedes "fd". The effective settings of the device * are not affected by this function. * * Returns negative on failure, non negative on success. Returns * failure only to indicate invalid arguments, so the return value can * be safely ignored. */ int term_set_hupcl (int fd, int on); /* F term_set_local. * * Enables ("local" = nonzero) or disables ("local" = zero) the * "local-mode" setting in the "nexttermios" structure associated with * the managed filedes "fd". The effective settings of the device are * not affected by this function. * * Returns negative on failure, non negative on success. Returns * failure only to indicate invalid arguments, so the return value can * be safely ignored. */ int term_set_local (int fd, int local); /* F temr_set * * Sets most of the parameters in the "nexttermios" structure * associated with the managed filedes "fd". Actually sets the * following: * * Raw mode if "raw" is nonzero. * Baudrate to "baud". * Parity mode to "parity". * Flow control mode to "fc". * Enables local mode if "local" is nonzero, dis. otherwise. * Enables HUP-on-close if "hupcl" is nonzero, dis. otherwise * * The effective settings of the device are not affected by this * function. Additionally if the filedes "fd" is not managed, it is * added to the framework. * * Returns negative on failure, non negative on success. On failure * none of the settings of "nexttermios" is affected. *If* the filedes * "fd" is already in the framework, then the function returns failure * only to indicate invalid arguments, so, in this case, the return * value can be safely ignored. If the function successfully adds the * filedes to the framework, and following this it fails, then it will * remove the filedes before returning. */ int term_set (int fd, int raw, int baud, enum parity_e parity, int databits, int stopbits, enum flowcntrl_e fc, int local, int hupcl); /* F term_get_baudrate * * Reads and decodes the current baudrate settings in the * "currtermios" structure of the managed filedes "fd". * * Returns the decoded output baudrate (as bits-per-second), or -1 if * the output baudrate cannot be decoded, or if "fd" does not * correspond to a managed filedes. If "ispeed" is not NULL, it writes * the decoded input baudrate to the integer pointed-to by "ispeed"; * if the input baudrate cannot be decoded in writes -1 instead. */ int term_get_baudrate (int fd, int *ispeed); /* F term_get_parity * * Reads and decodes the current parity settings in the * "currtermios" structure of the managed filedes "fd". * * Returns one of the "enum parity_e" members, or -1 if "fd" does not * correspond to a managed filedes. */ enum parity_e term_get_parity (int fd); /* F term_get_databits * * Reads and decodes the current databits settings in the * "currtermios" structure of the managed filedes "fd". * * Returns the number of databits (5..8), or -1 if "fd" does not * correspond to a managed filedes. */ int term_get_databits (int fd); /* F term_get_stopbits * * Reads and decodes the current stopbits settings in the * "currtermios" structure of the managed filedes "fd". * * Returns the number of databits (1 or 2), or -1 if "fd" does not * correspond to a managed filedes. */ int term_get_stopbits (int fd); /* F term_get_flowcntrl * * Reads and decodes the current flow-control settings in the * "currtermios" structure of the managed filedes "fd". * * Returns one of the "enum flowcntrl_e" members, or -1 if "fd" does * not correspond to a managed filedes. */ enum flowcntrl_e term_get_flowcntrl (int fd); /* F term_pulse_dtr * * Pulses the DTR line of the device associated with the managed * filedes "fd". The DTR line is lowered for 1sec and then raised * again. * * Returns negative on failure, non negative on success. */ int term_pulse_dtr (int fd); /* F term_lower_dtr * * Lowers the DTR line of the device associated with the managed * filedes "fd". * * Returns negative on failure, non negative on success. */ int term_lower_dtr (int fd); /* F term_raise_dtr * * Raises the DTR line of the device associated with the managed * filedes "fd". * * Returns negative on failure, non negative on success. */ int term_raise_dtr (int fd); /* F term_lower_rts * * Lowers the RTS line of the device associated with the managed * filedes "fd". * * Returns negative on failure, non negative on success. */ int term_lower_rts (int fd); /* F term_raise_rts * * Raises the RTS line of the device associated with the managed * filedes "fd". * * Returns negative on failure, non negative on success. */ int term_raise_rts (int fd); /* F term_get_mctl * * Get the status of the modem control lines of the serial port * (terminal) associated with the managed filedes "fd". * * On error (fd is not managed) return a negative. If the feature is * not available returns MCTL_UNAVAIL. Otherwise returns a word that * can be checked against the MCTL_* flags. */ int term_get_mctl (int fd); /* F term_drain * * Drains (flushes) the output queue of the device associated with the * managed filedes "fd". This functions blocks until all the contents * of output queue have been transmited. * * Returns negative on failure, non negative on success. */ int term_drain (int fd); /* F term_flush * * Discards all the contents of the input AND output queues of the * device associated with the managed filedes "fd". Although it is * called flush this functions does NOT FLUSHES the terminal * queues. It just DISCARDS their contents. The name has stuck from * the POSIX terminal call: "tcflush". * * Returns negative on failure, non negative on success. */ int term_flush (int fd); /* F term_fake_flush * * Fake a term_flush, by temporarily configuring the device associated * with the managed fd to no flow-control and waiting until its output * queue drains. * * Returns negative on failure, non-negative on success. */ int term_fake_flush(int fd); /* F term_break * * This function generates a break condition on the device associated * with the managed filedes "fd", by transmiting a stream of * zero-bits. The stream of zero-bits has a duriation typically * between 0.25 and 0.5 seconds. * * Returns negative on failure, non negative on success. */ int term_break(int fd); /***************************************************************************/ /* F term_baud_up * * Returns the next higher valid baudrate. Returns "baud" if there is * no higher valid baudrate. */ int term_baud_up (int baud); /* F term_baud_down * * Returns the next lower valid baudrate. Returns "baud" if there is * no lower valid baudrate. */ int term_baud_down (int baud); /* F term_baud_ok * * Returns non-zero if "baud" is a valid baudrate, zero otherwise. */ int term_baud_ok(int baud); /* F term_baud_std * * Returns non-zero if "baud" is a standard baudrate, zero otherwise. */ int term_baud_std(int baud); /***************************************************************************/ #endif /* of TERM_H */ /***************************************************************************/ /* * Local Variables: * mode:c * tab-width: 4 * c-basic-offset: 4 * End: */ picocom-3.1/termbits2.h000066400000000000000000000132111323455570200150760ustar00rootroot00000000000000/* * termbits2.c * * Stuff that we should include from kernel sources, if we could; but * we can't. Included from "termios2.h" * * by Nick Patavalis (npat@efault.net) * * ATTENTION: Linux-specific kludge! * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #ifndef TERMBITS2_H #define TERMBITS2_H #ifndef __linux__ #error "Linux specific code!" #endif /* We need tcflag_t, cc_t, speed_t, CBAUDEX, etc */ #include /* These definitions must correspond to the kernel structures as defined in: /arch//include/uapi/asm/termbits.h or /include/uapi/asm-generic/termbits.h which are the same as: /usr/include//asm/termbits.h or /usr/include/asm-generic/termbits.h Unfortunatelly, we cannot just include or or (all would do the trick) because then "struct termios" would be re-defined to the kernel version, which is not the same as the libc version. In effect, you cannot both include and because both define a "struct termios" which may or maynot be the same. We want our "struct termios" here to be the libc version (as defined in ), because that's what our callers use. As a result we cannot get the definion of "struct termios2" from the above header files, since this would also bring-in the clashing definition of the kernel version of "struct termios". If you have an idea for a better way out of this mess, I would REALLY like to hear it. I hope that soon GLIBC will pick-up termios2 and all these will be useless. Until then ... ATTENTION: For most architectures "struct termios2" and the associated constants we care about (NCCS, BOTHER, IBSHIFT) are the same. For some there are small differences, and some architectures do not support termios2 at all. I don't claim to have done a thorough job figuring out the specifics for every architecture, so your milleage may vary. In any case, if you want support for something that's missing, just copy the relevant definitions from the kernel header file in here, recompile, test, and send me a patch. */ #if defined (__alpha__) #error "Architecure has no termios2 support" #elif defined (__powerpc__) || defined (__powerpc64__) #define K_NCCS 19 /* The "old" termios is the same with termios2 for powerpc's */ struct termios2 { tcflag_t c_iflag; /* input mode flags */ tcflag_t c_oflag; /* output mode flags */ tcflag_t c_cflag; /* control mode flags */ tcflag_t c_lflag; /* local mode flags */ cc_t c_cc[K_NCCS]; /* control characters */ cc_t c_line; /* line discipline */ speed_t c_ispeed; /* input speed */ speed_t c_ospeed; /* output speed */ }; #define BOTHER 00037 #define IBSHIFT 16 /* powerpc ioctl numbers have the argument-size encoded. Make sure we use the correct structure (i.e. kernel termios, not LIBC termios) when calculating them. */ #define IOCTL_SETS _IOW('t', 20, struct termios2) #define IOCTL_SETSW _IOW('t', 21, struct termios2) #define IOCTL_SETSF _IOW('t', 22, struct termios2) #define IOCTL_GETS _IOR('t', 19, struct termios2) #elif defined (__mips__) #define K_NCCS 23 struct termios2 { tcflag_t c_iflag; /* input mode flags */ tcflag_t c_oflag; /* output mode flags */ tcflag_t c_cflag; /* control mode flags */ tcflag_t c_lflag; /* local mode flags */ cc_t c_line; /* line discipline */ cc_t c_cc[K_NCCS]; /* control characters */ speed_t c_ispeed; /* input speed */ speed_t c_ospeed; /* output speed */ }; #define BOTHER CBAUDEX #define IBSHIFT 16 #define IOCTL_SETS TCSETS2 #define IOCTL_SETSW TCSETSW2 #define IOCTL_SETSF TCSETSF2 #define IOCTL_GETS TCGETS2 #else /* All others */ #define K_NCCS 19 struct termios2 { tcflag_t c_iflag; /* input mode flags */ tcflag_t c_oflag; /* output mode flags */ tcflag_t c_cflag; /* control mode flags */ tcflag_t c_lflag; /* local mode flags */ cc_t c_line; /* line discipline */ cc_t c_cc[K_NCCS]; /* control characters */ speed_t c_ispeed; /* input speed */ speed_t c_ospeed; /* output speed */ }; #define BOTHER CBAUDEX #define IBSHIFT 16 #define IOCTL_SETS TCSETS2 #define IOCTL_SETSW TCSETSW2 #define IOCTL_SETSF TCSETSF2 #define IOCTL_GETS TCGETS2 #endif /* of architectures */ /***************************************************************************/ #endif /* of TERMBITS2_H */ /***************************************************************************/ /* * Local Variables: * mode:c * tab-width: 4 * c-basic-offset: 4 * indent-tabs-mode: nil * End: */ picocom-3.1/termios2.c000066400000000000000000000122761323455570200147340ustar00rootroot00000000000000/* * termios2.c * * Use termios2 interface to set custom baud rates to serial ports. * * by Nick Patavalis (npat@efault.net) * * ATTENTION: Linux-specific kludge! * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #include "custbaud.h" #if defined(__linux__) && defined(USE_CUSTOM_BAUD) #include #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0) #error "This code requires Linux kernel > 2.6!" #endif #include #include #include #include #include /* Contains the definition of the termios2 structure and some related constants that we should normally include from system headers. Unfortunatelly, we can't. See comments in "termbits2.h" for more. */ #include "termbits2.h" /* GLIBC termios use an (otherwise unused) bit in c_iflags to internally record the fact that ispeed was set to zero (which is special behavior and means "same as ospeed". We want to clear this bit before passing c_iflags back to the kernel. See: /sysdeps/unix/sysv/linux/speed.c */ #define IBAUD0 020000000000 int tc2setattr(int fd, int optional_actions, const struct termios *tios) { struct termios2 t2; int cmd; switch (optional_actions) { case TCSANOW: cmd = IOCTL_SETS; break; case TCSADRAIN: cmd = IOCTL_SETSW; break; case TCSAFLUSH: cmd = IOCTL_SETSF; break; default: errno = EINVAL; return -1; } t2.c_iflag = tios->c_iflag & ~IBAUD0; t2.c_oflag = tios->c_oflag; t2.c_cflag = tios->c_cflag; t2.c_lflag = tios->c_lflag; t2.c_line = tios->c_line; t2.c_ispeed = tios->c_ispeed; t2.c_ospeed = tios->c_ospeed; memcpy(&t2.c_cc[0], &tios->c_cc[0], K_NCCS * sizeof (cc_t)); return ioctl(fd, cmd, &t2); } int tc2getattr(int fd, struct termios *tios) { struct termios2 t2; size_t i; int r; r = ioctl(fd, IOCTL_GETS, &t2); if (r < 0) return r; tios->c_iflag = t2.c_iflag; tios->c_oflag = t2.c_oflag; tios->c_cflag = t2.c_cflag; tios->c_lflag = t2.c_lflag; tios->c_line = t2.c_line; tios->c_ispeed = t2.c_ispeed; tios->c_ospeed = t2.c_ospeed; memcpy(&tios->c_cc[0], &t2.c_cc[0], K_NCCS * sizeof (cc_t)); for (i = K_NCCS; i < NCCS; i++) tios->c_cc[i] = _POSIX_VDISABLE; return 0; } /* The termios2 interface supports separate input and output speeds. GLIBC's termios support only one terminal speed. So the standard tcsetispeed(3), actually sets the output-speed field, not the input-speed field (or does nothing if speed == B0). Use cf2setispeed if you want to set a *standard* input speed (one of the Bxxxxx speeds) that may be different from the output speed. Also if someone, somehow, has set the input speed to something other than B0, then you *must* use cf2setispeed() to change it. Using the standard cfsetispeed() obviously won't do (since it affects only the output-speed field). */ int cf2setispeed(struct termios *tios, speed_t speed) { if ( (speed & ~CBAUD) != 0 && (speed < B57600 || speed > __MAX_BAUD) ) { errno = EINVAL; return -1; } tios->c_ispeed = speed; tios->c_cflag &= ~((CBAUD | CBAUDEX) << IBSHIFT); tios->c_cflag |= (speed << IBSHIFT); return 0; } speed_t cf2getispeed(struct termios *tios) { return (tios->c_cflag >> IBSHIFT) & (CBAUD | CBAUDEX); } /* Use these to set custom input or output speeds (i.e. speeds that do not necessarily correspond to one of the Bxxx macros. */ int cf2setospeed_custom(struct termios *tios, int speed) { if ( speed <= 0 ) { errno = EINVAL; return -1; } tios->c_cflag &= ~(CBAUD | CBAUDEX); tios->c_cflag |= BOTHER; tios->c_ospeed = speed; return 0; } int cf2setispeed_custom(struct termios *tios, int speed) { if ( speed < 0 ) { errno = EINVAL; return -1; } if ( speed == 0 ) { /* Special case: ispeed == 0 means "same as ospeed". Kernel does this if it sees B0 in the "CIBAUD" field (i.e. in CBAUD << IBSHIFT) */ tios->c_cflag &= ~((CBAUD | CBAUDEX) << IBSHIFT); tios->c_cflag |= (B0 << IBSHIFT); } else { tios->c_cflag &= ~((CBAUD | CBAUDEX) << IBSHIFT); tios->c_cflag |= (BOTHER << IBSHIFT); tios->c_ispeed = speed; } return 0; } /***************************************************************************/ #endif /* __linux__ && USE_CUSTOM_BAUD */ /* * Local Variables: * mode:c * tab-width: 4 * c-basic-offset: 4 * End: */ picocom-3.1/termios2.h000066400000000000000000000056541323455570200147430ustar00rootroot00000000000000/* * termios2.h * * Use termios2 interface to set custom baud rates to serial ports. * * by Nick Patavalis (npat@efault.net) * * ATTENTION: Linux-specific kludge! * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #ifndef TERMIOS2_H #define TERMIOS2_H #include /* Replace termios functions, with termios2 functions */ #define tcsetattr tc2setattr #define tcgetattr tc2getattr #define cfsetispeed cf2setispeed #define cfgetispeed cf2getispeed /* And define these new ones */ #define cfsetospeed_custom cf2setospeed_custom #define cfsetispeed_custom cf2setispeed_custom #define cfgetospeed_custom(tiop) ((tiop)->c_ospeed) #define cfgetispeed_custom(tiop) ((tiop)->c_ispeed) /* Replacements for the standard tcsetattr(3), tcgetattr(3) * functions. Same user interface, but these use the new termios2 * kernel interface (new ioctl's) which allow custom baud-rate * setting. */ int tc2setattr(int fd, int optional_actions, const struct termios *tios); int tc2getattr(int fd, struct termios *tios); /* Replacements for the standard cfgetispeed(3), cfsetispeed(3) * functions. Use these to set / get standard *input* baudrates. You * can still use cfgetospeed(3), cfsetospeed(3) to set / get the * standard output baudrates. The new termios2 interface, unlike the * old one, supports different input and output speeds for a * device. The "speed" argument must be (and the return value will be) * one of the standard "Bxxxx" macros. If cf2getispeed() or * cfgetospeed(3) return CBAUDEX, then the respective baudrate is a * custom one. Read the "termios.c_ispeed" / "termios.c_ospeed" fields * to get the custom value (as a numeric speed). */ int cf2setispeed(struct termios *tios, speed_t speed); speed_t cf2getispeed(struct termios *tios); /* Use these to set *custom* input and output baudrates for a * device. The "speed" argument must be a numeric baudrate value * (e.g. 1234 for 1234 bps). */ int cf2setispeed_custom(struct termios *tios, int speed); int cf2setospeed_custom(struct termios *tios, int speed); /***************************************************************************/ #endif /* of TERMIOS2_H */ /***************************************************************************/ /* * Local Variables: * mode:c * tab-width: 4 * c-basic-offset: 4 * End: */ picocom-3.1/termios2.txt000066400000000000000000000152151323455570200153250ustar00rootroot00000000000000 Linux and custom serial-port baudrates (the gory details) ========================================================= Support for custom baudrate setting and reading in Linux is done through the "new" "termios2" terminal-attributes structure, and the respective ioctls: TCSETS2, TCSETSW2, TCSETSF2, and TCGETS2. The "termios2" structure is defined in: /arch//include/uapi/asm/termbits.h or /include/uapi/asm-generic/termbits.h which may have been coppied in your system headers directories as: /usr/include//asm/termbits.h or /usr/include/asm-generic/termbits.h The termios2 structure looks like this: #define NCCS 19 struct termios2 { tcflag_t c_iflag; /* input mode flags */ tcflag_t c_oflag; /* output mode flags */ tcflag_t c_cflag; /* control mode flags */ tcflag_t c_lflag; /* local mode flags */ cc_t c_line; /* line discipline */ cc_t c_cc[NCCS]; /* control characters */ speed_t c_ispeed; /* input speed */ speed_t c_ospeed; /* output speed */ }; In the same files you will also find defined some relevant macros (constants, flags, and bit-fields, for the "termios2" "c_*flag" fields). Important aside: Unfortunatelly, we cannot include the above-mentioned files in our code, since they clash badly with stuff defined in the LIBC-provided header files (where the user-visible "termios" structure is defined). Because of this clash between LIBC and the linux headers, we have to manually copy the "termios2" definition (and a few relevant constants) into our sources for the whole thing to work. This is definitely very klugy, but I can see no better way to make it work (after all, GLIBC does the same thing---replicates the kernel definitions itself---for the older "termios" interface). End aside, on with it... The new ioctls TCSETS2, TCSETSW2, TCSETSF2 pass a "termios2" structure to the kernel in order to set the tty attributes (among which the serial port's baudrate). The corresponding TCGETS2 ioctl retrieves a "termios2" structure from the kernel corresponding to the actual, effective tty settings. These ioctls are used by the "tc2setattr()" and "tc2getattr()" functions (see file "termios2.c"). These functions are passed a userspace, LIBC-defined "termios" structure (which is very similar, but not necessarily identical to the kernel's "termios2"), call the respective ioctls, and copy the relevant information to or from the "termios2" structure (as expected or returned by the kernel). The game between the kernel and the "termios2" structure, regarding how baudrate-related information is interpretted, is played like this: Bits "c_cflags & (CBAUD | CBAUDEX)" (they are sometimes called: "the CBAUD field"), together with field "c_ospeed" control the output baudrate. Bits "c_cflags & ((CBAUD | CBAUDEX) << IBSHIFT)" (they are sometimes called: "the CIBAUD field"), together with field "c_ispeed" control the input baudrate. BTW: Usually CBAUD & CBAUDEX == CBAUD. That is, CBAUDEX *is* one of the CBAUD bits. When issuing one of the TCSETS*2 ioctls, everything contained in the "termios2" structure is copied to a kernel-resident structure and the respective serial driver is notified. Upon the serial driver's request, the kernel determines the output baudrate. If the kernel sees that: c_cflag & CBAUD == BOTHER then "c_ospeed" is passed to the serial driver as the output baudrate. Otherwise "c_cflag & (CBAUD | CBAUDEX)" is matched against a table of standard baudrates (coresponding to the "Bxxxx" macros). The matching baudrate is located and passed to the serial driver as the output baudrate. You can see the respective code in "drivers/tty/tty_ioctl.c" (all files form now on relative to the linux-kernel source tree base), function "tty_termios_baud_rate()", which is what the serial drivers call to determine the output baudrate. If the driver requests it, the kernel also determines the input baudrate by checking (c_cflag >> IBSHIFT) & CBAUD. If it sees that: (c_cflag >> IBSHIFT) & CBAUD == B0 then the *output* baudrate is passed to the driver (as the input baudrate) determined as described above. If, on the other hand the kernel sees that: (c_cflag >> IBSHIFT) & CBAUD == BOTHER then "c_ispeed" is passed to the serial driver as the input baudrate. If, finaly, neither is true (i.e. the input baudate bits in "c_cflag" are neither B0, nor BOTHER), then "(c_cflag >> IBSHIFT) & (CBAUD|CBAUDEX)" is mached against the table of standard baudrates. The matching baudrate is located and passed to the serial driver as the input baudrate. You can see all these happen in "drivers/tty/tty_ioctl.c", function "tty_termios_input_baud_rate()", which is what the serial drivers call to determine the input baudrate. The serial driver, once it receives the requested baudrate values, it may choose to alter them (e.g because the requested values are not supported by the hardware). If it does so, it then passes-back to the kernel the actual, effective, baudrate values, so that the kernel can update its internal structure. As a result, the user will read the *effective* baudrate values with the next TCGETS2 ioctl (which may be different than the requested ones). The kernel updates the "termios2" structure with the effective baudrate values supplied by the serial driver by following a rather complicated procedure, which I will not describe in full detail here. The gist of it is this: If the user has requested a baudrate using one of the standard "Bxxx" values (i.e. by setting the CBAUD / CIBAUD fields in "c_cflag"), then the kernel will also try to report-back the effective baudrate as a standard "Bxxx" value (by setting the CBAUF / CIBAUD fields in "c_cflag"), *even* if it has to lie a little about the baudrate value. If lying "a little" is not enough, or if the user has requested a non-standard baudrate through "c_ispeed / c_ospeed", then the kernel will set the CBAUD / CIBAUD fields in "c_cflag" to BOTHER, and report the effective baudrate (numerically) using "c_ispeed" / "c_ospeed". Actually, the "c_ispeed" / "c_ospeed" fields are *always* updated by the kernel with the effective baudrate values, even if these values are also reported by setting the CBAUD / CIBAUD fields in "c_cflag" to one of the "Bxxx" values. The details of how the kernel updates the termios2 structure with the baudrate values supplied by the serial drivers can be seen in file "drivers/tty/tty_ioctl.c", or "drivers/tty/tty_baudrate.c" function "tty_termios_encode_baud_rate()" which is what the serial drivers call to notify the kernel about the effective baudrate.