From 6a500ed6a0f7077e7c70b138b642779a8813ea59 Mon Sep 17 00:00:00 2001 From: Michael 'Mickey' Lauer Date: Sat, 3 May 2008 18:41:43 +0200 Subject: [PATCH] initial upload from freesmartphone.org SVN as per rev 295 --- AUTHORS | 2 + COPYING | 340 ++++++ ChangeLog | 43 + INSTALL | 234 ++++ Makefile.am | 8 + NEWS | 0 README | 15 + TODO | 10 + autogen.sh | 16 + configure.ac | 40 + data/Makefile.am | 18 + data/gsm0710muxd | 25 + data/gsm0710muxd.conf | 10 + data/org.pyneo.muxer.service.in | 4 + src/Makefile.am | 24 + src/gsm0710muxd.c | 1945 +++++++++++++++++++++++++++++++ src/gsm0710muxd.vapi | 10 + src/mux.h | 221 ++++ src/mux.xml | 56 + src/muxercontrol.c | 98 ++ src/muxercontrol.h | 51 + src/muxercontrol.vala | 36 + 22 files changed, 3206 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 TODO create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 data/Makefile.am create mode 100644 data/gsm0710muxd create mode 100644 data/gsm0710muxd.conf create mode 100644 data/org.pyneo.muxer.service.in create mode 100644 src/Makefile.am create mode 100644 src/gsm0710muxd.c create mode 100644 src/gsm0710muxd.vapi create mode 100644 src/mux.h create mode 100644 src/mux.xml create mode 100644 src/muxercontrol.c create mode 100644 src/muxercontrol.h create mode 100644 src/muxercontrol.vala diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..a790f17 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +M. Dietrich (main program) +M. Lauer (build infrastructure) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..623b625 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..344b77e --- /dev/null +++ b/ChangeLog @@ -0,0 +1,43 @@ +2008-05-03 Michael Dietrich + + * work around logic channel 1 opening bug and try to reclaim it + +2008-04-28 Michael Dietrich + + * marcel holtmanns patch applied + * error checks on snprintf + * auto detect pm path + +2008-04-28 Michael Lauer + + * Add power management functions (emdete) + * Improve stability (emdete) + * Change API to org.freesmartphone.GSM.MUX + * Release as 0.9.1 + +2008-03-28 Michael Lauer + + * Clean up build, release as 0.9.0 + +2008-02-28 Michael Lauer + + * src/gsm0710muxd.c: catch up with device node changes in openmoko-kernel 2.6.24 + +2008-02-17 Michael Lauer + + * data/Makefile.am: fix invalid directory, system services + go into dbus system-services directory + +2008-02-07 Michael Lauer + + * configure.ac data/Makefile.am data/org.freedesktop.GSM.MUX.service.in: + ship dbus service file + * data/gsm0710muxd: remove useless init script, activation goes via dbus now + +2008-02-05 Michael Lauer + + * data/Makefile.am: ship dbus service configuration file + +2008-01-15 Michael Lauer + + * Autotoolize diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..5458714 --- /dev/null +++ b/INSTALL @@ -0,0 +1,234 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006 Free Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..181a4ce --- /dev/null +++ b/Makefile.am @@ -0,0 +1,8 @@ +SUBDIRS = src data + +# Extra clean files so that maintainer-clean removes *everything* +MAINTAINERCLEANFILES = aclocal.m4 compile config.guess config.sub \ + configure depcomp install-sh ltmain.sh \ + Makefile.in missing config.h.in \ + mkinstalldirs \ + intltool-extract intltool-merge intltool-update diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/README b/README new file mode 100644 index 0000000..4c54789 --- /dev/null +++ b/README @@ -0,0 +1,15 @@ +This is a user space multiplexer for GSM according to the +GSM 07.10 specification. Right now it contains some hardcoded +paths for the Openmoko Neo devices, it should work with all +kinds of modems that understand the +CMUX operation mode. + +Please send patches to smartphones-standards@lists.linuxtogo.org + +See src/gsm0710muxd.c for how to use it. + +Although gsm0710muxd has dbus system bus activation support, for now +you need to start it manually because it expects the -x parameter +(path to GSM power and reset sysfs nodes). + +:M: + diff --git a/TODO b/TODO new file mode 100644 index 0000000..024e8db --- /dev/null +++ b/TODO @@ -0,0 +1,10 @@ +1.0: +* Remove VC-not-getting-opened workaround and solve problem +* Documentation +* Project site @ fs.o wiki +* Dbus Error handling + +1.1: +* Automatic device detection and/or device plugins? +* More support for working around different modems' problems + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..e10c348 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +rm -rf autom4te.cache +rm -f aclocal.m4 ltmain.sh + +touch README + +echo "Running aclocal..." ; aclocal $ACLOCAL_FLAGS || exit 1 +echo "Running autoheader..." ; autoheader || exit 1 +echo "Running autoconf..." ; autoconf || exit 1 +echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1 + +if [ -z "$NOCONFIGURE" ]; then + ./configure --enable-maintainer-mode --prefix=/usr --sysconfdir=/etc "$@" +fi + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..bbf8878 --- /dev/null +++ b/configure.ac @@ -0,0 +1,40 @@ +AC_PREREQ(2.53) +AC_INIT() + +AM_INIT_AUTOMAKE(gsm0710muxd, 0.9.1) +AM_CONFIG_HEADER(config.h) + +AM_MAINTAINER_MODE + +AC_PREFIX_DEFAULT(/usr/local) + +if (test "${CFLAGS}" = ""); then + CFLAGS="-Wall -O2" +fi + +AC_LANG_C + +AC_PROG_CC +AC_PROG_INSTALL + +AC_PATH_PROG(VALAC, [valac]) + +PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.10, dummy=yes, + AC_MSG_ERROR(libglib-2.0 is required)) +AC_SUBST(DBUS_CFLAGS) +AC_SUBST(DBUS_LIBS) + +PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.0, dummy=yes, + AC_MSG_ERROR(libdbus is required)) +AC_SUBST(DBUS_CFLAGS) +AC_SUBST(DBUS_LIBS) + +PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1 >= 0.70, dummy=yes, + AC_MSG_ERROR(libdbus-glib is required)) +AC_SUBST(DBUS_GLIB_CFLAGS) +AC_SUBST(DBUS_GLIB_LIBS) + +DBUS_BINDING_TOOL="dbus-binding-tool" +AC_SUBST(DBUS_BINDING_TOOL) + +AC_OUTPUT(Makefile src/Makefile data/Makefile) diff --git a/data/Makefile.am b/data/Makefile.am new file mode 100644 index 0000000..d83117a --- /dev/null +++ b/data/Makefile.am @@ -0,0 +1,18 @@ +dbusdir = $(sysconfdir)/dbus-1/system.d + +dist_dbus_DATA = gsm0710muxd.conf + +servicedir = $(datadir)/dbus-1/system-services + +service_in_files = org.pyneo.muxer.service.in + +service_DATA = $(service_in_files:.service.in=.service) + +CLEANFILES = $(service_DATA) + +EXTRA_DIST = $(service_in_files) + +MAINTAINERCLEANFILES = Makefile.in + +$(service_DATA): $(service_in_files) + @sed -e "s|\@sbindir\@|$(sbindir)|" $<> $@ diff --git a/data/gsm0710muxd b/data/gsm0710muxd new file mode 100644 index 0000000..090c1b0 --- /dev/null +++ b/data/gsm0710muxd @@ -0,0 +1,25 @@ +#!/bin/sh -e +NAME=gsm0710muxd +SYSROOTOPT="-x /sys/bus/platform/devices/neo1973-pm-gsm.0" +case "$1" in + start) + start-stop-daemon --start --pidfile /var/run/${NAME}.pid \ + --make-pidfile --background --startas /usr/sbin/$NAME -- \ + $SYSROOTOPT -f 100 + ;; + stop) + start-stop-daemon --stop --pidfile /var/run/${NAME}.pid \ + --oknodo + rm -f /var/run/${NAME}.pid + ;; + restart) + $0 stop + sleep 1 + exec $0 start + ;; + *) + echo "Usage: $0 {start|stop}" >&2 + exit 1 + ;; +esac +exit 0 diff --git a/data/gsm0710muxd.conf b/data/gsm0710muxd.conf new file mode 100644 index 0000000..8ff3e6c --- /dev/null +++ b/data/gsm0710muxd.conf @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/data/org.pyneo.muxer.service.in b/data/org.pyneo.muxer.service.in new file mode 100644 index 0000000..48cbd46 --- /dev/null +++ b/data/org.pyneo.muxer.service.in @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.pyneo.muxer +Exec=@sbindir@/gsm0710muxd +User=root diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..3d3ee69 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,24 @@ +sbin_PROGRAMS = gsm0710muxd + +gsm0710muxd_SOURCES = gsm0710muxd.c + +gsm0710muxd_LDADD = @DBUS_GLIB_LIBS@ @DBUS_LIBS@ @GLIB_LIBS@ + +AM_CFLAGS = @GLIB_CFLAGS@ @DBUS_CFLAGS@ @DBUS_GLIB_CFLAGS@ + +BUILT_SOURCES = mux-glue.h + +nodist_gsm0710muxd_SOURCES = $(BUILT_SOURCES) + +CLEANFILES = mux-glue.h + +EXTRA_DIST = mux.xml muxercontrol.vala gsm0710muxd.vapi \ + muxercontrol.h muxercontrol.c + +MAINTAINERCLEANFILES = Makefile.in + +mux-glue.h: mux.xml + $(DBUS_BINDING_TOOL) --prefix=mux --mode=glib-server --output=$@ $< + +vala: muxercontrol.vala + $(VALAC) --vapidir=$(top_srcdir)/src --pkg=gsm0710muxd --pkg=dbus-glib-1 --ccode $< diff --git a/src/gsm0710muxd.c b/src/gsm0710muxd.c new file mode 100644 index 0000000..0fd246e --- /dev/null +++ b/src/gsm0710muxd.c @@ -0,0 +1,1945 @@ +/* + * GSM 07.10 Implementation with User Space Serial Ports + * + * Code heavily based on gsmMuxd written by + * Copyright (C) 2003 Tuukka Karvonen + * Modified November 2004 by David Jander + * Modified January 2006 by Tuukka Karvonen + * Modified January 2006 by Antti Haapakoski + * Modified March 2006 by Tuukka Karvonen + * Modified October 2006 by Vasiliy Novikov + * + * Copyright (C) 2008 M. Dietrich + * + * 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 _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // http://library.gnome.org/devel/glib/unstable/glib-core.html +#include // http://dbus.freedesktop.org/doc/dbus/libdbus-tutorial.html +#include // http://dbus.freedesktop.org/doc/dbus-glib/ +DBusConnection* dbus_g_connection_get_connection(DBusGConnection *gconnection); // why isn't this in dbus-glib.h? +// http://maemo.org/api_refs/4.0/dbus-glib/group__DBusGLibInternals.html#gfac56b6025a90951510d33423ff04120 +// http://wiki.bluez.org/wiki/HOWTO/DiscoveringDevices +// http://dbus.freedesktop.org/doc/api/html/example-service_8c-source.html +// ~/Source/openmoko/build/tmp/work/i686-linux/glib-2.0-native-2.12.4-r1/glib-2.12.4/tests/mainloop-test.c +// http://www.linuxquestions.org/questions/linux-software-2/dbus-problem-505442/ + +// dbus-send --system --print-reply --type=method_call --dest=org.pyneo.muxer /org/pyneo/Muxer org.freesmartphone.GSM.MUX.AllocChannel string:xxx + +///////////////////////////////////////////////////////////////// defines +#define LOG(lvl, f, ...) do{if(lvl<=syslog_level)syslog(lvl,"%s:%d:%s(): " f "\n", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);}while(0) +#define SYSCHECK(c) do{if((c)<0){\ + LOG(LOG_ERR, "system-error: '%s' (code: %d)", strerror(errno), errno);\ + return -1;\ + }}while(0) +#define GSM0710_FRAME_FLAG 0xF9// basic mode flag for frame start and end +#define GSM0710_FRAME_ADV_FLAG 0x7E// advanced mode flag for frame start and end +#define GSM0710_FRAME_ADV_ESC 0x7D// advanced mode escape symbol +#define GSM0710_FRAME_ADV_ESC_COPML 0x20// advanced mode escape complement mask +#define GSM0710_FRAME_ADV_ESCAPED_SYMS { GSM0710_FRAME_ADV_FLAG, GSM0710_FRAME_ADV_ESC, 0x11, 0x91, 0x13, 0x93 }// advanced mode escaped symbols: Flag, Escape, XON and XOFF +// bits: Poll/final, Command/Response, Extension +#define GSM0710_PF 0x10//16 +#define GSM0710_CR 0x02//2 +#define GSM0710_EA 0x01//1 +// type of frames +#define GSM0710_TYPE_SABM 0x2F//47 Set Asynchronous Balanced Mode +#define GSM0710_TYPE_UA 0x63//99 Unnumbered Acknowledgement +#define GSM0710_TYPE_DM 0x0F//15 Disconnected Mode +#define GSM0710_TYPE_DISC 0x43//67 Disconnect +#define GSM0710_TYPE_UIH 0xEF//239 Unnumbered information with header check +#define GSM0710_TYPE_UI 0x03//3 Unnumbered Acknowledgement +// control channel commands +#define GSM0710_CONTROL_PN (0x80|GSM0710_EA)//?? DLC parameter negotiation +#define GSM0710_CONTROL_CLD (0xC0|GSM0710_EA)//193 Multiplexer close down +#define GSM0710_CONTROL_PSC (0x40|GSM0710_EA)//??? Power Saving Control +#define GSM0710_CONTROL_TEST (0x20|GSM0710_EA)//33 Test Command +#define GSM0710_CONTROL_MSC (0xE0|GSM0710_EA)//225 Modem Status Command +#define GSM0710_CONTROL_NSC (0x10|GSM0710_EA)//17 Non Supported Command Response +#define GSM0710_CONTROL_RPN (0x90|GSM0710_EA)//?? Remote Port Negotiation Command +#define GSM0710_CONTROL_RLS (0x50|GSM0710_EA)//?? Remote Line Status Command +#define GSM0710_CONTROL_SNC (0xD0|GSM0710_EA)//?? Service Negotiation Command +// V.24 signals: flow control, ready to communicate, ring indicator, +// data valid three last ones are not supported by Siemens TC_3x +#define GSM0710_SIGNAL_FC 0x02 +#define GSM0710_SIGNAL_RTC 0x04 +#define GSM0710_SIGNAL_RTR 0x08 +#define GSM0710_SIGNAL_IC 0x40//64 +#define GSM0710_SIGNAL_DV 0x80//128 +#define GSM0710_SIGNAL_DTR 0x04 +#define GSM0710_SIGNAL_DSR 0x04 +#define GSM0710_SIGNAL_RTS 0x08 +#define GSM0710_SIGNAL_CTS 0x08 +#define GSM0710_SIGNAL_DCD 0x80//128 +// +#define GSM0710_COMMAND_IS(type, command) ((type & ~GSM0710_CR) == command) +#define GSM0710_FRAME_IS(type, frame) ((frame->control & ~GSM0710_PF) == type) +#ifndef min +#define min(a,b) ((a < b) ? a :b) +#endif +#define GSM0710_WRITE_RETRIES 5 +#define GSM0710_MAX_CHANNELS 32 +// Defines how often the modem is polled when automatic restarting is +// enabled The value is in seconds +#define GSM0710_POLLING_INTERVAL 5 +#define GSM0710_BUFFER_SIZE 2048 + +////////////////////////////////////////////////////// types +// +typedef struct GSM0710_Frame +{ + unsigned char channel; + unsigned char control; + int length; + unsigned char *data; +} GSM0710_Frame; + +// +typedef struct GSM0710_Buffer +{ + unsigned char data[GSM0710_BUFFER_SIZE]; + unsigned char *readp; + unsigned char *writep; + unsigned char *endp; + int flag_found;// set if last character read was flag + unsigned long received_count; + unsigned long dropped_count; + unsigned char adv_data[GSM0710_BUFFER_SIZE]; + int adv_length; + int adv_found_esc; +} GSM0710_Buffer; + +// Channel data +typedef struct Channel +{ + int id; // gsm 07 10 channel id + char* devicename; + int fd; + int opened; + unsigned char v24_signals; + char* ptsname; + char* origin; + int remaining; + unsigned char *tmp; + guint g_source; +} Channel; + +typedef enum MuxerStates +{ + MUX_STATE_OPENING, + MUX_STATE_INITILIZING, + MUX_STATE_MUXING, + MUX_STATE_CLOSING, + MUX_STATE_OFF, + MUX_STATES_COUNT // keep this the last +} MuxerStates; + +typedef struct Serial +{ + char *devicename; + char* pm_base_dir; + int fd; + MuxerStates state; + GSM0710_Buffer *in_buf;// input buffer + unsigned char *adv_frame_buf; + time_t frame_receive_time; + int ping_number; + guint g_source; + guint g_source_watchdog; +} Serial; + +/////////////////////////////////////////// function prototypes +/** + * increases buffer pointer by one and wraps around if necessary + */ +//void gsm0710_buffer_inc(GSM0710_Buffer *buf, void&* p); +#define gsm0710_buffer_inc(buf,p) do { p++; if (p == buf->endp) p = buf->data; } while (0) +/** + * Tells how many chars are saved into the buffer. + */ +//int gsm0710_buffer_length(GSM0710_Buffer *buf); +#define gsm0710_buffer_length(buf) ((buf->readp > buf->writep) ? (GSM0710_BUFFER_SIZE - (buf->readp - buf->writep)) : (buf->writep-buf->readp)) +/** + * tells how much free space there is in the buffer + */ +//int gsm0710_buffer_free(GSM0710_Buffer *buf); +#define gsm0710_buffer_free(buf) ((buf->readp > buf->writep) ? (buf->readp - buf->writep) : (GSM0710_BUFFER_SIZE - (buf->writep-buf->readp))) + +////////////////////////////////// constants & globals +static unsigned char close_channel_cmd[] = { GSM0710_CONTROL_CLD | GSM0710_CR, GSM0710_EA | (0 << 1) }; +static unsigned char test_channel_cmd[] = { GSM0710_CONTROL_TEST | GSM0710_CR, GSM0710_EA | (6 << 1), 'P', 'I', 'N', 'G', '\r', '\n', }; +//static unsigned char psc_channel_cmd[] = { GSM0710_CONTROL_PSC | GSM0710_CR, GSM0710_EA | (0 << 1), }; +static unsigned char wakeup_sequence[] = { GSM0710_FRAME_FLAG, GSM0710_FRAME_FLAG, }; +// crc table from gsm0710 spec +static const unsigned char r_crctable[] = {//reversed, 8-bit, poly=0x07 + 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, + 0x7C, 0x09, 0x98, 0xEA, 0x7B, 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, + 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67, 0x38, + 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, + 0x31, 0xA0, 0xD2, 0x43, 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, + 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F, 0x70, 0xE1, + 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, + 0xE8, 0x9A, 0x0B, 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, + 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17, 0x48, 0xD9, 0xAB, + 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, + 0xA2, 0x33, 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, + 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F, 0xE0, 0x71, 0x03, 0x92, + 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, + 0x9B, 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, + 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87, 0xD8, 0x49, 0x3B, 0xAA, 0xDF, + 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3, + 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, + 0xB8, 0xCD, 0x5C, 0x2E, 0xBF, 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, + 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB, 0x8C, + 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, + 0x85, 0x14, 0x66, 0xF7, 0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, + 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3, 0xB4, 0x25, + 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, + 0x2C, 0x5E, 0xCF, }; +// config stuff +static char* revision = "$Rev: 295 $"; +static int no_daemon = 1; +static int pin_code = -1; +static int use_ping = 0; +static int use_timeout = 0; +static int syslog_level = LOG_INFO; +static char* object_name = "/org/pyneo/Muxer"; +// serial io +static Serial serial; +// muxed io channels +static Channel channellist[GSM0710_MAX_CHANNELS]; // remember: [0] is not used acticly because it's the control channel +// some state +static GMainLoop* main_loop = NULL; +static DBusGConnection* g_conn = NULL; +// +CMUX=[,[,[,[,[,[,[,[,]]]]]]]] +static int cmux_mode = 1; +static int cmux_subset = 0; +static int cmux_port_speed = 5; +// Maximum Frame Size (N1): 64/31 +static int cmux_N1 = 64; +#if 0 +// Acknowledgement Timer (T1) sec/100: 10 +static int cmux_T1 = 10; +// Maximum number of retransmissions (N2): 3 +static int cmux_N2 = 3; +// Response Timer for multiplexer control channel (T2) sec/100: 30 +static int cmux_T2 = 30; +// Response Timer for wake-up procedure(T3) sec: 10 +static int cmux_T3 = 10; +// Window Size (k): 2 +static int cmux_k = 2; +#endif +// TODO: set automatically from at+cmux=? +// neo: +CMUX: (1),(0),(1-5),(10-100),(1-255),(0-100),(2-255),(1-255),(1-7) + +/* + * The following arrays must have equal length and the values must + * correspond. also it has to correspond to the gsm0710 spec regarding + * baud id of CMUX the command. + */ +static int baud_rates[] = { + 0, 9600, 19200, 38400, 57600, 115200, 230400, 460800 +}; +static speed_t baud_bits[] = { + 0, B9600, B19200, B38400, B57600, B115200, B230400, B460800 +}; + +/** + * Determine baud-rate index for CMUX command + */ +static int baud_rate_index( + int baud_rate) +{ + int i; + for (i = 0; i < sizeof(baud_rates) / sizeof(*baud_rates); ++i) + if (baud_rates[i] == baud_rate) + return i; + return -1; +} + +/** + * Calculates frame check sequence from given characters. + * + * PARAMS: + * input - character array + * length - number of characters in array (that are included) + * RETURNS: + * frame check sequence + */ +static unsigned char frame_calc_crc( + const unsigned char *input, + int length) +{ + unsigned char fcs = 0xFF; + int i; + for (i = 0; i < length; i++) + fcs = r_crctable[fcs ^ input[i]]; + return 0xFF - fcs; +} + +/** + * Escapes GSM0710_FRAME_ADV_ESCAPED_SYMS characters. + * returns escaped buffer length. + */ +static int fill_adv_frame_buf( + unsigned char *adv_buf, + const unsigned char *data, + int length) +{ + static const unsigned char esc[] = GSM0710_FRAME_ADV_ESCAPED_SYMS; + int i, esc_i, adv_i = 0; + for (i = 0; i < length; ++i, ++adv_i) + { + adv_buf[adv_i] = data[i]; + for (esc_i = 0; esc_i < sizeof(esc) / sizeof(esc[0]); ++esc_i) + if (data[i] == esc[esc_i]) + { + adv_buf[adv_i] = GSM0710_FRAME_ADV_ESC; + adv_i++; + adv_buf[adv_i] = data[i] ^ GSM0710_FRAME_ADV_ESC_COPML; + break; + } + } + return adv_i; +} + +/** + * ascii/hexdump a byte buffer + */ +static int syslogdump( + const char *prefix, + const unsigned char *ptr, + unsigned int length) +{ + if (LOG_DEBUG>syslog_level) + return 0; + char buffer[100]; + unsigned int offset = 0l; + int i; + while (offset < length) + { + int off; + strcpy(buffer, prefix); + off = strlen(buffer); + SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, "%08x: ", offset)); + off = strlen(buffer); + for (i = 0; i < 16; i++) + { + if (offset + i < length) + SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, "%02x%c", ptr[offset + i], i == 7 ? '-' : ' ')); + else + SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, " .%c", i == 7 ? '-' : ' ')); + off = strlen(buffer); + } + SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, " ")); + off = strlen(buffer); + for (i = 0; i < 16; i++) + if (offset + i < length) + { + SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, "%c", (ptr[offset + i] < ' ') ? '.' : ptr[offset + i])); + off = strlen(buffer); + } + offset += 16; + LOG(LOG_DEBUG, "%s", buffer); + } + return 0; +} + +/** + * Writes a frame to a logical channel. C/R bit is set to 1. + * Doesn't support FCS counting for GSM0710_TYPE_UI frames. + * + * PARAMS: + * channel - channel number (0 = control) + * input - the data to be written + * length - the length of the data + * type - the type of the frame (with possible P/F-bit) + * + * RETURNS: + * number of characters written + */ +static int write_frame( + int channel, + const unsigned char *input, + int length, + unsigned char type) +{ + LOG(LOG_DEBUG, "Enter"); +//flag, GSM0710_EA=1 C channel, frame type, length 1-2 + unsigned char prefix[5] = { GSM0710_FRAME_FLAG, GSM0710_EA | GSM0710_CR, 0, 0, 0 }; + unsigned char postfix[2] = { 0xFF, GSM0710_FRAME_FLAG }; + int prefix_length = 4; + int c; +// char w = 0; +// int count = 0; +// do +// { + syslogdump(">s ", (unsigned char *)wakeup_sequence, sizeof(wakeup_sequence)); + write(serial.fd, wakeup_sequence, sizeof(wakeup_sequence)); +// SYSCHECK(tcdrain(serial.fd)); +// fd_set rfds; +// FD_ZERO(&rfds); +// FD_SET(serial.fd, &rfds); +// struct timeval timeout; +// timeout.tv_sec = 0; +// timeout.tv_usec = 1000 / 100 * cmux_T2; +// int sel = select(serial.fd + 1, &rfds, NULL, NULL, &timeout); +// if (sel > 0 && FD_ISSET(serial.fd, &rfds)) +// read(serial.fd, &w, 1); +// else +// count++; +// } while (w != wakeup_sequence[0] && count < cmux_N2); +// if (w != wakeup_sequence[0]) +// LOG(LOG_WARNING, "Didn't get frame-flag after wakeup"); + LOG(LOG_DEBUG, "Sending frame to channel %d", channel); +//GSM0710_EA=1, Command, let's add address + prefix[1] = prefix[1] | ((63 & (unsigned char) channel) << 2); +//let's set control field + prefix[2] = type; +//let's not use too big frames + length = min(cmux_N1, length); + if (!cmux_mode) + { +//Modified acording PATCH CRC checksum +//postfix[0] = frame_calc_crc (prefix + 1, prefix_length - 1); +//length + if (length > 127) + { + prefix_length = 5; + prefix[3] = (0x007F & length) << 1; + prefix[4] = (0x7F80 & length) >> 7; + } + else + prefix[3] = 1 | (length << 1); + postfix[0] = frame_calc_crc(prefix + 1, prefix_length - 1); + c = write(serial.fd, prefix, prefix_length); + if (c != prefix_length) + { + LOG(LOG_WARNING, "Couldn't write the whole prefix to the serial port for the virtual port %d. Wrote only %d bytes", + channel, c); + return 0; + } + if (length > 0) + { + c = write(serial.fd, input, length); + if (length != c) + { + LOG(LOG_WARNING, "Couldn't write all data to the serial port from the virtual port %d. Wrote only %d bytes", + channel, c); + return 0; + } + } + c = write(serial.fd, postfix, 2); + if (c != 2) + { + LOG(LOG_WARNING, "Couldn't write the whole postfix to the serial port for the virtual port %d. Wrote only %d bytes", + channel, c); + return 0; + } + } + else//cmux_mode + { + int offs = 1; + serial.adv_frame_buf[0] = GSM0710_FRAME_ADV_FLAG; + offs += fill_adv_frame_buf(serial.adv_frame_buf + offs, prefix + 1, 2);// address, control + offs += fill_adv_frame_buf(serial.adv_frame_buf + offs, input, length);// data +//CRC checksum + postfix[0] = frame_calc_crc(prefix + 1, 2); + offs += fill_adv_frame_buf(serial.adv_frame_buf + offs, postfix, 1);// fcs + serial.adv_frame_buf[offs] = GSM0710_FRAME_ADV_FLAG; + offs++; + syslogdump(">s ", (unsigned char *)serial.adv_frame_buf, offs); + c = write(serial.fd, serial.adv_frame_buf, offs); + if (c != offs) + { + LOG(LOG_WARNING, "Couldn't write the whole advanced option packet to the serial port for the virtual port %d. Wrote only %d bytes", + channel, c); + return 0; + } + } + LOG(LOG_DEBUG, "Leave"); + return length; +} + +/* + * Handles received data from device. PARAMS: buf - buffer, which + * contains received data len - the length of the buffer channel - the + * number of devices (logical channel), where data was received + * RETURNS: the number of remaining bytes in partial packet + */ +static int handle_channel_data( + unsigned char *buf, + int len, + int channel) +{ + int written = 0; + int i = 0; + int last = 0; +//try to write 5 times + while (written != len && i < GSM0710_WRITE_RETRIES) + { + last = write_frame(channel, buf + written, len - written, GSM0710_TYPE_UIH); + written += last; + if (last == 0) + i++; + } + if (i == GSM0710_WRITE_RETRIES) + LOG(LOG_WARNING, "Couldn't write data to channel %d. Wrote only %d bytes, when should have written %d", + channel, written, len); + return 0; +} + +static int logical_channel_close(Channel* channel) +{ + if (channel->g_source >= 0) + g_source_remove(channel->g_source); + channel->g_source = -1; + if (channel->fd >= 0) + close(channel->fd); + channel->fd = -1; + if (channel->ptsname != NULL) + free(channel->ptsname); + channel->ptsname = NULL; + if (channel->tmp != NULL) + free(channel->tmp); + channel->tmp = NULL; + if (channel->origin != NULL) + free(channel->origin); + channel->origin = NULL; + channel->opened = 0; + channel->v24_signals = 0; + channel->remaining = 0; + return 0; +} + +static int logical_channel_init(Channel* channel, int id) +{ + channel->id = id; // connected channel-id + channel->devicename = id?"/dev/ptmx":NULL; // TODO do we need this to be dynamic anymore? + channel->fd = -1; + channel->g_source = -1; + channel->ptsname = NULL; + channel->tmp = NULL; + channel->origin = NULL; + return logical_channel_close(channel); +} + +gboolean pseudo_device_read(GIOChannel *source, GIOCondition condition, gpointer data) +{ + LOG(LOG_DEBUG, "Enter"); + Channel* channel = (Channel*)data; + if (condition == G_IO_IN) + { + unsigned char buf[4096]; + //information from virtual port + int len = read(channel->fd, buf + channel->remaining, sizeof(buf) - channel->remaining); + if (!channel->opened) + { + LOG(LOG_WARNING, "Write to a channel which wasn't acked to be open."); + write_frame(channel->id, NULL, 0, GSM0710_TYPE_SABM | GSM0710_PF); + LOG(LOG_DEBUG, "Leave"); + return TRUE; + } + if (len >= 0) + { + LOG(LOG_DEBUG, "Data from channel %d, %d bytes", channel->id, len); + if (channel->remaining > 0) + { + memcpy(buf, channel->tmp, channel->remaining); + free(channel->tmp); + channel->tmp = NULL; + } + if (len + channel->remaining > 0) + channel->remaining = handle_channel_data(buf, len + channel->remaining, channel->id); + //copy remaining bytes from last packet into tmp + if (channel->remaining > 0) + { + channel->tmp = malloc(channel->remaining); + memcpy(channel->tmp, buf + sizeof(buf) - channel->remaining, channel->remaining); + } + LOG(LOG_DEBUG, "Leave"); + return TRUE; + } + // dropped connection + if (cmux_mode) + write_frame(channel->id, NULL, 0, GSM0710_CONTROL_CLD | GSM0710_CR); + else + write_frame(channel->id, close_channel_cmd, 2, GSM0710_TYPE_UIH); + logical_channel_close(channel); + LOG(LOG_INFO, "Logical channel %d for %s closed", channel->id, channel->origin); + } + else if (condition == G_IO_HUP) + { + if (cmux_mode) + write_frame(channel->id, NULL, 0, GSM0710_CONTROL_CLD | GSM0710_CR); + else + write_frame(channel->id, close_channel_cmd, 2, GSM0710_TYPE_UIH); + logical_channel_close(channel); + LOG(LOG_INFO, "Logical channel %d for %s closed", channel->id, channel->origin); + } + LOG(LOG_DEBUG, "Leave"); + return FALSE; +} + +static gboolean watchdog(gpointer data); +static int close_devices(); + +static gboolean c_get_power(const char* origin) +{ + LOG(LOG_DEBUG, "Enter"); + LOG(LOG_DEBUG, "Leave"); + return serial.state != MUX_STATE_OFF; +} + +static gboolean c_set_power(const char* origin, gboolean on) +{ + LOG(LOG_DEBUG, "Enter"); + if (on) + { + if (serial.state == MUX_STATE_OFF) + { + LOG(LOG_INFO, "power on"); + serial.state = MUX_STATE_OPENING; + watchdog(&serial); + } + else + LOG(LOG_WARNING, "power on request received but was already on"); + } + else + { + if (serial.state == MUX_STATE_MUXING) + { + LOG(LOG_INFO, "power off"); + g_source_remove(serial.g_source_watchdog); + close_devices(); + } + else + LOG(LOG_WARNING, "power off received but wasn't on/muxing"); + } + LOG(LOG_DEBUG, "Leave"); + return TRUE; +} + +static gboolean c_reset_modem(const char* origin) +{ + LOG(LOG_DEBUG, "Enter"); + LOG(LOG_INFO, "modem reset"); + serial.state = MUX_STATE_CLOSING; + return TRUE; +} + +static gboolean c_alloc_channel(const char* origin, const char** name) +{ + LOG(LOG_DEBUG, "Enter"); + int i; + if (serial.state == MUX_STATE_MUXING) + for (i=1;imessage); + g_error_free(g_err); + return -1; + } + GObject* obj = (GObject*)muxer_control_gen(); + DBusError err; + memset(&err, 0, sizeof(err)); + if (dbus_bus_request_name(dbus_g_connection_get_connection(g_conn), "org.pyneo.muxer", DBUS_NAME_FLAG_ALLOW_REPLACEMENT|DBUS_NAME_FLAG_REPLACE_EXISTING, &err) < 0) + { + if (dbus_error_is_set(&err)) + LOG(LOG_ERR, "dbus error with dbus_bus_request_name '%s' '%s'", err.name, err.message); + else + LOG(LOG_ERR, "dbus error with dbus_bus_request_name"); + return -1; + } + dbus_g_object_type_install_info(TYPE_MUXER_CONTROL, &dbus_glib_mux_object_info); + dbus_g_connection_register_g_object(g_conn, object_name, obj); + return 0; +} + +static int dbus_deinit() +{ + if (g_conn) + dbus_g_connection_unref(g_conn); + return 0; +} + +static int dbus_signal_send_deactivate(const char* sigvalue) +{ + DBusConnection* conn = dbus_g_connection_get_connection(g_conn); + if (NULL == conn) + { + LOG(LOG_ERR, "Connection null"); + return -1; + } + DBusMessage* msg = dbus_message_new_signal(object_name, // object name of the signal + "org.freesmartphone.GSM.MUX", // interface name of the signal + "deactivate"); // name of the signal + if (NULL == msg) + { + LOG(LOG_ERR, "Message Null"); + return -1; + } + DBusMessageIter args; + dbus_message_iter_init_append(msg, &args); // append arguments onto signal + if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &sigvalue)) + { + LOG(LOG_ERR, "Out Of Memory"); + return -1; + } + dbus_uint32_t g_serial = 0; // unique number to associate replies with requests + if (!dbus_connection_send(conn, msg, &g_serial)) // send the message and flush the connection + { + LOG(LOG_ERR, "Out Of Memory"); + return -1; + } + dbus_connection_flush(conn); + // free the message + dbus_message_unref(msg); + return 0; +} + +/** + GPtrArray *table = parse("(14-5),(3-7),(4-9),(33)"); + + for(int i = 0; i < table->len; i++) + { + int *arr = g_ptr_array_index(table, i); + printf("(%d, %d)\n", arr[0], arr[1]); + } +*/ +GPtrArray* parse(const gchar* str) +{ + GPtrArray *table = g_ptr_array_new(); + int i = -1; + int first = -1; + int pos = 0; + while(str[++i] != 0) + { + if(str[i] == '(') + { + pos = i+1; + first = -1; + } + else if(str[i] == ')') + { + int *tuple = malloc(sizeof(int)*2); + + tuple[1] = atoi(str + pos); + tuple[0] = first == -1 ? tuple[1] : first; + + g_ptr_array_add(table, (gpointer)tuple); + } + else if(str[i] == '-') + { + first = atoi(str + pos); + pos = i+1; + } + } + return table; +} + +//////////////////////////////////////////////// real functions +/* Allocates memory for a new buffer and initializes it. + * + * RETURNS: + * the pointer to a new buufer + */ +static GSM0710_Buffer *gsm0710_buffer_init( + ) +{ + GSM0710_Buffer* buf = (GSM0710_Buffer*)malloc(sizeof(GSM0710_Buffer)); + if (buf) + { + memset(buf, 0, sizeof(GSM0710_Buffer)); + buf->readp = buf->data; + buf->writep = buf->data; + buf->endp = buf->data + GSM0710_BUFFER_SIZE; + } + return buf; +} + +/* Destroys the buffer (i.e. frees up the memory + * + * PARAMS: + * buf - buffer to be destroyed + */ +static void gsm0710_buffer_destroy( + GSM0710_Buffer* buf) +{ + free(buf); +} + +/* Writes data to the buffer + * + * PARAMS + * buf - pointer to the buffer + * input - input data (in user memory) + * length - how many characters should be written + * RETURNS + * number of characters written + */ +static int gsm0710_buffer_write( + GSM0710_Buffer* buf, + const unsigned char *input, + int length) +{ + LOG(LOG_DEBUG, "Enter"); + int c = buf->endp - buf->writep; + length = min(length, gsm0710_buffer_free(buf)); + if (length > c) + { + memcpy(buf->writep, input, c); + memcpy(buf->data, input + c, length - c); + buf->writep = buf->data + (length - c); + } + else + { + memcpy(buf->writep, input, length); + buf->writep += length; + if (buf->writep == buf->endp) + buf->writep = buf->data; + } + LOG(LOG_DEBUG, "Leave"); + return length; +} + +/** + * destroys a frame + */ +static void destroy_frame( + GSM0710_Frame * frame) +{ + if (frame->length > 0) + free(frame->data); + free(frame); +} + +/* Gets a frame from buffer. You have to remember to free this frame + * when it's not needed anymore + * + * PARAMS: + * buf - the buffer, where the frame is extracted + * RETURNS: + * frame or null, if there isn't ready frame with given index + */ +static GSM0710_Frame* gsm0710_base_buffer_get_frame( + GSM0710_Buffer * buf) +{ + int end; + int length_needed = 5;// channel, type, length, fcs, flag + unsigned char *data; + unsigned char fcs = 0xFF; + GSM0710_Frame *frame = NULL; +//Find start flag + while (!buf->flag_found && gsm0710_buffer_length(buf) > 0) + { + if (*buf->readp == GSM0710_FRAME_FLAG) + buf->flag_found = 1; + gsm0710_buffer_inc(buf, buf->readp); + } + if (!buf->flag_found)// no frame started + return NULL; +//skip empty frames (this causes troubles if we're using DLC 62) + while (gsm0710_buffer_length(buf) > 0 && (*buf->readp == GSM0710_FRAME_FLAG)) + { + gsm0710_buffer_inc(buf, buf->readp); + } + if (gsm0710_buffer_length(buf) >= length_needed) + { + data = buf->readp; + if ((frame = (GSM0710_Frame*)malloc(sizeof(GSM0710_Frame))) != NULL) + { + frame->channel = ((*data & 252) >> 2); + fcs = r_crctable[fcs ^ *data]; + gsm0710_buffer_inc(buf, data); + frame->control = *data; + fcs = r_crctable[fcs ^ *data]; + gsm0710_buffer_inc(buf, data); + frame->length = (*data & 254) >> 1; + fcs = r_crctable[fcs ^ *data]; + } + else + LOG(LOG_ALERT, "Out of memory, when allocating space for frame"); + if ((*data & 1) == 0) + { +//Current spec (version 7.1.0) states these kind of +//frames to be invalid Long lost of sync might be +//caused if we would expect a long frame because of an +//error in length field. + /* + gsm0710_buffer_inc(buf,data); + frame->length += (*data*128); + fcs = r_crctable[fcs^*data]; + length_needed++; + */ + free(frame); + buf->readp = data; + buf->flag_found = 0; + return gsm0710_base_buffer_get_frame(buf); + } + length_needed += frame->length; + if (!(gsm0710_buffer_length(buf) >= length_needed)) + { + free(frame); + return NULL; + } + gsm0710_buffer_inc(buf, data); +//extract data + if (frame->length > 0) + { + if ((frame->data = malloc(sizeof(char) * frame->length)) != NULL) + { + end = buf->endp - data; + if (frame->length > end) + { + memcpy(frame->data, data, end); + memcpy(frame->data + end, buf->data, frame->length - end); + data = buf->data + (frame->length - end); + } + else + { + memcpy(frame->data, data, frame->length); + data += frame->length; + if (data == buf->endp) + data = buf->data; + } + if (GSM0710_FRAME_IS(GSM0710_TYPE_UI, frame)) + { + for (end = 0; end < frame->length; end++) + fcs = r_crctable[fcs ^ (frame->data[end])]; + } + } + else + { + LOG(LOG_ALERT, "Out of memory, when allocating space for frame data"); + frame->length = 0; + } + } +//check FCS + if (r_crctable[fcs ^ (*data)] != 0xCF) + { + LOG(LOG_WARNING, "Dropping frame: FCS doesn't match"); + destroy_frame(frame); + buf->flag_found = 0; + buf->dropped_count++; + buf->readp = data; + return gsm0710_base_buffer_get_frame(buf); + } + else + { +//check end flag + gsm0710_buffer_inc(buf, data); + if (*data != GSM0710_FRAME_FLAG) + { + LOG(LOG_WARNING, "Dropping frame: End flag not found. Instead: %d", *data); + destroy_frame(frame); + buf->flag_found = 0; + buf->dropped_count++; + buf->readp = data; + return gsm0710_base_buffer_get_frame(buf); + } + else + buf->received_count++; + gsm0710_buffer_inc(buf, data); + } + buf->readp = data; + } + return frame; +} + +/* Gets a advanced option frame from buffer. You have to remember to free this frame + * when it's not needed anymore + * + * PARAMS: + * buf - the buffer, where the frame is extracted + * RETURNS: + * frame or null, if there isn't ready frame with given index + */ +static GSM0710_Frame *gsm0710_advanced_buffer_get_frame( + GSM0710_Buffer * buf) +{ + LOG(LOG_DEBUG, "Enter"); +l_begin: +//Find start flag + while (!buf->flag_found && gsm0710_buffer_length(buf) > 0) + { + if (*buf->readp == GSM0710_FRAME_ADV_FLAG) + { + buf->flag_found = 1; + buf->adv_length = 0; + buf->adv_found_esc = 0; + } + gsm0710_buffer_inc(buf, buf->readp); + } + if (!buf->flag_found)// no frame started + return NULL; + if (0 == buf->adv_length) +//skip empty frames (this causes troubles if we're using DLC 62) + while (gsm0710_buffer_length(buf) > 0 && (*buf->readp == GSM0710_FRAME_ADV_FLAG)) + gsm0710_buffer_inc(buf, buf->readp); + while (gsm0710_buffer_length(buf) > 0) + { + if (!buf->adv_found_esc && GSM0710_FRAME_ADV_FLAG == *(buf->readp)) + {// closing flag found + GSM0710_Frame *frame = NULL; + unsigned char *data = buf->adv_data; + unsigned char fcs = 0xFF; + gsm0710_buffer_inc(buf, buf->readp); + if (buf->adv_length < 3) + { + LOG(LOG_WARNING, "Too short adv frame, length:%d", buf->adv_length); + buf->flag_found = 0; + goto l_begin; + } + if ((frame = (GSM0710_Frame*)malloc(sizeof(GSM0710_Frame))) != NULL) + { + frame->channel = ((data[0] & 252) >> 2); + fcs = r_crctable[fcs ^ data[0]]; + frame->control = data[1]; + fcs = r_crctable[fcs ^ data[1]]; + frame->length = buf->adv_length - 3; + } + else + LOG(LOG_ALERT, "Out of memory, when allocating space for frame"); +//extract data + if (frame->length > 0) + { + if ((frame->data = (unsigned char *) malloc(sizeof(char) * frame->length))) + { + memcpy(frame->data, data + 2, frame->length); + if (GSM0710_FRAME_IS(GSM0710_TYPE_UI, frame)) + { + int i; + for (i = 0; i < frame->length; ++i) + fcs = r_crctable[fcs ^ (frame->data[i])]; + } + } + else + { + LOG(LOG_ALERT, "Out of memory, when allocating space for frame data"); + buf->flag_found = 0; + goto l_begin; + } + } +//check FCS + if (r_crctable[fcs ^ data[buf->adv_length - 1]] != 0xCF) + { + LOG(LOG_WARNING, "Dropping frame: FCS doesn't match"); + destroy_frame(frame); + buf->flag_found = 0; + buf->dropped_count++; + goto l_begin; + } + else + { + buf->received_count++; + buf->flag_found = 0; + LOG(LOG_DEBUG, "Leave success"); + return frame; + } + } + if (buf->adv_length >= sizeof(buf->adv_data)) + { + LOG(LOG_WARNING, "Too long adv frame, length:%d", buf->adv_length); + buf->flag_found = 0; + buf->dropped_count++; + goto l_begin; + } + if (buf->adv_found_esc) + { + buf->adv_data[buf->adv_length] = *(buf->readp) ^ GSM0710_FRAME_ADV_ESC_COPML; + buf->adv_length++; + buf->adv_found_esc = 0; + } + else if (GSM0710_FRAME_ADV_ESC == *(buf->readp)) + buf->adv_found_esc = 1; + else + { + buf->adv_data[buf->adv_length] = *(buf->readp); + buf->adv_length++; + } + gsm0710_buffer_inc(buf, buf->readp); + } + return NULL; +} + +/** + * Returns 1 if found, 0 otherwise. needle must be null-terminated. + * strstr might not work because WebBox sends garbage before the first + * OK + */ +static int memstr( + const char *haystack, + int length, + const char *needle) +{ + int i; + int j = 0; + if (needle[0] == '\0') + return 1; + for (i = 0; i < length; i++) + if (needle[j] == haystack[i]) + { + j++; + if (needle[j] == '\0') // Entire needle was found + return 1; + } + else + j = 0; + return 0; +} + +/* + * Sends an AT-command to a given serial port and waits for reply. + * PARAMS: fd - file descriptor cmd - command to - how many + * seconds to wait for response RETURNS: + * 0 on success (OK-response), -1 otherwise + */ +static int chat( + int serial_device_fd, + char *cmd, + int to) +{ + LOG(LOG_DEBUG, "Enter"); + unsigned char buf[1024]; + int sel; + int len; + int wrote = 0; + syslogdump(">s ", (unsigned char *) cmd, strlen(cmd)); + SYSCHECK(wrote = write(serial_device_fd, cmd, strlen(cmd))); + LOG(LOG_DEBUG, "Wrote %d bytes", wrote); + SYSCHECK(tcdrain(serial_device_fd)); + + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(serial_device_fd, &rfds); + struct timeval timeout; + timeout.tv_sec = to; + timeout.tv_usec = 0; + do + { + SYSCHECK(sel = select(serial_device_fd + 1, &rfds, NULL, NULL, &timeout)); + LOG(LOG_DEBUG, "Selected %d", sel); + if (FD_ISSET(serial_device_fd, &rfds)) + { + memset(buf, 0, sizeof(buf)); + len = read(serial_device_fd, buf, sizeof(buf)); + SYSCHECK(len); + LOG(LOG_DEBUG, "Read %d bytes from serial device", len); + syslogdump("length > 0) + { + type = frame->data[0];// only a byte long types are handled now skip extra bytes + for (i = 0; (frame->length > i && (frame->data[i] & GSM0710_EA) == 0); i++); + i++; + type_length = i; + if ((type & GSM0710_CR) == GSM0710_CR) + { +//command not ack extract frame length + while (frame->length > i) + { + length = (length * 128) + ((frame->data[i] & 254) >> 1); + if ((frame->data[i] & 1) == 1) + break; + i++; + } + i++; + switch ((type & ~GSM0710_CR)) + { + case GSM0710_CONTROL_CLD: + LOG(LOG_INFO, "The mobile station requested mux-mode termination"); + serial.state = MUX_STATE_CLOSING; + break; + case GSM0710_CONTROL_PSC: + LOG(LOG_DEBUG, "Power Service Control command: ***"); + LOG(LOG_DEBUG, "Frame->data = %s / frame->length = %d", frame->data + i, frame->length - i); + break; + case GSM0710_CONTROL_TEST: + LOG(LOG_DEBUG, "Test command: "); + LOG(LOG_DEBUG, "Frame->data = %s / frame->length = %d", frame->data + i, frame->length - i); + //serial->ping_number = 0; + break; + case GSM0710_CONTROL_MSC: + if (i + 1 < frame->length) + { + channel = ((frame->data[i] & 252) >> 2); + i++; + signals = (frame->data[i]); +//op.op = USSP_MSC; +//op.arg = USSP_RTS; +//op.len = 0; + LOG(LOG_DEBUG, "Modem status command on channel %d", channel); + if ((signals & GSM0710_SIGNAL_FC) == GSM0710_SIGNAL_FC) + LOG(LOG_DEBUG, "No frames allowed"); + else + { +//op.arg |= USSP_CTS; + LOG(LOG_DEBUG, "Frames allowed"); + } + if ((signals & GSM0710_SIGNAL_RTC) == GSM0710_SIGNAL_RTC) + { +//op.arg |= USSP_DSR; + LOG(LOG_DEBUG, "Signal RTC"); + } + if ((signals & GSM0710_SIGNAL_IC) == GSM0710_SIGNAL_IC) + { +//op.arg |= USSP_RI; + LOG(LOG_DEBUG, "Signal Ring"); + } + if ((signals & GSM0710_SIGNAL_DV) == GSM0710_SIGNAL_DV) + { +//op.arg |= USSP_DCD; + LOG(LOG_DEBUG, "Signal DV"); + } +//if (channel > 0) +//write(channellist[channel].fd, &op, +//sizeof(op)); + } + else + LOG(LOG_ERR, "Modem status command, but no info. i: %d, len: %d, data-len: %d", + i, length, frame->length); + break; + default: + LOG(LOG_ALERT, "Unknown command (%d) from the control channel", type); + if ((response = malloc(sizeof(char) * (2 + type_length))) != NULL) + { + i = 0; + response[i++] = GSM0710_CONTROL_NSC; + type_length &= 127; //supposes that type length is less than 128 + response[i++] = GSM0710_EA | (type_length << 1); + while (type_length--) + { + response[i] = frame->data[i - 2]; + i++; + } + write_frame(0, response, i, GSM0710_TYPE_UIH); + free(response); + supported = 0; + } + else + LOG(LOG_ALERT, "Out of memory, when allocating space for response"); + break; + } + if (supported) + { +//acknowledge the command + frame->data[0] = frame->data[0] & ~GSM0710_CR; + write_frame(0, frame->data, frame->length, GSM0710_TYPE_UIH); + } + } + else + { +//received ack for a command + if (GSM0710_COMMAND_IS(type, GSM0710_CONTROL_NSC)) + LOG(LOG_ERR, "The mobile station didn't support the command sent"); + else + LOG(LOG_DEBUG, "Command acknowledged by the mobile station"); + } + } + return 0; +} + +/* + * Extracts and handles frames from the receiver buffer. PARAMS: buf + * - the receiver buffer + */ +int extract_frames( + GSM0710_Buffer* buf) +{ + LOG(LOG_DEBUG, "Enter"); +//version test for Siemens terminals to enable version 2 functions + int frames_extracted = 0; + GSM0710_Frame *frame; + while ((frame = cmux_mode + ? gsm0710_advanced_buffer_get_frame(buf) + : gsm0710_base_buffer_get_frame(buf))) + { + frames_extracted++; + if ((GSM0710_FRAME_IS(GSM0710_TYPE_UI, frame) || GSM0710_FRAME_IS(GSM0710_TYPE_UIH, frame))) + { + LOG(LOG_DEBUG, "Frame is UI or UIH"); + if (frame->channel > 0) + { + LOG(LOG_DEBUG, "Frame channel > 0, pseudo channel"); +//data from logical channel + write(channellist[frame->channel].fd, frame->data, frame->length); + } + else + { +//control channel command + LOG(LOG_DEBUG, "Frame channel == 0, control channel command"); + handle_command(frame); + } + } + else + { +//not an information frame + LOG(LOG_DEBUG, "Not an information frame"); + switch ((frame->control & ~GSM0710_PF)) + { + case GSM0710_TYPE_UA: + LOG(LOG_DEBUG, "Frame is UA"); + if (channellist[frame->channel].opened) + { + SYSCHECK(logical_channel_close(channellist+frame->channel)); + LOG(LOG_INFO, "Logical channel %d for %s closed", + frame->channel, channellist[frame->channel].origin); + } + else + { + channellist[frame->channel].opened = 1; + if (frame->channel == 0) + { + LOG(LOG_DEBUG, "Control channel opened"); + //send version Siemens version test + //static unsigned char version_test[] = "\x23\x21\x04TEMUXVERSION2\0"; + //write_frame(0, version_test, sizeof(version_test), GSM0710_TYPE_UIH); + } + else + LOG(LOG_INFO, "Logical channel %d opened", frame->channel); + } + break; + case GSM0710_TYPE_DM: + if (channellist[frame->channel].opened) + { + SYSCHECK(logical_channel_close(channellist+frame->channel)); + LOG(LOG_INFO, "DM received, so the channel %d for %s was already closed", + frame->channel, channellist[frame->channel].origin); + } + else + { + if (frame->channel == 0) + { + LOG(LOG_INFO, "Couldn't open control channel.\n->Terminating"); + serial.state = MUX_STATE_CLOSING; +//close channels + } + else + LOG(LOG_INFO, "Logical channel %d for %s couldn't be opened", frame->channel, channellist[frame->channel].origin); + } + break; + case GSM0710_TYPE_DISC: + if (channellist[frame->channel].opened) + { + channellist[frame->channel].opened = 0; + write_frame(frame->channel, NULL, 0, GSM0710_TYPE_UA | GSM0710_PF); + if (frame->channel == 0) + { + serial.state = MUX_STATE_CLOSING; + LOG(LOG_INFO, "Control channel closed"); + } + else + LOG(LOG_INFO, "Logical channel %d for %s closed", frame->channel, channellist[frame->channel].origin); + } + else + { +//channel already closed + LOG(LOG_WARNING, "Received DISC even though channel %d for %s was already closed", + frame->channel, channellist[frame->channel].origin); + write_frame(frame->channel, NULL, 0, GSM0710_TYPE_DM | GSM0710_PF); + } + break; + case GSM0710_TYPE_SABM: +//channel open request + if (channellist[frame->channel].opened) + { + if (frame->channel == 0) + LOG(LOG_INFO, "Control channel opened"); + else + LOG(LOG_INFO, "Logical channel %d for %s opened", + frame->channel, channellist[frame->channel].origin); + } + else +//channel already opened + LOG(LOG_WARNING, "Received SABM even though channel %d for %s was already closed", + frame->channel, channellist[frame->channel].origin); + channellist[frame->channel].opened = 1; + write_frame(frame->channel, NULL, 0, GSM0710_TYPE_UA | GSM0710_PF); + break; + } + } + destroy_frame(frame); + } + LOG(LOG_DEBUG, "Leave"); + return frames_extracted; +} + +/** + * Function responsible by all signal handlers treatment + * any new signal must be added here + */ +void signal_treatment( + int param) +{ + switch (param) + { + case SIGPIPE: + exit(0); + break; + case SIGHUP: +//reread the configuration files + break; + case SIGINT: + case SIGTERM: + case SIGUSR1: + //exit(0); +//sig_term(param); + g_main_loop_quit(main_loop); + break; + case SIGKILL: + default: + exit(0); + break; + } +} + +static int modem_hw_(const char* pm_base_dir, const char* entry, int on) +{ + LOG(LOG_DEBUG, "Enter"); + if (pm_base_dir != NULL) + { + char fn[256]; + SYSCHECK(snprintf(fn, sizeof(fn), "%s/%s", pm_base_dir, entry)); + LOG(LOG_DEBUG, "echo %c > %s", on?'1':'0', fn); + int fd; + SYSCHECK(fd = open(fn, O_RDWR | O_NONBLOCK)); + SYSCHECK(write(fd, on?"1\n":"0\n", 2)); + SYSCHECK(close(fd)); + } + else + LOG(LOG_DEBUG, "no pm_base_dir"); + LOG(LOG_DEBUG, "Leave"); + return 0; +} + +static int modem_hw_off(const char* pm_base_dir) +{ + LOG(LOG_DEBUG, "Enter"); + SYSCHECK(modem_hw_(pm_base_dir, "power_on", 0)); + SYSCHECK(modem_hw_(pm_base_dir, "reset", 0)); + LOG(LOG_DEBUG, "Leave"); + return 0; +} + +static int modem_hw_on(const char* pm_base_dir) +{ + LOG(LOG_DEBUG, "Enter"); + SYSCHECK(modem_hw_off(pm_base_dir)); + sleep(1); + SYSCHECK(modem_hw_(pm_base_dir, "power_on", 1)); + sleep(1); + SYSCHECK(modem_hw_(pm_base_dir, "reset", 1)); + sleep(1); + SYSCHECK(modem_hw_(pm_base_dir, "reset", 0)); + sleep(1); + LOG(LOG_DEBUG, "Leave"); + return 0; +} + +gboolean serial_device_read(GIOChannel *source, GIOCondition condition, gpointer data) +{ + Serial* serial = (Serial*)data; + LOG(LOG_DEBUG, "Enter"); + if (condition == G_IO_IN) + { + switch (serial->state) + { + case MUX_STATE_MUXING: + { + unsigned char buf[4096]; + int len; + //input from serial port + LOG(LOG_DEBUG, "Serial Data"); + int length; + if ((length = gsm0710_buffer_free(serial->in_buf)) > 0 + && (len = read(serial->fd, buf, min(length, sizeof(buf)))) > 0) + { + syslogdump("in_buf, buf, len); + //extract and handle ready frames + if (extract_frames(serial->in_buf) > 0) + { + time(&serial->frame_receive_time); //get the current time + serial->ping_number = 0; + } + } + LOG(LOG_DEBUG, "Leave keep watching"); + return TRUE; + } + break; + default: + LOG(LOG_WARNING, "Don't know how to handle reading in state %d", serial->state); + break; + } + } + else if (condition == G_IO_HUP) + { + LOG(LOG_WARNING, "hup on serial file, closing"); + serial->state = MUX_STATE_CLOSING; + } + LOG(LOG_DEBUG, "Leave stop watching"); + return FALSE; +} + +int open_serial_device( + Serial* serial + ) +{ + LOG(LOG_DEBUG, "Enter"); + SYSCHECK(modem_hw_on(serial->pm_base_dir)); + int i; + for (i=0;ifd = open(serial->devicename, O_RDWR | O_NOCTTY | O_NONBLOCK)); + LOG(LOG_INFO, "Opened serial port"); + int fdflags; + SYSCHECK(fdflags = fcntl(serial->fd, F_GETFL)); + SYSCHECK(fcntl(serial->fd, F_SETFL, fdflags & ~O_NONBLOCK)); + struct termios t; + tcgetattr(serial->fd, &t); + t.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD); + t.c_cflag |= CREAD | CLOCAL | CS8 | CRTSCTS; + t.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG); + t.c_iflag &= ~(INPCK | IGNPAR | PARMRK | ISTRIP | IXANY | ICRNL); + t.c_iflag &= ~(IXON | IXOFF); + t.c_oflag &= ~(OPOST | OCRNL); + t.c_cc[VMIN] = 0; + t.c_cc[VINTR] = _POSIX_VDISABLE; + t.c_cc[VQUIT] = _POSIX_VDISABLE; + t.c_cc[VSTART] = _POSIX_VDISABLE; + t.c_cc[VSTOP] = _POSIX_VDISABLE; + t.c_cc[VSUSP] = _POSIX_VDISABLE; + speed_t speed = baud_bits[cmux_port_speed]; + cfsetispeed(&t, speed); + cfsetospeed(&t, speed); + SYSCHECK(tcsetattr(serial->fd, TCSANOW, &t)); + int status = TIOCM_DTR | TIOCM_RTS; + ioctl(serial->fd, TIOCMBIS, &status); + LOG(LOG_INFO, "Configured serial device"); + serial->ping_number = 0; + time(&serial->frame_receive_time); //get the current time + serial->state = MUX_STATE_INITILIZING; + return 0; +} + +int start_muxer( + Serial* serial + ) +{ + LOG(LOG_INFO, "Configuring modem"); + char gsm_command[100]; + if (chat(serial->fd, "\r\n\r\n\r\nAT\r\n", 1) < 0) + { + LOG(LOG_WARNING, "Modem does not respond to AT commands, trying close mux mode"); + //if (cmux_mode) we do not know now so write both + write_frame(0, NULL, 0, GSM0710_CONTROL_CLD | GSM0710_CR); + //else + write_frame(0, close_channel_cmd, 2, GSM0710_TYPE_UIH); + SYSCHECK(chat(serial->fd, "AT\r\n", 1)); + } + SYSCHECK(chat(serial->fd, "ATZ\r\n", 3)); + SYSCHECK(chat(serial->fd, "ATE0\r\n", 1)); + if (0)// additional siemens c35 init + { + SYSCHECK(snprintf(gsm_command, sizeof(gsm_command), "AT+IPR=%d\r\n", baud_rates[cmux_port_speed])); + SYSCHECK(chat(serial->fd, gsm_command, 1)); + SYSCHECK(chat(serial->fd, "AT\r\n", 1)); + SYSCHECK(chat(serial->fd, "AT&S0\r\n", 1)); + SYSCHECK(chat(serial->fd, "AT\\Q3\r\n", 1)); + } + //SYSCHECK(chat(serial->fd, "AT+CMUX=?\r\n", 1)); + if (pin_code >= 0) + { + LOG(LOG_DEBUG, "send pin %04d", pin_code); +//Some modems, such as webbox, will sometimes hang if SIM code +//is given in virtual channel + SYSCHECK(snprintf(gsm_command, sizeof(gsm_command), "AT+CPIN=%04d\r\n", pin_code)); + SYSCHECK(chat(serial->fd, gsm_command, 10)); + } + SYSCHECK(chat(serial->fd, "AT+CFUN=0\r\n", 10)); + SYSCHECK(snprintf(gsm_command, sizeof(gsm_command), "AT+CMUX=%d,%d,%d,%d" + //",%d,%d,%d,%d,%d" + "\r\n" + , cmux_mode + , cmux_subset + , cmux_port_speed + , cmux_N1 + //, cmux_T1 + //, cmux_N2 + //, cmux_T2 + //, cmux_T3 + //, cmux_k + )); + LOG(LOG_INFO, "Starting mux mode"); + SYSCHECK(chat(serial->fd, gsm_command, 3)); + serial->state = MUX_STATE_MUXING; + LOG(LOG_INFO, "Waiting for mux-mode"); + sleep(1); + LOG(LOG_INFO, "Init control channel"); + write_frame(0, NULL, 0, GSM0710_TYPE_SABM | GSM0710_PF); + GIOChannel* channel = g_io_channel_unix_new(serial->fd); + serial->g_source = g_io_add_watch(channel, G_IO_IN | G_IO_HUP, serial_device_read, serial); + return 0; +} + +static int close_devices() +{ + LOG(LOG_DEBUG, "Enter"); + g_source_remove(serial.g_source); + serial.g_source = -1; + int i; + for (i=1;i= 0) + { + SYSCHECK(dbus_signal_send_deactivate(channellist[i].ptsname)); + if (channellist[i].opened) + { + LOG(LOG_INFO, "Closing down the logical channel %d", i); + if (cmux_mode) + write_frame(i, NULL, 0, GSM0710_CONTROL_CLD | GSM0710_CR); +//multiplexer close down command doesn't work with benqM22a module, use: write_frame(0, NULL, 0, GSM0710_TYPE_DISC | GSM0710_PF); + else + write_frame(i, close_channel_cmd, 2, GSM0710_TYPE_UIH); + SYSCHECK(logical_channel_close(channellist+i)); + } + LOG(LOG_INFO, "Logical channel %d closed", channellist[i].id); + } + } + if (serial.fd >= 0) + { + if (cmux_mode) + write_frame(0, NULL, 0, GSM0710_CONTROL_CLD | GSM0710_CR); + else + write_frame(0, close_channel_cmd, 2, GSM0710_TYPE_UIH); + static const char* poff = "AT@POFF\r\n"; + syslogdump(">s ", (unsigned char *)poff, strlen(poff)); + write(serial.fd, poff, strlen(poff)); + SYSCHECK(close(serial.fd)); + serial.fd = -1; + } + SYSCHECK(modem_hw_off(serial.pm_base_dir)); + serial.state = MUX_STATE_OFF; + return 0; +} + +static gboolean watchdog(gpointer data) +{ + LOG(LOG_DEBUG, "Enter"); + Serial* serial = (Serial*)data; + LOG(LOG_DEBUG, "Serial state is %d", serial->state); + switch (serial->state) + { + case MUX_STATE_OPENING: + if (open_serial_device(serial) < 0) + LOG(LOG_WARNING, "Could not open all devices and start muxer"); + serial->g_source_watchdog = g_timeout_add_seconds(5, watchdog, data); // let the dog watch every 5 sec + LOG(LOG_INFO, "Watchdog started"); + case MUX_STATE_INITILIZING: + if (start_muxer(serial) < 0) + LOG(LOG_WARNING, "Could not open all devices and start muxer errno=%d", errno); + break; + case MUX_STATE_MUXING: + if (use_ping) + { + if (serial->ping_number > use_ping) + { + LOG(LOG_DEBUG, "no ping reply for %d times, resetting modem", serial->ping_number); + serial->state = MUX_STATE_CLOSING; + } + else + { + LOG(LOG_DEBUG, "Sending PING to the modem"); + //write_frame(0, psc_channel_cmd, sizeof(psc_channel_cmd), GSM0710_TYPE_UI); + write_frame(0, test_channel_cmd, sizeof(test_channel_cmd), GSM0710_TYPE_UI); + serial->ping_number++; + } + } + if (use_timeout) + { + time_t current_time; + time(¤t_time); //get the current time + if (current_time - serial->frame_receive_time > use_timeout) + { + LOG(LOG_DEBUG, "timeout, resetting modem"); + serial->state = MUX_STATE_CLOSING; + } + } + break; + case MUX_STATE_CLOSING: + close_devices(); + serial->state = MUX_STATE_OPENING; + break; + default: + LOG(LOG_WARNING, "Don't know how to handle state %d", serial->state); + break; + } + return 1; +} + +/** + * shows how to use this program + */ +static int usage( + char *_name) +{ + fprintf(stderr, "\tUsage: %s [options]\n", _name); + fprintf(stderr, "Options:\n"); + // process control + fprintf(stderr, "\t-d: Fork, get a daemon [%s]\n", no_daemon?"no":"yes"); + fprintf(stderr, "\t-v: verbose logging\n"); + // modem control + fprintf(stderr, "\t-s : Serial port device to connect to [%s]\n", serial.devicename); + fprintf(stderr, "\t-t : reset modem after this number of seconds of silence [%d]\n", use_timeout); + fprintf(stderr, "\t-P : PIN code to unlock SIM [%d]\n", pin_code); + fprintf(stderr, "\t-p : use ping and reset modem after this number of unanswered pings [%d]\n", use_ping); + fprintf(stderr, "\t-x : power managment base dir [%s]\n", serial.pm_base_dir?serial.pm_base_dir:""); + // legacy - will be removed + fprintf(stderr, "\t-b : mode baudrate [%d]\n", baud_rates[cmux_port_speed]); + fprintf(stderr, "\t-m : Mode (basic, advanced) [%s]\n", cmux_mode?"advanced":"basic"); + fprintf(stderr, "\t-f : Frame size [%d]\n", cmux_N1); + // + fprintf(stderr, "\t-h: Show this help message and show current settings.\n"); + return -1; +} + +/** + * The main program + */ +int main( + int argc, + char *argv[], + char *env[]) +{ + LOG(LOG_DEBUG, "Enter"); + int opt; + pid_t parent_pid; +//for fault tolerance + serial.devicename = "/dev/ttySAC0"; + while ((opt = getopt(argc, argv, "dvs:t:p:f:h?m:b:P:x:")) > 0) + { + switch (opt) + { + case 'v': + syslog_level++; + break; + case 'd': + no_daemon = !no_daemon; + break; + case 'x': + serial.pm_base_dir = optarg; + break; + case 's': + serial.devicename = optarg; + break; + case 't': + use_timeout = atoi(optarg); + break; + case 'p': + use_ping = atoi(optarg); + break; + case 'P': + pin_code = atoi(optarg); + break; + // will be removed if +CMUX? works + case 'f': + cmux_N1 = atoi(optarg); + break; + case 'm': + if (!strcmp(optarg, "basic")) + cmux_mode = 0; + else if (!strcmp(optarg, "advanced")) + cmux_mode = 1; + else + cmux_mode = 0; + break; + case 'b': + cmux_port_speed = baud_rate_index(atoi(optarg)); + break; + default: + case '?': + case 'h': + usage(argv[0]); + exit(0); + break; + } + } + if (serial.pm_base_dir == NULL) + { + // auto detect - i hate windows-like-behavior but mickey want's it ;) + struct stat sb; + int i; + static char* fn[] = { + "/sys/bus/platform/devices/neo1973-pm-gsm.0", + "/sys/bus/platform/devices/gta01-pm-gsm.0", + NULL + }; + for (i=0;fn[i];i++) + if (stat(fn[i], &sb) >= 0) + { + serial.pm_base_dir = fn[i]; + LOG(LOG_INFO, "using '%s' as basedir for pm", fn[i]); + break; + } + } +//daemonize show time + parent_pid = getpid(); + if (!no_daemon && daemon(0, 0)) + { + fprintf(stderr, "Failed to daemonize: %s (%d)", strerror(errno), errno); + exit(1); + } + umask(0); +//signals treatment + signal(SIGHUP, signal_treatment); + signal(SIGPIPE, signal_treatment); + signal(SIGKILL, signal_treatment); + signal(SIGINT, signal_treatment); + signal(SIGUSR1, signal_treatment); + signal(SIGTERM, signal_treatment); + if (no_daemon) + openlog(argv[0], LOG_NDELAY | LOG_PID | LOG_PERROR, LOG_LOCAL0); + else + openlog(argv[0], LOG_NDELAY | LOG_PID, LOG_LOCAL0); + SYSCHECK(dbus_init()); +//allocate memory for data structures + if ((serial.in_buf = gsm0710_buffer_init()) == NULL + || (serial.adv_frame_buf = (unsigned char*)malloc((cmux_N1 + 3) * 2 + 2)) == NULL) + { + LOG(LOG_ALERT, "Out of memory"); + exit(-1); + } + LOG(LOG_DEBUG, "%s %s starting", *argv, revision); +//Initialize modem and virtual ports + serial.state = MUX_STATE_OPENING; + watchdog(&serial); +//start waiting for input and forwarding it back and forth -- + main_loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(main_loop); // will/may be terminated in signal_treatment + g_main_loop_unref(main_loop); +//finalize everything + SYSCHECK(close_devices()); + free(serial.adv_frame_buf); + gsm0710_buffer_destroy(serial.in_buf); + LOG(LOG_INFO, "Received %ld frames and dropped %ld received frames during the mux-mode", + serial.in_buf->received_count, serial.in_buf->dropped_count); + SYSCHECK(dbus_deinit()); + LOG(LOG_DEBUG, "%s finished", argv[0]); + closelog();// close syslog + return 0; +} +// vim:path=/usr/include,/usr/include/glib-2.0,/usr/include/dbus-1.0,src: diff --git a/src/gsm0710muxd.vapi b/src/gsm0710muxd.vapi new file mode 100644 index 0000000..f19a903 --- /dev/null +++ b/src/gsm0710muxd.vapi @@ -0,0 +1,10 @@ +namespace gsm0710muxd { + [CCode (cname = "c_get_power")] + public bool c_get_power (string origin); + [CCode (cname = "c_set_power")] + public bool c_set_power (string origin, bool on); + [CCode (cname = "c_reset_modem")] + public bool c_reset_modem (string origin); + [CCode (cname = "c_alloc_channel")] + public bool c_alloc_channel (string origin, string channel); +} diff --git a/src/mux.h b/src/mux.h new file mode 100644 index 0000000..408da9f --- /dev/null +++ b/src/mux.h @@ -0,0 +1,221 @@ +/* Generated by dbus-binding-tool; do not edit! */ + + +#ifndef __dbus_glib_marshal_mux_MARSHAL_H__ +#define __dbus_glib_marshal_mux_MARSHAL_H__ + +#include + +G_BEGIN_DECLS + +#ifdef G_ENABLE_DEBUG +#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) +#define g_marshal_value_peek_char(v) g_value_get_char (v) +#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) +#define g_marshal_value_peek_int(v) g_value_get_int (v) +#define g_marshal_value_peek_uint(v) g_value_get_uint (v) +#define g_marshal_value_peek_long(v) g_value_get_long (v) +#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) +#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) +#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) +#define g_marshal_value_peek_enum(v) g_value_get_enum (v) +#define g_marshal_value_peek_flags(v) g_value_get_flags (v) +#define g_marshal_value_peek_float(v) g_value_get_float (v) +#define g_marshal_value_peek_double(v) g_value_get_double (v) +#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) +#define g_marshal_value_peek_param(v) g_value_get_param (v) +#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) +#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) +#define g_marshal_value_peek_object(v) g_value_get_object (v) +#else /* !G_ENABLE_DEBUG */ +/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. + * Do not access GValues directly in your code. Instead, use the + * g_value_get_*() functions + */ +#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int +#define g_marshal_value_peek_char(v) (v)->data[0].v_int +#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint +#define g_marshal_value_peek_int(v) (v)->data[0].v_int +#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint +#define g_marshal_value_peek_long(v) (v)->data[0].v_long +#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 +#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 +#define g_marshal_value_peek_enum(v) (v)->data[0].v_long +#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_float(v) (v)->data[0].v_float +#define g_marshal_value_peek_double(v) (v)->data[0].v_double +#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer +#endif /* !G_ENABLE_DEBUG */ + + +/* BOOLEAN:STRING,BOOLEAN,POINTER (/tmp/dbus-binding-tool-c-marshallers.QZI09T:1) */ +extern void dbus_glib_marshal_mux_BOOLEAN__STRING_BOOLEAN_POINTER (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); +void +dbus_glib_marshal_mux_BOOLEAN__STRING_BOOLEAN_POINTER (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_BOOLEAN_POINTER) (gpointer data1, + gpointer arg_1, + gboolean arg_2, + gpointer arg_3, + gpointer data2); + register GMarshalFunc_BOOLEAN__STRING_BOOLEAN_POINTER callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + gboolean v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 4); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_BOOLEAN__STRING_BOOLEAN_POINTER) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_marshal_value_peek_string (param_values + 1), + g_marshal_value_peek_boolean (param_values + 2), + g_marshal_value_peek_pointer (param_values + 3), + data2); + + g_value_set_boolean (return_value, v_return); +} + +/* BOOLEAN:STRING,POINTER,POINTER (/tmp/dbus-binding-tool-c-marshallers.QZI09T:2) */ +extern void dbus_glib_marshal_mux_BOOLEAN__STRING_POINTER_POINTER (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); +void +dbus_glib_marshal_mux_BOOLEAN__STRING_POINTER_POINTER (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer arg_3, + gpointer data2); + register GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + gboolean v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 4); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_marshal_value_peek_string (param_values + 1), + g_marshal_value_peek_pointer (param_values + 2), + g_marshal_value_peek_pointer (param_values + 3), + data2); + + g_value_set_boolean (return_value, v_return); +} + +/* BOOLEAN:STRING,POINTER (/tmp/dbus-binding-tool-c-marshallers.QZI09T:3) */ +extern void dbus_glib_marshal_mux_BOOLEAN__STRING_POINTER (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); +void +dbus_glib_marshal_mux_BOOLEAN__STRING_POINTER (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_POINTER) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer data2); + register GMarshalFunc_BOOLEAN__STRING_POINTER callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + gboolean v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_BOOLEAN__STRING_POINTER) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_marshal_value_peek_string (param_values + 1), + g_marshal_value_peek_pointer (param_values + 2), + data2); + + g_value_set_boolean (return_value, v_return); +} + +G_END_DECLS + +#endif /* __dbus_glib_marshal_mux_MARSHAL_H__ */ + +#include +static const DBusGMethodInfo dbus_glib_mux_methods[] = { + { (GCallback) muxer_control_power, dbus_glib_marshal_mux_BOOLEAN__STRING_BOOLEAN_POINTER, 0 }, + { (GCallback) muxer_control_power, dbus_glib_marshal_mux_BOOLEAN__STRING_POINTER_POINTER, 57 }, + { (GCallback) muxer_control_reset_modem, dbus_glib_marshal_mux_BOOLEAN__STRING_POINTER, 118 }, + { (GCallback) muxer_control_alloc_channel, dbus_glib_marshal_mux_BOOLEAN__STRING_POINTER_POINTER, 165 }, +}; + +const DBusGObjectInfo dbus_glib_mux_object_info = { + 0, + dbus_glib_mux_methods, + 4, +"org.freesmartphone.GSM.MUX\0SetPower\0S\0origin\0I\0s\0on\0I\0b\0\0org.freesmartphone.GSM.MUX\0GetPower\0S\0origin\0I\0s\0on\0O\0F\0N\0b\0\0org.freesmartphone.GSM.MUX\0Reset\0S\0origin\0I\0s\0\0org.freesmartphone.GSM.MUX\0AllocChannel\0S\0origin\0I\0s\0channel\0O\0F\0N\0s\0\0\0", +"\0", +"\0" +}; + diff --git a/src/mux.xml b/src/mux.xml new file mode 100644 index 0000000..fdb42e9 --- /dev/null +++ b/src/mux.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/muxercontrol.c b/src/muxercontrol.c new file mode 100644 index 0000000..fee4d84 --- /dev/null +++ b/src/muxercontrol.c @@ -0,0 +1,98 @@ +/* + Vala MuxerControl Code + + valac --vapidir=src --pkg=gsm0710muxd --pkg=dbus-glib-1 --ccode src/muxercontrol.vala +*/ + +#include "muxercontrol.h" +#include +#include + + + + +enum { + MUXER_CONTROL_DUMMY_PROPERTY +}; +static gpointer muxer_control_parent_class = NULL; + + + +void muxer_control_run (MuxerControl* self) { + GError * inner_error; + DBusGConnection* conn; + g_return_if_fail (IS_MUXER_CONTROL (self)); + inner_error = NULL; + conn = dbus_g_bus_get (DBUS_BUS_SYSTEM, &inner_error); + if (inner_error != NULL) { + g_critical ("file %s: line %d: uncaught error: %s", __FILE__, __LINE__, inner_error->message); + g_clear_error (&inner_error); + } + (conn == NULL ? NULL : (conn = (dbus_g_connection_unref (conn), NULL))); +} + + +gboolean muxer_control_reset_modem (MuxerControl* self, const char* origin) { + g_return_val_if_fail (IS_MUXER_CONTROL (self), FALSE); + g_return_val_if_fail (origin != NULL, FALSE); + return c_reset_modem (origin); +} + + +gboolean muxer_control_set_power (MuxerControl* self, const char* origin, gboolean on) { + g_return_val_if_fail (IS_MUXER_CONTROL (self), FALSE); + g_return_val_if_fail (origin != NULL, FALSE); + return c_set_power (origin, on); +} + + +gboolean muxer_control_get_power (MuxerControl* self, const char* origin, gboolean on) { + g_return_val_if_fail (IS_MUXER_CONTROL (self), FALSE); + g_return_val_if_fail (origin != NULL, FALSE); + return c_get_power (origin); +} + + +gboolean muxer_control_alloc_channel (MuxerControl* self, const char* origin, const char* channel) { + g_return_val_if_fail (IS_MUXER_CONTROL (self), FALSE); + g_return_val_if_fail (origin != NULL, FALSE); + g_return_val_if_fail (channel != NULL, FALSE); + return c_alloc_channel (origin, channel); +} + + +MuxerControl* muxer_control_gen (void) { + return muxer_control_new (); +} + + +/*[DBusInterface(name = "org.mobile.mux.RemoteInterface")] +interface Mux.RemoteInterface;*/ +MuxerControl* muxer_control_new (void) { + MuxerControl * self; + self = g_object_newv (TYPE_MUXER_CONTROL, 0, NULL); + return self; +} + + +static void muxer_control_class_init (MuxerControlClass * klass) { + muxer_control_parent_class = g_type_class_peek_parent (klass); +} + + +static void muxer_control_init (MuxerControl * self) { +} + + +GType muxer_control_get_type (void) { + static GType muxer_control_type_id = 0; + if (G_UNLIKELY (muxer_control_type_id == 0)) { + static const GTypeInfo g_define_type_info = { sizeof (MuxerControlClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) muxer_control_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (MuxerControl), 0, (GInstanceInitFunc) muxer_control_init }; + muxer_control_type_id = g_type_register_static (G_TYPE_OBJECT, "MuxerControl", &g_define_type_info, 0); + } + return muxer_control_type_id; +} + + + + diff --git a/src/muxercontrol.h b/src/muxercontrol.h new file mode 100644 index 0000000..37d3f8d --- /dev/null +++ b/src/muxercontrol.h @@ -0,0 +1,51 @@ +/* + Vala MuxerControl Code + + valac --vapidir=src --pkg=gsm0710muxd --pkg=dbus-glib-1 --ccode src/muxercontrol.vala +*/ + +#ifndef __MUXERCONTROL_H__ +#define __MUXERCONTROL_H__ + +#include +#include +#include +#include + +G_BEGIN_DECLS + + +#define TYPE_MUXER_CONTROL (muxer_control_get_type ()) +#define MUXER_CONTROL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MUXER_CONTROL, MuxerControl)) +#define MUXER_CONTROL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_MUXER_CONTROL, MuxerControlClass)) +#define IS_MUXER_CONTROL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MUXER_CONTROL)) +#define IS_MUXER_CONTROL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_MUXER_CONTROL)) +#define MUXER_CONTROL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_MUXER_CONTROL, MuxerControlClass)) + +typedef struct _MuxerControl MuxerControl; +typedef struct _MuxerControlClass MuxerControlClass; +typedef struct _MuxerControlPrivate MuxerControlPrivate; + +/*[DBusInterface(name = "org.mobile.mux.RemoteInterface")] +interface Mux.RemoteInterface;*/ +struct _MuxerControl { + GObject parent_instance; + MuxerControlPrivate * priv; +}; +struct _MuxerControlClass { + GObjectClass parent_class; +}; + +void muxer_control_run (MuxerControl* self); +gboolean muxer_control_reset_modem (MuxerControl* self, const char* origin); +gboolean muxer_control_set_power (MuxerControl* self, const char* origin, gboolean on); +gboolean muxer_control_get_power (MuxerControl* self, const char* origin, gboolean on); +gboolean muxer_control_alloc_channel (MuxerControl* self, const char* origin, const char* channel); +MuxerControl* muxer_control_gen (void); +MuxerControl* muxer_control_new (void); +GType muxer_control_get_type (void); + + +G_END_DECLS + +#endif diff --git a/src/muxercontrol.vala b/src/muxercontrol.vala new file mode 100644 index 0000000..0e36575 --- /dev/null +++ b/src/muxercontrol.vala @@ -0,0 +1,36 @@ +/* + Vala MuxerControl Code + + valac --vapidir=src --pkg=gsm0710muxd --pkg=dbus-glib-1 --ccode src/muxercontrol.vala +*/ + +//[DBusInterface(name = "org.mobile.mux.RemoteInterface")] +//interface Mux.RemoteInterface; + +public class MuxerControl : GLib.Object +{ + public void run() + { + DBus.Connection conn = DBus.Bus.get(DBus.BusType.SYSTEM); + } + public bool reset_modem(string origin) + { + return gsm0710muxd.c_reset_modem(origin); + } + public bool set_power(string origin, bool on) + { + return gsm0710muxd.c_set_power(origin, on); + } + public bool get_power(string origin) + { + return gsm0710muxd.c_get_power(origin); + } + public bool alloc_channel(string origin, string channel) + { + return gsm0710muxd.c_alloc_channel(origin, channel); + } + public static MuxerControl gen() + { + return new MuxerControl(); + } +} -- 2.39.5