├── .gitignore ├── CHANGES ├── COPYING ├── Makefile ├── README ├── README.arch ├── README.x11 ├── atparser.c ├── display.c ├── display.h ├── dsp.c ├── dsp.h ├── dtmf.c ├── dtmf.h ├── fsk.c ├── fsk.h ├── lm.c ├── lm.h ├── lmreal.c ├── lmsim.c ├── lmsoundcard.c ├── lmstates.h ├── nodisplay.c ├── serial.c ├── v21.c ├── v21.h ├── v22.c ├── v22.h ├── v23.c ├── v23.h ├── v34.c ├── v34.h ├── v34eq.c ├── v34gen.c ├── v34phase2.c ├── v34priv.h ├── v8.c ├── v8.h ├── v90.c ├── v90.h ├── v90gen.c └── v90priv.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | lm 3 | v34gen 4 | v34table.c 5 | v90gen 6 | v90table.c 7 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | * from version 0.2.4 to 0.2.5 2 | ============================= 3 | - major rewrite, the API becomes stable. 4 | - V8/V21/V23 should be usable. 5 | - added X11 interface for the simulator. 6 | - better line model for the simulator: generic FIR filter. 7 | Programmable echo generator (both neat & far end). 8 | - V22 tx code (needed for V34 phase 2). 9 | - V34: added adaptive equalizer, symbol timing recovery, phase 10 | recovery. Tests for fast training on the PP sequence (but not satisfactory). 11 | - added AT parser. 12 | - added serial protocol. 13 | - added working soundcard hw support. 14 | 15 | * from version 0.2.3 to 0.2.4 16 | ============================= 17 | 18 | - major V90 update, the algebraic part is finished, and the CP packet 19 | parsing is done. 20 | - added patches from Pavel (serial.c, lmreal.c) 21 | 22 | * from version 0.2.2 to 0.2.3 23 | ============================= 24 | 25 | - added V90 core, but no usable code yet. 26 | - more patches from pavel for ltmodem. 27 | 28 | * from version 0.2.1 to 0.2.2 29 | ============================= 30 | 31 | - added extended V34 modulation for 31200 & 33600 speeds. 32 | - added V34 negociation (not finished) 33 | - added Pavel patches for ltmodem 34 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) 19yy name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # uncomment to use X11 debug interface 2 | USE_X11=y 3 | 4 | CFLAGS= -O2 -Wall -g 5 | LDFLAGS= -g 6 | OBJS= lm.o lmsim.o lmreal.o lmsoundcard.o serial.o atparser.o \ 7 | dsp.o fsk.o v8.o v21.o v23.o dtmf.o \ 8 | v34.o v34table.o v22.o v34eq.o \ 9 | v90.o v90table.o 10 | INCLUDES= display.h fsk.h v21.h v34priv.h v90priv.h \ 11 | dsp.h lm.h v23.h v8.h \ 12 | dtmf.h lmstates.h v34.h v90.h 13 | PROG= lm 14 | 15 | ifdef USE_X11 16 | OBJS += display.o 17 | LDFLAGS += -L/usr/X11R6/lib -lX11 18 | else 19 | OBJS += nodisplay.o 20 | endif 21 | 22 | all: $(PROG) 23 | 24 | $(PROG): $(OBJS) 25 | gcc -o $(PROG) $(OBJS) -lm $(LDFLAGS) 26 | 27 | v34gen: v34gen.o dsp.o 28 | gcc -o $@ v34gen.o dsp.o -lm $(LDFLAGS) 29 | 30 | v34table.c: v34gen 31 | ./v34gen > $@ 32 | 33 | v90gen: v90gen.o 34 | gcc -o $@ $< -lm $(LDFLAGS) 35 | 36 | v90table.c: v90gen 37 | ./v90gen > $@ 38 | 39 | linmodem.dvi: linmodem.tex 40 | latex2e linmodem.tex 41 | 42 | clean: 43 | rm -f *.o *~ *.dat core gmon.out *.sw v34table.c v90table.c $(PROG) v34gen v90gen *.aux *.dvi *.log 44 | 45 | tar: 46 | ( cd .. ; tar zcvf linmodem.tgz linmodem --exclude CVS ) 47 | 48 | %.o: %.c $(INCLUDES) 49 | gcc $(CFLAGS) -c $*.c 50 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | Here is the generic Linux Modem. This modem is totally software, 3 | it means that all the DSP stuff is done by the main CPU, as in some so 4 | called "winmodems". See the main project page at 5 | http://www.enst.fr/~bellard/linmodem.html. 6 | 7 | Linmodem is also a research project. It contains all the necessary 8 | stuff to test new digital communication algorithms. The line simulator 9 | and the X11 interface can be used to simulate a complete communication 10 | chain. 11 | 12 | Linmodem is the first modem to integrate a graphical user interface 13 | which show the data transmitted graphically (QAM constellation, real 14 | time FFT of the received signal, etc...) and which will allow you to 15 | monitor the line quality. 16 | 17 | What's done: 18 | ----------- 19 | 20 | - V34 modulator (sampling rate of 8000 Hz) 21 | - V34 demodulator (sampling rate of 8000 Hz), but no echo cancellor. 22 | - Algebraic part of V90. 23 | - DTMF dialing/receive. 24 | - V8 protocol. 25 | - V21 modulation & demodulation 26 | - V23 modulation & demodulation 27 | - sample code to test the protocol. 28 | - sample code to test V21, V22, V23, V34 and V90 independently from the modem. 29 | - a basic phone line simulator (with echos & typical line 30 | amplitude/phase distortion). 31 | - an X11 interface (see README.x11) 32 | - soundcard interface. 33 | - AT command parser & sample tty simulator. 34 | - asynchronous protocol. 35 | 36 | See the homepage of the project at 37 | http://www.enst.fr/~bellard/linmodem.html to know what are the tasks 38 | you could do. 39 | 40 | Read the file README.arch to know the details of the 41 | implementation. Next versions will contain the first draft on the 42 | algorithms which are implemented. 43 | 44 | Testing: 45 | ------- 46 | 47 | Yes, you can already hear the modem ! 48 | 49 | compile everything, then type: 50 | 51 | lm -sv 52 | 53 | You will see a lot of debug stuff. Then you can press Control C to 54 | stop the call. If you play the files 'ans.sw' and 'cal.sw' on your 55 | soundcard (16 bit, signed 8kHz), you will hear the DTMF pulses, the V8 56 | negociation, and a sample V21 connection. The X11 interface allows you 57 | to see the signals exchanged. 58 | 59 | Data pump testing: 60 | ----------------- 61 | 62 | With the option '-m modulation_name', you can test the V21, V22, V23, 63 | V34 and V90 data pumps. You can understand what's going on in this 64 | test only if you have a basic knowledge of the modulations. 65 | 66 | The X11 interface can be used to monitor all the main data pump 67 | parameters, except for V90 which is not yet completely integrated in 68 | the tests (see README.x11). 69 | 70 | Real modems: 71 | ----------- 72 | 73 | Linmodem won't contain any 74 | hardware modem to support modems directly, but it will use kernel 75 | drivers which give a unified API to every driver (see README.arch to 76 | have an idea of the API) 77 | 78 | Some test code is included in lmreal.c to work with the LTModem stuff 79 | available at http://www.close.u-net.com/ltmodem.html. However, it was 80 | not tested so don't expect it to work in this version. 81 | 82 | Soundcard testing: 83 | ----------------- 84 | 85 | If you have two PCs connected by soundcards (connect line in -> line 86 | out), you may try the soundcard support of linmodem (not tested now, 87 | but should work): 88 | 89 | 'lm -tv' launches linmodem on your soundcard (device '/dev/dsp'). Then 90 | you can type 'ATDTxxx' to compose a number and launch a connection. On 91 | the other PC, type 'ATA' to receive the connection. It should work in 92 | V23 (or V21 if you change the defaults modulations in lm.c). 93 | 94 | With 'lm -t', linmodem simulates a serial line on '/dev/ttyz0'. You 95 | can use minicom or any other terminal emulator to send AT commands. 96 | 97 | Enjoy :-) 98 | 99 | Fabrice Bellard - bellard@email.enst.fr - http://www.enst.fr/~bellard 100 | -------------------------------------------------------------------------------- /README.arch: -------------------------------------------------------------------------------- 1 | 2 | Linmodem architecture 3 | 4 | Copyright (c) 2000 Fabrice Bellard 5 | 6 | 7 | 1) Overview: 8 | ----------- 9 | 10 | The hardware dependent layer (for example lmreal.c, lmsim.c, 11 | lmsoundcard.c) must call the function 12 | 13 | void sm_process(struct sm_state *sm, s16 *output, s16 *input, int nb_samples); 14 | 15 | at least every 10 ms. It must supply 'nb_samples' 16 bit input samples 16 | at 8000 Hz. The function sm_process returns the 'output' samples it 17 | has computed. These samples can them be sent to the phone line. 18 | 19 | 'sm_process' handles the dialing, ring detection and Vxx protocol 20 | initization. Then, each protocol can supply a similar function. For 21 | example, 'v8.c' supplies the function: 22 | 23 | int V8_process(V8State *sm, s16 *output, s16 *input, int nb_samples); 24 | 25 | It returns the modulation to which the modem must go after the V8 26 | phase. 27 | 28 | Note that no threads are used. It implies that each 'xx_process' 29 | function must use an internal state machine. The first parameter 30 | ('V8State' here) is usually the structure in which the state is 31 | stored. 32 | 33 | 2) Timing: 34 | --------- 35 | 36 | The protocols must use only 'nb_samples' as a timing, not the real 37 | time of the system. It allows to simulate the whole modem without 38 | changing anything. 39 | 40 | 41 | 3) Reentrancy: 42 | ------------- 43 | 44 | Each protocol must be reentrant, so that multiple modems can be 45 | instanciated at the same time. It is needed for example to do 46 | simulations. 47 | 48 | 4) Data handling: 49 | ---------------- 50 | 51 | When a protocol gets a bit from the input samples, it should can a function 52 | 53 | int get_bit(void *opaque); 54 | 55 | provided at its initialization with the opaque parameter 'opaque'. The 56 | same should be done for output with : 57 | 58 | void put_bit(void *opaque, int bit); 59 | 60 | 'sm_process' instanciate each protocol by giving it one of its 61 | standard bit I/O functions. These functions are responsible from 62 | handling the higher level protocol (asynchronous, LAPM, V42bis). 63 | 64 | See the file 'serial.c' to see how the data can be handled. V42/V42bis 65 | should be added the same way. 66 | 67 | The decoded bytes are put in the FIFO sm->rx_fifo. This fifo is then 68 | return to the modem tty. The inverse is done with sm->tx_fifo. 69 | 70 | 5) Modem configuration: 71 | ---------------------- 72 | 73 | The configuration parameters are defined in 'lm.c'. See 'struct 74 | LinModemConfig default_lm_config'. 75 | 76 | 6) Linmodem harware interface: 77 | ----------------------------- 78 | 79 | See the file lmsoundcard.c which gives an example to interface to a 80 | sound card with the Open Sound System API. 81 | 82 | 7) Linmodem kernel interface: 83 | ---------------------------- 84 | 85 | The hardware interface to an actual modem is not completely defined 86 | yet. However, it will be very close to the Open Sound System API: 87 | 88 | - the write() & read() syscalls write & read 16 bit samples from the 89 | modem. 90 | 91 | - An ioctl can select the sampling rate (at least 8000 Hz must be 92 | available). 93 | 94 | - an ioctl set/reset the offhook relay. 95 | 96 | - an ioctl set/reset the pulse relay. 97 | 98 | - an ioctl gives the state of the ring detection. Each time the ring 99 | rings, the event POLLPRI (urgent data) should be set so that the 100 | poll() syscall can handle it. 101 | 102 | - an ioctl changes the input & output gains, as the volume for a sound 103 | card. 104 | 105 | 8) AT command parser: 106 | -------------------- 107 | 108 | See the file atparse.c: The parser must remain sample. We do not want 109 | to support all the AT commands, but only the minimal subset so that 110 | linux programs can work : 'chat' for PPP, 'mgetty/vgetty' for 111 | voice/data/fax calls, 'sendfax' to send faxes. 112 | 113 | -------------------------------------------------------------------------------- /README.x11: -------------------------------------------------------------------------------- 1 | 2 | Linmodem contains an X11 interface which can be used to monitor the 3 | modem parameters. It is used for example in v34 testing (lm -m v34). The 4 | X11 simulation works only in 16 bit mode. If you are interested by 5 | other screen depths, please implement them :-) 6 | 7 | The function keys are used to change the parameters which are dumped 8 | on the screen: 9 | 10 | * for V34: 11 | 12 | F1 : dump the brut samples which enter into the modem (at 8000Hz). A 13 | hamming windowed FFT is done to output the spectral power. 14 | 15 | F2 : dump the echo cancellor parameters (not implemented yet). 16 | 17 | F3 : dump the samples after frequency normalization & symbol timing 18 | recovery. You have 3 samples per baud for V34. A hamming windowed FFT 19 | is done to output the spectral power. 20 | 21 | F4 : dump the equalizer filter in both time & frequency domains. 22 | 23 | F5 : dump the QAM points just after the equalizer and phase 24 | recovery. This graphic can be used to monitor the overall modem 25 | quality. 26 | 27 | 28 | * for V21/V23 tests 29 | 30 | F1: same as V34 31 | 32 | F3: decision samples 33 | -------------------------------------------------------------------------------- /atparser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple AT command parser 3 | * 4 | * Copyright (c) 2000 Fabrice Bellard. 5 | * 6 | * This code is released under the GNU General Public License version 7 | * 2. Please read the file COPYING to know the exact terms of the 8 | * license. 9 | * 10 | */ 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "lm.h" 18 | 19 | #define DEBUG 20 | 21 | static void parse_at_line(struct lm_at_state *s, const char *line); 22 | static void at_putc(struct lm_at_state *s, int c); 23 | static void at_printf(struct lm_at_state *s, char *fmt, ...); 24 | 25 | /* 26 | * This AT command parser is not intended to be complete nor accurate 27 | * but to provide the minimum functionality so that the programs can 28 | * make a data/voice/fax connection. 29 | */ 30 | 31 | void lm_at_parser_init(struct lm_at_state *s, struct sm_state *sm) 32 | { 33 | s->sm = sm; 34 | s->at_line_ptr = 0; 35 | s->at_state = AT_MODE_COMMAND; 36 | } 37 | 38 | void lm_at_parser(struct lm_at_state *s) 39 | { 40 | int state, c; 41 | 42 | switch(s->at_state) { 43 | case AT_MODE_COMMAND: 44 | for(;;) { 45 | /* handle incoming character */ 46 | c = sm_get_bit(&s->sm->tx_fifo); 47 | if (c == -1) 48 | break; 49 | 50 | if (c == '\n' || c == '\r') { 51 | /* line validation */ 52 | s->at_line[s->at_line_ptr] = '\0'; 53 | if (s->at_line_ptr != 0) { 54 | at_putc(s, '\n'); 55 | parse_at_line(s, s->at_line); 56 | } 57 | s->at_line_ptr = 0; 58 | } else if (c == '\b') { 59 | /* backspace */ 60 | if (s->at_line_ptr > 0) { 61 | s->at_line_ptr--; 62 | at_printf(s, "\b \b"); 63 | } 64 | } else { 65 | /* add new char */ 66 | if (s->at_line_ptr < (sizeof(s->at_line) - 1)) { 67 | s->at_line[s->at_line_ptr++] = c; 68 | at_putc(s, c); 69 | } 70 | } 71 | } 72 | break; 73 | case AT_MODE_DIALING: 74 | state = lm_get_state(s->sm); 75 | if (state == LM_STATE_IDLE) { 76 | at_printf(s, "ERROR\n"); 77 | s->at_state = AT_MODE_COMMAND; 78 | } else if (state == LM_STATE_CONNECTED) { 79 | at_printf(s, "CONNECT\n"); 80 | s->at_state = AT_MODE_CONNECTED; 81 | } 82 | break; 83 | 84 | case AT_MODE_CONNECTED: 85 | if (lm_get_state(s->sm) == LM_STATE_IDLE) { 86 | at_printf(s, "OK\n"); 87 | s->at_state = AT_MODE_COMMAND; 88 | } 89 | break; 90 | } 91 | } 92 | 93 | /* return TRUE if val is a prefix of str. If it returns TRUE, ptr is 94 | set to the next character in 'str' after the prefix */ 95 | #if 0 96 | static int strstart(const char *str, const char *val, const char **ptr) 97 | { 98 | const char *p, *q; 99 | p = str; 100 | q = val; 101 | while (*q != '\0') { 102 | if (*p != *q) 103 | return 0; 104 | p++; 105 | q++; 106 | } 107 | *ptr = p; 108 | return 1; 109 | } 110 | #endif 111 | 112 | static int strcasestart(const char *str, const char *val, const char **ptr) 113 | { 114 | const char *p, *q; 115 | p = str; 116 | q = val; 117 | while (*q != '\0') { 118 | if (toupper(*p) != toupper(*q)) 119 | return 0; 120 | p++; 121 | q++; 122 | } 123 | *ptr = p; 124 | return 1; 125 | } 126 | 127 | static void at_putc(struct lm_at_state *s, int c) 128 | { 129 | if (c == '\n') 130 | sm_put_bit(&s->sm->rx_fifo, '\r'); 131 | sm_put_bit(&s->sm->rx_fifo, c); 132 | } 133 | 134 | static void at_printf(struct lm_at_state *s, char *fmt, ...) 135 | { 136 | char buf[256], *p; 137 | int c; 138 | 139 | va_list ap; 140 | 141 | va_start(ap, fmt); 142 | snprintf(buf, sizeof(buf), fmt, ap); 143 | p = buf; 144 | while (*p) { 145 | c = *p++; 146 | at_putc(s, c); 147 | } 148 | va_end(ap); 149 | } 150 | 151 | static void parse_at_line(struct lm_at_state *s, const char *line) 152 | { 153 | const char *p; 154 | struct sm_state *sm = s->sm; 155 | 156 | if (strcasestart(line, "ATD", &p)) { 157 | int pulse; 158 | 159 | pulse = sm->lm_config->pulse_dial; 160 | if (strcasestart(p, "P", &p)) 161 | pulse = 1; 162 | if (strcasestart(p, "T", &p)) 163 | pulse = 0; 164 | lm_start_dial(sm, pulse, p); 165 | s->at_state = AT_MODE_DIALING; 166 | } else if (strcasestart(line, "ATI", &p)) { 167 | at_printf(s, "Linmodem " LM_VERSION "\n"); 168 | } else if (strcasestart(line, "ATZ", &p)) { 169 | at_printf(s, "OK\n"); 170 | } else if (strcasestart(line, "ATA", &p)) { 171 | lm_start_receive(sm); 172 | s->at_state = AT_MODE_DIALING; 173 | } else if (strcasestart(line, "ATH", &p)) { 174 | lm_hangup(sm); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /display.c: -------------------------------------------------------------------------------- 1 | /* 2 | * X11 interface for linmodem 3 | * 4 | * Copyright (c) 2000 Fabrice Bellard. 5 | * 6 | * This code is released under the GNU General Public License version 7 | * 2. Please read the file COPYING to know the exact terms of the 8 | * license. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "lm.h" 20 | 21 | 22 | #define NB_MODES 5 23 | 24 | enum { 25 | DISP_MODE_SAMPLE, /* display the brut samples */ 26 | DISP_MODE_ECHOCANCEL, /* display the echo cancellor info */ 27 | DISP_MODE_SAMPLESYNC, /* display the samples after freq normalize 28 | & symbol recovery */ 29 | DISP_MODE_EQUALIZER, /* display the equalizer filter */ 30 | DISP_MODE_QAM, /* display the qam */ 31 | } disp_state; 32 | 33 | char *mode_str[NB_MODES] = { 34 | "Sample", 35 | "Echo Cancel", 36 | "Sample Sync", 37 | "Equalizer", 38 | "QAM", 39 | }; 40 | 41 | 42 | #define QAM_SIZE 460 43 | 44 | static void set_state(int state); 45 | 46 | /**************************/ 47 | 48 | #define RGB(r, g, b) ((((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3)) 49 | 50 | Display *display; 51 | Window window; 52 | GC gc; 53 | XFontStruct *xfont; 54 | unsigned int fg, bg; 55 | int minx, miny; 56 | 57 | int font_xsize, font_ysize; 58 | 59 | int lm_display_init(void) 60 | { 61 | XSizeHints hint; 62 | int screen; 63 | XVisualInfo vinfo; 64 | int size_x = 640; 65 | int size_y = 480; 66 | XSetWindowAttributes xwa; 67 | char *fontname = "fixed"; 68 | 69 | display = XOpenDisplay(""); 70 | if (display == NULL) { 71 | return -1; 72 | } 73 | screen = DefaultScreen(display); 74 | 75 | bg = RGB(0, 0, 0); 76 | fg = RGB(255, 255, 255); 77 | 78 | /* Fill in hint structure */ 79 | 80 | hint.x = 0; 81 | hint.y = 0; 82 | hint.width = size_x; 83 | hint.height = size_y; 84 | hint.flags = PPosition | PSize; 85 | 86 | /* Make the window */ 87 | if (!XMatchVisualInfo(display, screen, 16, TrueColor, &vinfo)) { 88 | printf("A 16 bit visual is need by this program\n"); 89 | return -1; 90 | } 91 | 92 | window = XCreateSimpleWindow(display, 93 | DefaultRootWindow(display), 94 | hint.x, hint.y, 95 | hint.width, hint.height, 96 | 4, fg, bg); 97 | /* Enable backing store */ 98 | xwa.backing_store = Always; 99 | XChangeWindowAttributes(display, window, CWBackingStore, &xwa); 100 | 101 | XSelectInput(display, window, StructureNotifyMask); 102 | 103 | /* Tell other applications about this window */ 104 | 105 | XSetStandardProperties(display, window, 106 | "linmodem", "linmodem", 107 | None, NULL, 0, &hint); 108 | 109 | /* Map window. */ 110 | 111 | XMapWindow(display, window); 112 | 113 | /* Wait for map. */ 114 | while (1) { 115 | XEvent xev; 116 | XNextEvent(display, &xev); 117 | if (xev.type == MapNotify && xev.xmap.event == window) 118 | break; 119 | } 120 | XSelectInput(display, window, KeyPressMask 121 | | ButtonPressMask); 122 | 123 | gc = XCreateGC(display, window, 0, 0); 124 | 125 | xfont = XLoadQueryFont (display, fontname); 126 | if (!xfont) { 127 | fprintf(stderr, "Could not load font '%s'\n", fontname); 128 | return -1; 129 | } 130 | font_xsize = xfont->max_bounds.rbearing - xfont->min_bounds.lbearing; 131 | font_ysize = xfont->max_bounds.ascent + xfont->max_bounds.descent; 132 | 133 | set_state(DISP_MODE_SAMPLE); 134 | 135 | return 0; 136 | } 137 | 138 | void lm_display_close(void) 139 | { 140 | XCloseDisplay(display); 141 | } 142 | 143 | void printf_at(int x, int y, char *fmt, ...) 144 | { 145 | va_list ap; 146 | char buf[1024]; 147 | 148 | va_start(ap, fmt); 149 | 150 | vsnprintf(buf, sizeof(buf), fmt, ap); 151 | 152 | XSetFont(display, gc, xfont->fid); 153 | 154 | XSetForeground(display, gc, bg); 155 | XFillRectangle(display, window, gc, 156 | x * font_xsize, y * font_ysize, 157 | font_xsize * strlen(buf), font_ysize); 158 | 159 | XSetForeground(display, gc, fg); 160 | XDrawString(display, window, gc, x * font_xsize, (y + 1) * font_ysize - 1, 161 | buf, strlen(buf)); 162 | 163 | va_end(ap); 164 | } 165 | 166 | /* draw a graph at (x1, y1, x1 + w, y1 + h). The points are computed 167 | by calc_func */ 168 | 169 | #define DG_AUTOSCALE_YMIN 0x0001 170 | #define DG_AUTOSCALE_YMAX 0x0002 171 | 172 | void draw_graph(char *title, 173 | int x1, int y1, int w, int h, 174 | float xmin, float xmax, float ymin, float ymax, 175 | int flags, float (*calc_func)(float)) 176 | { 177 | int i, yy, xx; 178 | float x, y; 179 | int ly; 180 | float tab[1024]; 181 | 182 | /* auto scale */ 183 | for(i=0;i ymax) 196 | ymax = y; 197 | } 198 | } 199 | 200 | /* draw ! */ 201 | 202 | XSetForeground(display, gc, bg); 203 | XFillRectangle(display, window, gc, x1, y1, w, h); 204 | 205 | XSetForeground(display, gc, RGB(255, 0, 0)); 206 | XDrawRectangle(display, window, gc, x1, y1, w, h); 207 | 208 | /* axis */ 209 | XSetForeground(display, gc, RGB(0, 255, 0)); 210 | if (xmin <= 0.0 && 0.0 <= xmax) { 211 | xx = (int)rint(((0.0 - xmin) / (xmax - xmin)) * (w-1)) + x1; 212 | XDrawLine(display, window, gc, 213 | xx, y1, xx, y1 + h - 1); 214 | } 215 | 216 | if (ymin <= 0.0 && 0.0 <= ymax) { 217 | yy = y1 + h - 1 - (int)rint(((0.0 - ymin) / (ymax - ymin)) * (h-1)); 218 | XDrawLine(display, window, gc, 219 | x1, yy, x1 + w - 1, yy); 220 | } 221 | 222 | XSetForeground(display, gc, RGB(255, 255, 255)); 223 | ly = -1; 224 | for(i=0;i= ymin && y <= ymax) { 227 | yy = y1 + h - 1 - (int)rint(((y - ymin) / (ymax - ymin)) * (h-1)); 228 | if (ly >= 0) { 229 | XDrawLine(display, window, gc, 230 | i - 1, ly, i, yy); 231 | } else { 232 | XDrawPoint(display, window, gc, 233 | i, yy); 234 | } 235 | ly = yy; 236 | } else { 237 | ly = -1; 238 | } 239 | } 240 | 241 | 242 | /* title */ 243 | XSetForeground(display, gc, RGB(0, 255, 0)); 244 | 245 | printf_at((x1+font_xsize-1) / font_xsize, 246 | (y1+font_ysize-1) / font_ysize, 247 | "%s - ymin=%6.3e ymax=%6.3e", title, ymin, ymax); 248 | 249 | } 250 | 251 | /***************************************************/ 252 | /* utilities */ 253 | 254 | 255 | /***************************************************/ 256 | 257 | /* si and sq must be betwen -1.0 and 1.0 */ 258 | 259 | int nb_samples = 0; 260 | 261 | void lm_dump_qam(float si, float sq) 262 | { 263 | int x, y; 264 | 265 | if (disp_state != DISP_MODE_QAM) 266 | return; 267 | 268 | x = (int)(si * (QAM_SIZE/2)) + (QAM_SIZE/2); 269 | y = (int)(sq * (QAM_SIZE/2)) + (QAM_SIZE/2); 270 | if (x < 0 || x >= QAM_SIZE || 271 | y < 0 || y >= QAM_SIZE) 272 | return; 273 | 274 | XSetForeground(display, gc, RGB(255, 255, 255)); 275 | XDrawPoint(display, window, gc, x, y); 276 | 277 | nb_samples++; 278 | printf_at(minx, 1, "# samples: %d", nb_samples); 279 | } 280 | 281 | /* print samples */ 282 | #define NB_SAMPLES 512 283 | 284 | float sample_mem[NB_CHANNELS][NB_SAMPLES]; 285 | int sample_pos[NB_CHANNELS]; 286 | 287 | float sample_hamming[NB_SAMPLES]; 288 | int sample_hamming_init = 0; 289 | complex sample_fft[NB_SAMPLES]; 290 | int sample_channel; 291 | 292 | float calc_sample(float x) 293 | { 294 | return sample_mem[sample_channel][(int)x]; 295 | } 296 | 297 | float calc_sample_pow(float x) 298 | { 299 | complex *p = &sample_fft[(int)x]; 300 | return p->re * p->re + p->im * p->im; 301 | } 302 | 303 | void draw_samples(int channel) 304 | { 305 | int i; 306 | sample_channel = channel; 307 | 308 | draw_graph("Sample", 309 | 0, 0, QAM_SIZE, QAM_SIZE/2, 310 | 0.0, NB_SAMPLES - 1, 0.0, 0.0, 311 | DG_AUTOSCALE_YMAX | DG_AUTOSCALE_YMIN, 312 | calc_sample); 313 | 314 | if (!sample_hamming_init) { 315 | calc_hamming(sample_hamming, NB_SAMPLES); 316 | sample_hamming_init = 1; 317 | } 318 | 319 | for(i=0;i 1) 365 | val = 1; 366 | 367 | y = (int)(val * (QAM_SIZE/2)) + (QAM_SIZE/2); 368 | time += 0.5; 369 | if (time >= 1.0) 370 | time -= 1.0; 371 | x = (int)(time * QAM_SIZE); 372 | 373 | XSetForeground(display, gc, RGB(255, 255, 255)); 374 | if (x > last_eye_x[channel] && 0) { 375 | XDrawLine(display, window, gc, 376 | last_eye_x[channel], last_eye_y[channel], x, y); 377 | } else { 378 | XDrawPoint(display, window, gc, x, y); 379 | } 380 | last_eye_x[channel] = x; 381 | last_eye_y[channel] = y; 382 | } 383 | #endif 384 | 385 | /* print equalizer */ 386 | 387 | #define EQ_FFT_SIZE 144 388 | 389 | static int eq_count = 0; 390 | static s32 (*eq_filter)[2]; 391 | static int eq_norm; 392 | static complex eq_fft[EQ_FFT_SIZE]; 393 | 394 | float calc_eq_re(float x) 395 | { 396 | return (float)eq_filter[(int)rint(x)][0] / (float)eq_norm; 397 | } 398 | 399 | float calc_eq_im(float x) 400 | { 401 | return (float)eq_filter[(int)rint(x)][1] / (float)eq_norm; 402 | } 403 | 404 | float calc_eq_pow(float x) 405 | { 406 | complex *p = &eq_fft[(int)x]; 407 | return p->re * p->re + p->im * p->im; 408 | } 409 | 410 | float calc_eq_phase(float x) 411 | { 412 | complex *p = &eq_fft[(int)x]; 413 | return atan2(p->im, p->re); 414 | } 415 | 416 | void lm_dump_equalizer(s32 eq_filter1[][2], int norm, int size) 417 | { 418 | int i; 419 | 420 | if (disp_state != DISP_MODE_EQUALIZER) 421 | return; 422 | 423 | if (++eq_count == 1) { 424 | eq_count = 0; 425 | eq_filter = eq_filter1; 426 | eq_norm = norm; 427 | 428 | draw_graph("Eqz real", 429 | 0, 0, QAM_SIZE, QAM_SIZE/4, 430 | 0.0, size - 1, -1.5, 1.5, 431 | 0, 432 | calc_eq_re); 433 | 434 | draw_graph("Eqz imag", 435 | 0, QAM_SIZE/4, QAM_SIZE, QAM_SIZE/4, 436 | 0.0, size - 1, -1.5, 1.5, 437 | 0, 438 | calc_eq_im); 439 | 440 | for(i=0;i> (COS_BITS-1)) - s0; 26 | s0 = s1; 27 | s1 = s2; 28 | j += k; 29 | if (j >= n) j -= n; 30 | } 31 | 32 | y_re = s1 - ((cos_tab[k] * s0) >> COS_BITS); 33 | /* cannot use cos_tab because n is even */ 34 | y_im = s1 - ((sin_tab[k] * s0) >> COS_BITS); 35 | #else 36 | y_re = y_im = 0; 37 | for(i=0;i= n) j -= n; 42 | } 43 | y_re = y_re >> COS_BITS; 44 | y_im = y_im >> COS_BITS; 45 | #endif 46 | y_2 = y_re * y_re + y_im * y_im; 47 | return y_2; 48 | } 49 | 50 | /* horrible fft code - only needed to debug or fixed table generation */ 51 | 52 | #define FFT_MAX_SIZE 2048 53 | 54 | static float norm; 55 | static float wfft[FFT_MAX_SIZE]; 56 | static short tinv[FFT_MAX_SIZE]; 57 | static int nf = 0, nf2, nf4; 58 | 59 | int fft_init(int n) 60 | { 61 | float p,k; 62 | int i,j,a,c, nk; 63 | 64 | nf=n; 65 | nf2=nf/2; 66 | nf4=nf/4; 67 | nk=0; 68 | while (n>>=1) nk++; 69 | norm=1/sqrt(nf); 70 | 71 | k=0; 72 | p=(2*M_PI)/nf; 73 | for(i=0;i<=nf4;i++) { 74 | wfft[i]=cos(k); 75 | k+=p; 76 | } 77 | 78 | for(i=0;i>=1; 84 | } 85 | tinv[i]= c<=i ? -1 : c; 86 | } 87 | 88 | return 0; 89 | } 90 | 91 | /* r = TRUE : reverse FFT */ 92 | void fft_calc(complex *x,int n, int r) 93 | { 94 | int i,j,k,l; 95 | complex a,b,c; 96 | complex *p,*q; 97 | 98 | /* auto init of coefficients */ 99 | if (n != nf) { 100 | fft_init(n); 101 | } 102 | 103 | k=nf2; 104 | l=1; 105 | do { 106 | p=x; 107 | q=x+k; 108 | i=l; 109 | do { 110 | j=0; 111 | do { 112 | a=*p; 113 | b=*q; 114 | p->re=a.re+b.re; 115 | p->im=a.im+b.im; 116 | b.re=a.re-b.re; 117 | b.im=a.im-b.im; 118 | if (j==0) { 119 | *q=b; 120 | } else if (j==nf4) { 121 | if (r) { 122 | q->re=b.im; 123 | q->im=-b.re; 124 | } else { 125 | q->re=-b.im; 126 | q->im=b.re; 127 | } 128 | q->re=-b.im; 129 | q->im=b.re; 130 | } else if (jre=b.re*c.re-b.im*c.im; 135 | q->im=b.im*c.re+b.re*c.im; 136 | } else { 137 | c.re=-wfft[nf2-j]; 138 | c.im=wfft[j-nf4]; 139 | if (r) c.im=-c.im; 140 | q->re=b.re*c.re-b.im*c.im; 141 | q->im=b.im*c.re+b.re*c.im; 142 | } 143 | p++; 144 | q++; 145 | j+=l; 146 | } while (j>=1; 151 | l<<=1; 152 | } while (k); 153 | 154 | for(i=0,p=x;ire*=norm; 156 | p->im*=norm; 157 | } 158 | 159 | for(i=0,p=x;i> (PHASE_BITS - COS_TABLE_BITS)) & (COS_TABLE_SIZE-1)]; 32 | } 33 | 34 | static inline int dsp_dot_prod(const s16 *tab1, const s16 *tab2, 35 | int n, int sum) 36 | { 37 | int i; 38 | 39 | for(i=0;i>= shift; 60 | } 61 | } 62 | 63 | static inline int dsp_max_bits(s16 *tab, int n) 64 | { 65 | int i, max, v, b; 66 | max = 0; 67 | for(i=0;i max) 70 | max = v; 71 | } 72 | b = 0; 73 | while (max != 0) { 74 | b++; 75 | max>>=1; 76 | } 77 | return b; 78 | } 79 | 80 | static inline int dsp_sqr(int n) 81 | { 82 | return n*n; 83 | } 84 | 85 | int compute_DFT(s16 *cos_tab, s16 *sin_tab, s16 *x, int k,int n); 86 | 87 | typedef struct { 88 | float re,im; 89 | } complex; 90 | 91 | /* medium speed FFT */ 92 | void fft_calc(complex *x,int n, int r); 93 | 94 | /* slow FFT for any size */ 95 | void slow_fft(complex *output, complex *input, int n, int r); 96 | 97 | /* compute the hamming window */ 98 | void calc_hamming(float *ham, int NF); 99 | -------------------------------------------------------------------------------- /dtmf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * DTMF demodulator, inspirated from the multimon project of Thomas 3 | * Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu). It is different 4 | * in the sense that it uses a true block based DFT estimator. 5 | * 6 | * Copyright (c) 1999 Fabrice Bellard. 7 | * 8 | * This code is released under the GNU General Public License version 9 | * 2. Please read the file COPYING to know the exact terms of the 10 | * license. 11 | */ 12 | 13 | #include "lm.h" 14 | 15 | /* 16 | * DTMF frequencies 17 | * 18 | * 1209 1336 1477 1633 19 | * 697 1 2 3 A 20 | * 770 4 5 6 B 21 | * 852 7 8 9 C 22 | * 941 * 0 # D 23 | * */ 24 | 25 | static const char *dtmf_transl = "123A456B789C*0#D"; 26 | 27 | static int dtmf_freq[] = { 28 | 1209, 1336, 1477, 1633, 29 | 697, 770, 852, 941, 30 | }; 31 | 32 | #define SAMPLE_RATE 8000 33 | 34 | /* Each DTMF digit is estimed on N samples by estimating the DFT of 35 | the signal. It is quite reliable, but the frequency resolution is 36 | not accurate enough to meet the very strict ITU requirements. */ 37 | 38 | /* DTMF modulation */ 39 | 40 | void DTMF_mod_init(DTMF_mod_state *s) 41 | { 42 | s->t1 = s->t2 = 0; 43 | s->omega1 = 0; 44 | s->samples_left = 0; 45 | } 46 | 47 | /* compute parameters for a new digit */ 48 | static void compute_params(DTMF_mod_state *s) 49 | { 50 | const char *p; 51 | int v,digit,f1,f2; 52 | 53 | /* if we were playing a digit, we make a pause */ 54 | if (s->omega1 != 0) 55 | goto nodigit; 56 | 57 | digit = s->get_digit(s->opaque); 58 | if (digit == -1) 59 | goto nodigit; 60 | p = dtmf_transl; 61 | while (*p != digit && *p) p++; 62 | if (*p) { 63 | v = p - dtmf_transl; 64 | f1 = dtmf_freq[v & 3]; 65 | f2 = dtmf_freq[4 + (v >> 2)]; 66 | s->omega1 = (PHASE_BASE * f1) / SAMPLE_RATE; 67 | s->omega2 = (PHASE_BASE * f2) / SAMPLE_RATE; 68 | /* amplitude */ 69 | s->amp = (int) (pow(10, s->dtmf_level / 20.0) * 32768.0); 70 | /* number of samples to play */ 71 | s->samples_left = (s->digit_length_ms * SAMPLE_RATE) / 1000; 72 | } else { 73 | nodigit: 74 | s->omega1 = 0; 75 | s->samples_left = (s->digit_pause_ms * SAMPLE_RATE) / 1000; 76 | } 77 | } 78 | 79 | void DTMF_mod(DTMF_mod_state *s, s16 *samples, unsigned int nb) 80 | { 81 | int len, t1, t2, amp, i; 82 | 83 | while (nb > 0) { 84 | if (s->samples_left == 0) { 85 | compute_params(s); 86 | } 87 | 88 | len = nb; 89 | if (len > s->samples_left) 90 | len = s->samples_left; 91 | 92 | if (s->omega1 != 0) { 93 | t1 = s->t1; 94 | t2 = s->t2; 95 | amp = s->amp; 96 | for(i=0;i> COS_BITS; 99 | samples[i] = v; 100 | t1 += s->omega1; 101 | t2 += s->omega2; 102 | } 103 | s->t1 = t1; 104 | s->t2 = t2; 105 | } else { 106 | memset(samples, 0, nb * 2); /* silence between digits */ 107 | } 108 | 109 | nb -= len; 110 | samples += len; 111 | s->samples_left -= len; 112 | } 113 | } 114 | 115 | /* DTMF demodulation */ 116 | 117 | void DTMF_demod_init(DTMF_demod_state *s) 118 | { 119 | int i; 120 | for(i=0;icos_tab[i] = (int) (cos( 2 * M_PI * i / DTMF_N) * COS_BASE); 122 | s->sin_tab[i] = (int) (sin( 2 * M_PI * i / DTMF_N) * COS_BASE); 123 | } 124 | for(i=0;i<8;i++) { 125 | float v; 126 | v = (float)dtmf_freq[i] / (float)SAMPLE_RATE * (float)DTMF_N; 127 | s->dtmf_coefs[i] = (int)rint(v); 128 | } 129 | 130 | s->buf_ptr = 0; 131 | s->last_digit = 0; 132 | } 133 | 134 | int find_max(int *val,int n) 135 | { 136 | int i,j,max; 137 | 138 | j = 0; 139 | max = val[0]; 140 | for(i=1;i max) { 142 | j = i; 143 | max = val[i]; 144 | } 145 | } 146 | return j; 147 | } 148 | 149 | void DTMF_demod(DTMF_demod_state *s, 150 | const s16 *samples, unsigned int nb) 151 | { 152 | int i, j, power[8], power0, v1, v2, digit, bits, p1, p2, p0; 153 | 154 | for(j=0;jbuf[s->buf_ptr++] = samples[j]; 156 | 157 | if (s->buf_ptr >= DTMF_N) { 158 | /* decision based on one block */ 159 | bits = dsp_max_bits(s->buf, DTMF_N); 160 | if (bits < 8) bits = 8; 161 | dsp_sar_tab(s->buf, DTMF_N, bits - 8); 162 | 163 | power0 = dsp_norm2(s->buf, DTMF_N, 0); 164 | 165 | for(i=0;i<8;i++) { 166 | power[i] = compute_DFT(s->cos_tab, s->sin_tab, s->buf, 167 | s->dtmf_coefs[i], DTMF_N); 168 | } 169 | 170 | v1 = find_max(power, 4); 171 | v2 = find_max(power + 4, 4); 172 | p0 = (int)(power0 * 0.3); 173 | p1 = (2 * power[v1]) / DTMF_N; 174 | p2 = (2 * power[v2 + 4]) / DTMF_N; 175 | #if 0 176 | printf("%d %d %d %f %f\n",p0, v1, v2, (float) p1 / p0,(float) p2 / p0); 177 | #endif 178 | if (p1 > p0 && p2 > p0) 179 | digit = dtmf_transl[v1 | (v2 << 2)]; 180 | else 181 | digit = 0; 182 | 183 | if (digit != s->last_digit) { 184 | if (digit != 0) { 185 | s->put_digit(s->opaque, digit); 186 | } 187 | s->last_digit = digit; 188 | } 189 | s->buf_ptr = 0; 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /dtmf.h: -------------------------------------------------------------------------------- 1 | 2 | /* modulation */ 3 | typedef struct { 4 | /* parameters */ 5 | int dtmf_level; /* in dB */ 6 | int digit_length_ms; 7 | int digit_pause_ms; 8 | void *opaque; 9 | int (*get_digit)(void *opaque); 10 | 11 | /* internal state */ 12 | int omega1,omega2,t1,t2; 13 | int samples_left; 14 | int amp; 15 | } DTMF_mod_state; 16 | 17 | void DTMF_mod_init(DTMF_mod_state *s); 18 | void DTMF_mod(DTMF_mod_state *s, s16 *samples, unsigned int nb); 19 | 20 | /* demodulation */ 21 | #define DTMF_N 205 22 | 23 | typedef struct { 24 | /* parameters */ 25 | void *opaque; 26 | void (*put_digit)(void *opaque, int digit); 27 | 28 | /* internal state */ 29 | s16 buf[DTMF_N]; 30 | int buf_ptr; 31 | s16 cos_tab[DTMF_N]; 32 | s16 sin_tab[DTMF_N]; 33 | int last_digit; 34 | int dtmf_coefs[8]; /* coefficient number of the DFT */ 35 | } DTMF_demod_state; 36 | 37 | void DTMF_demod_init(DTMF_demod_state *s); 38 | void DTMF_demod(DTMF_demod_state *s, 39 | const s16 *samples, unsigned int nb); 40 | -------------------------------------------------------------------------------- /fsk.c: -------------------------------------------------------------------------------- 1 | /* 2 | * generic FSK modulator & demodulator 3 | * 4 | * Copyright (c) 1999,2000 Fabrice Bellard. 5 | * 6 | * This code is released under the GNU General Public License version 7 | * 2. Please read the file COPYING to know the exact terms of the 8 | * license. 9 | */ 10 | #include "lm.h" 11 | 12 | void FSK_mod_init(FSK_mod_state *s) 13 | { 14 | int b; 15 | 16 | s->omega[0] = (PHASE_BASE * s->f_lo) / s->sample_rate; 17 | s->omega[1] = (PHASE_BASE * s->f_hi) / s->sample_rate; 18 | s->baud_incr = (s->baud_rate * 0x10000) / s->sample_rate; 19 | s->phase = 0; 20 | s->baud_frac = 0; 21 | b = 0; 22 | s->current_bit = b; 23 | } 24 | 25 | void FSK_mod(FSK_mod_state *s, s16 *samples, unsigned int nb) 26 | { 27 | int phase,baud_frac,b,i; 28 | 29 | phase = s->phase; 30 | baud_frac = s->baud_frac; 31 | b = s->current_bit; 32 | 33 | for(i=0;ibaud_incr; 35 | if (baud_frac >= 0x10000) { 36 | baud_frac -= 0x10000; 37 | b = s->get_bit(s->opaque); 38 | } 39 | samples[i] = dsp_cos(phase); 40 | phase += s->omega[b]; 41 | } 42 | s->phase = phase; 43 | s->baud_frac = baud_frac; 44 | s->current_bit = b; 45 | } 46 | 47 | void FSK_demod_init(FSK_demod_state *s) 48 | { 49 | float phase; 50 | int i, a; 51 | 52 | s->baud_incr = (s->baud_rate * 0x10000) / s->sample_rate; 53 | s->baud_pll = 0; 54 | s->baud_pll_adj = s->baud_incr / 4; 55 | 56 | s->filter_size = s->sample_rate / s->baud_rate; 57 | 58 | memset(s->filter_buf, 0, sizeof(s->filter_buf)); 59 | s->buf_ptr = s->filter_size; 60 | s->lastsample = 0; 61 | 62 | /* compute the filters */ 63 | for(i=0;ifilter_size;i++) { 64 | phase = 2 * M_PI * s->f_lo * i / (float)s->sample_rate; 65 | s->filter_lo_i[i] = (int) (cos(phase) * COS_BASE); 66 | s->filter_lo_q[i] = (int) (sin(phase) * COS_BASE); 67 | 68 | phase = 2 * M_PI * s->f_hi * i / (float)s->sample_rate; 69 | s->filter_hi_i[i] = (int) (cos(phase) * COS_BASE); 70 | s->filter_hi_q[i] = (int) (sin(phase) * COS_BASE); 71 | } 72 | 73 | s->shift = -2; 74 | a = s->filter_size; 75 | while (a != 0) { 76 | s->shift++; 77 | a /= 2; 78 | } 79 | printf("shift=%d\n", s->shift); 80 | } 81 | 82 | void FSK_demod(FSK_demod_state *s, const s16 *samples, unsigned int nb) 83 | { 84 | int buf_ptr, corr, newsample, baud_pll, i; 85 | int sum; 86 | 87 | baud_pll = s->baud_pll; 88 | buf_ptr = s->buf_ptr; 89 | 90 | for(i=0;ifilter_buf[buf_ptr++] = samples[i] >> s->shift; 93 | if (buf_ptr == FSK_FILTER_BUF_SIZE) { 94 | memmove(s->filter_buf, 95 | s->filter_buf + FSK_FILTER_BUF_SIZE - s->filter_size, 96 | s->filter_size * sizeof(s16)); 97 | buf_ptr = s->filter_size; 98 | } 99 | 100 | /* non coherent FSK demodulation - not optimal, but it seems 101 | very difficult to do another way */ 102 | corr = dsp_dot_prod(s->filter_buf + buf_ptr - s->filter_size, 103 | s->filter_hi_i, s->filter_size, 0); 104 | corr = corr >> COS_BITS; 105 | sum = corr * corr; 106 | 107 | corr = dsp_dot_prod(s->filter_buf + buf_ptr - s->filter_size, 108 | s->filter_hi_q, s->filter_size, 0); 109 | corr = corr >> COS_BITS; 110 | sum += corr * corr; 111 | 112 | corr = dsp_dot_prod(s->filter_buf + buf_ptr - s->filter_size, 113 | s->filter_lo_i, s->filter_size, 0); 114 | corr = corr >> COS_BITS; 115 | sum -= corr * corr; 116 | 117 | corr = dsp_dot_prod(s->filter_buf + buf_ptr - s->filter_size, 118 | s->filter_lo_q, s->filter_size, 0); 119 | corr = corr >> COS_BITS; 120 | sum -= corr * corr; 121 | 122 | lm_dump_sample(CHANNEL_SAMPLESYNC, sum / 32768.0); 123 | // printf("sum=%0.3f\n", sum / 65536.0); 124 | newsample = sum > 0; 125 | 126 | /* baud PLL synchronisation : when we see a transition of 127 | frequency, we tend to modify the baud phase so that it is 128 | in the middle of two bits */ 129 | if (s->lastsample != newsample) { 130 | s->lastsample = newsample; 131 | // printf("pll=%0.3f (%d)\n", baud_pll / 65536.0, newsample); 132 | if (baud_pll < 0x8000) 133 | baud_pll += s->baud_pll_adj; 134 | else 135 | baud_pll -= s->baud_pll_adj; 136 | } 137 | 138 | baud_pll += s->baud_incr; 139 | 140 | if (baud_pll >= 0x10000) { 141 | baud_pll -= 0x10000; 142 | // printf("baud=%f (%d)\n", baud_pll / 65536.0, s->lastsample); 143 | s->put_bit(s->opaque, s->lastsample); 144 | } 145 | } 146 | 147 | s->baud_pll = baud_pll; 148 | s->buf_ptr = buf_ptr; 149 | } 150 | 151 | /* test for FSK using V21 or V23 */ 152 | 153 | #define NB_SAMPLES 40 154 | 155 | #define MAXDELAY 32 156 | 157 | static int tx_bits[MAXDELAY], tx_ptr = 0, rx_ptr = 0; 158 | static int tx_blank = 32; 159 | 160 | /* transmit random bits with a sync header (31 ones, 1 zero) */ 161 | static int test_get_bit(void *opaque) 162 | { 163 | int bit; 164 | 165 | if (tx_blank != 0) { 166 | /* send 1 at the beginning for synchronization */ 167 | bit = (tx_blank > 1); 168 | tx_blank--; 169 | } else { 170 | bit = random() % 2; 171 | tx_bits[tx_ptr] = bit; 172 | if (++tx_ptr == MAXDELAY) 173 | tx_ptr = 0; 174 | } 175 | return bit; 176 | } 177 | 178 | static int nb_bits = 0, errors = 0, sync_count = 0, got_sync = 0; 179 | 180 | static void test_put_bit(void *opaque, int bit) 181 | { 182 | int tbit; 183 | 184 | if (!got_sync) { 185 | 186 | if (bit) { 187 | sync_count++; 188 | } else { 189 | if (sync_count > 16) 190 | got_sync = 1; 191 | sync_count = 0; 192 | } 193 | } else { 194 | tbit = tx_bits[rx_ptr]; 195 | if (++rx_ptr == MAXDELAY) 196 | rx_ptr = 0; 197 | if (bit != tbit) { 198 | errors++; 199 | } 200 | nb_bits++; 201 | } 202 | } 203 | 204 | void FSK_test(int do_v23) 205 | { 206 | FSK_mod_state tx; 207 | FSK_demod_state rx; 208 | int err, calling; 209 | struct LineModelState *line_state; 210 | s16 buf[NB_SAMPLES]; 211 | s16 buf1[NB_SAMPLES]; 212 | s16 buf2[NB_SAMPLES]; 213 | s16 buf3[NB_SAMPLES]; 214 | FILE *f1; 215 | 216 | err = lm_display_init(); 217 | if (err < 0) { 218 | fprintf(stderr, "Could not init X display\n"); 219 | exit(1); 220 | } 221 | 222 | line_state = line_model_init(); 223 | 224 | f1 = fopen("cal.sw", "wb"); 225 | if (f1 == NULL) { 226 | perror("cal.sw"); 227 | exit(1); 228 | } 229 | 230 | calling = 0; 231 | if (do_v23) { 232 | V23_mod_init(&tx, calling, test_get_bit, NULL); 233 | V23_demod_init(&rx, 1 - calling, test_put_bit, NULL); 234 | } else { 235 | V21_mod_init(&tx, calling, test_get_bit, NULL); 236 | V21_demod_init(&rx, 1 - calling, test_put_bit, NULL); 237 | } 238 | 239 | nb_bits = 0; 240 | errors = 0; 241 | for(;;) { 242 | if (lm_display_poll_event()) 243 | break; 244 | 245 | FSK_mod(&tx, buf, NB_SAMPLES); 246 | memset(buf3, 0, sizeof(buf3)); 247 | 248 | line_model(line_state, buf1, buf, buf2, buf3, NB_SAMPLES); 249 | 250 | fwrite(buf, 1, NB_SAMPLES * 2, f1); 251 | 252 | FSK_demod(&rx, buf1, NB_SAMPLES); 253 | } 254 | 255 | fclose(f1); 256 | 257 | printf("errors=%d nb_bits=%d Pe=%f\n", 258 | errors, nb_bits, (float) errors / (float)nb_bits); 259 | } 260 | -------------------------------------------------------------------------------- /fsk.h: -------------------------------------------------------------------------------- 1 | #ifndef FSK_H 2 | #define FSK_H 3 | 4 | typedef struct { 5 | /* parameters */ 6 | int f_lo,f_hi; 7 | int sample_rate; 8 | int baud_rate; 9 | 10 | /* local variables */ 11 | int phase, baud_frac, baud_incr; 12 | int omega[2]; 13 | int current_bit; 14 | void *opaque; 15 | get_bit_func get_bit; 16 | } FSK_mod_state; 17 | 18 | /* max = 106 for 75 bauds */ 19 | #define FSK_FILTER_SIZE 128 20 | #define FSK_FILTER_BUF_SIZE 256 21 | 22 | typedef struct { 23 | /* parameters */ 24 | int f_lo,f_hi; 25 | int sample_rate; 26 | int baud_rate; 27 | 28 | /* local variables */ 29 | int filter_size; 30 | s16 filter_lo_i[FSK_FILTER_SIZE]; 31 | s16 filter_lo_q[FSK_FILTER_SIZE]; 32 | 33 | s16 filter_hi_i[FSK_FILTER_SIZE]; 34 | s16 filter_hi_q[FSK_FILTER_SIZE]; 35 | 36 | s16 filter_buf[FSK_FILTER_BUF_SIZE]; 37 | int buf_ptr; 38 | 39 | int baud_incr; 40 | int baud_pll, baud_pll_adj, baud_pll_threshold; 41 | int lastsample; 42 | int shift; 43 | 44 | void *opaque; 45 | put_bit_func put_bit; 46 | } FSK_demod_state; 47 | 48 | void FSK_mod_init(FSK_mod_state *s); 49 | void FSK_mod(FSK_mod_state *s, s16 *samples, unsigned int nb); 50 | void FSK_demod_init(FSK_demod_state *s); 51 | void FSK_demod(FSK_demod_state *s, const s16 *samples, unsigned int nb); 52 | 53 | void FSK_test(int do_v23); 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /lm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The Generic Linux Soft Modem 3 | * 4 | * Copyright (c) 1999,2000 Fabrice Bellard. 5 | * Copyright (c) 1999 Pavel Machek 6 | * 7 | * This code is released under the GNU General Public License version 8 | * 2. Please read the file COPYING to know the exact terms of the 9 | * license. 10 | * 11 | * This implementation is totally clean room. It was written by 12 | * reading the ITU specification and by using basic signal processing 13 | * knowledge. 14 | */ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "lm.h" 23 | #include "v34.h" 24 | #include "v90.h" 25 | 26 | #define DEBUG 27 | 28 | int lm_debug = 0; 29 | int debug_state = 0; 30 | 31 | /* default parameters */ 32 | static LinModemConfig default_lm_config = 33 | { 34 | pulse_dial: 0, 35 | dtmf_level: -9, 36 | dtmf_digit_length: 150, 37 | dtmf_pause_length: 100, 38 | available_modulations: V8_MOD_V21 | V8_MOD_V23, 39 | }; 40 | 41 | /* fifo handling */ 42 | 43 | void sm_init_fifo(struct sm_fifo *f, u8 *buf, int size) 44 | { 45 | f->sptr = buf; 46 | f->eptr = buf + size; 47 | f->wptr = f->rptr = f->sptr; 48 | f->size = 0; 49 | f->max_size = size; 50 | } 51 | 52 | void sm_flush(struct sm_fifo *f) 53 | { 54 | f->wptr = f->rptr = f->sptr; 55 | f->size = 0; 56 | } 57 | 58 | int sm_size(struct sm_fifo *f) 59 | { 60 | return f->size; 61 | } 62 | 63 | void sm_put_bit(struct sm_fifo *f, int v) 64 | { 65 | if (f->size < f->max_size) { 66 | *f->wptr++ = v; 67 | if (f->wptr == f->eptr) f->wptr = f->sptr; 68 | f->size++; 69 | } 70 | } 71 | 72 | /* put bits, from MSB to LSB */ 73 | void sm_put_bits(struct sm_fifo *f, int v, int n) 74 | { 75 | int i; 76 | for(i=n-1;i>=0;i--) { 77 | sm_put_bit(f, (v >> i) & 1); 78 | } 79 | } 80 | 81 | int sm_peek_bit(struct sm_fifo *f) 82 | { 83 | if (f->size > 0) 84 | return *f->rptr; 85 | else 86 | return -1; 87 | } 88 | 89 | int sm_get_bit(struct sm_fifo *f) 90 | { 91 | int v; 92 | 93 | if (f->size > 0) { 94 | f->size--; 95 | v = *f->rptr++; 96 | if (f->rptr == f->eptr) f->rptr = f->sptr; 97 | return v; 98 | } else { 99 | /* fifo empty */ 100 | return -1; 101 | } 102 | } 103 | 104 | /* return -1 if not enough bits */ 105 | int sm_get_bits(struct sm_fifo *f, int n) 106 | { 107 | int v,i; 108 | 109 | if (f->size < n) 110 | return -1; 111 | 112 | v = 0; 113 | for(i=n-1;i>=0;i--) { 114 | v |= (sm_get_bit(f) << i); 115 | } 116 | return v; 117 | } 118 | 119 | /* timer handling */ 120 | 121 | /* note: the current time handling is horrible because we use a global 122 | state which is initialized when entering in sm_process() */ 123 | static unsigned int sim_time; 124 | 125 | 126 | /* current time, in samples */ 127 | int sm_time(void) 128 | { 129 | return sim_time; 130 | } 131 | 132 | /* delay is in ms */ 133 | void sm_set_timer(struct sm_timer *t, int delay) 134 | { 135 | t->timeout = sm_time() + (delay * 8000) / 1000; 136 | } 137 | 138 | /* return 1 if timer expired */ 139 | int sm_check_timer(struct sm_timer *t) 140 | { 141 | long timeout; 142 | 143 | timeout = sm_time(); 144 | return (timeout >= t->timeout); 145 | } 146 | 147 | /* 148 | Main modem state machine. It handles the dialing & rings, and then 149 | call the corresponding protocol handlers. 150 | */ 151 | 152 | char *sm_states_str[] = { 153 | #define TAG(s) #s , 154 | #include "lmstates.h" 155 | }; 156 | 157 | static int dtmf_get_digit(void *opaque) 158 | { 159 | struct sm_state *sm = opaque; 160 | if (sm->dtmf_ptr < sm->dtmf_len) { 161 | return sm->call_num[sm->dtmf_ptr++]; 162 | } else { 163 | return -1; 164 | } 165 | } 166 | 167 | static void dtmf_put_digit(void *opaque, int digit) 168 | { 169 | printf("DTMF: got digit '%c'\n", digit); 170 | } 171 | 172 | void sm_process(struct sm_state *sm, s16 *output, s16 *input, int nb_samples) 173 | { 174 | /* XXX: time hack */ 175 | sim_time = sm->time; 176 | 177 | /* modulation */ 178 | switch(sm->state) { 179 | case SM_DTMF_DIAL_WAIT: 180 | case SM_DTMF_DIAL_WAIT1: 181 | DTMF_mod(&sm->dtmf_tx, output, nb_samples); 182 | break; 183 | default: 184 | memset(output, 0, nb_samples * sizeof(s16)); 185 | break; 186 | } 187 | 188 | /* demodulation */ 189 | switch(sm->state) { 190 | case SM_TEST_RING2: 191 | DTMF_demod(&sm->dtmf_rx, input, nb_samples); 192 | break; 193 | } 194 | 195 | /* write state transition */ 196 | if (lm_debug) { 197 | if (sm->state != sm->debug_laststate) { 198 | sm->debug_laststate = sm->state; 199 | printf("%s: state: %s\n", sm->name, sm_states_str[sm->state]); 200 | } 201 | } 202 | 203 | switch(sm->state) { 204 | 205 | /* nothing to do (except waiting for a connection) */ 206 | case SM_IDLE: 207 | break; 208 | 209 | case SM_GO_ONHOOK: 210 | { 211 | sm->hw->set_offhook(sm->hw_state, 0); 212 | sm->state = SM_IDLE; 213 | } 214 | break; 215 | 216 | /* calling modem */ 217 | case SM_CALL: 218 | { 219 | sm->calling = 1; 220 | sm->hangup_request = 0; 221 | sm->state = SM_DTMF_DIAL; 222 | sm->hw->set_offhook(sm->hw_state, 1); 223 | sm_set_timer(&sm->dtmf_timer, 2000); 224 | } 225 | break; 226 | 227 | case SM_DTMF_DIAL: 228 | if (sm->hangup_request) { 229 | sm->state = SM_GO_ONHOOK; 230 | } else if (sm_check_timer(&sm->dtmf_timer)) { 231 | DTMF_mod_state *p = &sm->dtmf_tx; 232 | 233 | sm->dtmf_ptr = 0; 234 | sm->dtmf_len = strlen(sm->call_num); 235 | 236 | p->get_digit = dtmf_get_digit; 237 | p->opaque = sm; 238 | p->dtmf_level = sm->lm_config->dtmf_level; 239 | p->digit_length_ms = sm->lm_config->dtmf_digit_length; 240 | p->digit_pause_ms = sm->lm_config->dtmf_pause_length; 241 | DTMF_mod_init(p); 242 | 243 | sm->state = SM_DTMF_DIAL_WAIT; 244 | } 245 | break; 246 | 247 | case SM_DTMF_DIAL_WAIT: 248 | { 249 | if (sm->dtmf_ptr >= sm->dtmf_len) { 250 | /* wait some time after dialing */ 251 | sm_set_timer(&sm->dtmf_timer, 1000); 252 | sm->state = SM_DTMF_DIAL_WAIT1; 253 | } 254 | } 255 | break; 256 | 257 | case SM_DTMF_DIAL_WAIT1: 258 | { 259 | if (sm_check_timer(&sm->dtmf_timer)) { 260 | /* start of V8 */ 261 | V8_init(&sm->u.v8_state, 1, sm->lm_config->available_modulations); 262 | sm->state = SM_V8; 263 | } 264 | } 265 | break; 266 | 267 | /* answer modem */ 268 | 269 | /* wait 2 sec until ring detected (for simulation only) */ 270 | /* we try to recognize the DTMF value for fun :-) */ 271 | case SM_TEST_RING: 272 | { 273 | sm->calling = 0; 274 | sm->dtmf_rx.opaque = sm; 275 | sm->dtmf_rx.put_digit = dtmf_put_digit; 276 | DTMF_demod_init(&sm->dtmf_rx); 277 | 278 | sm_set_timer(&sm->ring_timer, 5000); 279 | sm->state = SM_TEST_RING2; 280 | } 281 | break; 282 | 283 | case SM_TEST_RING2: 284 | { 285 | if (sm_check_timer(&sm->ring_timer)) { 286 | sm->state = SM_RECEIVE; 287 | } 288 | } 289 | break; 290 | 291 | /* entry point to receive a connection */ 292 | 293 | case SM_RECEIVE: 294 | { 295 | sm->calling = 0; 296 | sm->hangup_request = 0; 297 | sm->hw->set_offhook(sm->hw_state, 1); 298 | V8_init(&sm->u.v8_state, 0, sm->lm_config->available_modulations); 299 | sm->state = SM_V8; 300 | } 301 | break; 302 | 303 | /* V8 handling (both calling & receive) */ 304 | case SM_V8: 305 | { 306 | int ret; 307 | if (sm->hangup_request) { 308 | printf("ddezde\n"); 309 | sm->state = SM_GO_ONHOOK; 310 | } else { 311 | ret = V8_process(&sm->u.v8_state, output, input, nb_samples); 312 | switch(ret) { 313 | case V8_MOD_HANGUP: 314 | sm->state = SM_GO_ONHOOK; 315 | break; 316 | case V8_MOD_V21: 317 | V21_init(&sm->u.v21_state, sm->calling, 318 | serial_get_bit, serial_put_bit, sm); 319 | sm->state = SM_V21; 320 | break; 321 | case V8_MOD_V23: 322 | V23_init(&sm->u.v23_state, sm->calling, 323 | serial_get_bit, serial_put_bit, sm); 324 | sm->state = SM_V23; 325 | break; 326 | } 327 | } 328 | } 329 | break; 330 | 331 | /* V21 handling (both calling & receive) */ 332 | case SM_V21: 333 | { 334 | int ret; 335 | ret = V21_process(&sm->u.v21_state, output, input, nb_samples); 336 | if (ret || sm->hangup_request) 337 | sm->state = SM_GO_ONHOOK; 338 | } 339 | break; 340 | 341 | /* V23 handling (both calling & receive) */ 342 | case SM_V23: 343 | { 344 | int ret; 345 | ret = V23_process(&sm->u.v23_state, output, input, nb_samples); 346 | if (ret || sm->hangup_request) 347 | sm->state = SM_GO_ONHOOK; 348 | } 349 | break; 350 | } 351 | 352 | /* XXX: time hack */ 353 | sm->time = sim_time + nb_samples; 354 | } 355 | 356 | /* 357 | * Send a dial request. 358 | */ 359 | int lm_start_dial(struct sm_state *s, int pulse, const char *number) 360 | { 361 | if (s->state != SM_IDLE) 362 | return -1; 363 | s->pulse_dial = pulse; 364 | strcpy(s->call_num, number); 365 | s->state = SM_CALL; 366 | return 0; 367 | } 368 | 369 | /* 370 | * Send a receive request (for example to respond to a ring) 371 | */ 372 | int lm_start_receive(struct sm_state *s) 373 | { 374 | if (s->state != SM_IDLE) 375 | return -1; 376 | s->state = SM_RECEIVE; 377 | return 0; 378 | } 379 | 380 | /* 381 | * disconnect the modem 382 | */ 383 | int lm_hangup(struct sm_state *s) 384 | { 385 | if (s->state == SM_IDLE) 386 | return -1; 387 | s->hangup_request = 1; 388 | return 0; 389 | } 390 | 391 | /* 392 | * return a simplified state of the modem. 393 | */ 394 | enum lm_get_state_val lm_get_state(struct sm_state *s) 395 | { 396 | switch(s->state) { 397 | case SM_IDLE: 398 | return LM_STATE_IDLE; 399 | case SM_V21: 400 | case SM_V23: 401 | return LM_STATE_CONNECTED; 402 | default: 403 | return LM_STATE_CONNECTING; 404 | } 405 | } 406 | 407 | 408 | void lm_init(struct sm_state *sm, struct sm_hw_info *hw, const char *name) 409 | { 410 | memset(sm, 0, sizeof(*sm)); 411 | sm->hw = hw; 412 | 413 | /* pretty name */ 414 | strcpy(sm->name, name); 415 | 416 | /* init fifos */ 417 | sm_init_fifo(&sm->tx_fifo, sm->tx_fifo_buf, SM_FIFO_SIZE); 418 | sm_init_fifo(&sm->rx_fifo, sm->rx_fifo_buf, SM_FIFO_SIZE); 419 | 420 | /* we open the hardware driver */ 421 | sm->hw_state = malloc(sizeof(struct lm_interface_state)); 422 | sm->hw_state->sm = sm; 423 | sm->hw->open(sm->hw_state); 424 | 425 | sm->debug_laststate = -1; 426 | sm->state = SM_IDLE; 427 | 428 | /* config */ 429 | sm->lm_config = &default_lm_config; 430 | } 431 | 432 | 433 | void sigusr1_debug(int dummy) 434 | { 435 | printf( "<<>>\n" ); 436 | debug_state = 1; 437 | } 438 | 439 | void help(void) 440 | { 441 | printf("Linux Generic Software Modem\n" 442 | "Copyright (c) 1999, 2000 Fabrice Bellard\n" 443 | "\n" 444 | "usage: lm [options]" 445 | "Test options:\n" 446 | "-v : verbose mode (additive)\n" 447 | "-s : modem test with the line simulator\n" 448 | "-m mod: test the modulation 'mod'. 'mod' can be:\n" 449 | " v21, v23, v22, v34, v90\n" 450 | "\n" 451 | "Sound card support\n" 452 | "-t : use sound card as modem\n" 453 | "\n" 454 | "LTmodem support:\n" 455 | "-a : test answer mode with ltmodem\n" 456 | "-c command: use 'command' as modem driver\n" 457 | "-d number: dial 'number'\n" 458 | ); 459 | } 460 | 461 | enum { 462 | MODE_NONE, 463 | MODE_LINESIM, 464 | MODE_V21TEST, 465 | MODE_V22TEST, 466 | MODE_V23TEST, 467 | MODE_V34TEST, 468 | MODE_V90TEST, 469 | MODE_LTMODEM_CALL, 470 | MODE_LTMODEM_ANSWER, 471 | MODE_SOUNDCARD, 472 | }; 473 | 474 | 475 | extern char *modem_command, *dial_number; 476 | 477 | int main(int argc, char **argv) 478 | { 479 | int c, mode, calling; 480 | 481 | signal(SIGUSR1, sigusr1_debug); 482 | 483 | mode = MODE_NONE; 484 | calling = 0; 485 | 486 | for(;;) { 487 | c = getopt(argc, argv, "hvstrac:d:m:"); 488 | if (c == -1) break; 489 | switch(c) { 490 | case 'v': 491 | lm_debug++; 492 | break; 493 | case 'm': 494 | if (!strcasecmp(optarg, "v21")) 495 | mode = MODE_V21TEST; 496 | else if (!strcasecmp(optarg, "v22")) 497 | mode = MODE_V22TEST; 498 | else if (!strcasecmp(optarg, "v23")) 499 | mode = MODE_V23TEST; 500 | else if (!strcasecmp(optarg, "v34")) 501 | mode = MODE_V34TEST; 502 | else if (!strcasecmp(optarg, "v90")) 503 | mode = MODE_V90TEST; 504 | else { 505 | fprintf(stderr, "incorrect modulation: '%s'\n", optarg); 506 | exit(1); 507 | } 508 | break; 509 | case 's': 510 | mode = MODE_LINESIM; 511 | break; 512 | case 't': 513 | mode = MODE_SOUNDCARD; 514 | break; 515 | 516 | /* LTmodem options */ 517 | case 'c': 518 | modem_command = optarg; 519 | break; 520 | case 'r': 521 | break; 522 | case 'a': /* "Answer" mode */ 523 | mode = MODE_LTMODEM_ANSWER; 524 | break; 525 | case 'd': /* Dial given number and exit mode */ 526 | mode = MODE_LTMODEM_CALL; 527 | dial_number = optarg; 528 | break; 529 | default: 530 | help(); 531 | exit(1); 532 | } 533 | } 534 | 535 | if (mode == MODE_NONE) { 536 | help(); 537 | exit(1); 538 | } 539 | 540 | srandom(0); /* we want a deterministic test */ 541 | dsp_init(); 542 | V34_static_init(); 543 | 544 | switch(mode) { 545 | case MODE_V21TEST: 546 | FSK_test(0); 547 | break; 548 | case MODE_V22TEST: 549 | V22_test(); 550 | break; 551 | case MODE_V23TEST: 552 | FSK_test(1); 553 | break; 554 | case MODE_V34TEST: 555 | V34_test(); 556 | break; 557 | case MODE_V90TEST: 558 | V90_test(); 559 | break; 560 | case MODE_LINESIM: 561 | line_simulate(); 562 | break; 563 | case MODE_LTMODEM_CALL: 564 | case MODE_LTMODEM_ANSWER: 565 | real_test(mode == MODE_LTMODEM_CALL); 566 | system("ltmodem -c"); 567 | break; 568 | case MODE_SOUNDCARD: 569 | soundcard_modem(); 570 | break; 571 | } 572 | 573 | return 0; 574 | } 575 | 576 | 577 | 578 | 579 | 580 | -------------------------------------------------------------------------------- /lm.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "dsp.h" 8 | 9 | #define LM_VERSION "0.2.5" 10 | 11 | /* bit fifo */ 12 | 13 | struct sm_fifo { 14 | unsigned char *sptr, *wptr, *rptr, *eptr; 15 | int size, max_size; 16 | }; 17 | 18 | void sm_flush(struct sm_fifo *f); 19 | int sm_size(struct sm_fifo *f); 20 | void sm_put_bit(struct sm_fifo *f, int v); 21 | void sm_put_bits(struct sm_fifo *f, int v, int n); 22 | int sm_get_bit(struct sm_fifo *f); 23 | int sm_get_bits(struct sm_fifo *f, int n); 24 | void sm_init_fifo(struct sm_fifo *f, u8 *buf, int size); 25 | 26 | /* bit I/O for data pumps */ 27 | typedef void (*put_bit_func)(void *opaque, int bit); 28 | typedef int (*get_bit_func)(void *opaque); 29 | 30 | /* timer */ 31 | struct sm_timer { 32 | long timeout; 33 | }; 34 | 35 | int sm_time(void); 36 | void sm_set_timer(struct sm_timer *t, int delay); 37 | int sm_check_timer(struct sm_timer *t); 38 | 39 | /* debug */ 40 | extern int lm_debug; 41 | extern char *sm_states_str[]; 42 | 43 | /* protocol description */ 44 | 45 | #include "dtmf.h" 46 | #include "fsk.h" 47 | #include "v21.h" 48 | #include "v22.h" 49 | #include "v23.h" 50 | #include "v8.h" 51 | #include "v34.h" 52 | 53 | /* modem state */ 54 | #define SM_FIFO_SIZE 4096 55 | 56 | struct sm_state { 57 | /* pretty name of the modem (to debug) */ 58 | char name[16]; 59 | 60 | struct sm_hw_info *hw; 61 | struct lm_interface_state *hw_state; 62 | 63 | /* bytes to be transmitted */ 64 | struct sm_fifo tx_fifo; 65 | u8 tx_fifo_buf[SM_FIFO_SIZE]; 66 | 67 | /* received chars */ 68 | struct sm_fifo rx_fifo; 69 | u8 rx_fifo_buf[SM_FIFO_SIZE]; 70 | 71 | /* true if we are the caller */ 72 | int calling; 73 | /* phone number to call */ 74 | char call_num[64]; 75 | int pulse_dial; /* TRUE if we must use pulse dialing */ 76 | 77 | /* dialing */ 78 | struct sm_timer dtmf_timer; 79 | DTMF_mod_state dtmf_tx; 80 | int dtmf_ptr, dtmf_len; /* pointer in call_num */ 81 | 82 | /* dtmf receive: for testing (or voice mode in the future) */ 83 | struct sm_timer ring_timer; 84 | DTMF_demod_state dtmf_rx; 85 | 86 | /* modulation state */ 87 | union { 88 | V8State v8_state; 89 | V21State v21_state; 90 | V23State v23_state; 91 | } u; 92 | 93 | /* serial state */ 94 | int serial_data_bits; /* 5 to 8 */ 95 | int serial_parity, serial_use_parity; 96 | int serial_wordsize; 97 | 98 | unsigned int serial_buf; 99 | int serial_cnt; 100 | 101 | unsigned int serial_tx_buf; 102 | int serial_tx_cnt; 103 | 104 | /* main modem state */ 105 | int state; 106 | int debug_laststate; 107 | int hangup_request; 108 | unsigned int time; /* current time (in samples) */ 109 | 110 | /* config */ 111 | struct LinModemConfig *lm_config; 112 | }; 113 | 114 | /* linmodem configuration registers */ 115 | typedef struct LinModemConfig { 116 | int pulse_dial; /* default dial type */ 117 | int dtmf_level; /* in dB */ 118 | int dtmf_digit_length; /* in ms */ 119 | int dtmf_pause_length; /* in ms */ 120 | int available_modulations; /* mask of available modulations */ 121 | } LinModemConfig; 122 | 123 | /* abstract line interface driver */ 124 | struct lm_interface_state { 125 | struct sm_state *sm; 126 | int handle; 127 | }; 128 | 129 | /* modem hardware interface abstraction */ 130 | /* XXX: must be slightly modified for kernel mode operation */ 131 | struct sm_hw_info { 132 | int (*open)(struct lm_interface_state *s); 133 | void (*close)(struct lm_interface_state *s); 134 | 135 | /* off hook or on hook modem */ 136 | void (*set_offhook)(struct lm_interface_state *s, int v); 137 | 138 | /* when the ring is enabled, an event E_RING is sent to the 139 | process if a ring occured */ 140 | void (*set_ring)(struct lm_interface_state *s, int v); 141 | 142 | /* the main modem loop is here */ 143 | void (*main_loop)(struct lm_interface_state *s); 144 | }; 145 | 146 | /* general state of the modem */ 147 | 148 | enum { 149 | #define TAG(s) s, 150 | #include "lmstates.h" 151 | }; 152 | 153 | void lm_init(struct sm_state *sm, struct sm_hw_info *hw, const char *name); 154 | 155 | /* main modem process */ 156 | void sm_process(struct sm_state *sm, s16 *output, s16 *input, int nb_samples); 157 | 158 | int lm_start_dial(struct sm_state *s, int pulse, const char *number); 159 | int lm_start_receive(struct sm_state *s); 160 | int lm_hangup(struct sm_state *s); 161 | 162 | enum lm_get_state_val { 163 | LM_STATE_IDLE, 164 | LM_STATE_CONNECTING, 165 | LM_STATE_CONNECTED, 166 | }; 167 | 168 | enum lm_get_state_val lm_get_state(struct sm_state *s); 169 | 170 | /* lmsim.c */ 171 | 172 | void line_simulate(void); 173 | 174 | struct LineModelState; 175 | 176 | struct LineModelState *line_model_init(void); 177 | void line_model(struct LineModelState *s, 178 | s16 *output1, const s16 *input1, 179 | s16 *output2, const s16 *input2, 180 | int nb_samples); 181 | 182 | /* lmreal.c */ 183 | 184 | void real_test(int calling); 185 | 186 | /* lmsoundcard.c */ 187 | void soundcard_modem(void); 188 | 189 | /* serial.c */ 190 | 191 | void serial_init(struct sm_state *s, int data_bits, int parity); 192 | int serial_get_bit(void *opaque); 193 | void serial_put_bit(void *opaque, int bit); 194 | 195 | /* atparser.c */ 196 | 197 | enum lm_at_state_type { 198 | AT_MODE_COMMAND, 199 | AT_MODE_DIALING, 200 | AT_MODE_CONNECTED, 201 | }; 202 | 203 | struct lm_at_state { 204 | char at_line[256]; 205 | int at_line_ptr; 206 | int at_state; 207 | struct sm_state *sm; /* corresponding modem state */ 208 | }; 209 | 210 | void lm_at_parser_init(struct lm_at_state *s, struct sm_state *sm); 211 | void lm_at_parser(struct lm_at_state *s); 212 | 213 | #include "display.h" 214 | -------------------------------------------------------------------------------- /lmreal.c: -------------------------------------------------------------------------------- 1 | /* real modem: suitable for ltmodem */ 2 | 3 | /* Copyright 1999 Pavel Machek , distribute under GPL v2 */ 4 | 5 | #include "lm.h" 6 | #include 7 | 8 | #define NB_SAMPLES 0x50 9 | 10 | extern struct sm_hw_info sm_hw_null; 11 | 12 | void readit(int f, void *buf, int len) 13 | { 14 | int res; 15 | while (len > 0) { 16 | if ((res = read(f, buf, len)) <= 0) { 17 | printf("Read failed: %m"); 18 | exit(5); 19 | } 20 | len -= res; 21 | buf += res; 22 | } 23 | } 24 | 25 | char *modem_command = "tee /tmp/delme.xmit | ltmodem -u 2> /dev/null | tee /tmp/delme.rec\n", 26 | *dial_number = "31415926"; 27 | 28 | void real_test(int calling) 29 | { 30 | int fildesin[2]; 31 | int fildesout[2]; 32 | int i; 33 | struct sm_state sm, *dce = &sm; 34 | s16 in_buf[NB_SAMPLES]; 35 | s16 out_buf[NB_SAMPLES]; 36 | 37 | lm_init(dce, &sm_hw_null, "real"); 38 | 39 | strcpy(dce->call_num,dial_number); 40 | 41 | pipe(fildesin); 42 | pipe(fildesout); 43 | 44 | printf( "Starting communication with ltmodem\n" ); 45 | fflush(stdout); fflush(stderr); 46 | 47 | if (!fork()) { 48 | close(0); 49 | dup(fildesin[0]); 50 | close(1); 51 | dup(fildesout[1]); 52 | close(fildesin[0]); 53 | close(fildesin[1]); 54 | close(fildesout[0]); 55 | close(fildesout[1]); 56 | system( modem_command ); 57 | exit(0); 58 | } 59 | 60 | /* test call */ 61 | 62 | if (calling) { 63 | lm_start_dial(dce, 0, dial_number); 64 | } else { 65 | lm_start_receive(dce); 66 | } 67 | 68 | close(fildesin[0]); 69 | close(fildesout[1]); 70 | 71 | printf( "Kicking modem..." ); fflush(stdout); 72 | bzero(out_buf, 2*NB_SAMPLES); 73 | { 74 | int i; 75 | for (i=0; i<100; i++) { 76 | write(fildesin[1], out_buf, 2*NB_SAMPLES); 77 | } 78 | } 79 | printf( "Modem kicked\n" ); 80 | 81 | /* answer_dce->state = SM_TEST_RING; */ 82 | for(;;) { 83 | if (lm_get_state(dce) == LM_STATE_IDLE) 84 | break; 85 | 86 | readit(fildesout[0], in_buf, NB_SAMPLES*2); 87 | 88 | sm_process(dce, out_buf, in_buf, NB_SAMPLES); 89 | 90 | if ((i = write(fildesin[1], out_buf, NB_SAMPLES*2)) != NB_SAMPLES*2) { 91 | printf( "Error writing -- got short sample (%d,%m)\n",i ); 92 | } 93 | } 94 | printf( "Looks like we are done\n" ); 95 | } 96 | -------------------------------------------------------------------------------- /lmsim.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of the phone line simulator 3 | * 4 | * Copyright (c) 1999,2000 Fabrice Bellard. 5 | * 6 | * This code is released under the GNU General Public License version 7 | * 2. Please read the file COPYING to know the exact terms of the 8 | * license. 9 | * 10 | */ 11 | #include "lm.h" 12 | 13 | #define NB_SAMPLES 40 /* 5 ms */ 14 | #define SAMPLE_RATE 8000 15 | 16 | #define SAMPLE_REF 0x4000 /* 0 dB reference (sample level) */ 17 | 18 | /* 'calling' is used to know in which direction we transmit for echo cancellation */ 19 | struct sm_hw_info sm_hw_null; 20 | 21 | 22 | /* transmit from 'A' to 'B' */ 23 | static void tx_rx(struct sm_state *A, struct sm_state *B, int dump) 24 | { 25 | /* transmit data from call_dce */ 26 | if (sm_size(&A->tx_fifo) < 10) { 27 | int i; 28 | 29 | for(i=0;i<256;i++) 30 | sm_put_bit(&A->tx_fifo, i); 31 | } 32 | 33 | /* receive data from answer_dce */ 34 | for(;;) { 35 | int c; 36 | c = sm_get_bit(&B->rx_fifo); 37 | if (c == -1) 38 | break; 39 | if (dump) { 40 | printf("[%02x]", c); 41 | fflush(stdout); 42 | } 43 | } 44 | } 45 | 46 | void line_simulate(void) 47 | { 48 | struct sm_state sm1, sm2, *call_dce = &sm1, *answer_dce = &sm2; 49 | s16 answer_buf[NB_SAMPLES], call_buf[NB_SAMPLES]; 50 | s16 answer_buf1[NB_SAMPLES], call_buf1[NB_SAMPLES]; 51 | FILE *f1,*f2; 52 | struct LineModelState *line_state; 53 | int err; 54 | 55 | err = lm_display_init(); 56 | if (err < 0) { 57 | fprintf(stderr, "Could not init X display\n"); 58 | exit(1); 59 | } 60 | 61 | line_state = line_model_init(); 62 | 63 | /* init two modems */ 64 | lm_init(call_dce, &sm_hw_null, "cal"); 65 | lm_init(answer_dce, &sm_hw_null, "ans"); 66 | 67 | /* start calls */ 68 | lm_start_dial(call_dce, 0, "1234567890"); 69 | lm_start_receive(answer_dce); 70 | answer_dce->state = SM_TEST_RING; 71 | 72 | f1 = fopen("cal.sw", "wb"); 73 | if (f1 == NULL) { 74 | perror("cal.sw"); 75 | exit(1); 76 | } 77 | 78 | f2 = fopen("ans.sw", "wb"); 79 | if (f1 == NULL) { 80 | perror("ans.sw"); 81 | exit(1); 82 | } 83 | 84 | memset(answer_buf, 0, sizeof(answer_buf)); 85 | 86 | /* init asynchronous tx & rx */ 87 | serial_init(call_dce, 8, 'N'); 88 | serial_init(answer_dce, 8, 'N'); 89 | 90 | for(;;) { 91 | lm_display_poll_event(); 92 | 93 | /* transmit & receive in both direction & dump call to ans modem */ 94 | tx_rx(call_dce, answer_dce, 0); 95 | tx_rx(answer_dce, call_dce, 1); 96 | 97 | /* exit connection if ONHOOK state */ 98 | 99 | if (lm_get_state(call_dce) == LM_STATE_IDLE || 100 | lm_get_state(answer_dce) == LM_STATE_IDLE) 101 | break; 102 | 103 | /* simulate both modem & output the samples to disk */ 104 | 105 | sm_process(call_dce, call_buf, answer_buf1, NB_SAMPLES); 106 | fwrite(call_buf, 1, NB_SAMPLES * 2, f1); 107 | 108 | sm_process(answer_dce, answer_buf, call_buf1, NB_SAMPLES); 109 | fwrite(answer_buf, 1, NB_SAMPLES * 2, f2); 110 | 111 | /* simulate the phone line */ 112 | line_model(line_state, 113 | call_buf1, call_buf, 114 | answer_buf1, answer_buf, NB_SAMPLES); 115 | } 116 | 117 | fclose(f1); 118 | fclose(f2); 119 | 120 | for(;;) { 121 | if (lm_display_poll_event()) 122 | break; 123 | } 124 | 125 | lm_display_close(); 126 | } 127 | 128 | static int sim_open(struct lm_interface_state *s) 129 | { 130 | return 0; 131 | } 132 | 133 | static void sim_close(struct lm_interface_state *s) 134 | { 135 | } 136 | 137 | static void sim_set_offhook(struct lm_interface_state *s, int v) 138 | { 139 | if (v) { 140 | printf("%s: offhook\n",s->sm->name); 141 | } else { 142 | printf("%s: onhook\n",s->sm->name); 143 | } 144 | } 145 | 146 | static void sim_set_ring(struct lm_interface_state *s, int v) 147 | { 148 | } 149 | 150 | static void sim_main_loop(struct lm_interface_state *s) 151 | { 152 | } 153 | 154 | struct sm_hw_info sm_hw_null = 155 | { 156 | sim_open, 157 | sim_close, 158 | sim_set_offhook, 159 | sim_set_ring, 160 | sim_main_loop, 161 | }; 162 | 163 | /* simple phone line model */ 164 | 165 | #define LINE_FILTER_SIZE 129 166 | #define A 0.99 /* constant for exponential averaging for power estimations */ 167 | #define FFT_SIZE 1024 168 | 169 | /* state of a uni directional line */ 170 | typedef struct { 171 | float buf[LINE_FILTER_SIZE]; /* last transmitted samples (ring buffer, 172 | used by the line filter) */ 173 | int buf_ptr; /* pointer of the last transmitted sample in buf */ 174 | float tx_pow; /* estimated transmit power */ 175 | float rx_pow; /* estimated receive power */ 176 | float noise_pow; /* estimated noise power */ 177 | } UniDirLineState; 178 | 179 | 180 | typedef struct LineModelState { 181 | UniDirLineState line1, line2; 182 | float fout1, fout2; 183 | } LineModelState; 184 | 185 | static float line_filter[LINE_FILTER_SIZE]; 186 | static float sigma; /* gaussian noise sigma */ 187 | static int nb_clamped; /* number of overflows */ 188 | static float modem_hybrid_echo; /* echo level created by the modem hybrid */ 189 | static float cs_hybrid_echo; /* echo level created by the central site hybrid */ 190 | 191 | #define RANDMAX 0x7fffffff 192 | 193 | float random_unif(void) 194 | { 195 | return (float) random() / RANDMAX; 196 | } 197 | 198 | float random_gaussian(void) 199 | { 200 | float v1, v2, s , m; 201 | do { 202 | v1 = 2 * random_unif() - 1; 203 | v2 = 2 * random_unif() - 1; 204 | s = v1 * v1 + v2 * v2; 205 | } while (s >= 1); 206 | m = sqrt(-2 * log(s)/s); 207 | return v1 * m; 208 | } 209 | 210 | /* tabulated medium range telephone line respond (from p 537, Digital 211 | Communication, John G. Proakis */ 212 | 213 | /* amp 1.0 -> 2.15, freq = 3000 Hz -> 3.2, by 0.2 increments 214 | delay = 4 ms -> 2.2 215 | */ 216 | 217 | float phone_amp[23] = { 218 | 0, 219 | 0.9, 220 | 1.4, 221 | 1.8, 222 | 2.0, 223 | 2.1, 224 | 2.3, 225 | 2.3, 226 | 2.2, 227 | 2.1, 228 | 2.0, 229 | 1.85, 230 | 1.75, 231 | 1.55, 232 | 1.3, 233 | 1.1, 234 | 0.8, 235 | 0.55, 236 | 0.25, 237 | 0.05, 238 | 0.05, 239 | 0.05, 240 | 0.00, 241 | }; 242 | 243 | float phone_delay[23] = { 244 | 2.2, /* NA */ 245 | 2.2, /* NA */ 246 | 2.2, 247 | 0.9, 248 | 0.5, 249 | 0.25, 250 | 0.1, 251 | 0.05, 252 | 0.0, 253 | 0.0, 254 | 0.0, 255 | 0.05, 256 | 0.1, 257 | 0.2, 258 | 0.4, 259 | 0.5, 260 | 0.9, 261 | 1.2, 262 | 2.2, 263 | 2.2, /* NA */ 264 | 2.2, /* NA */ 265 | 2.2, /* NA */ 266 | 2.2, /* NA */ 267 | }; 268 | 269 | static void build_line_impulse_response(void) 270 | { 271 | float f, f1, a, amp, phase, delay; 272 | int index, i, j; 273 | complex tab[FFT_SIZE]; 274 | FILE *outfile; 275 | 276 | for(i=0;itx_pow = (v * v) * (1.0 - A) + A * s->tx_pow; 375 | 376 | /* add the sample in the filter buffer */ 377 | p = s->buf_ptr; 378 | s->buf[p] = v; 379 | if (++p == LINE_FILTER_SIZE) 380 | p = 0; 381 | s->buf_ptr = p; 382 | 383 | /* apply the filter */ 384 | sum = 0; 385 | for(j=0;jbuf[p]; 387 | if (++p == LINE_FILTER_SIZE) 388 | p = 0; 389 | } 390 | 391 | /* add noise */ 392 | noise = random_gaussian() * sigma; 393 | sum += noise; 394 | 395 | /* (testing only: noise power) */ 396 | s->noise_pow = (noise * noise) * (1.0 - A) + A * s->noise_pow; 397 | 398 | /* compute rx_power */ 399 | s->rx_pow = (sum * sum) * (1.0 - A) + A * s->rx_pow; 400 | 401 | /* dump estimations */ 402 | if (calling && ++dump_count == 50) { 403 | float ref_db; 404 | 405 | dump_count = 0; 406 | ref_db = compute_db(SAMPLE_REF * SAMPLE_REF); 407 | lm_dump_linesim_power(compute_db(s->tx_pow) - ref_db, 408 | compute_db(s->rx_pow) - ref_db, 409 | compute_db(s->noise_pow) - ref_db); 410 | } 411 | 412 | return sum; 413 | } 414 | 415 | static int clamp(float a) 416 | { 417 | if (a < -32768) { 418 | a = -32768; 419 | nb_clamped++; 420 | } else if (a > 32767) { 421 | a = 32767; 422 | nb_clamped++; 423 | } 424 | return (int)rint(a); 425 | } 426 | 427 | /* modem (cal) modem (ans) 428 | * 429 | * input1 -> output1 (line1) 430 | * output2 <- input2 (line2) 431 | * 432 | */ 433 | void line_model(LineModelState *s, 434 | s16 *output1, const s16 *input1, 435 | s16 *output2, const s16 *input2, 436 | int nb_samples) 437 | { 438 | int i; 439 | float in1, in2, out1, out2; 440 | float tmp1, tmp2; 441 | 442 | for(i=0;ifout2 * cs_hybrid_echo; 448 | 449 | /* echo from ans modem central site hybrid */ 450 | tmp2 = in2 + s->fout1 * cs_hybrid_echo; 451 | 452 | /* line filters & noise */ 453 | s->fout1 = calc_line_filter(&s->line1, tmp1, 1); 454 | 455 | s->fout2 = calc_line_filter(&s->line2, tmp2, 0); 456 | 457 | /* echo from ans modem hybrid */ 458 | out1 = s->fout1 + in2 * modem_hybrid_echo; 459 | lm_dump_sample(CHANNEL_SAMPLE, out1 / 32768.0); 460 | 461 | /* echo from cal modem hybrid */ 462 | out2 = s->fout2 + in1 * modem_hybrid_echo; 463 | 464 | output1[i] = clamp(out1); 465 | output2[i] = clamp(out2); 466 | } 467 | } 468 | -------------------------------------------------------------------------------- /lmsoundcard.c: -------------------------------------------------------------------------------- 1 | /* sample interface code to use a linux soundcard */ 2 | #define _XOPEN_SOURCE 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "lm.h" 11 | 12 | /* OSS buffer size */ 13 | #define FRAGMENT_BITS 8 14 | #define NB_FRAGMENTS (32768 >> FRAGMENT_BITS) 15 | 16 | /* 128 samples : 16 ms, maybe too much ? */ 17 | #define NB_SAMPLES ((1 << FRAGMENT_BITS)/2) 18 | 19 | /* default pty */ 20 | 21 | extern struct sm_hw_info sm_hw_soundcard; 22 | 23 | void soundcard_modem(void) 24 | { 25 | struct sm_state sm1, *dce = &sm1; 26 | struct sm_hw_info *hw = &sm_hw_soundcard; 27 | s16 in_buf[NB_SAMPLES]; 28 | s16 out_buf[NB_SAMPLES]; 29 | u8 buf[1024]; 30 | struct lm_at_state at_parser; 31 | fd_set rfds, wfds; 32 | int hw_handle, tty_handle, max_handle, n; 33 | int out_buf_flushed, i, len; 34 | 35 | if (!lm_debug) { 36 | tty_handle = open("/dev/ptmx", O_RDWR); 37 | if (tty_handle < 0) { 38 | perror("/dev/ptmx"); 39 | return; 40 | } 41 | grantpt(tty_handle); 42 | unlockpt(tty_handle); 43 | printf("linmodem tty is '%s'\n", ptsname(tty_handle)); 44 | } else { 45 | printf("linmodem tty is stdout\n"); 46 | tty_handle = 0; 47 | } 48 | fcntl(tty_handle, F_SETFL, O_NONBLOCK); 49 | 50 | lm_init(dce, hw, "sc"); 51 | lm_at_parser_init(&at_parser, dce); 52 | 53 | 54 | hw_handle = dce->hw_state->handle; 55 | out_buf_flushed = 1; 56 | /* XXX: non block mode ? */ 57 | 58 | /* test call */ 59 | printf("linmodem started.\n"); 60 | for(;;) { 61 | /* sound card & tty handling */ 62 | FD_ZERO(&rfds); 63 | FD_SET(hw_handle, &rfds); 64 | FD_SET(tty_handle, &rfds); 65 | FD_ZERO(&wfds); 66 | if (!out_buf_flushed) 67 | FD_SET(hw_handle, &wfds); 68 | if (sm_size(&dce->rx_fifo) > 0) 69 | FD_SET(tty_handle, &wfds); 70 | max_handle = tty_handle; 71 | if (hw_handle > tty_handle) 72 | max_handle = hw_handle; 73 | 74 | n = select(max_handle + 1, &rfds, &wfds, NULL, NULL); 75 | if (n > 0) { 76 | /* process at commands */ 77 | lm_at_parser(&at_parser); 78 | 79 | /* read from tty */ 80 | if (FD_ISSET(tty_handle, &rfds)) { 81 | len = read(tty_handle, buf, sizeof(buf)); 82 | for(i=0;itx_fifo, buf[i]); 84 | } 85 | } 86 | /* write to tty */ 87 | if (FD_ISSET(tty_handle, &wfds)) { 88 | struct sm_fifo *f = &dce->rx_fifo; 89 | int size; 90 | size = f->eptr - f->rptr; 91 | if (size > f->size) 92 | size = f->size; 93 | len = write(tty_handle, f->rptr, size); 94 | if (len > 0) { 95 | f->rptr += len; 96 | f->size -= len; 97 | if (f->rptr == f->eptr) 98 | f->rptr = f->sptr; 99 | } 100 | } 101 | 102 | /* we assume that the modem read & write per block of 103 | NB_SAMPLES. It makes no sense the underlying hardware 104 | does something else */ 105 | 106 | /* read from modem */ 107 | if (FD_ISSET(hw_handle, &rfds) && out_buf_flushed) { 108 | len = read(hw_handle, in_buf, NB_SAMPLES * 2); 109 | if (len == NB_SAMPLES * 2) { 110 | /* process the modem samples */ 111 | sm_process(dce, out_buf, in_buf, NB_SAMPLES); 112 | out_buf_flushed = 0; 113 | } 114 | } 115 | /* write to modem */ 116 | if (FD_ISSET(hw_handle, &wfds)) { 117 | len = write(hw_handle, out_buf, NB_SAMPLES * 2); 118 | if (len == NB_SAMPLES * 2) { 119 | out_buf_flushed = 1; 120 | } 121 | } 122 | } 123 | } 124 | } 125 | 126 | static int soundcard_open(struct lm_interface_state *s) 127 | { 128 | int tmp, err; 129 | /* init the sound card to 8000 Hz, Mono, 16 bits */ 130 | 131 | s->handle = open("/dev/dsp", O_RDWR); 132 | if (s->handle < 0) { 133 | perror("/dev/dsp"); 134 | exit(1); 135 | } 136 | 137 | /* set the card to duplex */ 138 | tmp=0; 139 | err=ioctl(s->handle, SNDCTL_DSP_SETDUPLEX, &tmp); 140 | if (err < 0) { 141 | perror("SNDCTL_DSP_SETDUPLEX"); 142 | } 143 | 144 | /* buffer size */ 145 | tmp=(NB_FRAGMENTS << 16) | FRAGMENT_BITS; 146 | err=ioctl(s->handle, SNDCTL_DSP_SETFRAGMENT, &tmp); 147 | if (err < 0) { 148 | perror("set fragment"); 149 | } 150 | 151 | tmp=AFMT_S16_LE; 152 | err=ioctl(s->handle,SNDCTL_DSP_SETFMT,&tmp); 153 | if (err < 0) goto error; 154 | 155 | /* should be last */ 156 | tmp = 8000; 157 | err=ioctl(s->handle,SNDCTL_DSP_SPEED,&tmp); 158 | if (err < 0) goto error; 159 | 160 | return 0; 161 | error: 162 | close(s->handle); 163 | return -1; 164 | } 165 | 166 | static void soundcard_close(struct lm_interface_state *s) 167 | { 168 | close(s->handle); 169 | } 170 | 171 | static void soundcard_set_offhook(struct lm_interface_state *s, int v) 172 | { 173 | if (v) { 174 | printf("%s: offhook\n",s->sm->name); 175 | } else { 176 | printf("%s: onhook\n",s->sm->name); 177 | } 178 | } 179 | 180 | static void soundcard_set_ring(struct lm_interface_state *s, int v) 181 | { 182 | } 183 | 184 | static void soundcard_main_loop(struct lm_interface_state *s) 185 | { 186 | 187 | 188 | } 189 | 190 | struct sm_hw_info sm_hw_soundcard = 191 | { 192 | soundcard_open, 193 | soundcard_close, 194 | soundcard_set_offhook, 195 | soundcard_set_ring, 196 | soundcard_main_loop, 197 | }; 198 | 199 | -------------------------------------------------------------------------------- /lmstates.h: -------------------------------------------------------------------------------- 1 | /* modem states */ 2 | 3 | /* sm_process */ 4 | TAG(SM_IDLE) 5 | TAG(SM_CALL) 6 | TAG(SM_GO_ONHOOK) 7 | TAG(SM_PREDTMF_WAIT) 8 | TAG(SM_DTMF_DIAL) 9 | TAG(SM_DTMF_DIAL_WAIT) 10 | TAG(SM_DTMF_DIAL_WAIT1) 11 | TAG(SM_TEST_RING) 12 | TAG(SM_TEST_RING2) 13 | TAG(SM_RECEIVE) 14 | TAG(SM_V8) 15 | TAG(SM_V21) 16 | TAG(SM_V23) 17 | 18 | /* V8_process: call */ 19 | TAG(V8_WAIT_1SECOND) 20 | TAG(V8_CI) 21 | TAG(V8_CI_SEND) 22 | TAG(V8_CI_OFF) 23 | TAG(V8_GOT_ANSAM) 24 | TAG(V8_CM_SEND) 25 | TAG(V8_CJ_SEND) 26 | TAG(V8_SIGC) 27 | 28 | /* V8_process: answer */ 29 | TAG(V8_WAIT) 30 | TAG(V8_CM_WAIT) 31 | TAG(V8_JM_SEND) 32 | TAG(V8_SIGA) 33 | 34 | /* V34 phase 2 */ 35 | TAG(V34_P2_INFO0_SEND) 36 | 37 | 38 | #undef TAG 39 | -------------------------------------------------------------------------------- /nodisplay.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Stubs for X11 interface for linmodem 3 | * 4 | * Copyright (c) 2000 Fabrice Bellard, 2014 Geoffrey Thomas 5 | * 6 | * This code is released under the GNU General Public License version 7 | * 2. Please read the file COPYING to know the exact terms of the 8 | * license. 9 | */ 10 | 11 | #include "lm.h" 12 | 13 | int lm_display_init(void) 14 | { 15 | return 0; 16 | } 17 | 18 | void lm_display_close(void) 19 | { 20 | } 21 | 22 | void lm_dump_qam(float si, float sq) 23 | { 24 | } 25 | 26 | void draw_samples(int channel) 27 | { 28 | } 29 | 30 | void lm_dump_sample(int channel, float val) 31 | { 32 | } 33 | 34 | void lm_dump_equalizer(s32 eq_filter1[][2], int norm, int size) 35 | { 36 | } 37 | 38 | void lm_dump_agc(float gain) 39 | { 40 | } 41 | 42 | void lm_dump_linesim_power(float tx_db, float rx_db, float noise_db) 43 | { 44 | } 45 | 46 | int lm_display_poll_event(void) 47 | { 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /serial.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial encoder/decoder. 3 | * 4 | * Copyright (c) 2000 Fabrice Bellard. 5 | * 6 | * This code is released under the GNU General Public License version 7 | * 2. Please read the file COPYING to know the exact terms of the 8 | * license. 9 | * 10 | */ 11 | 12 | #include "lm.h" 13 | 14 | /* Init the serial encoder & decoder. 5 <= data_bits <= 8 and parity 15 | can be 'E', 'O', or 'N' */ 16 | void serial_init(struct sm_state *s, int data_bits, int parity) 17 | { 18 | s->serial_data_bits = data_bits; 19 | s->serial_use_parity = (parity == 'E' || parity == 'O'); 20 | s->serial_parity = (parity == 'O'); 21 | s->serial_wordsize = data_bits + 2 + s->serial_use_parity; 22 | 23 | /* rx init */ 24 | s->serial_buf = 0; 25 | s->serial_cnt = 0; 26 | 27 | /* tx init */ 28 | s->serial_tx_buf = 0; 29 | s->serial_tx_cnt = 0; 30 | } 31 | 32 | /* return a bit from the tx fifo with serial encoding */ 33 | int serial_get_bit(void *opaque) 34 | { 35 | struct sm_state *s = opaque; 36 | int data, j, bit, p; 37 | 38 | if (s->serial_tx_cnt == 0) { 39 | data = sm_get_bit(&s->tx_fifo); 40 | if (data == -1) 41 | return 1; 42 | s->serial_tx_cnt = s->serial_wordsize; 43 | if (s->serial_use_parity) { 44 | p = s->serial_parity; 45 | for(j=0;jserial_data_bits;j++) p ^= (data >> j) & 1; 46 | s->serial_tx_buf = (data << 2) | (p << 1) | 1; 47 | } else { 48 | s->serial_tx_buf = (data << 1) | 1; 49 | } 50 | } 51 | s->serial_tx_cnt--; 52 | bit = (s->serial_tx_buf >> s->serial_tx_cnt) & 1; 53 | return bit; 54 | } 55 | 56 | /* decode a serial stream and put it in rx_fifo. Not optimized */ 57 | void serial_put_bit(void *opaque, int bit) 58 | { 59 | struct sm_state *s = opaque; 60 | int mask, p, j, data; 61 | 62 | s->serial_buf = (s->serial_buf << 1) | bit; 63 | if (s->serial_cnt >= (s->serial_wordsize-1)) { 64 | mask = 1 | (1 << (s->serial_wordsize-1)); 65 | 66 | if ((s->serial_buf & mask) == 0x1) { 67 | data = (s->serial_buf & ((1 << s->serial_wordsize) - 1)) >> 1; 68 | 69 | if (s->serial_use_parity) { 70 | p = s->serial_parity; 71 | for(j=0;j<=s->serial_data_bits;j++) p ^= (data >> j) & 1; 72 | if (!p) 73 | sm_put_bit(&s->rx_fifo, data >> 1); 74 | } else { 75 | sm_put_bit(&s->rx_fifo, data); 76 | } 77 | 78 | s->serial_cnt = 0; 79 | } 80 | } else { 81 | s->serial_cnt++; 82 | } 83 | } 84 | 85 | -------------------------------------------------------------------------------- /v21.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of the V21 modulation/demodulation 3 | * 4 | * Copyright (c) 1999,2000 Fabrice Bellard. 5 | * 6 | * This code is released under the GNU General Public License version 7 | * 2. Please read the file COPYING to know the exact terms of the 8 | * license. 9 | */ 10 | #include "lm.h" 11 | 12 | #define SAMPLE_RATE 8000 13 | 14 | void V21_mod_init(FSK_mod_state *s, int calling, get_bit_func get_bit, void *opaque) 15 | { 16 | if (calling) { 17 | /* channel 1 */ 18 | s->f_lo = 1080 + 100; 19 | s->f_hi = 1080 - 100; 20 | } else { 21 | /* channel 2 */ 22 | s->f_lo = 1750 + 100; 23 | s->f_hi = 1750 - 100; 24 | } 25 | s->baud_rate = 300; 26 | s->sample_rate = SAMPLE_RATE; 27 | s->get_bit = get_bit; 28 | s->opaque = opaque; 29 | 30 | FSK_mod_init(s); 31 | } 32 | 33 | 34 | void V21_demod_init(FSK_demod_state *s, int calling, put_bit_func put_bit, void *opaque) 35 | { 36 | if (!calling) { 37 | /* channel 1 */ 38 | s->f_lo = 1080 + 100; 39 | s->f_hi = 1080 - 100; 40 | } else { 41 | /* channel 2 */ 42 | s->f_lo = 1750 + 100; 43 | s->f_hi = 1750 - 100; 44 | } 45 | s->baud_rate = 300; 46 | s->sample_rate = SAMPLE_RATE; 47 | s->put_bit = put_bit; 48 | s->opaque = opaque; 49 | FSK_demod_init(s); 50 | } 51 | 52 | void V21_init(V21State *s, int calling, 53 | get_bit_func get_bit, put_bit_func put_bit, void *opaque) 54 | { 55 | V21_mod_init(&s->tx, calling, get_bit, opaque); 56 | V21_demod_init(&s->rx, calling, put_bit, opaque); 57 | } 58 | 59 | int V21_process(V21State *s, s16 *output, s16 *input, int nb_samples) 60 | { 61 | /* XXX: handle disconnect detection by looking at the power */ 62 | FSK_mod(&s->tx, output, nb_samples); 63 | FSK_demod(&s->rx, input, nb_samples); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /v21.h: -------------------------------------------------------------------------------- 1 | 2 | void V21_mod_init(FSK_mod_state *s, int calling, get_bit_func get_bit, void *opaque); 3 | void V21_demod_init(FSK_demod_state *s, int calling, put_bit_func put_bit, void *opaque); 4 | 5 | typedef struct { 6 | FSK_mod_state tx; 7 | FSK_demod_state rx; 8 | } V21State; 9 | 10 | void V21_init(V21State *s, int calling, 11 | get_bit_func get_bit, put_bit_func put_bit, void *opaque); 12 | int V21_process(V21State *sm, s16 *output, s16 *input, int nb_samples); 13 | 14 | -------------------------------------------------------------------------------- /v22.c: -------------------------------------------------------------------------------- 1 | /* 2 | * V22 modulator & demodulator 3 | * 4 | * Copyright (c) 1999,2000 Fabrice Bellard. 5 | * 6 | * This code is released under the GNU General Public License version 7 | * 2. Please read the file COPYING to know the exact terms of the 8 | * license. 9 | */ 10 | #include "lm.h" 11 | 12 | /* 13 | * This code is also used by the V34 phase 2 at 600 bits/s. V22bis 14 | * 2400 bps is implemented in the modulation but not in the 15 | * demodulation. 16 | */ 17 | 18 | void V22_mod_init(V22ModState *s) 19 | { 20 | s->baud_phase = 0; 21 | s->baud_num = 3; 22 | s->baud_denom = 40; 23 | s->tx_filter_wsize = V22_TX_FILTER_SIZE / s->baud_denom; 24 | memset(s->tx_buf, 0, sizeof(s->tx_buf)); 25 | s->tx_outbuf_ptr = 0; 26 | s->carrier_phase = 0; 27 | s->carrier2_phase = 0; 28 | s->Z = 0; 29 | 30 | if (s->calling) { 31 | /* call modem DPSK: 600 bps, carrier at 1200 Hz, 0 db */ 32 | s->carrier_incr = (PHASE_BASE * 1200.0) / V34_SAMPLE_RATE; 33 | } else { 34 | /* answer modem DPSK: 600 bps, carrier at 2400 Hz, -1 db, 35 | guard tone at 1800 Hz, -7db */ 36 | s->carrier_incr = (PHASE_BASE * 2400.0) / V34_SAMPLE_RATE; 37 | s->carrier2_incr = (PHASE_BASE * 1800.0) / V34_SAMPLE_RATE; 38 | } 39 | } 40 | 41 | static void V22_mod_baseband(V22ModState *s, s16 *x_ptr, s16 *y_ptr) 42 | { 43 | int x, y, x1, y1, b1, b2; 44 | 45 | /* handle each kind of modulation */ 46 | switch(s->mod_type) { 47 | default: 48 | case V34_MOD_600: 49 | b1 = s->get_bit(s->opaque); 50 | /* rotation by 0 or 180 degrees */ 51 | s->Z = s->Z ^ (b1 << 1); 52 | x1 = 0x2000; 53 | y1 = 0x2000; 54 | break; 55 | case V22_MOD_600: 56 | b1 = s->get_bit(s->opaque); 57 | /* rotation by 90 or 270 degrees */ 58 | s->Z = (s->Z + ((b1 << 1) | 1)) & 3; 59 | x1 = 0x2000; 60 | y1 = 0x2000; 61 | break; 62 | case V22_MOD_1200: 63 | b1 = s->get_bit(s->opaque); 64 | b2 = s->get_bit(s->opaque); 65 | b2 ^= (1 - b1); 66 | s->Z = (s->Z + ((b1 << 1) | b2)) & 3; 67 | x1 = 0x2000; 68 | y1 = 0x2000; 69 | break; 70 | case V22_MOD_2400: 71 | /* quadrant selection */ 72 | b1 = s->get_bit(s->opaque); 73 | b2 = s->get_bit(s->opaque); 74 | b2 ^= (1 - b1); 75 | s->Z = (s->Z + ((b1 << 1) | b2)) & 3; 76 | /* 4 positions inside the quadrant */ 77 | b1 = s->get_bit(s->opaque); 78 | b2 = s->get_bit(s->opaque); 79 | /* XXX: normalize */ 80 | x1 = 0x1000; 81 | if (b2) 82 | x1 += 0x2000; 83 | y1 = 0x1000; 84 | if (b1) 85 | y1 += 0x2000; 86 | break; 87 | } 88 | 89 | /* rotate counter clockwise */ 90 | switch(s->Z) { 91 | case 0: 92 | x = x1; 93 | y = y1; 94 | break; 95 | case 1: 96 | x = -y1; 97 | y = x1; 98 | break; 99 | case 2: 100 | x = -x1; 101 | y = -y1; 102 | break; 103 | default: 104 | case 3: 105 | x = y1; 106 | y = -x1; 107 | break; 108 | } 109 | *x_ptr = x; 110 | *y_ptr = y; 111 | } 112 | 113 | void V22_mod(V22ModState *s, s16 *samples, unsigned int nb) 114 | { 115 | int i, j, k, val, si, sq, ph; 116 | 117 | for(i=0;ibaud_phase; 121 | si = sq = 0; 122 | for(j=0;jtx_filter_wsize;j++) { 123 | k = (s->tx_outbuf_ptr - j - 1) & 124 | (V22_TX_BUF_SIZE - 1); 125 | si += s->tx_buf[k][0] * v22_tx_filter[ph]; 126 | sq += s->tx_buf[k][1] * v22_tx_filter[ph]; 127 | ph += s->baud_denom; 128 | } 129 | si = si >> 14; 130 | sq = sq >> 14; 131 | 132 | /* get next baseband symbol ? */ 133 | s->baud_phase += s->baud_num; 134 | if (s->baud_phase >= s->baud_denom) { 135 | s->baud_phase -= s->baud_denom; 136 | V22_mod_baseband(s, 137 | &s->tx_buf[s->tx_outbuf_ptr][0], 138 | &s->tx_buf[s->tx_outbuf_ptr][1]); 139 | 140 | s->tx_outbuf_ptr = (s->tx_outbuf_ptr + 1) & (V22_TX_BUF_SIZE - 1); 141 | } 142 | 143 | val = (si * dsp_cos(s->carrier_phase) - 144 | sq * dsp_cos((PHASE_BASE/4) - s->carrier_phase)) >> COS_BITS; 145 | s->carrier_phase += s->carrier_incr; 146 | if (!s->calling) { 147 | /* a 1800 Hz tone is added for answer modem modulation at 6 dB below it */ 148 | val += (dsp_cos(s->carrier2_phase) >> 1); 149 | s->carrier2_phase += s->carrier2_incr; 150 | } 151 | samples[i] = val; 152 | } 153 | } 154 | 155 | void V22_demod_init(V22DemodState *s) 156 | { 157 | s->baud_phase = 0; 158 | s->baud_num = 3; 159 | s->baud_denom = 40; 160 | 161 | s->carrier_phase = 0; 162 | 163 | if (!s->calling) { 164 | /* call modem DPSK: 600 bps, carrier at 1200 Hz, 0 db */ 165 | s->carrier_incr = (PHASE_BITS * 1200) / 8000; 166 | } else { 167 | /* answer modem DPSK: 600 bps, carrier at 2400 Hz, -1 db, 168 | guard tone at 1800 Hz, -7db */ 169 | s->carrier_incr = (PHASE_BITS * 2400) / 8000; 170 | } 171 | } 172 | 173 | void V22_demod(V22DemodState *s, s16 *samples, unsigned int nb) 174 | { 175 | 176 | 177 | } 178 | 179 | 180 | /* test for FSK using V21 or V23 */ 181 | 182 | #define NB_SAMPLES 40 183 | 184 | #define MAXDELAY 32 185 | 186 | static int tx_bits[MAXDELAY], tx_ptr = 0, rx_ptr = 0; 187 | static int tx_blank = 32; 188 | 189 | /* transmit random bits with a sync header (31 ones, 1 zero) */ 190 | static int test_get_bit(void *opaque) 191 | { 192 | int bit; 193 | 194 | if (tx_blank != 0) { 195 | /* send 1 at the beginning for synchronization */ 196 | bit = (tx_blank > 1); 197 | tx_blank--; 198 | } else { 199 | bit = random() % 2; 200 | tx_bits[tx_ptr] = bit; 201 | if (++tx_ptr == MAXDELAY) 202 | tx_ptr = 0; 203 | } 204 | return bit; 205 | } 206 | 207 | static int nb_bits = 0, errors = 0, sync_count = 0, got_sync = 0; 208 | 209 | static void test_put_bit(void *opaque, int bit) 210 | { 211 | int tbit; 212 | 213 | if (!got_sync) { 214 | 215 | if (bit) { 216 | sync_count++; 217 | } else { 218 | if (sync_count > 16) 219 | got_sync = 1; 220 | sync_count = 0; 221 | } 222 | } else { 223 | tbit = tx_bits[rx_ptr]; 224 | if (++rx_ptr == MAXDELAY) 225 | rx_ptr = 0; 226 | if (bit != tbit) { 227 | errors++; 228 | } 229 | nb_bits++; 230 | } 231 | } 232 | 233 | void V22_test(void) 234 | { 235 | V22ModState tx; 236 | V22DemodState rx; 237 | int err, calling; 238 | struct LineModelState *line_state; 239 | s16 buf[NB_SAMPLES]; 240 | s16 buf1[NB_SAMPLES]; 241 | s16 buf2[NB_SAMPLES]; 242 | s16 buf3[NB_SAMPLES]; 243 | FILE *f1; 244 | 245 | err = lm_display_init(); 246 | if (err < 0) { 247 | fprintf(stderr, "Could not init X display\n"); 248 | exit(1); 249 | } 250 | 251 | line_state = line_model_init(); 252 | 253 | f1 = fopen("cal.sw", "wb"); 254 | if (f1 == NULL) { 255 | perror("cal.sw"); 256 | exit(1); 257 | } 258 | 259 | calling = 0; 260 | 261 | tx.calling = calling; 262 | tx.opaque = NULL; 263 | tx.get_bit = test_get_bit; 264 | tx.mod_type = V34_MOD_600; 265 | V22_mod_init(&tx); 266 | 267 | rx.calling = !calling; 268 | rx.opaque = NULL; 269 | rx.put_bit = test_put_bit; 270 | rx.mod_type = tx.mod_type; 271 | V22_demod_init(&rx); 272 | 273 | nb_bits = 0; 274 | errors = 0; 275 | for(;;) { 276 | if (lm_display_poll_event()) 277 | break; 278 | 279 | V22_mod(&tx, buf, NB_SAMPLES); 280 | memset(buf3, 0, sizeof(buf3)); 281 | 282 | line_model(line_state, buf1, buf, buf2, buf3, NB_SAMPLES); 283 | 284 | fwrite(buf, 1, NB_SAMPLES * 2, f1); 285 | 286 | V22_demod(&rx, buf1, NB_SAMPLES); 287 | } 288 | 289 | fclose(f1); 290 | 291 | printf("errors=%d nb_bits=%d Pe=%f\n", 292 | errors, nb_bits, (float) errors / (float)nb_bits); 293 | } 294 | -------------------------------------------------------------------------------- /v22.h: -------------------------------------------------------------------------------- 1 | 2 | enum ModulationType { 3 | V34_MOD_600, 4 | V22_MOD_600, 5 | V22_MOD_1200, 6 | V22_MOD_2400, 7 | }; 8 | 9 | /* 40 phases (sure too much, but we don't optimize right now) */ 10 | #define V22_TX_FILTER_SIZE (20 * 40) 11 | #define V22_TX_BUF_SIZE 64 12 | 13 | typedef struct { 14 | /* parameters */ 15 | int calling; 16 | enum ModulationType mod_type; 17 | void *opaque; 18 | get_bit_func get_bit; 19 | 20 | /* state */ 21 | int baud_phase, baud_num, baud_denom; 22 | int carrier_phase, carrier_incr; 23 | int carrier2_phase, carrier2_incr; 24 | int tx_filter_wsize; 25 | s16 tx_buf[V22_TX_BUF_SIZE][2]; /* complex symbols to be sent */ 26 | int tx_outbuf_ptr; /* index of the next symbol in tx_buf */ 27 | int Z; /* last value transmitted */ 28 | } V22ModState; 29 | 30 | typedef struct { 31 | /* parameters */ 32 | int calling; 33 | enum ModulationType mod_type; 34 | void *opaque; 35 | put_bit_func put_bit; 36 | 37 | int baud_phase, baud_num, baud_denom; 38 | int carrier_phase, carrier_incr; 39 | } V22DemodState; 40 | 41 | extern s16 v22_tx_filter[V22_TX_FILTER_SIZE]; 42 | 43 | void V22_mod_init(V22ModState *s); 44 | void V22_mod(V22ModState *s, s16 *samples, unsigned int nb); 45 | 46 | void V22_test(void); 47 | -------------------------------------------------------------------------------- /v23.c: -------------------------------------------------------------------------------- 1 | /* 2 | * generic V23 modulator & demodulator 3 | * 4 | * Copyright (c) 1999 Fabrice Bellard. 5 | * 6 | * This code is released under the GNU General Public License version 7 | * 2. Please read the file COPYING to know the exact terms of the 8 | * license. 9 | */ 10 | #include 11 | #include 12 | 13 | #include "lm.h" 14 | #include "fsk.h" 15 | 16 | #define SAMPLE_RATE 8000 17 | 18 | void V23_mod_init(FSK_mod_state *s, int calling, get_bit_func get_bit, void *opaque) 19 | { 20 | if (calling) { 21 | /* 75 bauds */ 22 | s->f_lo = 390; 23 | s->f_hi = 450; 24 | s->baud_rate = 75; 25 | } else { 26 | /* 1200 bauds */ 27 | s->f_lo = 1300; 28 | s->f_hi = 2100; 29 | s->baud_rate = 1200; 30 | } 31 | s->sample_rate = SAMPLE_RATE; 32 | s->get_bit = get_bit; 33 | s->opaque = opaque; 34 | 35 | FSK_mod_init(s); 36 | } 37 | 38 | 39 | void V23_demod_init(FSK_demod_state *s, int calling, put_bit_func put_bit, void *opaque) 40 | { 41 | if (!calling) { 42 | /* 75 bauds */ 43 | s->f_lo = 390; 44 | s->f_hi = 450; 45 | s->baud_rate = 75; 46 | } else { 47 | /* 1200 bauds */ 48 | s->f_lo = 1300; 49 | s->f_hi = 2100; 50 | s->baud_rate = 1200; 51 | } 52 | s->sample_rate = SAMPLE_RATE; 53 | s->put_bit = put_bit; 54 | s->opaque = opaque; 55 | 56 | FSK_demod_init(s); 57 | } 58 | 59 | 60 | void V23_init(V23State *s, int calling, 61 | get_bit_func get_bit, put_bit_func put_bit, void *opaque) 62 | { 63 | V23_mod_init(&s->tx, calling, get_bit, opaque); 64 | V23_demod_init(&s->rx, calling, put_bit, opaque); 65 | } 66 | 67 | int V23_process(V23State *s, s16 *output, s16 *input, int nb_samples) 68 | { 69 | FSK_mod(&s->tx, output, nb_samples); 70 | FSK_demod(&s->rx, input, nb_samples); 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /v23.h: -------------------------------------------------------------------------------- 1 | 2 | void V23_mod_init(FSK_mod_state *s, int calling, get_bit_func get_bit, void *opaque); 3 | void V23_demod_init(FSK_demod_state *s, int calling, put_bit_func put_bit, void *opaque); 4 | 5 | typedef struct { 6 | FSK_mod_state tx; 7 | FSK_demod_state rx; 8 | } V23State; 9 | 10 | void V23_init(V23State *s, int calling, 11 | get_bit_func get_bit, put_bit_func put_bit, void *opaque); 12 | int V23_process(V23State *s, s16 *output, s16 *input, int nb_samples); 13 | -------------------------------------------------------------------------------- /v34.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geofft/linmodem/7d5596faf5bd972fe5499e84c10d749dca76dfe5/v34.c -------------------------------------------------------------------------------- /v34.h: -------------------------------------------------------------------------------- 1 | #ifndef V34_H 2 | #define V34_H 3 | 4 | #include "v34priv.h" 5 | 6 | /* should be called once to init some V34 static tables */ 7 | void V34_static_init(void); 8 | 9 | struct V34State; 10 | 11 | void V34_init(struct V34State *s, int calling); 12 | int V34_process(struct V34State *s, s16 *output, s16 *input, int nb_samples); 13 | 14 | /* V34 half duplex test with line simulator */ 15 | void V34_test(void); 16 | 17 | #endif 18 | 19 | -------------------------------------------------------------------------------- /v34eq.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of the V34 equalizer 3 | * 4 | * Copyright (c) 2000 Fabrice Bellard. 5 | * 6 | * This code is released under the GNU General Public License version 7 | * 2. Please read the file COPYING to know the exact terms of the 8 | * license. 9 | * 10 | * This implementation is totally clean room. It was written by 11 | * reading the V34 specification and by using basic signal processing 12 | * knowledge. 13 | */ 14 | #include "lm.h" 15 | #include "v34priv.h" 16 | 17 | //#define DEBUG 18 | 19 | #define SQRT3_2 (int)(0.8660254 * 0x4000) 20 | 21 | #define CMUL(a,b,c) \ 22 | {\ 23 | (a).re=((b).re*(c).re-(b).im*(c).im) >> 14;\ 24 | (a).im=((b).im*(c).re+(b).re*(c).im) >> 14;\ 25 | } 26 | 27 | #define SCALE(a,b,shift) \ 28 | {\ 29 | (a).re=(b).re >> (shift);\ 30 | (a).im=(b).im >> (shift);\ 31 | } 32 | 33 | #define FFT23_SIZE (EQ_FRAC * V34_PP_SIZE) 34 | #define RENORM 256.0 35 | #define FRAC 16384.0 36 | 37 | static icomplex fft144_table[FFT23_SIZE]; 38 | static s16 fft144_reverse[FFT23_SIZE]; 39 | 40 | icomplex tabPP[V34_PP_SIZE]; /* PP is used to generate the PP signal */ 41 | static icomplex tabPP_fft[V34_PP_SIZE]; 42 | 43 | /* Compute an fft on an array whose size n = 2^k.3^l. The algorithm is 44 | not the most efficient, but it is simple. Each stage of the fft 45 | normalize the result: it is divided by 2 (for fft2) or 4 (for fft3) 46 | at each stage. For 144, the renormalization is 2^8 */ 47 | static void fft23(icomplex *output, icomplex *tab, unsigned int n) 48 | { 49 | unsigned int s, i, j, k; 50 | icomplex *p, *q, *r, *c1_ptr, *c2_ptr; 51 | s = n; 52 | k = 1; 53 | while (s != 1) { 54 | if ((s % 3) == 0) { 55 | /* we handle first the '3' factors */ 56 | s /= 3; 57 | for(p = tab;p> 14; 79 | tmp6 = b.im; 80 | tmp7 = c.im; 81 | tmp8 = (SQRT3_2 * (tmp6 - tmp7)) >> 14; 82 | tmp11 = tmp6 + tmp7; 83 | 84 | p->re = (tmp1 + tmp4); 85 | tmp5 = tmp1 - (tmp4 >> 1); 86 | c.re = (tmp5 - tmp8); 87 | b.re = (tmp5 + tmp8); 88 | p->im = tmp10 + tmp11; 89 | tmp12 = tmp10 - (tmp11 >> 1); 90 | b.im = (tmp9 + tmp12); 91 | c.im = (tmp12 - tmp9); 92 | 93 | /* post multiplications */ 94 | CMUL(*q, b, *c1_ptr); 95 | CMUL(*r, c, *c2_ptr); 96 | 97 | p++; 98 | q++; 99 | r++; 100 | c1_ptr += k; 101 | c2_ptr += 2 * k; 102 | if (c2_ptr >= (fft144_table + n)) 103 | c2_ptr -= n; 104 | } 105 | } 106 | k *= 3; 107 | } else { 108 | /* '2' factors */ 109 | s /= 2; 110 | for(p=tab;pre = (a.re + b.re); 121 | p->im = (a.im + b.im); 122 | b.re = (a.re - b.re); 123 | b.im = (a.im - b.im); 124 | 125 | /* post multiplication */ 126 | CMUL(*q, b, *c1_ptr); 127 | p++; 128 | q++; 129 | c1_ptr += k; 130 | } 131 | } 132 | k *= 2; 133 | } 134 | } 135 | 136 | /* now we reverse the indices : cannot permute in place because 137 | fft_reverse is not involutive */ 138 | for(i=0;i vmax) 292 | vmax = v; 293 | v = abs(tab[i].im); 294 | if (v > vmax) 295 | vmax = v; 296 | } 297 | lshift = 0; 298 | while (vmax < 0x4000) { 299 | vmax <<= 1; 300 | lshift++; 301 | } 302 | #if defined(DEBUG) || 1 303 | printf("vmax=%d lshift=%d\n", vmax, lshift); 304 | #endif 305 | 306 | for(i=0;i> 14; 321 | if (norm == 0) 322 | norm = 1; 323 | c.re = (c.re << 14) / norm; 324 | c.im = (c.im << 14) / norm; 325 | 326 | b.re = tab[i].re; 327 | b.im = - tab[i].im; 328 | CMUL(a, c, b); 329 | tab1[i] = a; 330 | 331 | b.re = tab[48 + i].re; 332 | b.im = - tab[48 + i].im; 333 | CMUL(a, c, b); 334 | tab1[48 + i] = a; 335 | } 336 | 337 | for(i=24;i<48;i++) { 338 | icomplex a, b, c; 339 | int norm; 340 | 341 | c = tabPP_fft[i]; 342 | b = tab[i]; 343 | norm = b.re * b.re + b.im * b.im; 344 | norm = norm >> 14; 345 | if (norm == 0) 346 | norm = 1; 347 | c.re = (c.re << 14) / norm; 348 | c.im = (c.im << 14) / norm; 349 | 350 | b.re = tab[i].re; 351 | b.im = - tab[i].im; 352 | CMUL(a, c, b); 353 | tab1[i] = a; 354 | } 355 | 356 | for(i=FFT23_SIZE/2;i vmax) { 387 | vmax = v; 388 | j = i; 389 | } 390 | } 391 | 392 | /* center & renormalize */ 393 | renorm = (int) (256.0 / FFT23_SIZE * RENORM * RENORM * 4.0 / 394 | (1 << (14 - lshift))); 395 | 396 | #if defined(DEBUG) 397 | printf("Equalizer:\n"); 398 | printf("center=%d renorm=%d\n", j, renorm); 399 | #endif 400 | 401 | #if 0 402 | k = FFT23_SIZE/2; 403 | while (((j - k) % 3) != 0) { 404 | if (++j == FFT23_SIZE) 405 | j = 0; 406 | } 407 | #else 408 | k = 0; 409 | j = 0; 410 | #endif 411 | 412 | for(i=0;ieq_filter[k][0] = (tab1[j].re * renorm) << 8; 414 | // s->eq_filter[k][1] = (tab1[j].im * renorm) << 8; 415 | if (++k == FFT23_SIZE) 416 | k = 0; 417 | if (++j == FFT23_SIZE) 418 | j = 0; 419 | } 420 | 421 | #ifdef DEBUG 422 | for(i=0;ieq_filter[i][0] / (1 << 30), 426 | (float)s->eq_filter[i][1] / (1 << 30)); 427 | } 428 | #endif 429 | } 430 | 431 | #undef CMUL 432 | 433 | #define CMUL(a,b,c) \ 434 | {\ 435 | (a).re=((b).re*(c).re-(b).im*(c).im);\ 436 | (a).im=((b).im*(c).re+(b).re*(c).im);\ 437 | } 438 | 439 | void V34_fast_equalize(V34DSPState *s, s16 *input) 440 | { 441 | complex tab[144], tab1[144]; 442 | complex a, b, c; 443 | float norm, d; 444 | int i; 445 | 446 | for(i=0;ieq_filter[i][0] = (int)(tab[i].re * FRAC * FRAC / 12) << 16; 504 | s->eq_filter[i][1] = (int)(tab[i].im * FRAC * FRAC / 12) << 16; 505 | } 506 | } 507 | -------------------------------------------------------------------------------- /v34gen.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geofft/linmodem/7d5596faf5bd972fe5499e84c10d749dca76dfe5/v34gen.c -------------------------------------------------------------------------------- /v34phase2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of the V34 phase 2 3 | * 4 | * Copyright (c) 1999,2000 Fabrice Bellard. 5 | * 6 | * This code is released under the GNU General Public License version 7 | * 2. Please read the file COPYING to know the exact terms of the 8 | * license. 9 | * 10 | * This implementation is totally clean room. It was written by 11 | * reading the V34 specification and by using basic signal processing 12 | * knowledge. 13 | */ 14 | #include "lm.h" 15 | #include "v34priv.h" 16 | 17 | #define DEBUG 18 | 19 | #define INFO_SYNC 0x72 20 | 21 | /* send the v34 info0 sequence */ 22 | void V34_send_info0(V34State *s, int ack) 23 | { 24 | u8 buf[48], *p, *q; 25 | int crc; 26 | 27 | p = buf; 28 | put_bits(&p, 4, 0xf); /* fill bits */ 29 | put_bits(&p, 8, INFO_SYNC); /* sync word */ 30 | 31 | put_bits(&p, 1, 1); /* symbol rate 2743 supported ? */ 32 | put_bits(&p, 1, 1); /* symbol rate 2800 supported ? */ 33 | put_bits(&p, 1, 1); /* symbol rate 3429 supported ? */ 34 | put_bits(&p, 1, 1); /* symbol rate 3000, low carrier supported ? */ 35 | put_bits(&p, 1, 1); /* symbol rate 3000, high carrier supported ? */ 36 | put_bits(&p, 1, 1); /* symbol rate 3200, low carrier supported ? */ 37 | put_bits(&p, 1, 1); /* symbol rate 3200, high carrier supported ? */ 38 | 39 | put_bits(&p, 1, 1); /* symbol rate 3429 disallowed ? */ 40 | put_bits(&p, 1, 1); /* can power reduce ? */ 41 | put_bits(&p, 3, 5); /* difference between emit & receive sym rate */ 42 | put_bits(&p, 1, 0); /* from CME modem ? */ 43 | put_bits(&p, 1, 0); /* reserved by ITU */ 44 | put_bits(&p, 2, 0); /* tx clock source: 0=internal */ 45 | put_bits(&p, 1, ack); /* ack reception */ 46 | 47 | /* crc */ 48 | crc = calc_crc(buf + 12, p - (buf + 12)); 49 | put_bits(&p, 16, crc); 50 | 51 | put_bits(&p, 4, 0xf); /* fill bits */ 52 | 53 | for(q=buf;qcal (XXX : 3200) */ 109 | put_bits(&p, 3, 4); /* sym rate cal->ans (XXX : 3200) */ 110 | 111 | put_bits(&p, 10, 0); /* frequency offset (XXX) */ 112 | 113 | /* crc */ 114 | crc = calc_crc(buf + 12, p - (buf + 12)); 115 | put_bits(&p, 16, crc); 116 | 117 | put_bits(&p, 4, 0xf); /* fill bits */ 118 | } 119 | 120 | 121 | void V34_send_L1(V34State *s, int rep) 122 | { 123 | static char ph[25] = { 124 | /* 150 */ 1,-1, 1, 1, 125 | /* 750 */ 1, 0, 1, 0, 126 | /*1350 */ 1, 1,-1, 0, 127 | /*1950 */ 1, 1,-1, 0, 128 | /*2550 */ 1,-1, 1,-1, 129 | /*3150 */ -1,-1,-1, 1, 130 | /*3750 */ 1 }; 131 | 132 | for(n=0;nstate) { 146 | case V34_P2_INFO0_SEND: 147 | V34_send_info0( 148 | 149 | } 150 | 151 | /* demodulation */ 152 | switch(s->state) { 153 | case V34_P2_INFO0_SEND: 154 | 155 | 156 | } 157 | } 158 | 159 | -------------------------------------------------------------------------------- /v34priv.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geofft/linmodem/7d5596faf5bd972fe5499e84c10d749dca76dfe5/v34priv.h -------------------------------------------------------------------------------- /v8.c: -------------------------------------------------------------------------------- 1 | /* 2 | * V8 protocol handler 3 | * 4 | * Copyright (c) 1999,2000 Fabrice Bellard. 5 | * 6 | * This code is released under the GNU General Public License version 7 | * 2. Please read the file COPYING to know the exact terms of the 8 | * license. 9 | * 10 | * This implementation is totally clean room. It was written by 11 | * reading the ITU specification and by using basic signal processing 12 | * knowledge. 13 | */ 14 | #include "lm.h" 15 | 16 | static void V8_mod_init(V8_mod_state *s) 17 | { 18 | s->sample_rate = V8_SAMPLE_RATE; 19 | 20 | /* ANSam tone: 2100 Hz, amplitude modulated at 15 Hz, with phase 21 | reversal every 450 ms */ 22 | s->phase = 0; 23 | s->phase_incr = (int) (PHASE_BASE * 2100.0 / s->sample_rate); 24 | s->mod_phase = 0; 25 | s->mod_phase_incr = (int) (PHASE_BASE * 15.0 / s->sample_rate); 26 | s->phase_reverse_samples = (int) (s->sample_rate * 0.450); 27 | s->phase_reverse_left = 0; 28 | /* XXX: incorrect power */ 29 | s->amp = (int) (pow(10, s->tone_level / 20.0) * 32768.0); 30 | } 31 | 32 | static void V8_mod(V8_mod_state *s, s16 *samples, unsigned int nb) 33 | { 34 | int amp,i; 35 | 36 | for(i=0;iphase_reverse_left == 0) { 39 | s->phase_reverse_left = s->phase_reverse_samples; 40 | s->phase += PHASE_BASE / 2; 41 | } 42 | 43 | amp = (dsp_cos(s->mod_phase) * (int)(0.2 * COS_BASE)) >> COS_BITS; 44 | amp += COS_BASE; /* between 0.8 and 1.2 */ 45 | samples[i] = (amp * dsp_cos(s->phase)) >> COS_BITS; 46 | s->mod_phase += s->mod_phase_incr; 47 | s->phase += s->phase_incr; 48 | } 49 | } 50 | 51 | /* Recognize the V8 ANSam tone. Some other tones (in particular V21 52 | tone) may be added later. We compute the DFT for every interesting 53 | frequency and do a threshold with the power. Not the best method, 54 | but easy to implement and quite reliable. */ 55 | 56 | static void V8_demod_init(V8_demod_state *s) 57 | { 58 | int i; 59 | 60 | for(i=0;icos_tab[i] = (int) (cos( 2 * M_PI * i / V8_N) * COS_BASE); 62 | s->sin_tab[i] = (int) (sin( 2 * M_PI * i / V8_N) * COS_BASE); 63 | } 64 | 65 | s->buf_ptr = 0; 66 | s->v8_ANSam_detected = 0; 67 | } 68 | 69 | static void V8_demod(V8_demod_state *s, const s16 *samples, unsigned int nb) 70 | { 71 | int i, p0, p1; 72 | 73 | for(i=0;ibuf[s->buf_ptr++] = samples[i]; 75 | if (s->buf_ptr >= V8_N) { 76 | s->buf_ptr = 0; 77 | dsp_sar_tab(s->buf, V8_N, 8); 78 | p0 = dsp_norm2(s->buf, V8_N, 0); 79 | p1 = compute_DFT(s->cos_tab, s->sin_tab, s->buf, DFT_COEF_2100, V8_N); 80 | /* XXX: this test is incorrect (not homogenous) */ 81 | if ((p0 > 1000) && (p1 > (5*p0))) { 82 | /* V8 tone recognized */ 83 | s->v8_ANSam_detected = 1; 84 | } 85 | } 86 | } 87 | } 88 | 89 | /* V8 stream decoding */ 90 | static void ci_decode(V8State *s) 91 | { 92 | int data = s->rx_data[0]; 93 | if (data == 0x83) { 94 | printf("CI: data call\n"); 95 | } 96 | } 97 | 98 | /* CM or JM decoding */ 99 | static void cm_decode(V8State *s) 100 | { 101 | u8 *p; 102 | int c; 103 | 104 | if (s->got_cm) 105 | return; 106 | 107 | if (s->cm_count > 0) { 108 | /* we must receive two identical CM sequences */ 109 | if (s->cm_count == s->rx_data_ptr && 110 | !memcmp(s->cm_data, s->rx_data, s->rx_data_ptr)) { 111 | /* got CM !! */ 112 | s->got_cm = 1; 113 | /* decode it */ 114 | /* XXX: this decoding is sufficient for modulations, but 115 | not exhaustive */ 116 | s->decoded_modulations = 0; 117 | p = s->cm_data; 118 | /* zero is used to indicate the end */ 119 | s->cm_data[s->cm_count] = 0; 120 | 121 | c = *p++; 122 | /* call function */ 123 | if ((c & 0xf8) != 0x80) 124 | return; 125 | if (c != V8_CALL_FUNC_DATA) 126 | return; 127 | 128 | /* modulation */ 129 | c = *p++; 130 | if ((c & 0xf8) != V8_MODN0) 131 | return; 132 | 133 | if (c & V8_MODN0_V90) 134 | s->decoded_modulations |= V8_MOD_V90; 135 | if (c & V8_MODN0_V34) 136 | s->decoded_modulations |= V8_MOD_V34; 137 | 138 | c = *p++; 139 | if ((c & 0x1c) == V8_EXT) { 140 | /* ignored */ 141 | c = *p++; 142 | if ((c & 0x1c) == V8_EXT) { 143 | if (c & V8_MODN2_V23) 144 | s->decoded_modulations |= V8_MOD_V23; 145 | if (c & V8_MODN2_V21) 146 | s->decoded_modulations |= V8_MOD_V21; 147 | /* skip other extensions */ 148 | do { 149 | c = *p++; 150 | } while ((c & 0x1c) == V8_EXT); 151 | } 152 | } 153 | return; 154 | } 155 | } 156 | 157 | /* save the current CM sequence */ 158 | s->cm_count = s->rx_data_ptr; 159 | memcpy(s->cm_data, s->rx_data, s->rx_data_ptr); 160 | } 161 | 162 | static void put_bit(void *opaque, int bit) 163 | { 164 | V8State *s = opaque; 165 | int new_state, i; 166 | 167 | /* wait ten ones & synchro */ 168 | s->bit_sync = ((s->bit_sync << 1) | bit) & ((1 << 20) - 1); 169 | if (s->bit_sync == ((V8_TEN_ONES << 10) | V8_CI_SYNC)) { 170 | new_state = V8_CI_SYNC; 171 | goto data_init; 172 | } else if (s->bit_sync == ((V8_TEN_ONES << 10) | V8_CM_SYNC)) { 173 | new_state = V8_CM_SYNC; 174 | data_init: 175 | /* debug */ 176 | if (s->data_state == V8_CI_SYNC) { 177 | printf("CI: "); 178 | } else if (s->data_state == V8_CM_SYNC) { 179 | if (s->calling) 180 | printf("JM: "); 181 | else 182 | printf("CM: "); 183 | } 184 | for(i=0;irx_data_ptr;i++) printf(" %02x", s->rx_data[i]); 185 | printf("\n"); 186 | 187 | /* decode previous sequence */ 188 | switch(s->data_state) { 189 | case V8_CI_SYNC: 190 | ci_decode(s); 191 | break; 192 | case V8_CM_SYNC: 193 | cm_decode(s); 194 | break; 195 | } 196 | s->data_state = new_state; 197 | s->bit_buf = 0; 198 | s->bit_cnt = 0; 199 | s->rx_data_ptr = 0; 200 | } 201 | 202 | /* parse octets with 1 bit start, 1 bit stop */ 203 | if (s->data_state) { 204 | s->bit_buf = ((s->bit_buf << 1) | bit) & ((1 << 10) - 1); 205 | s->bit_cnt++; 206 | /* start, stop ? */ 207 | if ((s->bit_buf & 0x201) == 0x001 && s->bit_cnt >= 10) { 208 | int data; 209 | /* store the available data */ 210 | data = (s->bit_buf >> 1) & 0xff; 211 | printf("got data: %d %02x\n", s->data_state, data); 212 | /* CJ detection */ 213 | if (data == 0) { 214 | if (++s->data_zero_count == 3) { 215 | s->got_cj = 1; 216 | printf("got CJ\n"); 217 | } 218 | } else { 219 | s->data_zero_count = 0; 220 | } 221 | 222 | if (s->rx_data_ptr < (sizeof(s->rx_data)-1)) { 223 | s->rx_data[s->rx_data_ptr++] = data; 224 | } 225 | 226 | s->bit_cnt = 0; 227 | } 228 | } 229 | } 230 | 231 | static void v8_decode_init(V8State *s) 232 | { 233 | V21_demod_init(&s->v21_rx, s->calling, put_bit, s); 234 | s->data_state = 0; 235 | s->bit_sync = 0; 236 | s->cm_count = 0; 237 | s->got_cm = 0; 238 | 239 | s->got_cj = 0; 240 | s->data_zero_count = 0; 241 | s->rx_data_ptr = 0; 242 | } 243 | 244 | 245 | static int get_bit(void *opaque) 246 | { 247 | V8State *s = opaque; 248 | int bit; 249 | 250 | bit = sm_get_bit(&s->tx_fifo); 251 | if (bit < 0) 252 | bit = 1; 253 | return bit; 254 | } 255 | 256 | static void v8_put_byte(V8State *s, int data) 257 | { 258 | /* insert start & stop bits */ 259 | sm_put_bits(&s->tx_fifo, ((data & 0xff) << 1) | 1, 10); 260 | } 261 | 262 | 263 | void V8_init(V8State *sm, int calling, int mod_mask) 264 | { 265 | sm->debug_laststate = -1; 266 | sm->calling = calling; 267 | if (sm->calling) { 268 | sm->state = V8_WAIT_1SECOND; 269 | sm_set_timer(&sm->v8_start_timer, 1000); 270 | } else { 271 | /* wait 200 ms */ 272 | sm_set_timer(&sm->v8_connect_timer, 200); 273 | sm->state = V8_WAIT; 274 | } 275 | sm_init_fifo(&sm->rx_fifo, sm->rx_buf, sizeof(sm->rx_buf)); 276 | sm_init_fifo(&sm->tx_fifo, sm->tx_buf, sizeof(sm->tx_buf)); 277 | sm->modulation_mask = mod_mask; 278 | } 279 | 280 | /* send CM or JM */ 281 | static void cm_send(V8State *s, int mod_mask) 282 | { 283 | int val; 284 | 285 | sm_put_bits(&s->tx_fifo, V8_TEN_ONES, 10); 286 | sm_put_bits(&s->tx_fifo, V8_CM_SYNC, 10); 287 | 288 | /* data call */ 289 | v8_put_byte(s, V8_CALL_FUNC_DATA); 290 | 291 | /* supported modulations */ 292 | val = V8_MODN0; 293 | if (mod_mask & V8_MOD_V90) 294 | val |= V8_MODN0_V90; 295 | if (mod_mask & V8_MOD_V34) 296 | val |= V8_MODN0_V34; 297 | v8_put_byte(s, val); 298 | v8_put_byte(s, V8_EXT); 299 | val = V8_EXT; 300 | if (mod_mask & V8_MOD_V23) 301 | val |= V8_MODN2_V23; 302 | if (mod_mask & V8_MOD_V21) 303 | val |= V8_MODN2_V21; 304 | v8_put_byte(s, val); 305 | 306 | /* for now, no LAPM */ 307 | //v8_put_byte(s, V8_DATA_LAPM); 308 | 309 | /* We are not on celullar connection. What is that, 310 | anyway? GSM? Don't send this - we don't what it is 311 | for, anyway. */ 312 | //v8_put_byte(s, V8_DATA_NOCELULAR); 313 | } 314 | 315 | /* selection the modulation according to V8 priority from the bits in 'mask' */ 316 | static int select_modulation(int mask) 317 | { 318 | int val; 319 | 320 | val = V8_MOD_HANGUP; 321 | /* use modulations in this order */ 322 | if (mask & V8_MOD_V21) 323 | val = V8_MOD_V21; 324 | if (mask & V8_MOD_V23) 325 | val = V8_MOD_V23; 326 | if (mask & V8_MOD_V34) 327 | val = V8_MOD_V34; 328 | if (mask & V8_MOD_V90) 329 | val = V8_MOD_V90; 330 | return val; 331 | } 332 | 333 | 334 | /* V8 protocol handler */ 335 | int V8_process(V8State *s, s16 *output, s16 *input, int nb_samples) 336 | { 337 | int ret = 0; 338 | 339 | /* modulation part */ 340 | switch (s->state) { 341 | case V8_CI_SEND: 342 | case V8_CM_SEND: 343 | case V8_JM_SEND: 344 | case V8_CJ_SEND: 345 | /* modulate with V21 */ 346 | FSK_mod(&s->v21_tx, output, nb_samples); 347 | break; 348 | 349 | case V8_CM_WAIT: 350 | /* send ANSam modulation */ 351 | V8_mod(&s->v8_tx, output, nb_samples); 352 | break; 353 | 354 | default: 355 | /* output nothing */ 356 | memset(output, 0, nb_samples * sizeof(s16)); 357 | break; 358 | } 359 | 360 | /* demodulation part */ 361 | switch (s->state) { 362 | case V8_CI: 363 | case V8_CI_OFF: 364 | case V8_CI_SEND: 365 | /* detect ANSam */ 366 | V8_demod(&s->v8_rx, input, nb_samples); 367 | break; 368 | 369 | case V8_CM_WAIT: 370 | case V8_CM_SEND: 371 | case V8_JM_SEND: 372 | /* V21 receive */ 373 | FSK_demod(&s->v21_rx, input, nb_samples); 374 | break; 375 | 376 | default: 377 | break; 378 | } 379 | 380 | /* state machine */ 381 | 382 | if (lm_debug) { 383 | if (s->state != s->debug_laststate) { 384 | s->debug_laststate = s->state; 385 | printf("%s: V8: state: %s\n", 386 | s->calling ? "cal" : "ans", sm_states_str[s->state]); 387 | } 388 | } 389 | 390 | switch(s->state) { 391 | 392 | case V8_WAIT_1SECOND: 393 | { 394 | /* wait 1 second before sending the first CI packet */ 395 | if (sm_check_timer(&s->v8_start_timer)) { 396 | s->state = V8_CI; 397 | s->v8_ci_count = 0; 398 | V8_demod_init(&s->v8_rx); /* init ANSam detection */ 399 | V21_mod_init(&s->v21_tx, 1, get_bit, s); 400 | } 401 | } 402 | break; 403 | 404 | /* send the CI packets */ 405 | case V8_CI: 406 | { 407 | int i; 408 | 409 | /* send 4 CI packets (at least 3 must be sent) */ 410 | for(i=0;i<4;i++) { 411 | sm_put_bits(&s->tx_fifo, V8_TEN_ONES, 10); 412 | sm_put_bits(&s->tx_fifo, V8_CI_SYNC, 10); 413 | v8_put_byte(s, V8_CALL_FUNC_DATA); 414 | } 415 | s->state = V8_CI_SEND; 416 | } 417 | break; 418 | 419 | case V8_CI_SEND: 420 | { 421 | if (sm_size(&s->tx_fifo) == 0) { 422 | s->state = V8_CI_OFF; 423 | sm_set_timer(&s->v8_ci_timer, 500); /* 0.5 s off */ 424 | } 425 | } 426 | break; 427 | 428 | case V8_CI_OFF: 429 | { 430 | /* check if an ANSam tone is detected */ 431 | if (s->v8_rx.v8_ANSam_detected) { 432 | sm_set_timer(&s->v8_ci_timer, V8_TE); 433 | s->state = V8_GOT_ANSAM; 434 | } else if (sm_check_timer(&s->v8_ci_timer)) { 435 | if (++s->v8_ci_count == V8_MAX_CI_SEQ) { 436 | ret = V8_MOD_HANGUP; 437 | } 438 | else { 439 | s->state = V8_CI; 440 | } 441 | } 442 | } 443 | break; 444 | 445 | case V8_GOT_ANSAM: 446 | { 447 | if (sm_check_timer(&s->v8_ci_timer)) { 448 | v8_decode_init(s); 449 | s->state = V8_CM_SEND; 450 | } 451 | } 452 | break; 453 | 454 | case V8_CM_SEND: 455 | { 456 | if (s->got_cm) { 457 | /* if JM detected, we send CJ & wait for 75 ms before exiting V8 */ 458 | 459 | s->selected_mod_mask = s->modulation_mask & s->decoded_modulations; 460 | s->selected_modulation = select_modulation(s->selected_mod_mask); 461 | 462 | /* flush tx queue */ 463 | sm_flush(&s->tx_fifo); 464 | v8_put_byte(s, 0); 465 | v8_put_byte(s, 0); 466 | v8_put_byte(s, 0); 467 | /* a few more bytes to fill the time */ 468 | v8_put_byte(s, 0); 469 | v8_put_byte(s, 0); 470 | v8_put_byte(s, 0); 471 | v8_put_byte(s, 0); 472 | v8_put_byte(s, 0); 473 | v8_put_byte(s, 0); 474 | s->state = V8_CJ_SEND; 475 | } else if (sm_size(&s->tx_fifo) == 0) { 476 | /* send CM */ 477 | cm_send(s, s->modulation_mask); 478 | } 479 | } 480 | break; 481 | 482 | case V8_CJ_SEND: 483 | /* wait until CJ is sent */ 484 | if (sm_size(&s->tx_fifo) == 0) { 485 | sm_set_timer(&s->v8_start_timer, 75); 486 | s->state = V8_SIGC; 487 | } 488 | break; 489 | 490 | case V8_SIGC: 491 | if (sm_check_timer(&s->v8_start_timer)) { 492 | /* it's OK, let's start the wanted modulation */ 493 | ret = s->selected_modulation; 494 | } 495 | break; 496 | 497 | 498 | /* V8 answer */ 499 | 500 | case V8_WAIT: 501 | { 502 | if (sm_check_timer(&s->v8_connect_timer)) { 503 | /* send the ANSam tone */ 504 | s->v8_tx.tone_level = -3; /* XXX: fix it */ 505 | V8_mod_init(&s->v8_tx); 506 | 507 | /* prepare V21 to receive CI or CM */ 508 | v8_decode_init(s); 509 | 510 | /* wait at most 5 seconds */ 511 | sm_set_timer(&s->v8_connect_timer, 5000); 512 | s->state = V8_CM_WAIT; 513 | } 514 | } 515 | break; 516 | 517 | case V8_CM_WAIT: 518 | { 519 | if (sm_check_timer(&s->v8_connect_timer)) { 520 | /* timeout */ 521 | ret = V8_MOD_HANGUP; 522 | } else { 523 | if (s->got_cm) { 524 | /* stop sending ANSam & send JM */ 525 | V21_mod_init(&s->v21_tx, 0, get_bit, s); 526 | /* timeout for JM */ 527 | sm_set_timer(&s->v8_connect_timer, 5000); 528 | s->state = V8_JM_SEND; 529 | s->selected_mod_mask = s->modulation_mask & s->decoded_modulations; 530 | s->selected_modulation = select_modulation(s->selected_mod_mask); 531 | } 532 | } 533 | } 534 | break; 535 | 536 | case V8_JM_SEND: 537 | { 538 | if (sm_check_timer(&s->v8_connect_timer)) { 539 | /* timeout */ 540 | ret = V8_MOD_HANGUP; 541 | } else if (s->got_cj) { 542 | /* stop sending JM & wait 75 ms */ 543 | sm_set_timer(&s->v8_connect_timer, 75); 544 | s->state = V8_SIGA; 545 | } else if (sm_size(&s->tx_fifo) == 0) { 546 | /* Send JM */ 547 | cm_send(s, s->selected_mod_mask); 548 | } 549 | } 550 | break; 551 | 552 | case V8_SIGA: 553 | if (sm_check_timer(&s->v8_connect_timer)) { 554 | ret = s->selected_modulation; 555 | } 556 | break; 557 | } 558 | return ret; 559 | } 560 | -------------------------------------------------------------------------------- /v8.h: -------------------------------------------------------------------------------- 1 | 2 | #define V8_SAMPLE_RATE 8000 3 | 4 | /* V8 tone ANSam tone synthesis */ 5 | typedef struct { 6 | /* parameters */ 7 | int tone_level; 8 | 9 | /* internal */ 10 | int sample_rate; 11 | int phase, phase_incr; 12 | int mod_phase, mod_phase_incr; 13 | int phase_reverse_samples; 14 | int phase_reverse_left; 15 | int amp; 16 | } V8_mod_state; 17 | 18 | 19 | /* ANSam tone detection */ 20 | /* 25 ms window */ 21 | #define V8_N 200 22 | #define DFT_COEF_2100 ((int)((2100.0 / V8_SAMPLE_RATE * V8_N) + 0.5)) 23 | 24 | 25 | typedef struct { 26 | int buf_ptr; 27 | s16 buf[V8_N]; 28 | s16 cos_tab[V8_N]; 29 | s16 sin_tab[V8_N]; 30 | int v8_ANSam_detected; /* true if ANSam detected */ 31 | } V8_demod_state; 32 | 33 | /* Te period, as in the V8 spec 500 <= Te */ 34 | #define V8_TE 800 35 | 36 | /* V8 main state */ 37 | typedef struct { 38 | int calling; /* true if we are the calling modem */ 39 | int state; /* current state of the V8 protocol */ 40 | int debug_laststate; 41 | struct sm_timer v8_start_timer; 42 | struct sm_timer v8_ci_timer; 43 | struct sm_timer v8_connect_timer; 44 | int v8_ci_count; 45 | FSK_mod_state v21_tx; 46 | FSK_demod_state v21_rx; 47 | struct sm_fifo rx_fifo; 48 | struct sm_fifo tx_fifo; 49 | u8 rx_buf[256]; 50 | u8 tx_buf[256]; 51 | V8_mod_state v8_tx; 52 | V8_demod_state v8_rx; 53 | 54 | /* available modulations */ 55 | int modulation_mask; 56 | 57 | /* V8 data parsing */ 58 | unsigned int bit_buf; 59 | unsigned int bit_sync; 60 | int bit_cnt; 61 | int data_state; /* indicates the type of synchro */ 62 | u8 rx_data[64]; 63 | int rx_data_ptr; 64 | 65 | /* CM/JM parsing */ 66 | u8 cm_data[64]; 67 | int cm_count; 68 | int got_cm; 69 | int decoded_modulations; /* modulation mask decoded from CM/JM */ 70 | 71 | /* CJ parsing */ 72 | int got_cj; 73 | int data_zero_count; 74 | 75 | int selected_mod_mask; /* selected modulation mask */ 76 | int selected_modulation; /* see V8_MOD_xxx */ 77 | } V8State; 78 | 79 | /* V8 protocol definitions */ 80 | #define V8_MAX_CI_SEQ 10 /* maximum number of CI packets sent */ 81 | 82 | #define V8_TEN_ONES 0x3ff 83 | #define V8_CI_SYNC 0x001 84 | #define V8_CM_SYNC 0x00f 85 | 86 | #define V8_CALL_FUNC_DATA 0x83 87 | 88 | #define V8_MODN0 0xA0 89 | #define V8_EXT 0x08 90 | 91 | #define V8_MODN0_V90 0x04 /* FIXME */ 92 | #define V8_MODN0_V34 0x02 93 | #define V8_MODN2_V21 0x01 94 | #define V8_MODN2_V23 0x20 95 | 96 | #define V8_DATA_NOCELULAR 0xB0 97 | #define V8_DATA_LAPM 0x54 98 | 99 | #define V8_MOD_V90 (1 << 0) /* FIXME */ 100 | #define V8_MOD_V34 (1 << 1) /* V34 duplex */ 101 | #define V8_MOD_V23 (1 << 10) /* V23 duplex */ 102 | #define V8_MOD_V21 (1 << 12) /* V21 duplex */ 103 | 104 | #define V8_MOD_HANGUP 0x8000 /* indicate hangup */ 105 | 106 | void V8_init(V8State *sm, int calling, int mod_mask); 107 | int V8_process(V8State *sm, s16 *output, s16 *input, int nb_samples); 108 | -------------------------------------------------------------------------------- /v90.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of the V90 modulation/demodulation 3 | * 4 | * Copyright (c) 1999,2000 Fabrice Bellard. 5 | * 6 | * This code is released under the GNU General Public License version 7 | * 2. Please read the file COPYING to know the exact terms of the 8 | * license. 9 | * 10 | * This implementation is totally clean room. It was written by 11 | * reading the V90 specification and by using basic signal processing 12 | * knowledge. 13 | */ 14 | 15 | #include "lm.h" 16 | #include "v90priv.h" 17 | #include "v34priv.h" 18 | 19 | #define DEBUG 20 | 21 | /* Compute the average power of a given constellation : 22 | nothing complicated here, except that each ucode must be counted 23 | correctly. We took the algorithm of the spec. It could be very 24 | optimized and simplified. 25 | */ 26 | int compute_power(V90EncodeState *s) 27 | { 28 | int m,v,i,j; 29 | u64 p,n,r[6],k[6],a; 30 | 31 | n = ((u64)1 << s->K) - 1; 32 | for(i=0;i<6;i++) { 33 | r[i] = n; 34 | k[i] = n % s->M[i]; 35 | n = n / s->M[i]; 36 | } 37 | 38 | p = 0; 39 | a = 1; 40 | for(i=0;i<6;i++) { 41 | m = s->M[i]; 42 | for(j=0;jK) - a * (r[i] - r[i+1]); 47 | } else { 48 | n = a * r[i+1]; 49 | } 50 | v = s->ucode_to_linear[s->m_to_ucode[i][j]]; 51 | p += v * v * n; 52 | } 53 | a = a * m; 54 | } 55 | return p / ((u64) 6 << s->K); 56 | } 57 | 58 | static const int sign_op[4] = { 0, 0x55, 0xff, 0xaa }; 59 | 60 | /* Select the best method for the current shaping frame 61 | We find the the shortest path in a treillis of depth ld 62 | */ 63 | static void select_best_signs(V90EncodeState *s, int sp_frame_size, int pp) 64 | { 65 | int ucode_ptr, depth, i; 66 | int state, lstate, lstate_min; 67 | int t_min, x_min, y_min, v_min, w_min, sg; 68 | int x1, y1, v1, w1, x, y, v, w; 69 | u8 mem_l[2][TREILLIS_MAX_DEPTH+2], 70 | mem_t[2][TREILLIS_MAX_DEPTH+2]; 71 | s16 mem_x[2][TREILLIS_MAX_DEPTH+2], 72 | mem_y[2][TREILLIS_MAX_DEPTH+2], 73 | mem_v[2][TREILLIS_MAX_DEPTH+2], 74 | mem_w[2][TREILLIS_MAX_DEPTH+2]; 75 | 76 | /* save new pp signs */ 77 | s->pp[s->ucode_ptr] = pp; 78 | 79 | /* Find best path starting at state Q */ 80 | 81 | ucode_ptr = (s->ucode_ptr - (sp_frame_size * s->ld)) & (UCODE_BUF_SIZE-1); 82 | 83 | /* fill the treillis memory */ 84 | mem_t[s->Q][0] = s->t; 85 | mem_x[s->Q][0] = s->x; 86 | mem_y[s->Q][0] = s->y; 87 | mem_v[s->Q][0] = s->v; 88 | mem_w[s->Q][0] = 0; 89 | 90 | for(depth = 0; depth <= s->ld; depth++) { 91 | 92 | for(state = 0; state < 2; state++) { 93 | 94 | w_min = 0x7fffffff; 95 | lstate_min = t_min = x_min = y_min = v_min = 0; 96 | 97 | /* we select the current state at the beginning of the treillis */ 98 | if (depth == 0) 99 | lstate = s->Q; 100 | else 101 | lstate = 0; 102 | 103 | do { 104 | /* compute the signs */ 105 | sg = mem_t[lstate][depth] ^ s->pp[ucode_ptr]; 106 | /* apply the bit invertion method */ 107 | sg ^= sign_op[(state << 1) | lstate]; 108 | 109 | x1 = mem_x[lstate][depth]; 110 | y1 = mem_y[lstate][depth]; 111 | v1 = mem_v[lstate][depth]; 112 | w1 = mem_w[lstate][depth]; 113 | 114 | /* apply the spectral shaping filter to the frame */ 115 | for(i=0;iucode_to_linear[s->ucode[(ucode_ptr + i) & (UCODE_BUF_SIZE-1)]]; 117 | if (((sg >> i) & 1) == 0) 118 | x = -x; 119 | 120 | y = x - ((s->b1 * x1 + s->a1 * y1) >> 6); 121 | v = y - ((s->b2 * y1 + s->a2 * v1) >> 6); 122 | w = ((v * v) >> 4) + w1; 123 | 124 | x1 = x; 125 | y1 = y; 126 | v1 = v; 127 | w1 = w; 128 | } 129 | 130 | /* best transition ? */ 131 | if (w1 < w_min) { 132 | t_min = sg; 133 | x_min = x1; 134 | y_min = y1; 135 | v_min = v1; 136 | w_min = w1; 137 | lstate_min = lstate; 138 | } 139 | lstate++; 140 | } while (lstate < 2 && depth != 0); 141 | 142 | /* selects the best transition */ 143 | mem_t[state][depth+1] = t_min; 144 | mem_x[state][depth+1] = x_min; 145 | mem_y[state][depth+1] = y_min; 146 | mem_v[state][depth+1] = v_min; 147 | mem_w[state][depth+1] = w_min; 148 | mem_l[state][depth+1] = lstate_min; 149 | } 150 | 151 | ucode_ptr = (ucode_ptr + sp_frame_size) & (UCODE_BUF_SIZE-1); 152 | } 153 | 154 | /* now select the best next state by recursing thru the treillis */ 155 | if (mem_w[1][s->ld + 1] < mem_w[0][s->ld + 1]) 156 | state = 1; 157 | else 158 | state = 0; 159 | 160 | for(depth=s->ld;depth>0;depth--) 161 | state = mem_l[state][depth]; 162 | 163 | s->Q = state; 164 | 165 | /* update current values */ 166 | s->t = mem_t[state][1]; 167 | s->x = mem_x[state][1]; 168 | s->y = mem_y[state][1]; 169 | s->v = mem_v[state][1]; 170 | 171 | s->ucode_ptr = (s->ucode_ptr + sp_frame_size) & (UCODE_BUF_SIZE - 1); 172 | } 173 | 174 | /* 175 | * converts (S+K) data bits to 6 a/u law values (note: we output 176 | * linear values which may be converted back to u/a law). A delay of 177 | * (ld * frame_size) is introduced due to the shaping treillis. 178 | */ 179 | static void v90_encode_mapping_frame(V90EncodeState *s, s16 *samples, u8 *data) 180 | { 181 | int k, l, i, j, frame_size, nb_frames, p, signs; 182 | u64 v; 183 | int pv[3]; 184 | 185 | /* modulo mapping to ucodes */ 186 | v = 0; 187 | for(i=0;iK;i++) v |= (data[i+s->S] << i); 188 | for(i=0;i<6;i++) { 189 | k = v % s->M[i]; 190 | v /= s->M[i]; 191 | /* compute the corresponding ucode */ 192 | s->ucode[(s->ucode_ptr + i) & (UCODE_BUF_SIZE - 1)] = s->m_to_ucode[i][k]; 193 | } 194 | 195 | /* computation of the sign of the ucodes */ 196 | switch(s->S) { 197 | case 6: 198 | default: 199 | /* no redundancy & spectral shaping */ 200 | l = s->last_sign; 201 | signs = 0; 202 | for(i=0;i<6;i++) { 203 | l = data[i] ^ l; 204 | signs |= (l << i); 205 | } 206 | s->last_sign = l; 207 | s->ucode_ptr = (s->ucode_ptr + 6) & (UCODE_BUF_SIZE - 1); 208 | frame_size = 6; 209 | goto skip_spectral_shaping; 210 | 211 | case 5: 212 | /* 1 bit of redundancy */ 213 | { 214 | int pp1, pp3, pp5; 215 | 216 | pp1 = data[0] ^ s->last_sign; 217 | pp3 = data[2] ^ pp1; 218 | pp5 = data[4] ^ pp3; 219 | s->last_sign = pp5; 220 | 221 | pv[0] = (pp1 << 1) | (data[1] << 2) | (pp3 << 3) | 222 | (data[3] << 4) | (pp5 << 5); 223 | 224 | frame_size = 6; 225 | } 226 | break; 227 | case 4: 228 | /* 2 bits of redundancy */ 229 | { 230 | int pp1, pp4; 231 | 232 | pp1 = data[0] ^ s->last_sign; 233 | pp4 = data[2] ^ pp1; 234 | 235 | s->last_sign = pp4; 236 | 237 | pv[0] = (pp1 << 1) | (data[1] << 2); 238 | pv[1] = (pp4 << 1) | (data[3] << 2); 239 | 240 | frame_size = 3; 241 | } 242 | break; 243 | 244 | case 3: 245 | /* 3 bits of redundancy */ 246 | { 247 | int pp1, pp3, pp5; 248 | 249 | pp1 = data[0] ^ s->last_sign; 250 | pp3 = data[1] ^ pp1; 251 | pp5 = data[2] ^ pp3; 252 | 253 | s->last_sign = pp5; 254 | 255 | pv[0] = (pp1 << 1); 256 | pv[1] = (pp3 << 1); 257 | pv[2] = (pp5 << 1); 258 | 259 | frame_size = 2; 260 | } 261 | break; 262 | } 263 | 264 | /* select the best signs for each frame (with a delay of ld) */ 265 | nb_frames = 6-s->S; 266 | signs = 0; 267 | for(i=0,j=0; it & ((1 << frame_size) - 1); 270 | signs |= (l << j); 271 | } 272 | 273 | skip_spectral_shaping: 274 | 275 | /* now the signs are computed, we can compute the pcm values from 276 | the ucodes. It may be faster to use the convertion already done 277 | for spectral shaping */ 278 | p = (s->ucode_ptr - 6 - (frame_size * s->ld)) & (UCODE_BUF_SIZE - 1); 279 | for(i=0;i<6;i++) { 280 | int x; 281 | x = s->ucode_to_linear[s->ucode[p]]; 282 | if (((signs >> i) & 1) == 0) 283 | x = -x; 284 | 285 | samples[i] = x; 286 | p = (p + 1) & (UCODE_BUF_SIZE - 1); 287 | } 288 | } 289 | 290 | /* 291 | * converts 6 a/u law samples to (S+K) data bits 292 | */ 293 | static void v90_decode_mapping_frame(V90DecodeState *s, u8 *data, s16 *samples) 294 | { 295 | s16 *tab; 296 | int d1, d2, i, j, l, val, v, m_min, m_max, m; 297 | u8 signs[6]; 298 | u64 bitbuf; 299 | 300 | /* find signs & ucode */ 301 | bitbuf = 0; 302 | for(j=5;j>=0;j--) { 303 | val = samples[j]; 304 | if (val < 0) { 305 | val = - val; 306 | signs[j] = 0; 307 | } else { 308 | signs[j] = 1; 309 | } 310 | /* We look for the value closest to val with a binary search: 311 | see Knuth section 6.2 exercice 1. */ 312 | tab = &s->m_to_linear[j][0]; 313 | m_min = 0; 314 | m_max = s->M[j] - 1; 315 | while (m_min <= m_max) { 316 | m = (m_min + m_max) >> 1; 317 | v = tab[m]; 318 | if (v == val) 319 | goto found; 320 | else if (val > v) { 321 | m_max = m - 1; 322 | } else { 323 | m_min = m + 1; 324 | } 325 | } 326 | d1 = tab[m_max] - val; 327 | d2 = val - tab[m_min]; 328 | if (d1 < d2) 329 | m = m_max; 330 | else 331 | m = m_min; 332 | found: 333 | /* now we update the modulo value */ 334 | bitbuf = bitbuf * s->M[j] + m; 335 | } 336 | 337 | /* output the K bits */ 338 | for(i=0;iK;i++) 339 | data[i + s->S] = (bitbuf >> i) & 1; 340 | 341 | switch(s->S) { 342 | default: 343 | case 6: 344 | /* no redundant bit */ 345 | l = s->last_sign; 346 | for(i=0;i<6;i++) { 347 | data[i] = l ^ signs[i]; 348 | l = signs[i]; 349 | } 350 | s->last_sign = l; 351 | break; 352 | case 5: 353 | /* 1 redundant bit */ 354 | { 355 | int pp1, pp3, pp5, t0, pv0, Q1; 356 | 357 | t0 = 0; 358 | for(i=0;i<6;i++) 359 | t0 |= (signs[i] << i); 360 | 361 | pv0 = s->t ^ t0; 362 | Q1 = (pv0 & 1) ^ s->Q; 363 | pv0 ^= sign_op[s->Q | (Q1 << 1)] & 0x3f; 364 | s->t = t0; 365 | s->Q = Q1; 366 | 367 | /* extract the data bits */ 368 | data[1] = (pv0 >> 2) & 1; 369 | data[3] = (pv0 >> 4) & 1; 370 | pp1 = ((pv0 >> 1) & 1); 371 | pp3 = ((pv0 >> 3) & 1); 372 | pp5 = ((pv0 >> 5) & 1); 373 | data[0] = pp1 ^ s->last_sign; 374 | data[2] = pp1 ^ pp3; 375 | data[4] = pp3 ^ pp5; 376 | s->last_sign = pp5; 377 | } 378 | break; 379 | case 4: 380 | /* 2 redundant bits */ 381 | { 382 | int pp1, pp4, t0, t1, pv0, pv1, Q1, Q2; 383 | 384 | t0 = signs[0] | (signs[1] << 1) | (signs[2] << 2); 385 | t1 = signs[3] | (signs[4] << 1) | (signs[5] << 2); 386 | 387 | pv0 = s->t ^ t0; 388 | Q1 = (pv0 & 1) ^ s->Q; 389 | pv0 ^= sign_op[s->Q | (Q1 << 1)] & 7; 390 | 391 | pv1 = t0 ^ t1; 392 | Q2 = (pv1 & 1) ^ Q1; 393 | pv1 ^= sign_op[Q1 | (Q2 << 1)] & 7; 394 | 395 | s->t = t1; 396 | s->Q = Q2; 397 | 398 | data[1] = (pv0 >> 2) & 1; 399 | data[3] = (pv1 >> 2) & 1; 400 | pp1 = (pv0 >> 1) & 1; 401 | pp4 = (pv1 >> 1) & 1; 402 | data[0] = pp1 ^ s->last_sign; 403 | data[2] = pp4 ^ pp1; 404 | s->last_sign = pp4; 405 | } 406 | break; 407 | case 3: 408 | /* 3 redundant bits */ 409 | { 410 | int pp1, pp3, pp5, t0, t1, t2, pv0, pv1, pv2, Q1, Q2, Q3; 411 | 412 | t0 = signs[0] | (signs[1] << 1); 413 | t1 = signs[2] | (signs[3] << 1); 414 | t2 = signs[4] | (signs[5] << 1); 415 | 416 | pv0 = s->t ^ t0; 417 | Q1 = (pv0 & 1) ^ s->Q; 418 | pv0 ^= sign_op[s->Q | (Q1 << 1)] & 3; 419 | 420 | pv1 = t0 ^ t1; 421 | Q2 = (pv1 & 1) ^ Q1; 422 | pv1 ^= sign_op[Q1 | (Q2 << 1)] & 3; 423 | 424 | pv2 = t1 ^ t2; 425 | Q3 = (pv2 & 1) ^ Q2; 426 | pv2 ^= sign_op[Q2 | (Q3 << 1)] & 3; 427 | 428 | s->t = t2; 429 | s->Q = Q3; 430 | 431 | pp1 = (pv0 >> 1) & 1; 432 | pp3 = (pv1 >> 1) & 1; 433 | pp5 = (pv2 >> 1) & 1; 434 | 435 | data[0] = pp1 ^ s->last_sign; 436 | data[1] = pp3 ^ pp1; 437 | data[2] = pp5 ^ pp3; 438 | s->last_sign = pp5; 439 | } 440 | break; 441 | } 442 | } 443 | 444 | static void compute_constellation(V90EncodeState *s, 445 | u8 m_index[6], u8 ucode_used[6][128]) 446 | { 447 | int i,j,k,m; 448 | 449 | /* the ucode are taken from the bigger value down to the smaller value */ 450 | for(j=0;j<6;j++) { 451 | k = m_index[j]; 452 | m = 0; 453 | for(i=127;i>=0;i--) { 454 | if (ucode_used[k][i]) { 455 | s->m_to_ucode[j][m] = i; 456 | m++; 457 | } 458 | } 459 | s->M[j] = m; 460 | } 461 | 462 | #ifdef DEBUG 463 | for(j=0;j<6;j++) { 464 | printf("M[%d]: ", j); 465 | for(i=0;iM[j];i++) { 466 | printf("%3d ", s->m_to_ucode[j][i]); 467 | } 468 | printf("\n"); 469 | } 470 | #endif 471 | } 472 | 473 | 474 | void v90_encode_init(V90EncodeState *s) 475 | { 476 | } 477 | 478 | 479 | 480 | void v90_decode_init(V90DecodeState *s) 481 | { 482 | int i,j,m; 483 | 484 | /* some test values (You can modify them to test the 485 | modulator/demodulator) */ 486 | for(i=0;i<6;i++) { 487 | for(j=0;j<16;j++) 488 | s->ucode_used[i][10 + j * 6] = 1; 489 | } 490 | 491 | s->K = 4 * 6; 492 | s->S = 5; 493 | s->alaw = 1; 494 | s->ld = 2; 495 | s->a1 = (int) (0.1 * 64); 496 | s->a2 = (int) (0.2 * 64); 497 | s->b1 = (int) (-0.1 * 64); 498 | s->b2 = (int) (0.1 * 64); 499 | 500 | 501 | /* we suppose that all other values are set to zero */ 502 | 503 | 504 | /* compute the decode tables */ 505 | if (s->alaw) 506 | s->ucode_to_linear = v90_alaw_ucode_to_linear; 507 | else 508 | s->ucode_to_linear = v90_ulaw_ucode_to_linear; 509 | 510 | for(j=0;j<6;j++) { 511 | m = 0; 512 | for(i=127;i>=0;i--) { 513 | if (s->ucode_used[j][i]) { 514 | s->m_to_linear[j][m] = s->ucode_to_linear[i]; 515 | m++; 516 | } 517 | } 518 | s->M[j] = m; 519 | } 520 | } 521 | 522 | static u8 test_buf[1000]; 523 | 524 | /* send a CP frame (analog modem) */ 525 | static void v90_send_CP(V90DecodeState *s, int is_CP, int ack) 526 | { 527 | u8 *buf, *p; 528 | int i, crc, drn; 529 | 530 | buf = test_buf; 531 | 532 | p = buf; 533 | put_bits(&p, 17, 0x1ffff); /* frame sync */ 534 | 535 | put_bits(&p, 1, 0); /* start bit */ 536 | put_bits(&p, 1, 0); /* reserved */ 537 | put_bits(&p, 1, is_CP); /* 0=CPt 1=CP frame */ 538 | drn = s->K + s->S; 539 | if (is_CP) 540 | drn -= 20; 541 | else 542 | drn -= 8; 543 | put_bits(&p, 5, drn); /* drn: speed */ 544 | put_bits(&p, 5, 0); /* reserved */ 545 | put_bits(&p, 1, 0); /* 1 if silence asked */ 546 | put_bits(&p, 2, 6 - s->S); /* Sr */ 547 | put_bits(&p, 1, ack); /* ack */ 548 | 549 | put_bits(&p, 1, 0); /* start bit */ 550 | put_bits(&p, 1, s->alaw); /* u/a law selection */ 551 | for(i=0;i<13;i++) { 552 | put_bits(&p, 1, 1); /* speed (i+2) * 2400 supported (V34 part) */ 553 | } 554 | put_bits(&p, 2, s->ld); 555 | 556 | put_bits(&p, 1, 0); /* start bit */ 557 | put_bits(&p, 16, 0); /* RMS value for TRN1d */ 558 | 559 | put_bits(&p, 1, 0); /* start bit */ 560 | put_bits(&p, 8, s->a1 & 0xff); /* spectral shaping parameters */ 561 | put_bits(&p, 8, s->a2 & 0xff); /* spectral shaping parameters */ 562 | put_bits(&p, 1, 0); /* start bit */ 563 | put_bits(&p, 8, s->b1 & 0xff); /* spectral shaping parameters */ 564 | put_bits(&p, 8, s->b2 & 0xff); /* spectral shaping parameters */ 565 | 566 | put_bits(&p, 1, 0); /* start bit */ 567 | for(i=0;i<6;i++) { 568 | if (i == 4) 569 | put_bits(&p, 1, 0); /* start bit */ 570 | put_bits(&p, 4, 0); /* modulation index */ 571 | } 572 | 573 | put_bits(&p, 1, 0); /* different different tx - D/A constellations ? */ 574 | put_bits(&p, 7, 0); /* reserved */ 575 | 576 | /* transmit the constellation */ 577 | for(i=0;i<128;i++) { 578 | if ((i & 15) == 0) 579 | put_bits(&p, 1, 0); /* start bit */ 580 | put_bits(&p, 1, s->ucode_used[0][i]); 581 | } 582 | 583 | /* CRC */ 584 | put_bits(&p, 1, 0); /* start bit */ 585 | crc = calc_crc(buf + 17, p - (buf+17)); 586 | put_bits(&p, 16, crc); 587 | 588 | put_bits(&p, 3, 0); /* fill */ 589 | printf("CP size= %d\n", p - buf); 590 | } 591 | 592 | static int get_bit(u8 **pp) 593 | { 594 | u8 *p; 595 | int v; 596 | 597 | p = *pp; 598 | v = *p++; 599 | *pp = p; 600 | return v; 601 | } 602 | 603 | 604 | static int get_bits(u8 *p, int n) 605 | { 606 | int i, v; 607 | 608 | v = 0; 609 | for(i=n-1;i>=0;i--) { 610 | v |= *p++ << i; 611 | } 612 | return v; 613 | } 614 | 615 | /* parse the CP packet & compute the V90 parameters */ 616 | static void v90_parse_CP(V90EncodeState *s, u8 *buf) 617 | { 618 | u8 m_index[6]; 619 | u8 ucode_used[7][128]; 620 | int drn, i, j, k, nb_constellations; 621 | 622 | /* now the whole packet is can be read */ 623 | 624 | s->S = 6 - get_bits(buf + 31, 2); 625 | s->alaw = get_bits(buf + 35, 1); 626 | s->ld = get_bits(buf + 49, 2); 627 | s->a1 = (s8) get_bits(buf + 69, 8); 628 | s->a2 = (s8) get_bits(buf + 77, 8); 629 | s->b1 = (s8) get_bits(buf + 86, 8); 630 | s->b2 = (s8) get_bits(buf + 94, 8); 631 | 632 | for(i=0;i<4;i++) 633 | m_index[i] = get_bits(buf + 103 + i * 4, 4); 634 | 635 | for(i=0;i<2;i++) 636 | m_index[4 + i] = get_bits(buf + 120 + i * 4, 4); 637 | nb_constellations = 0; 638 | for(i=0;i<6;i++) { 639 | if (m_index[i] > nb_constellations) nb_constellations = m_index[i]; 640 | } 641 | nb_constellations++; 642 | if (buf[128]) 643 | nb_constellations++; 644 | 645 | for(i=0;i> 4)) + (k & 15)]; 649 | } 650 | } 651 | 652 | /* compute K */ 653 | drn = get_bits(buf + 20, 5); 654 | if (buf[19]) 655 | drn += 20; 656 | else 657 | drn += 8; 658 | s->K = drn - s->S; 659 | 660 | if (s->alaw) 661 | s->ucode_to_linear = v90_alaw_ucode_to_linear; 662 | else 663 | s->ucode_to_linear = v90_ulaw_ucode_to_linear; 664 | 665 | printf("V90_received_CP:\n"); 666 | compute_constellation(s, m_index, ucode_used); 667 | 668 | printf("S=%d K=%d R=%d alaw=%d ld=%d a1=%d a2=%d b1=%d b2=%d\n", 669 | s->S, s->K, ((s->S + s->K) * 8000) / 6, 670 | s->alaw, s->ld, s->a1, s->a2, s->b1, s->b2); 671 | } 672 | 673 | /* received & parse the CP packet */ 674 | static void v90_receive_CP(V90EncodeState *s) 675 | { 676 | u8 buf[1024], *p, *q; 677 | int b, i, frame_index, one_count, frame_count, nb_constellations; 678 | int crc1; 679 | u8 m_index[6]; 680 | 681 | p = test_buf; 682 | 683 | wait_sync: 684 | one_count = 0; 685 | 686 | while (get_bit(&p)) { 687 | one_count++; 688 | } 689 | if (one_count != 17) 690 | goto wait_sync; 691 | 692 | #ifdef DEBUG 693 | printf("got CP sync\n"); 694 | #endif 695 | 696 | frame_index = 0; 697 | frame_count = 8; 698 | crc1 = 1; 699 | q = buf + 17; 700 | while (frame_index < frame_count) { 701 | printf("%2d: ", frame_index); 702 | *q++ = 0; 703 | for(i=0;i<16;i++) { 704 | b = get_bit(&p); 705 | *q++ = b; 706 | printf("%d", b); 707 | } 708 | printf("\n"); 709 | 710 | if (frame_index == 6) { 711 | /* compute the number of constellation to read */ 712 | for(i=0;i<4;i++) { 713 | m_index[i] = get_bits(buf + 103 + i * 4, 4); 714 | } 715 | for(i=0;i<2;i++) { 716 | m_index[4 + i] = get_bits(buf + 120 + i * 4, 4); 717 | } 718 | nb_constellations = 0; 719 | for(i=0;i<6;i++) { 720 | if (m_index[i] > nb_constellations) nb_constellations = m_index[i]; 721 | } 722 | nb_constellations++; 723 | if (buf[128]) 724 | nb_constellations++; 725 | frame_count += 8 * nb_constellations; 726 | } 727 | 728 | if (frame_index == (frame_count - 1)) { 729 | /* check the crc (it must be zero because we include the crc itself) */ 730 | crc1 = calc_crc(buf + 17, q - (buf+17)); 731 | } 732 | 733 | if (get_bit(&p) != 0) { 734 | printf("start bit expected\n"); 735 | goto wait_sync; 736 | } 737 | frame_index++; 738 | } 739 | if (crc1 != 0) 740 | goto wait_sync; 741 | 742 | v90_parse_CP(s, buf); 743 | } 744 | 745 | /* simple test of V90 algebraic computations */ 746 | /* Note: if ld != 0 and 3 <= S <= 4, the delay introduced with data[][] 747 | is not correct */ 748 | 749 | void V90_test(void) 750 | { 751 | int i,j,n,l; 752 | V90EncodeState v90_enc; 753 | V90DecodeState v90_dec; 754 | u8 data[5][48], data1[48]; 755 | s16 samples[6]; 756 | 757 | /* init modem state */ 758 | memset(&v90_enc, 0, sizeof(v90_enc)); 759 | v90_encode_init(&v90_enc); 760 | 761 | memset(&v90_dec, 0, sizeof(v90_dec)); 762 | v90_decode_init(&v90_dec); 763 | 764 | /* send the CP sequence which contains the modulation parameters */ 765 | v90_send_CP(&v90_dec, 1, 0); 766 | 767 | /* "receive" it ! */ 768 | v90_receive_CP(&v90_enc); 769 | 770 | /* number of data bits per mapping frame */ 771 | n = v90_enc.S + v90_enc.K; 772 | 773 | /* transmit & receive 1000 mapping frames */ 774 | memset(data, 0, sizeof(data)); 775 | l = 0; 776 | for(i=0;i<1000;i++) { 777 | for(j=0;j 15 | #include 16 | #include 17 | 18 | /* from g711.c by SUN microsystems (unrestricted use) */ 19 | 20 | #define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ 21 | #define QUANT_MASK (0xf) /* Quantization field mask. */ 22 | #define NSEGS (8) /* Number of A-law segments. */ 23 | #define SEG_SHIFT (4) /* Left shift for segment number. */ 24 | #define SEG_MASK (0x70) /* Segment field mask. */ 25 | 26 | #define BIAS (0x84) /* Bias for linear code. */ 27 | /* 28 | * alaw2linear() - Convert an A-law value to 16-bit linear PCM 29 | * 30 | */ 31 | int 32 | alaw2linear(a_val) 33 | unsigned char a_val; 34 | { 35 | int t; 36 | int seg; 37 | 38 | a_val ^= 0x55; 39 | 40 | t = (a_val & QUANT_MASK) << 4; 41 | seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; 42 | switch (seg) { 43 | case 0: 44 | t += 8; 45 | break; 46 | case 1: 47 | t += 0x108; 48 | break; 49 | default: 50 | t += 0x108; 51 | t <<= seg - 1; 52 | } 53 | return ((a_val & SIGN_BIT) ? t : -t); 54 | } 55 | 56 | int 57 | ulaw2linear(u_val) 58 | unsigned char u_val; 59 | { 60 | int t; 61 | 62 | /* Complement to obtain normal u-law value. */ 63 | u_val = ~u_val; 64 | 65 | /* 66 | * Extract and bias the quantization bits. Then 67 | * shift up by the segment number and subtract out the bias. 68 | */ 69 | t = ((u_val & QUANT_MASK) << 3) + BIAS; 70 | t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; 71 | 72 | return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); 73 | } 74 | 75 | int main(int argc, char **argv) 76 | { 77 | int i; 78 | 79 | printf("/* THIS SOURCE CODE IS AUTOMATICALLY GENERATED - DO NOT MODIFY */\n"); 80 | 81 | printf("/*\n" 82 | " * V90 tables\n" 83 | " * \n" 84 | " * Copyright (c) 1999 Fabrice Bellard.\n" 85 | " *\n" 86 | " * This code is released under the GNU General Public License version\n" 87 | " * 2. Please read the file COPYING to know the exact terms of the\n" 88 | " * license.\n" 89 | " */\n"); 90 | 91 | printf("#include \"lm.h\"\n" 92 | "#include \"v90priv.h\"\n" 93 | "\n"); 94 | 95 | printf("const s16 v90_ulaw_ucode_to_linear[128]= {\n"); 96 | for(i=0;i<128;i++) { 97 | printf("%5d,", ulaw2linear(i ^ 0xff)); 98 | if ((i & 7) == 7) printf("\n"); 99 | } 100 | printf("};\n"); 101 | 102 | printf("const s16 v90_alaw_ucode_to_linear[128]= {\n"); 103 | for(i=0;i<128;i++) { 104 | printf("%5d,", alaw2linear(i ^ 0xd5)); 105 | if ((i & 7) == 7) printf("\n"); 106 | } 107 | printf("};\n"); 108 | 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /v90priv.h: -------------------------------------------------------------------------------- 1 | #ifndef V90PRIV_H 2 | #define V90PRIV_H 3 | 4 | #define V90_SAMPLE_RATE 8000 5 | #define TREILLIS_MAX_DEPTH 4 6 | /* ring buffer size of the previous ucodes : must be a power of two */ 7 | #define UCODE_BUF_SIZE (TREILLIS_MAX_DEPTH * 8) 8 | 9 | /* state of the signal processing part of the V90 modem */ 10 | typedef struct V90EncodeState { 11 | struct sm_state *sm; 12 | 13 | int alaw; /* true=alaw, false=ulaw */ 14 | 15 | /* frame parameters (a frame = 6 PAM values) */ 16 | int S; /* sign bits (3 <= S <= 6) */ 17 | int K; /* number of bits for the ring coder */ 18 | int a1, a2, b1, b2; /* spectral conformer parameters */ 19 | 20 | int M[6]; /* ring size */ 21 | u8 m_to_ucode[6][128]; /* encoding table */ 22 | int ld; /* depth for spectral shaping (0 <= ld <= 3) */ 23 | 24 | /* sign mapper */ 25 | int ucode_ptr; /* index of the first pam value of the 26 | current mapping frame */ 27 | u8 ucode[UCODE_BUF_SIZE]; /* current output of the modulator */ 28 | u8 pp[UCODE_BUF_SIZE]; /* corresponding signs (grouped by frame) */ 29 | int last_sign; /* sign of the last computed frame */ 30 | 31 | /* spectral shaping treillis */ 32 | u8 t; /* signs of the frame */ 33 | s16 x; /* last x value: not stricly needed, but simply the treillis computation */ 34 | s16 y; /* memory for spectral shaping filter */ 35 | s16 v; /* idem */ 36 | s16 w; /* idem */ 37 | int Q; /* current shaping treillis state 38 | (with a delay of ld) */ 39 | const s16 *ucode_to_linear; /* table to retrieve the linear values from ucodes */ 40 | } V90EncodeState; 41 | 42 | const s16 v90_ulaw_ucode_to_linear[128]; 43 | const s16 v90_alaw_ucode_to_linear[128]; 44 | 45 | typedef struct V90DecodeState { 46 | struct sm_state *sm; 47 | 48 | int alaw; /* true=alaw, false=ulaw */ 49 | 50 | /* frame parameters (a frame = 6 PAM values) */ 51 | int S; /* sign bits (3 <= S <= 6) */ 52 | int K; /* number of bits for the ring coder */ 53 | 54 | int M[6]; /* ring size */ 55 | u8 ucode_used[6][128]; 56 | s16 m_to_linear[6][128]; /* give the estimated linear value of each received modulo */ 57 | int ld; 58 | s8 a1, a2, b1, b2; 59 | int last_sign; 60 | int t; 61 | int Q; 62 | const s16 *ucode_to_linear; /* table to retrieve the linear values from ucodes */ 63 | } V90DecodeState; 64 | 65 | #endif 66 | --------------------------------------------------------------------------------