From: Michael 'Mickey' Lauer Date: Sat, 3 May 2008 16:41:43 +0000 (+0200) Subject: initial upload from freesmartphone.org SVN as per rev 295 X-Git-Tag: milestone2~6 X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=6a500ed6a0f7077e7c70b138b642779a8813ea59;p=gsm0710muxd.git initial upload from freesmartphone.org SVN as per rev 295 --- 6a500ed6a0f7077e7c70b138b642779a8813ea59 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(); + } +}