diff options
author | jdixon <jdixon@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-09-14 00:34:13 +0000 |
---|---|---|
committer | jdixon <jdixon@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-09-14 00:34:13 +0000 |
commit | d2a6abb108dfc6464a7a8d610349b79490bca137 (patch) | |
tree | 32c4e4f89b8d3cbf8b42a183197bce1b6d0fd5ff /channels/xpmr | |
parent | cb7cdf96a39392d713753d099e6e1521826dde14 (diff) |
Added channel driver for USB Radio device and
support thereof.
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@82366 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/xpmr')
-rwxr-xr-x | channels/xpmr/LICENSE | 341 | ||||
-rwxr-xr-x | channels/xpmr/sinetabx.h | 300 | ||||
-rwxr-xr-x | channels/xpmr/xpmr.c | 2266 | ||||
-rwxr-xr-x | channels/xpmr/xpmr.h | 553 | ||||
-rwxr-xr-x | channels/xpmr/xpmr_coef.h | 963 |
5 files changed, 4423 insertions, 0 deletions
diff --git a/channels/xpmr/LICENSE b/channels/xpmr/LICENSE new file mode 100755 index 000000000..a52b16e40 --- /dev/null +++ b/channels/xpmr/LICENSE @@ -0,0 +1,341 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/channels/xpmr/sinetabx.h b/channels/xpmr/sinetabx.h new file mode 100755 index 000000000..1ceb659e7 --- /dev/null +++ b/channels/xpmr/sinetabx.h @@ -0,0 +1,300 @@ +/* + * sinetabx.h - for Xelatec Private Mobile Radio Processes + * + * All Rights Reserved. Copyright (C)2007, Xelatec, LLC + * + * 20070808 1235 Steven Henke, W9SH, sph@xelatec.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This version may be optionally licenced under the GNU LGPL licence. + * + * A license has been granted to Digium (via disclaimer) for the use of + * this code. + * + */ + +/*! \file + * + * \brief Private Land Mobile Radio Channel Voice and Signaling Processor + * + * \author Steven Henke, W9SH <sph@xelatec.com> Xelatec, LLC + */ + +#ifndef XPMR_SINETABX_H +#define XPMR_SINETABX_H 1 + +#define SAMPLES_PER_SINE 256 + +const i16 sinetablex[]={ +0, // 0 +804, // 1 +1608, // 2 +2410, // 3 +3212, // 4 +4011, // 5 +4808, // 6 +5602, // 7 +6393, // 8 +7179, // 9 +7962, // 10 +8739, // 11 +9512, // 12 +10278, // 13 +11039, // 14 +11793, // 15 +12539, // 16 +13279, // 17 +14010, // 18 +14732, // 19 +15446, // 20 +16151, // 21 +16846, // 22 +17530, // 23 +18204, // 24 +18868, // 25 +19519, // 26 +20159, // 27 +20787, // 28 +21403, // 29 +22005, // 30 +22594, // 31 +23170, // 32 +23731, // 33 +24279, // 34 +24811, // 35 +25329, // 36 +25832, // 37 +26319, // 38 +26790, // 39 +27245, // 40 +27683, // 41 +28105, // 42 +28510, // 43 +28898, // 44 +29268, // 45 +29621, // 46 +29956, // 47 +30273, // 48 +30571, // 49 +30852, // 50 +31113, // 51 +31356, // 52 +31580, // 53 +31785, // 54 +31971, // 55 +32137, // 56 +32285, // 57 +32412, // 58 +32521, // 59 +32609, // 60 +32678, // 61 +32728, // 62 +32757, // 63 +32767, // 64 +32757, // 65 +32728, // 66 +32678, // 67 +32609, // 68 +32521, // 69 +32412, // 70 +32285, // 71 +32137, // 72 +31971, // 73 +31785, // 74 +31580, // 75 +31356, // 76 +31113, // 77 +30852, // 78 +30571, // 79 +30273, // 80 +29956, // 81 +29621, // 82 +29268, // 83 +28898, // 84 +28510, // 85 +28105, // 86 +27683, // 87 +27245, // 88 +26790, // 89 +26319, // 90 +25832, // 91 +25329, // 92 +24811, // 93 +24279, // 94 +23731, // 95 +23170, // 96 +22594, // 97 +22005, // 98 +21403, // 99 +20787, // 100 +20159, // 101 +19519, // 102 +18868, // 103 +18204, // 104 +17530, // 105 +16846, // 106 +16151, // 107 +15446, // 108 +14732, // 109 +14010, // 110 +13279, // 111 +12539, // 112 +11793, // 113 +11039, // 114 +10278, // 115 +9512, // 116 +8739, // 117 +7962, // 118 +7179, // 119 +6393, // 120 +5602, // 121 +4808, // 122 +4011, // 123 +3212, // 124 +2410, // 125 +1608, // 126 +804, // 127 +0, // 128 +-804, // 129 +-1608, // 130 +-2410, // 131 +-3212, // 132 +-4011, // 133 +-4808, // 134 +-5602, // 135 +-6393, // 136 +-7179, // 137 +-7962, // 138 +-8739, // 139 +-9512, // 140 +-10278, // 141 +-11039, // 142 +-11793, // 143 +-12539, // 144 +-13279, // 145 +-14010, // 146 +-14732, // 147 +-15446, // 148 +-16151, // 149 +-16846, // 150 +-17530, // 151 +-18204, // 152 +-18868, // 153 +-19519, // 154 +-20159, // 155 +-20787, // 156 +-21403, // 157 +-22005, // 158 +-22594, // 159 +-23170, // 160 +-23731, // 161 +-24279, // 162 +-24811, // 163 +-25329, // 164 +-25832, // 165 +-26319, // 166 +-26790, // 167 +-27245, // 168 +-27683, // 169 +-28105, // 170 +-28510, // 171 +-28898, // 172 +-29268, // 173 +-29621, // 174 +-29956, // 175 +-30273, // 176 +-30571, // 177 +-30852, // 178 +-31113, // 179 +-31356, // 180 +-31580, // 181 +-31785, // 182 +-31971, // 183 +-32137, // 184 +-32285, // 185 +-32412, // 186 +-32521, // 187 +-32609, // 188 +-32678, // 189 +-32728, // 190 +-32757, // 191 +-32767, // 192 +-32757, // 193 +-32728, // 194 +-32678, // 195 +-32609, // 196 +-32521, // 197 +-32412, // 198 +-32285, // 199 +-32137, // 200 +-31971, // 201 +-31785, // 202 +-31580, // 203 +-31356, // 204 +-31113, // 205 +-30852, // 206 +-30571, // 207 +-30273, // 208 +-29956, // 209 +-29621, // 210 +-29268, // 211 +-28898, // 212 +-28510, // 213 +-28105, // 214 +-27683, // 215 +-27245, // 216 +-26790, // 217 +-26319, // 218 +-25832, // 219 +-25329, // 220 +-24811, // 221 +-24279, // 222 +-23731, // 223 +-23170, // 224 +-22594, // 225 +-22005, // 226 +-21403, // 227 +-20787, // 228 +-20159, // 229 +-19519, // 230 +-18868, // 231 +-18204, // 232 +-17530, // 233 +-16846, // 234 +-16151, // 235 +-15446, // 236 +-14732, // 237 +-14010, // 238 +-13279, // 239 +-12539, // 240 +-11793, // 241 +-11039, // 242 +-10278, // 243 +-9512, // 244 +-8739, // 245 +-7962, // 246 +-7179, // 247 +-6393, // 248 +-5602, // 249 +-4808, // 250 +-4011, // 251 +-3212, // 252 +-2410, // 253 +-1608, // 254 +-804, // 255 +}; + +#endif /* !XPMR_SINETABX_H */ diff --git a/channels/xpmr/xpmr.c b/channels/xpmr/xpmr.c new file mode 100755 index 000000000..c67e40841 --- /dev/null +++ b/channels/xpmr/xpmr.c @@ -0,0 +1,2266 @@ +/* + * xpmr.c - Xelatec Private Mobile Radio Processes + * + * All Rights Reserved. Copyright (C)2007, Xelatec, LLC + * + * 20070808 1235 Steven Henke, W9SH, sph@xelatec.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This version may be optionally licenced under the GNU LGPL licence. + * + * A license has been granted to Digium (via disclaimer) for the use of + * this code. + * + */ + +/*! \file + * + * \brief Private Land Mobile Radio Channel Voice and Signaling Processor + * + * \author Steven Henke, W9SH <sph@xelatec.com> Xelatec, LLC + */ +/* + FYI = For Your Information + PMR = Private Mobile Radio + RX = Receive + TX = Transmit + CTCSS = Continuous Tone Coded Squelch System + TONE = Same as above. + LSD = Low Speed Data, subaudible signaling. May be tones or codes. + VOX = Voice Operated Transmit + DSP = Digital Signal Processing + LPF = Low Pass Filter + FIR = Finite Impulse Response (Filter) + IIR = Infinite Impulse Response (Filter) +*/ +#include <stdio.h> +#include <ctype.h> +#include <math.h> +#include <string.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <sys/time.h> +#include <stdlib.h> +#include <errno.h> + +#include "xpmr.h" +#include "xpmr_coef.h" +#include "sinetabx.h" + +static i16 pmrChanIndex=0; // count of created pmr instances + +/* + Convert a Frequency in Hz to a zero based CTCSS Table index +*/ +i16 CtcssFreqIndex(float freq) +{ + i16 i,hit=-1; + + for(i=0;i<CTCSS_NUM_CODES;i++){ + if(freq==freq_ctcss[i])hit=i; + } + return hit; +} +/* + pmr_rx_frontend + Takes a block of data and low pass filters it. + Determines the amplitude of high frequency noise for carrier detect. + Decimates input data to change the rate. +*/ +i16 pmr_rx_frontend(t_pmr_sps *mySps) +{ + #define DCgainBpfNoise 65536 + + i16 samples,iOutput, *input, *output, *noutput; + i16 *x, *coef, *coef2; + i32 i, naccum, outputGain, calcAdjust; + i64 y; + i16 nx, hyst, setpt, compOut; + i16 amax, amin, apeak, discounteru, discounterl, discfactor; + i16 decimator, decimate, doNoise; + + TRACEX(("pmr_rx_frontend()\n")); + + if(!mySps->enabled)return(1); + + decimator = mySps->decimator; + decimate = mySps->decimate; + + input = mySps->source; + output = mySps->sink; + noutput = mySps->parentChan->pRxNoise; + + nx = mySps->nx; + coef = mySps->coef; + coef2 = mySps->coef2; + + calcAdjust = mySps->calcAdjust; + outputGain = mySps->outputGain; + + amax=mySps->amax; + amin=mySps->amin; + apeak=mySps->apeak; + discounteru=mySps->discounteru; + discounterl=mySps->discounterl; + discfactor=mySps->discfactor; + setpt=mySps->setpt; + hyst=mySps->hyst; + compOut=mySps->compOut; + + samples=mySps->nSamples*decimate; + x=mySps->x; + iOutput=0; + + if(mySps->parentChan->rxCdType!=CD_XPMR_VOX)doNoise=1; + else doNoise=0; + + for(i=0;i<samples;i++) + { + i16 n; + + //shift the old samples + for(n=nx-1; n>0; n--) + x[n] = x[n-1]; + + x[0] = input[i*2]; + + --decimator; + + if(decimator<=0) + { + decimator=decimate; + + y=0; + for(n=0; n<nx; n++) + y += coef[n] * x[n]; + + y=((y/calcAdjust)*outputGain)/M_Q8; + + if(y>32767)y=32767; + else if(y<-32767)y=-32767; + + output[iOutput]=y; // Rx Baseband decimated + noutput[iOutput++] = apeak; // Rx Noise + } + + if(doNoise) + { + // calculate noise output + naccum=0; + for(n=0; n<nx; n++) + naccum += coef_fir_bpf_noise_1[n] * x[n]; + + naccum /= DCgainBpfNoise; + + if(naccum>amax) + { + amax=naccum; + discounteru=discfactor; + } + else if(--discounteru<=0) + { + discounteru=discfactor; + amax=(i32)((amax*32700)/32768); + } + + if(naccum<amin) + { + amin=naccum; + discounterl=discfactor; + } + else if(--discounterl<=0) + { + discounterl=discfactor; + amin=(i32)((amin*32700)/32768); + } + + apeak=(amax-amin)/2; + + } // if doNoise + } + + if(doNoise) + { + ((t_pmr_chan *)(mySps->parentChan))->rxRssi=apeak; + + if(apeak>setpt || (compOut&&(apeak>(setpt-hyst)))) compOut=1; + else compOut=0; + mySps->compOut=compOut; + mySps->amax=amax; + mySps->amin=amin; + mySps->apeak=apeak; + mySps->discounteru=discounteru; + mySps->discounterl=discounterl; + } + + return 0; +} +/* + pmr general purpose fir + works on a block of samples +*/ +i16 pmr_gp_fir(t_pmr_sps *mySps) +{ + i32 nsamples,inputGain,outputGain,calcAdjust; + i16 *input, *output; + i16 *x, *coef; + i32 i, ii; + i16 nx, hyst, setpt, compOut; + i16 amax, amin, apeak=0, discounteru=0, discounterl=0, discfactor; + i16 decimator, decimate, interpolate; + i16 numChanOut, selChanOut, mixOut, monoOut; + + TRACEX(("pmr_gp_fir() %i\n",mySps->enabled)); + + if(!mySps->enabled)return(1); + + inputGain = mySps->inputGain; + calcAdjust = mySps->calcAdjust; + outputGain = mySps->outputGain; + + input = mySps->source; + output = mySps->sink; + x = mySps->x; + nx = mySps->nx; + coef = mySps->coef; + + decimator = mySps->decimator; + decimate = mySps->decimate; + interpolate = mySps->interpolate; + + setpt = mySps->setpt; + compOut = mySps->compOut; + + inputGain = mySps->inputGain; + outputGain = mySps->outputGain; + numChanOut = mySps->numChanOut; + selChanOut = mySps->selChanOut; + mixOut = mySps->mixOut; + monoOut = mySps->monoOut; + + amax=mySps->amax; + amin=mySps->amin; + + discfactor=mySps->discfactor; + hyst=mySps->hyst; + setpt=mySps->setpt; + nsamples=mySps->nSamples; + + if(mySps->option==3) + { + mySps->option=0; + mySps->enabled=0; + for(i=0;i<nsamples;i++) + { + if(monoOut) + output[(i*2)]=output[(i*2)+1]=0; + else + output[(i*numChanOut)+selChanOut]=0; + } + return 0; + } + + ii=0; + for(i=0;i<nsamples;i++) + { + int ix; + + int64_t y=0; + + if(decimate<0) + { + decimator=decimate; + } + + for(ix=0;ix<interpolate;ix++) + { + i16 n; + y=0; + + for(n=nx-1; n>0; n--) + x[n] = x[n-1]; + x[0] = (input[i]*inputGain)/M_Q8; + + #if 0 + --decimator; + if(decimator<=0) + { + decimator=decimate; + for(n=0; n<nx; n++) + y += coef[n] * x[n]; + y /= (outputGain*3); + output[ii++]=y; + } + #else + for(n=0; n<nx; n++) + y += coef[n] * x[n]; + + y=((y/calcAdjust)*outputGain)/M_Q8; + + if(mixOut){ + if(monoOut){ + output[(ii*2)]=output[(ii*2)+1]+=y; + } + else{ + output[(ii*numChanOut)+selChanOut]+=y; + } + } + else{ + if(monoOut){ + output[(ii*2)]=output[(ii*2)+1]=y; + } + else{ + output[(ii*numChanOut)+selChanOut]=y; + } + } + ii++; + #endif + } + + // amplitude detector + if(setpt) + { + i16 accum=y; + + if(accum>amax) + { + amax=accum; + discounteru=discfactor; + } + else if(--discounteru<=0) + { + discounteru=discfactor; + amax=(i32)((amax*32700)/32768); + } + + if(accum<amin) + { + amin=accum; + discounterl=discfactor; + } + else if(--discounterl<=0) + { + discounterl=discfactor; + amin=(i32)((amin*32700)/32768); + } + + apeak = (i32)(amax-amin)/2; + + if(apeak>setpt)compOut=1; + else if(compOut&&(apeak<(setpt-hyst)))compOut=0; + } + } + + mySps->decimator = decimator; + + mySps->amax=amax; + mySps->amin=amin; + mySps->apeak=apeak; + mySps->discounteru=discounteru; + mySps->discounterl=discounterl; + + mySps->compOut=compOut; + + return 0; +} +/* + general purpose integrator lpf +*/ +i16 gp_inte_00(t_pmr_sps *mySps) +{ + i16 npoints; + i16 *input, *output; + + i32 inputGain, outputGain,calcAdjust; + i32 i; + i32 accum; + + i32 state00; + i16 coeff00, coeff01; + + TRACEX(("gp_inte_00() %i\n",mySps->enabled)); + if(!mySps->enabled)return(1); + + input = mySps->source; + output = mySps->sink; + + npoints=mySps->nSamples; + + inputGain=mySps->inputGain; + outputGain=mySps->outputGain; + calcAdjust=mySps->calcAdjust; + + coeff00=((i16*)mySps->coef)[0]; + coeff01=((i16*)mySps->coef)[1]; + state00=((i32*)mySps->x)[0]; + + // note fixed gain of 2 to compensate for attenuation + // in passband + + for(i=0;i<npoints;i++) + { + accum=input[i]; + state00 = accum + (state00*coeff01)/M_Q15; + accum = (state00*coeff00)/(M_Q15/4); + output[i]=(accum*outputGain)/M_Q8; + } + + ((i32*)(mySps->x))[0]=state00; + + return 0; +} +/* + general purpose differentiator hpf +*/ +i16 gp_diff(t_pmr_sps *mySps) +{ + i16 *input, *output; + i16 npoints; + i32 inputGain, outputGain, calcAdjust; + i32 i; + i32 temp0,temp1; + i16 x0; + i32 y0; + i16 a0,a1; + i16 b0; + i16 *coef; + i16 *x; + + input = mySps->source; + output = mySps->sink; + + npoints=mySps->nSamples; + + inputGain=mySps->inputGain; + outputGain=mySps->outputGain; + calcAdjust=mySps->calcAdjust; + + coef=(i16*)(mySps->coef); + x=(i16*)(mySps->x); + a0=coef[0]; + a1=coef[1]; + b0=coef[2]; + + x0=x[0]; + + TRACEX(("gp_diff()\n")); + + for (i=0;i<npoints;i++) + { + temp0 = x0 * a1; + x0 = input[i]; + temp1 = input[i] * a0; + y0 = (temp0 + temp1)/calcAdjust; + output[i]=(y0*outputGain)/M_Q8; + } + + x[0]=x0; + + return 0; +} +/* ---------------------------------------------------------------------- + CenterSlicer +*/ +i16 CenterSlicer(t_pmr_sps *mySps) +{ + i16 npoints,lhit,uhit; + i16 *input, *output, *buff; + + i32 inputGain, outputGain, inputGainB; + i32 i; + i32 accum; + + i32 amax; // buffer amplitude maximum + i32 amin; // buffer amplitude minimum + i32 apeak; // buffer amplitude peak + i32 center; + i32 setpt; // amplitude set point for peak tracking + + i32 discounteru; // amplitude detector integrator discharge counter upper + i32 discounterl; // amplitude detector integrator discharge counter lower + i32 discfactor; // amplitude detector integrator discharge factor + + TRACEX(("CenterSlicer() %i\n",mySps->enabled)); + + input = mySps->source; + output = mySps->sink; + buff = mySps->buff; + + npoints=mySps->nSamples; + + inputGain=mySps->inputGain; + outputGain=mySps->outputGain; + inputGainB=mySps->inputGainB; + + amax=mySps->amax; + amin=mySps->amin; + setpt=mySps->setpt; + apeak=mySps->apeak; + discounteru=mySps->discounteru; + discounterl=mySps->discounterl; + + discfactor=mySps->discfactor; + npoints=mySps->nSamples; + + for(i=0;i<npoints;i++) + { + accum=input[i]; + + lhit=uhit=0; + + if(accum>amax) + { + amax=accum; + uhit=1; + if(amin<(amax-setpt)) + { + amin=(amax-setpt); + lhit=1; + } + } + else if(accum<amin) + { + amin=accum; + lhit=1; + if(amax>(amin+setpt)) + { + amax=(amin+setpt); + uhit=1; + } + } + + if(--discounteru<=0 && amax>0) + { + amax--; + uhit=1; + } + + if(--discounterl<=0 && amin<0) + { + amin++; + lhit=1; + } + + if(uhit)discounteru=discfactor; + if(lhit)discounterl=discfactor; + + apeak = (amax-amin)/2; + center = (amax+amin)/2; + accum = accum - center; + output[i]=accum; + + // do limiter function + if(accum>inputGainB)accum=inputGainB; + else if(accum<-inputGainB)accum=-inputGainB; + buff[i]=accum; + + #if XPMR_DEBUG0 == 1 + #if 0 + mySps->debugBuff0[i]=center; + #endif + #if 0 + if(mySps->parentChan->frameCountRx&0x01) mySps->parentChan->prxDebug1[i]=amax; + else mySps->parentChan->prxDebug1[i]=amin; + #endif + #endif + } + + mySps->amax=amax; + mySps->amin=amin; + mySps->apeak=apeak; + mySps->discounteru=discounteru; + mySps->discounterl=discounterl; + + return 0; +} +/* ---------------------------------------------------------------------- + MeasureBlock + determine peak amplitude +*/ +i16 MeasureBlock(t_pmr_sps *mySps) +{ + i16 npoints; + i16 *input, *output; + + i32 inputGain, outputGain; + i32 i; + i32 accum; + + i16 amax; // buffer amplitude maximum + i16 amin; // buffer amplitude minimum + i16 apeak=0; // buffer amplitude peak (peak to peak)/2 + i16 setpt; // amplitude set point for amplitude comparator + + i32 discounteru; // amplitude detector integrator discharge counter upper + i32 discounterl; // amplitude detector integrator discharge counter lower + i32 discfactor; // amplitude detector integrator discharge factor + + TRACEX(("MeasureBlock() %i\n",mySps->enabled)); + + if(!mySps->enabled)return 1; + + if(mySps->option==3) + { + mySps->amax = mySps->amin = mySps->apeak = \ + mySps->discounteru = mySps->discounterl = \ + mySps->enabled = 0; + return 1; + } + + input = mySps->source; + output = mySps->sink; + + npoints=mySps->nSamples; + + inputGain=mySps->inputGain; + outputGain=mySps->outputGain; + + amax=mySps->amax; + amin=mySps->amin; + setpt=mySps->setpt; + discounteru=mySps->discounteru; + discounterl=mySps->discounterl; + + discfactor=mySps->discfactor; + npoints=mySps->nSamples; + + for(i=0;i<npoints;i++) + { + accum=input[i]; + + if(accum>amax) + { + amax=accum; + discounteru=discfactor; + } + else if(--discounteru<=0) + { + discounteru=discfactor; + amax=(i32)((amax*32700)/32768); + } + + if(accum<amin) + { + amin=accum; + discounterl=discfactor; + } + else if(--discounterl<=0) + { + discounterl=discfactor; + amin=(i32)((amin*32700)/32768); + } + + apeak = (i32)(amax-amin)/2; + if(output)output[i]=apeak; + } + + mySps->amax=amax; + mySps->amin=amin; + mySps->apeak=apeak; + mySps->discounteru=discounteru; + mySps->discounterl=discounterl; + if(apeak>=setpt) mySps->compOut=1; + else mySps->compOut=0; + + //TRACEX((" -MeasureBlock()=%i\n",mySps->apeak)); + return 0; +} +/* + SoftLimiter +*/ +i16 SoftLimiter(t_pmr_sps *mySps) +{ + i16 npoints; + //i16 samples, lhit,uhit; + i16 *input, *output; + + i32 inputGain, outputGain; + i32 i; + i32 accum; + i32 tmp; + + i32 amax; // buffer amplitude maximum + i32 amin; // buffer amplitude minimum + //i32 apeak; // buffer amplitude peak + i32 setpt; // amplitude set point for amplitude comparator + i16 compOut; // amplitude comparator output + + input = mySps->source; + output = mySps->sink; + + inputGain=mySps->inputGain; + outputGain=mySps->outputGain; + + npoints=mySps->nSamples; + + setpt=mySps->setpt; + amax=(setpt*124)/128; + amin=-amax; + + TRACEX(("SoftLimiter() %i %i %i) \n",amin, amax,setpt)); + + for(i=0;i<npoints;i++) + { + accum=input[i]; + //accum=input[i]*mySps->inputGain/256; + + if(accum>setpt) + { + tmp=((accum-setpt)*4)/128; + accum=setpt+tmp; + if(accum>amax)accum=amax; + compOut=1; + accum=setpt; + } + else if(accum<-setpt) + { + tmp=((accum+setpt)*4)/128; + accum=(-setpt)-tmp; + if(accum<amin)accum=amin; + compOut=1; + accum=-setpt; + } + + output[i]=(accum*outputGain)/M_Q8; + } + + return 0; +} +/* + SigGen() - sine, square function generator + sps overloaded values + discfactor = phase factor + discfactoru = phase index + if source is not NULL then mix it in! + + sign table and output gain are in Q15 format (32767=.999) +*/ +i16 SigGen(t_pmr_sps *mySps) +{ + #define PH_FRACT_FACT 128 + + i32 ph; + i16 i,outputgain,waveform,numChanOut,selChanOut; + i32 accum; + + TRACEX(("SigGen(%i) \n",mySps->option)); + + if(!mySps->freq ||!mySps->enabled)return 0; + + outputgain=mySps->outputGain; + waveform=0; + numChanOut=mySps->numChanOut; + selChanOut=mySps->selChanOut; + + if(mySps->option==1) + { + mySps->option=0; + mySps->state=1; + mySps->discfactor= + (SAMPLES_PER_SINE*mySps->freq*PH_FRACT_FACT)/mySps->sampleRate/10; + + TRACEX((" SigGen() discfactor = %i\n",mySps->discfactor)); + if(mySps->discounterl)mySps->state=2; + } + else if(mySps->option==2) + { + i16 shiftfactor=CTCSS_TURN_OFF_SHIFT; + // phase shift request + mySps->option=0; + mySps->state=2; + mySps->discounterl=CTCSS_TURN_OFF_TIME-(2*MS_PER_FRAME); // + + mySps->discounteru = \ + (mySps->discounteru + (((SAMPLES_PER_SINE*shiftfactor)/360)*PH_FRACT_FACT)) % (SAMPLES_PER_SINE*PH_FRACT_FACT); + //printf("shiftfactor = %i\n",shiftfactor); + //shiftfactor+=10; + } + else if(mySps->option==3) + { + // stop it and clear the output buffer + mySps->option=0; + mySps->state=0; + mySps->enabled=0; + for(i=0;i<mySps->nSamples;i++) + mySps->sink[(i*numChanOut)+selChanOut]=0; + return(0); + } + else if(mySps->state==2) + { + // doing turn off + mySps->discounterl-=MS_PER_FRAME; + if(mySps->discounterl<=0) + { + mySps->option=3; + mySps->state=2; + } + } + else if(mySps->state==0) + { + return(0); + } + + ph=mySps->discounteru; + + for(i=0;i<mySps->nSamples;i++) + { + if(!waveform) + { + // sine + //tmp=(sinetablex[ph/PH_FRACT_FACT]*amplitude)/M_Q16; + accum=sinetablex[ph/PH_FRACT_FACT]; + accum=(accum*outputgain)/M_Q8; + } + else + { + // square + if(ph>SAMPLES_PER_SINE/2) + accum=outputgain/M_Q8; + else + accum=-outputgain/M_Q8; + } + + if(mySps->source)accum+=mySps->source[i]; + + mySps->sink[(i*numChanOut)+selChanOut]=accum; + + ph=(ph+mySps->discfactor)%(SAMPLES_PER_SINE*PH_FRACT_FACT); + } + + mySps->discounteru=ph; + + return 0; +} +/* + adder/mixer + takes existing buffer and adds source buffer to destination buffer + sink buffer = (sink buffer * gain) + source buffer +*/ +i16 pmrMixer(t_pmr_sps *mySps) +{ + i32 accum; + i16 i, *input, *inputB, *output; + i16 inputGain, inputGainB; // apply to input data in Q7.8 format + i16 outputGain; // apply to output data in Q7.8 format + i16 discounteru,discounterl,amax,amin,setpt,discfactor; + i16 npoints,uhit,lhit,apeak,measPeak; + + TRACEX(("pmrMixer()\n")); + + input = mySps->source; + inputB = mySps->sourceB; + output = mySps->sink; + + inputGain=mySps->inputGain; + inputGainB=mySps->inputGainB; + outputGain=mySps->outputGain; + + amax=mySps->amax; + amin=mySps->amin; + setpt=mySps->setpt; + discounteru=mySps->discounteru; + discounterl=mySps->discounteru; + + discfactor=mySps->discfactor; + npoints=mySps->nSamples; + measPeak=mySps->measPeak; + + for(i=0;i<npoints;i++) + { + accum = ((input[i]*inputGain)/M_Q8) + + ((inputB[i]*inputGainB)/M_Q8); + + accum=(accum*outputGain)/M_Q8; + output[i]=accum; + + if(measPeak){ + lhit=uhit=0; + + if(accum>amax){ + amax=accum; + uhit=1; + if(amin<(amax-setpt)){ + amin=(amax-setpt); + lhit=1; + } + } + else if(accum<amin){ + amin=accum; + lhit=1; + if(amax>(amin+setpt)){ + amax=(amin+setpt); + uhit=1; + } + } + + if(--discounteru<=0 && amax>0){ + amax--; + uhit=1; + } + + if(--discounterl<=0 && amin<0){ + amin++; + lhit=1; + } + + if(uhit)discounteru=discfactor; + if(lhit)discounterl=discfactor; + } + } + + if(measPeak){ + apeak = (amax-amin)/2; + mySps->apeak=apeak; + mySps->amax=amax; + mySps->amin=amin; + mySps->discounteru=discounteru; + mySps->discounterl=discounterl; + } + + return 0; +} +/* + DelayLine +*/ +i16 DelayLine(t_pmr_sps *mySps) +{ + i16 *input, *output, *buff; + i16 i, npoints,buffsize,inindex,outindex; + + TRACEX((" DelayLine() %i\n",mySps->enabled)); + + input = mySps->source; + output = mySps->sink; + buff = (i16*)(mySps->buff); + buffsize = mySps->buffSize; + npoints = mySps->nSamples; + + outindex = mySps->buffOutIndex; + inindex = outindex + mySps->buffLead; + + for(i=0;i<npoints;i++) + { + inindex %= buffsize; + outindex %= buffsize; + + buff[inindex]=input[i]; + output[i]=buff[outindex]; + inindex++; + outindex++; + } + mySps->buffOutIndex=outindex; + + return 0; +} +/* + Continuous Tone Coded Squelch (CTCSS) Detector +*/ +i16 ctcss_detect(t_pmr_chan *pmrChan) +{ + i16 i,points2do, points=0, *pInput, hit, thit,relax; + i16 tnum, tmp, indexWas=0, indexNow, gain, peakwas=0, diffpeak; + i16 difftrig; + i16 lasttv0=0, lasttv1=0, lasttv2=0, tv0, tv1, tv2, indexDebug; + + TRACEX(("ctcss_detect(%p) %i %i %i %i\n",pmrChan, + pmrChan->rxCtcss->enabled, + pmrChan->rxCtcssIndex, + pmrChan->rxCtcss->testIndex, + pmrChan->rxCtcss->decode)); + + if(!pmrChan->rxCtcss->enabled)return(1); + + relax = pmrChan->rxCtcss->relax; + pInput = pmrChan->rxCtcss->input; + gain = pmrChan->rxCtcss->gain; + + if(relax) difftrig=(-0.1*M_Q15); + else difftrig=(-0.05*M_Q15); + + thit=hit=-1; + + //TRACEX((" ctcss_detect() %i %i %i %i\n", CTCSS_NUM_CODES,0,0,0)); + + for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++) + { + i32 accum, peak; + t_tdet *ptdet; + i16 fudgeFactor; + i16 binFactor; + + //TRACEX((" ctcss_detect() tnum=%i %i\n",tnum,pmrChan->rxCtcssMap[tnum])); + + if( (pmrChan->rxCtcssMap[tnum] < 0) || + (pmrChan->rxCtcss->decode>=0 && (tnum!= pmrChan->rxCtcss->decode)) || + (!pmrChan->rxCtcss->multiFreq && (tnum!= pmrChan->rxCtcssIndex)) + ) + continue; + + //TRACEX((" ctcss_detect() tnum=%i\n",tnum)); + + ptdet=&(pmrChan->rxCtcss->tdet[tnum]); + indexDebug=0; + points=points2do=pmrChan->nSamplesRx; + fudgeFactor=ptdet->fudgeFactor; + binFactor=ptdet->binFactor; + + while(ptdet->counter < (points2do*CTCSS_SCOUNT_MUL)) + { + //TRACEX((" ctcss_detect() - inner loop\n")); + tmp=(ptdet->counter/CTCSS_SCOUNT_MUL)+1; + ptdet->counter-=(tmp*CTCSS_SCOUNT_MUL); + points2do-=tmp; + indexNow=points-points2do; + + ptdet->counter += ptdet->counterFactor; + + accum = pInput[indexNow-1]; // dude's major bug fix! + + peakwas=ptdet->peak; + + ptdet->z[ptdet->zIndex]+= + (((accum - ptdet->z[ptdet->zIndex])*binFactor)/M_Q15); + + peak = abs(ptdet->z[0]-ptdet->z[2]) + abs(ptdet->z[1]-ptdet->z[3]); + + if (ptdet->peak < peak) + ptdet->peak += ( ((peak-ptdet->peak)*binFactor)/M_Q15); + else + ptdet->peak=peak; + + { + static const i16 a0=13723; + static const i16 a1=-13723; + i32 temp0,temp1; + i16 x0; + + //differentiate + x0=ptdet->zd; + temp0 = x0 * a1; + ptdet->zd = ptdet->peak; + temp1 = ptdet->peak * a0; + diffpeak = (temp0 + temp1)/1024; + } + + if(diffpeak<(-0.03*M_Q15))ptdet->dvd-=4; + else if(ptdet->dvd<0)ptdet->dvd++; + + if((ptdet->dvd < -12) && diffpeak > (-0.02*M_Q15))ptdet->dvu+=2; + else if(ptdet->dvu)ptdet->dvu--; + + tmp=ptdet->setpt; + if(pmrChan->rxCtcss->decode==tnum) + { + if(relax)tmp=(tmp*55)/100; + else tmp=(tmp*80)/100; + } + + if(ptdet->peak > tmp) + { + if(ptdet->decode<(fudgeFactor*32))ptdet->decode++; + } + else if(pmrChan->rxCtcss->decode==tnum) + { + if(ptdet->peak > ptdet->hyst)ptdet->decode--; + else if(relax) ptdet->decode--; + else ptdet->decode-=4; + } + else + { + ptdet->decode=0; + } + + if((pmrChan->rxCtcss->decode==tnum) && !relax && (ptdet->dvu > (0.00075*M_Q15))) + { + ptdet->decode=0; + ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=ptdet->dvu=0; + //printf("ctcss_detect() turnoff code!\n"); + } + + if(ptdet->decode<0 || !pmrChan->rxCarrierDetect)ptdet->decode=0; + + if(ptdet->decode>=fudgeFactor)thit=tnum; + + #if XPMR_DEBUG0 == 1 + //if(thit>=0 && thit==tnum) + // printf(" ctcss_detect() %i %i %i %i \n",tnum,ptdet->peak,ptdet->setpt,ptdet->hyst); + + // tv0=accum; + tv0=ptdet->peak; + tv1=diffpeak; + tv2=ptdet->dvu; + + //tv1=ptdet->zi*100; + while(indexDebug<indexNow) + { + if(indexDebug==0)lasttv0=ptdet->pDebug0[points-1]; + if(ptdet->pDebug0)ptdet->pDebug0[indexDebug]=lasttv0; + + if(indexDebug==0)lasttv1=ptdet->pDebug1[points-1]; + if(ptdet->pDebug1)ptdet->pDebug1[indexDebug]=lasttv1; + + if(indexDebug==0)lasttv2=ptdet->pDebug2[points-1]; + if(ptdet->pDebug2)ptdet->pDebug2[indexDebug]=lasttv2; + + indexDebug++; + } + lasttv0=tv0; + lasttv1=tv1; + lasttv2=tv2*100; + #endif + indexWas=indexNow; + ptdet->zIndex=(++ptdet->zIndex)%4; + } + ptdet->counter-=(points2do*CTCSS_SCOUNT_MUL); + + #if XPMR_DEBUG0 == 1 + for(i=indexWas;i<points;i++) + { + if(ptdet->pDebug0)ptdet->pDebug0[i]=lasttv0; + if(ptdet->pDebug1)ptdet->pDebug1[i]=lasttv1; + if(ptdet->pDebug2)ptdet->pDebug2[i]=lasttv2; + } + #endif + } + + //TRACEX((" ctcss_detect() thit %i\n",thit)); + + if(pmrChan->rxCtcss->BlankingTimer>0)pmrChan->rxCtcss->BlankingTimer-=points; + if(pmrChan->rxCtcss->BlankingTimer<0)pmrChan->rxCtcss->BlankingTimer=0; + + if(thit>=0 && pmrChan->rxCtcss->decode<0 && !pmrChan->rxCtcss->BlankingTimer) + { + pmrChan->rxCtcss->decode=thit; + } + else if(thit<0 && pmrChan->rxCtcss->decode>=0) + { + pmrChan->rxCtcss->BlankingTimer=SAMPLE_RATE_NETWORK/5; + pmrChan->rxCtcss->decode=-1; + + for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++) + { + t_tdet *ptdet=NULL; + ptdet=&(pmrChan->rxCtcss->tdet[tnum]); + ptdet->decode=0; + ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=0; + } + } + //TRACEX((" ctcss_detect() thit %i %i\n",thit,pmrChan->rxCtcss->decode)); + return(0); +} +/* + TxTestTone +*/ +static i16 TxTestTone(t_pmr_chan *pChan, i16 function) +{ + if(function==1) + { + pChan->spsSigGen1->enabled=1; + pChan->spsSigGen1->option=1; + pChan->spsTx->source=pChan->spsSigGen1->sink; + } + else + { + pChan->spsSigGen1->option=3; + } + return 0; +} +/* + assumes: + sampling rate is 48KS/s + samples are all 16 bits + samples are filtered and decimated by 1/6th +*/ +t_pmr_chan *createPmrChannel(t_pmr_chan *tChan, i16 numSamples) +{ + i16 i, *inputTmp; + + t_pmr_chan *pChan; + t_pmr_sps *pSps; + t_dec_ctcss *pDecCtcss; + t_tdet *ptdet; + + TRACEX(("createPmrChannel(%p,%i)\n",tChan,numSamples)); + + pChan = (t_pmr_chan *)calloc(sizeof(t_pmr_chan),1); + + if(pChan==NULL) + { + printf("createPmrChannel() failed\n"); + return(NULL); + } + + pChan->nSamplesRx=numSamples; + pChan->nSamplesTx=numSamples; + + pChan->index=pmrChanIndex++; + + for(i=0;i<CTCSS_NUM_CODES;i++) + { + pChan->rxCtcssMap[i]=-1; + } + + pChan->rxCtcssIndex=-1; + + if(tChan==NULL) + { + pChan->rxNoiseSquelchEnable=0; + pChan->rxHpfEnable=0; + pChan->rxDeEmpEnable=0; + pChan->rxCenterSlicerEnable=0; + pChan->rxCtcssDecodeEnable=0; + pChan->rxDcsDecodeEnable=0; + + pChan->rxCarrierPoint = 17000; + pChan->rxCarrierHyst = 2500; + + pChan->rxCtcssFreq=103.5; + + pChan->txHpfEnable=0; + pChan->txLimiterEnable=0; + pChan->txPreEmpEnable=0; + pChan->txLpfEnable=1; + pChan->txCtcssFreq=103.5; + pChan->txMixA=TX_OUT_VOICE; + pChan->txMixB=TX_OUT_LSD; + } + else + { + pChan->rxDemod=tChan->rxDemod; + pChan->rxCdType=tChan->rxCdType; + pChan->rxSquelchPoint = tChan->rxSquelchPoint; + pChan->rxCarrierHyst = 3000; + pChan->rxCtcssFreq=tChan->rxCtcssFreq; + + for(i=0;i<CTCSS_NUM_CODES;i++) + pChan->rxCtcssMap[i]=tChan->rxCtcssMap[i]; + + pChan->txMod=tChan->txMod; + pChan->txHpfEnable=1; + pChan->txLpfEnable=1; + pChan->txCtcssFreq=tChan->txCtcssFreq; + pChan->txMixA=tChan->txMixA; + pChan->txMixB=tChan->txMixB; + pChan->radioDuplex=tChan->radioDuplex; + } + + TRACEX(("misc settings \n")); + + if(pChan->rxCdType==CD_XPMR_NOISE){ + pChan->rxNoiseSquelchEnable=1; + } + + if(pChan->rxDemod==RX_AUDIO_FLAT){ + pChan->rxHpfEnable=1; + pChan->rxDeEmpEnable=1; + } + + pChan->rxCarrierPoint=(pChan->rxSquelchPoint*32767)/100; + pChan->rxCarrierHyst = 3000; //pChan->rxCarrierPoint/15; + + pChan->rxDcsDecodeEnable=0; + + if(pChan->rxCtcssFreq!=0){ + pChan->rxHpfEnable=1; + pChan->rxCenterSlicerEnable=1; + pChan->rxCtcssDecodeEnable=1; + pChan->rxCtcssIndex=CtcssFreqIndex(pChan->rxCtcssFreq); + } + + if(pChan->txMod){ + pChan->txPreEmpEnable=1; + pChan->txLimiterEnable=1; + } + + TRACEX(("calloc buffers \n")); + + pChan->pRxDemod = calloc(numSamples,2); + pChan->pRxNoise = calloc(numSamples,2); + pChan->pRxBase = calloc(numSamples,2); + pChan->pRxHpf = calloc(numSamples,2); + pChan->pRxLsd = calloc(numSamples,2); + pChan->pRxSpeaker = calloc(numSamples,2); + pChan->pRxCtcss = calloc(numSamples,2); + pChan->pRxDcTrack = calloc(numSamples,2); + pChan->pRxLsdLimit = calloc(numSamples,2); + + + pChan->pTxBase = calloc(numSamples,2); + pChan->pTxHpf = calloc(numSamples,2); + pChan->pTxPreEmp = calloc(numSamples,2); + pChan->pTxLimiter = calloc(numSamples,2); + pChan->pTxLsd = calloc(numSamples,2); + pChan->pTxLsdLpf = calloc(numSamples,2); + pChan->pTxComposite = calloc(numSamples,2); + pChan->pSigGen0 = calloc(numSamples,2); + pChan->pSigGen1 = calloc(numSamples,2); + + pChan->pTxCode = calloc(numSamples,2); + pChan->pTxOut = calloc(numSamples,2*2*6); // output buffer + + #if XPMR_DEBUG0 == 1 + pChan->pTxPttIn = calloc(numSamples,2); + pChan->pTxPttOut = calloc(numSamples,2); + pChan->prxDebug0 = calloc(numSamples,2); + pChan->prxDebug1 = calloc(numSamples,2); + pChan->prxDebug2 = calloc(numSamples,2); + pChan->prxDebug3 = calloc(numSamples,2); + pChan->ptxDebug0 = calloc(numSamples,2); + pChan->ptxDebug1 = calloc(numSamples,2); + pChan->ptxDebug2 = calloc(numSamples,2); + pChan->ptxDebug3 = calloc(numSamples,2); + pChan->pNull = calloc(numSamples,2); + for(i=0;i<numSamples;i++)pChan->pNull[i]=((i%(numSamples/2))*8000)-4000; + #endif + + TRACEX(("create ctcss\n")); + + pDecCtcss = (t_dec_ctcss *)calloc(sizeof(t_dec_ctcss),1); + + pChan->rxCtcss=pDecCtcss; + pDecCtcss->enabled=1; + pDecCtcss->gain=1*M_Q8; + pDecCtcss->limit=8192; + pDecCtcss->input=pChan->pRxLsdLimit; + pDecCtcss->testIndex=pChan->rxCtcssIndex; + if(!pDecCtcss->testIndex)pDecCtcss->testIndex=1; + pChan->rxCtcssMap[pChan->rxCtcssIndex]=pChan->rxCtcssIndex; + pDecCtcss->decode=-1; + + for(i=0;i<CTCSS_NUM_CODES;i++) + { + ptdet=&(pChan->rxCtcss->tdet[i]); + ptdet->state=1; + ptdet->setpt=(M_Q15*0.067); // 0.069 + ptdet->hyst =(M_Q15*0.020); + ptdet->counterFactor=coef_ctcss_div[i]; + ptdet->binFactor=(M_Q15*0.135); // was 0.140 + ptdet->fudgeFactor=8; + } + + // General Purpose Function Generator + pSps=pChan->spsSigGen1=createPmrSps(); + pSps->parentChan=pChan; + pSps->sink=pChan->pSigGen1; + pSps->numChanOut=1; + pSps->selChanOut=0; + pSps->sigProc=SigGen; + pSps->nSamples=pChan->nSamplesTx; + pSps->sampleRate=SAMPLE_RATE_NETWORK; + pSps->freq=10000; // in increments of 0.1 Hz + pSps->outputGain=(.25*M_Q8); + pSps->option=0; + pSps->interpolate=1; + pSps->decimate=1; + pSps->enabled=0; + + + // CTCSS ENCODER + pSps = pChan->spsSigGen0 = createPmrSps(); + pSps->parentChan=pChan; + pSps->sink=pChan->pTxLsd; + pSps->sigProc=SigGen; + pSps->numChanOut=1; + pSps->selChanOut=0; + pSps->nSamples=pChan->nSamplesTx; + pSps->sampleRate=SAMPLE_RATE_NETWORK; + pSps->freq=pChan->txCtcssFreq*10; // in increments of 0.1 Hz + pSps->outputGain=(0.5*M_Q8); + pSps->option=0; + pSps->interpolate=1; + pSps->decimate=1; + pSps->enabled=0; + + + // Tx LSD Low Pass Filter + pSps=pChan->spsTxLsdLpf=pSps->nextSps=createPmrSps(); + pSps->source=pChan->pTxLsd; + pSps->sink=pChan->pTxLsdLpf; + pSps->sigProc=pmr_gp_fir; + pSps->enabled=0; + pSps->numChanOut=1; + pSps->selChanOut=0; + pSps->nSamples=pChan->nSamplesTx; + pSps->decimator=pSps->decimate=1; + pSps->interpolate=1; + pSps->inputGain=(1*M_Q8); + pSps->outputGain=(1*M_Q8); + + if(pChan->txCtcssFreq>203.0) + { + pSps->ncoef=taps_fir_lpf_250_9_66; + pSps->size_coef=2; + pSps->coef=(void*)coef_fir_lpf_250_9_66; + pSps->nx=taps_fir_lpf_250_9_66; + pSps->size_x=2; + pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); + pSps->calcAdjust=gain_fir_lpf_250_9_66; + } + else + { + pSps->ncoef=taps_fir_lpf_215_9_88; + pSps->size_coef=2; + pSps->coef=(void*)coef_fir_lpf_215_9_88; + pSps->nx=taps_fir_lpf_215_9_88; + pSps->size_x=2; + pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); + pSps->calcAdjust=gain_fir_lpf_215_9_88; + } + + pSps->inputGain=(1*M_Q8); + pSps->outputGain=(1*M_Q8); + + if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); + + + // RX Process + TRACEX(("create rx\n")); + pSps = NULL; + + // allocate space for first sps and set pointers + pSps=pChan->spsRx=createPmrSps(); + pSps->parentChan=pChan; + pSps->source=NULL; //set when called + pSps->sink=pChan->pRxBase; + pSps->sigProc=pmr_rx_frontend; + pSps->enabled=1; + pSps->decimator=pSps->decimate=6; + pSps->interpolate=pSps->interpolate=1; + pSps->nSamples=pChan->nSamplesRx; + pSps->ncoef=taps_fir_bpf_noise_1; + pSps->size_coef=2; + pSps->coef=(void*)coef_fir_lpf_3K_1; + pSps->coef2=(void*)coef_fir_bpf_noise_1; + pSps->nx=taps_fir_bpf_noise_1; + pSps->size_x=2; + pSps->x=(void*)(calloc(pSps->nx,pSps->size_coef)); + pSps->calcAdjust=(gain_fir_lpf_3K_1*256)/0x0100; + pSps->outputGain=(1.0*M_Q8); + pSps->discfactor=2; + pSps->hyst=pChan->rxCarrierHyst; + pSps->setpt=pChan->rxCarrierPoint; + pChan->prxSquelchAdjust=&pSps->setpt; + #if XPMR_DEBUG0 == 1 + pSps->debugBuff0=pChan->pRxDemod; + pSps->debugBuff1=pChan->pRxNoise; + pSps->debugBuff2=pChan->prxDebug0; + #endif + + + // allocate space for next sps and set pointers + // Rx SubAudible Decoder Low Pass Filter + pSps=pSps->nextSps=createPmrSps(); + pSps->parentChan=pChan; + pSps->source=pChan->pRxBase; + pSps->sink=pChan->pRxLsd; + pSps->sigProc=pmr_gp_fir; + pSps->enabled=1; + pSps->numChanOut=1; + pSps->selChanOut=0; + pSps->nSamples=pChan->nSamplesRx; + pSps->decimator=pSps->decimate=1; + pSps->interpolate=1; + + if(pChan->rxCtcssFreq>203.5) + { + pSps->ncoef=taps_fir_lpf_250_9_66; + pSps->size_coef=2; + pSps->coef=(void*)coef_fir_lpf_250_9_66; + pSps->nx=taps_fir_lpf_250_9_66; + pSps->size_x=2; + pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); + pSps->calcAdjust=gain_fir_lpf_250_9_66; + } + else + { + pSps->ncoef=taps_fir_lpf_215_9_88; + pSps->size_coef=2; + pSps->coef=(void*)coef_fir_lpf_215_9_88; + pSps->nx=taps_fir_lpf_215_9_88; + pSps->size_x=2; + pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); + pSps->calcAdjust=gain_fir_lpf_215_9_88; + } + + pSps->inputGain=(1*M_Q8); + pSps->outputGain=(1*M_Q8); + pChan->prxCtcssMeasure=pSps->sink; + pChan->prxCtcssAdjust=&(pSps->outputGain); + + + // allocate space for next sps and set pointers + // CenterSlicer + if(pChan->rxCenterSlicerEnable) + { + pSps=pSps->nextSps=createPmrSps(); + pSps->parentChan=pChan; + pSps->source=pChan->pRxLsd; + pSps->sink=pChan->pRxDcTrack; + pSps->buff=pChan->pRxLsdLimit; + pSps->sigProc=CenterSlicer; + pSps->enabled=1; + pSps->nSamples=pChan->nSamplesRx; + pSps->discfactor=800; + pSps->inputGain=(1*M_Q8); + pSps->outputGain=(1*M_Q8); + pSps->setpt=3000; + pSps->inputGainB=1000; // limiter set point + } + + // allocate space for next sps and set pointers + // Rx HPF + pSps=pSps->nextSps=createPmrSps(); + pSps->parentChan=pChan; + pChan->spsRxHpf=pSps; + pSps->source=pChan->pRxBase; + pSps->sink=pChan->pRxHpf; + pSps->sigProc=pmr_gp_fir; + pSps->enabled=1; + pSps->numChanOut=1; + pSps->selChanOut=0; + pSps->nSamples=pChan->nSamplesRx; + pSps->decimator=pSps->decimate=1; + pSps->interpolate=1; + pSps->ncoef=taps_fir_hpf_300_9_66; + pSps->size_coef=2; + pSps->coef=(void*)coef_fir_hpf_300_9_66; + pSps->nx=taps_fir_hpf_300_9_66; + pSps->size_x=2; + pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); + if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); + pSps->calcAdjust=gain_fir_hpf_300_9_66; + pSps->inputGain=(1*M_Q8); + pSps->outputGain=(1*M_Q8); + pChan->spsRxOut=pSps; + + // allocate space for next sps and set pointers + // Rx DeEmp + if(pChan->rxDeEmpEnable){ + pSps=pSps->nextSps=createPmrSps(); + pSps->parentChan=pChan; + pChan->spsRxDeEmp=pSps; + pSps->source=pChan->pRxHpf; + pSps->sink=pChan->pRxSpeaker; + pChan->spsRxOut=pSps; // OUTPUT STRUCTURE! maw + pSps->sigProc=gp_inte_00; + pSps->enabled=1; + pSps->nSamples=pChan->nSamplesRx; + + pSps->ncoef=taps_int_lpf_300_1_2; + pSps->size_coef=2; + pSps->coef=(void*)coef_int_lpf_300_1_2; + + pSps->nx=taps_int_lpf_300_1_2; + pSps->size_x=4; + pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); + if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); + pSps->calcAdjust=gain_int_lpf_300_1_2/2; + pSps->inputGain=(1.0*M_Q8); + pSps->outputGain=(1.0*M_Q8); + pChan->prxVoiceMeasure=pSps->sink; + pChan->prxVoiceAdjust=&(pSps->outputGain); + } + + if(pChan->rxDelayLineEnable) + { + TRACEX(("create delayline\n")); + pSps=pChan->spsDelayLine=pSps->nextSps=createPmrSps(); + pSps->sigProc=DelayLine; + pSps->source=pChan->pRxSpeaker; + pSps->sink=pChan->pRxSpeaker; + pSps->enabled=0; + pSps->inputGain=1*M_Q8; + pSps->outputGain=1*M_Q8; + pSps->nSamples=pChan->nSamplesRx; + pSps->buffSize=4096; + pSps->buff=calloc(4096,2); // one second maximum + pSps->buffLead = (SAMPLE_RATE_NETWORK*0.100); + pSps->buffOutIndex=0; + } + + if(pChan->rxCdType==CD_XPMR_VOX) + { + TRACEX(("create vox measureblock\n")); + pSps=pChan->spsRxVox=pSps->nextSps=createPmrSps(); + pSps->sigProc=MeasureBlock; + pSps->parentChan=pChan; + pSps->source=pChan->pRxBase; + pSps->sink=pChan->prxDebug1; + pSps->inputGain=1*M_Q8; + pSps->outputGain=1*M_Q8; + pSps->nSamples=pChan->nSamplesRx; + pSps->discfactor=3; + pSps->setpt=(0.01*M_Q15); + pSps->hyst=(pSps->setpt/10); + pSps->enabled=1; + } + + // tuning measure block + pSps=pChan->spsMeasure=pSps->nextSps=createPmrSps(); + pSps->parentChan=pChan; + pSps->source=pChan->spsRx->sink; + pSps->sink=pChan->prxDebug2; + pSps->sigProc=MeasureBlock; + pSps->enabled=0; + pSps->nSamples=pChan->nSamplesRx; + pSps->discfactor=10; + + pSps->nextSps=NULL; // last sps in chain RX + + + // CREATE TRANSMIT CHAIN + TRACEX((" create tx\n")); + inputTmp=NULL; + pSps = NULL; + + // allocate space for first sps and set pointers + + // Tx HPF SubAudible + if(pChan->txHpfEnable) + { + pSps=createPmrSps(); + pChan->spsTx=pSps; + pSps->source=pChan->pTxBase; + pSps->sink=pChan->pTxHpf; + pSps->sigProc=pmr_gp_fir; + pSps->enabled=1; + pSps->numChanOut=1; + pSps->selChanOut=0; + pSps->nSamples=pChan->nSamplesTx; + pSps->decimator=pSps->decimate=1; + pSps->interpolate=1; + pSps->ncoef=taps_fir_hpf_300_9_66; + pSps->size_coef=2; + pSps->coef=(void*)coef_fir_hpf_300_9_66; + pSps->nx=taps_fir_hpf_300_9_66; + pSps->size_x=2; + pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); + if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); + pSps->calcAdjust=gain_fir_hpf_300_9_66; + pSps->inputGain=(1*M_Q8); + pSps->outputGain=(1*M_Q8); + inputTmp=pChan->pTxHpf; + } + + // Tx PreEmphasis + if(pChan->txPreEmpEnable) + { + if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(); + else pSps=pSps->nextSps=createPmrSps(); + + pSps->parentChan=pChan; + pSps->source=inputTmp; + pSps->sink=pChan->pTxPreEmp; + + pSps->sigProc=gp_diff; + pSps->enabled=1; + pSps->nSamples=pChan->nSamplesTx; + + pSps->ncoef=taps_int_hpf_4000_1_2; + pSps->size_coef=2; + pSps->coef=(void*)coef_int_hpf_4000_1_2; + + pSps->nx=taps_int_hpf_4000_1_2; + pSps->size_x=2; + pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); + if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); + pSps->outputGain=(1*M_Q8); + pSps->calcAdjust=gain_int_hpf_4000_1_2; + pSps->inputGain=(1*M_Q8); + pSps->outputGain=(1*M_Q8); + inputTmp=pSps->sink; + } + + // Tx Limiter + if(pChan->txLimiterEnable) + { + if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(); + else pSps=pSps->nextSps=createPmrSps(); + pSps->source=inputTmp; + pSps->sink=pChan->pTxLimiter; + pSps->sigProc=SoftLimiter; + pSps->enabled=1; + pSps->nSamples=pChan->nSamplesTx; + pSps->inputGain=(1*M_Q8); + pSps->outputGain=(1*M_Q8); + pSps->setpt=12000; + inputTmp=pSps->sink; + } + + // Composite Mix of Voice and LSD + if((pChan->txMixA==TX_OUT_COMPOSITE)||(pChan->txMixB==TX_OUT_COMPOSITE)) + { + if(pSps==NULL) + pSps=pChan->spsTx=createPmrSps(); + else + pSps=pSps->nextSps=createPmrSps(); + pSps->source=inputTmp; + pSps->sourceB=pChan->pTxLsdLpf; //asdf ??? !!! maw pTxLsdLpf + pSps->sink=pChan->pTxComposite; + pSps->sigProc=pmrMixer; + pSps->enabled=1; + pSps->nSamples=pChan->nSamplesTx; + pSps->inputGain=2*M_Q8; + pSps->inputGainB=1*M_Q8/8; + pSps->outputGain=1*M_Q8; + pSps->setpt=0; + inputTmp=pSps->sink; + pChan->ptxCtcssAdjust=&pSps->inputGainB; + } + + // Chan A Upsampler and Filter + if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(); + else pSps=pSps->nextSps=createPmrSps(); + + pChan->spsTxOutA=pSps; + if(!pChan->spsTx)pChan->spsTx=pSps; + pSps->parentChan=pChan; + + if(pChan->txMixA==TX_OUT_COMPOSITE) + { + pSps->source=pChan->pTxComposite; + } + else if(pChan->txMixA==TX_OUT_LSD) + { + pSps->source=pChan->pTxLsdLpf; + } + else if(pChan->txMixA==TX_OUT_VOICE) + { + pSps->source=pChan->pTxHpf; + } + else if (pChan->txMixA==TX_OUT_AUX) + { + pSps->source=inputTmp; + } + else + { + pSps->source=NULL; + } + + pSps->sink=pChan->pTxOut; + pSps->sigProc=pmr_gp_fir; + pSps->enabled=1; + pSps->numChanOut=2; + pSps->selChanOut=0; + pSps->nSamples=pChan->nSamplesTx; + pSps->interpolate=6; + pSps->ncoef=taps_fir_lpf_3K_1; + pSps->size_coef=2; + pSps->coef=(void*)coef_fir_lpf_3K_1; + pSps->nx=taps_fir_lpf_3K_1; + pSps->size_x=2; + pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); + if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); + pSps->calcAdjust=gain_fir_lpf_3K_1; + pSps->inputGain=(1*M_Q8); + pSps->outputGain=(1*M_Q8); + if(pChan->txMixA==pChan->txMixB)pSps->monoOut=1; + else pSps->monoOut=0; + + + // Chan B Upsampler and Filter + if((pChan->txMixA!=pChan->txMixB)&&(pChan->txMixB!=TX_OUT_OFF)) + { + if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(); + else pSps=pSps->nextSps=createPmrSps(); + + pChan->spsTxOutB=pSps; + pSps->parentChan=pChan; + if(pChan->txMixB==TX_OUT_COMPOSITE) + { + pSps->source=pChan->pTxComposite; + } + else if(pChan->txMixB==TX_OUT_LSD) + { + pSps->source=pChan->pTxLsdLpf; + // pChan->ptxCtcssAdjust=&pSps->inputGain; + } + else if(pChan->txMixB==TX_OUT_VOICE) + { + pSps->source=inputTmp; + } + else if(pChan->txMixB==TX_OUT_AUX) + { + pSps->source=pChan->pTxHpf; + } + else + { + pSps->source=NULL; + } + + pSps->sink=pChan->pTxOut; + pSps->sigProc=pmr_gp_fir; + pSps->enabled=1; + pSps->numChanOut=2; + pSps->selChanOut=1; + pSps->mixOut=0; + pSps->nSamples=pChan->nSamplesTx; + pSps->interpolate=6; + pSps->ncoef=taps_fir_lpf_3K_1; + pSps->size_coef=2; + pSps->coef=(void*)coef_fir_lpf_3K_1; + pSps->nx=taps_fir_lpf_3K_1; + pSps->size_x=2; + pSps->x=(void*)(calloc(pSps->nx,pSps->size_x)); + if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); + pSps->calcAdjust=(gain_fir_lpf_3K_1); + pSps->inputGain=(1*M_Q8); + pSps->outputGain=(1*M_Q8); + + } + + pSps->nextSps=NULL; + + #if XPMR_DEBUG0 == 1 + { + TRACEX((" configure tracing\n")); + t_tdet *ptdet; + + pChan->rxCtcss->pDebug0=calloc(numSamples,2); + pChan->rxCtcss->pDebug1=calloc(numSamples,2); + pChan->rxCtcss->pDebug2=calloc(numSamples,2); + + for(i=0;i<CTCSS_NUM_CODES;i++){ + ptdet=&(pChan->rxCtcss->tdet[i]); + ptdet->pDebug0=calloc(numSamples,2); + ptdet->pDebug1=calloc(numSamples,2); + ptdet->pDebug2=calloc(numSamples,2); + } + + // buffer, 2 bytes per sample, and 16 channels + pChan->prxDebug=calloc(numSamples*16,2); + pChan->ptxDebug=calloc(numSamples*16,2); + } + #endif + + TRACEX((" createPmrChannel() end\n")); + + return pChan; +} +/* +*/ +i16 destroyPmrChannel(t_pmr_chan *pChan) +{ + t_pmr_sps *pmr_sps, *tmp_sps; + + TRACEX(("destroyPmrChannel()\n")); + + free(pChan->pRxDemod); + free(pChan->pRxNoise); + free(pChan->pRxBase); + free(pChan->pRxHpf); + free(pChan->pRxLsd); + free(pChan->pRxSpeaker); + free(pChan->pRxDcTrack); + if(pChan->pRxLsdLimit)free(pChan->pRxLsdLimit); + free(pChan->pTxBase); + free(pChan->pTxHpf); + free(pChan->pTxPreEmp); + free(pChan->pTxLimiter); + free(pChan->pTxLsd); + free(pChan->pTxLsdLpf); + if(pChan->pTxComposite)free(pChan->pTxComposite); + free(pChan->pTxCode); + free(pChan->pTxOut); + + if(pChan->pSigGen0)free(pChan->pSigGen0); + if(pChan->pSigGen1)free(pChan->pSigGen1); + + #if XPMR_DEBUG0 == 1 + free(pChan->pTxPttIn); + free(pChan->pTxPttOut); + if(pChan->prxDebug)free(pChan->prxDebug); + if(pChan->ptxDebug)free(pChan->ptxDebug); + free(pChan->rxCtcss->pDebug0); + free(pChan->rxCtcss->pDebug1); + + free(pChan->prxDebug0); + free(pChan->prxDebug1); + free(pChan->prxDebug2); + free(pChan->prxDebug3); + + free(pChan->ptxDebug0); + free(pChan->ptxDebug1); + free(pChan->ptxDebug2); + free(pChan->ptxDebug3); + + i16 i; + for(i=0;i<CTCSS_NUM_CODES;i++) + { + free(pChan->rxCtcss->tdet[i].pDebug0); + free(pChan->rxCtcss->tdet[i].pDebug1); + free(pChan->rxCtcss->tdet[i].pDebug2); + } + #endif + + free(pChan->pRxCtcss); + + pmr_sps=pChan->spsRx; + + while(pmr_sps) + { + tmp_sps = pmr_sps; + pmr_sps = tmp_sps->nextSps; + destroyPmrSps(tmp_sps); + } + + free(pChan); + + return 0; +} +/* +*/ +t_pmr_sps *createPmrSps(void) +{ + t_pmr_sps *pSps; + + TRACEX(("createPmrSps()\n")); + + pSps = (t_pmr_sps *)calloc(sizeof(t_pmr_sps),1); + + if(!pSps)printf("Error: createPmrSps()\n"); + + // pSps->x=calloc(pSps->nx,pSps->size_x); + + return pSps; +} +/* +*/ +i16 destroyPmrSps(t_pmr_sps *pSps) +{ + TRACEX(("destroyPmrSps(%i)\n",pSps->index)); + + if(pSps->x!=NULL)free(pSps->x); + free(pSps); + return 0; +} +/* + PmrRx does the whole buffer +*/ +i16 PmrRx(t_pmr_chan *pChan, i16 *input, i16 *output) +{ + int i,ii; + t_pmr_sps *pmr_sps; + + TRACEX(("PmrRx() %i\n",pChan->frameCountRx)); + + if(pChan==NULL){ + printf("PmrRx() pChan == NULL\n"); + return 1; + } + + pChan->frameCountRx++; + + pmr_sps=pChan->spsRx; // first sps + pmr_sps->source=input; + + if(output!=NULL)pChan->spsRxOut->sink=output; //last sps + + #if 0 + if(pChan->inputBlanking>0) + { + pChan->inputBlanking-=pChan->nSamplesRx; + if(pChan->inputBlanking<0)pChan->inputBlanking=0; + for(i=0;i<pChan->nSamplesRx*6;i++) + input[i]=0; + } + #endif + + // || (pChan->radioDuplex && (pChan->pttIn || pChan->pttOut))) + if(pChan->rxCpuSaver && !pChan->rxCarrierDetect) + { + if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=0; + if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=0; + } + else + { + if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=1; + if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=1; + } + + i=0; + while(pmr_sps!=NULL && pmr_sps!=0) + { + TRACEX(("PmrRx() sps %i\n",i++)); + pmr_sps->sigProc(pmr_sps); + pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps); + //pmr_sps=NULL; // sph maw + } + + #define XPMR_VOX_HANGTIME 2000 + + if(pChan->rxCdType==CD_XPMR_VOX) + { + if(pChan->spsRxVox->compOut) + { + pChan->rxVoxTimer=XPMR_VOX_HANGTIME; //VOX HangTime in ms + } + if(pChan->rxVoxTimer>0) + { + pChan->rxVoxTimer-=MS_PER_FRAME; + pChan->rxCarrierDetect=1; + } + else + { + pChan->rxVoxTimer=0; + pChan->rxCarrierDetect=0; + } + } + else + { + pChan->rxCarrierDetect=!pChan->spsRx->compOut; + } + + if( !pChan->rxCpuSaver || pChan->rxCarrierDetect + || pChan->rxCtcss->decode!=-1) ctcss_detect(pChan); + + #if XPMR_DEBUG0 == 1 + // TRACEX(("Write file.\n")); + ii=0; + if(pChan->b.rxCapture) + { + for(i=0;i<pChan->nSamplesRx;i++) + { + pChan->prxDebug[ii++]=input[i*2*6]; // input data + pChan->prxDebug[ii++]=output[i]; // output data + pChan->prxDebug[ii++]=pChan->rxCarrierDetect*M_Q14; // carrier detect + if(pChan->rxCtcss) + pChan->prxDebug[ii++]=pChan->rxCtcss->decode*M_Q15/CTCSS_NUM_CODES; // decoded ctcss + else + pChan->prxDebug[ii++]=0; + + pChan->prxDebug[ii++]=pChan->pRxNoise[i]; // rssi + pChan->prxDebug[ii++]=pChan->pRxBase[i]; // decimated, low pass filtered + pChan->prxDebug[ii++]=pChan->pRxHpf[i]; // output to network + pChan->prxDebug[ii++]=pChan->pRxSpeaker[i]; + + pChan->prxDebug[ii++]=pChan->pRxLsd[i]; // CTCSS Filtered + pChan->prxDebug[ii++]=pChan->pRxDcTrack[i]; // DC Restoration + pChan->prxDebug[ii++]=pChan->pRxLsdLimit[i]; // Amplitude Limited + + //pChan->prxDebug[ii++]=pChan->rxCtcss->tdet[pChan->rxCtcss->testIndex+1].pDebug0[i]; // Upper Adjacent CTCSS Code + pChan->prxDebug[ii++]=pChan->rxCtcss->tdet[pChan->rxCtcss->testIndex].pDebug0[i]; // Primary CTCSS Code + pChan->prxDebug[ii++]=pChan->rxCtcss->tdet[pChan->rxCtcss->testIndex].pDebug1[i]; // dv/dt of decoder output + pChan->prxDebug[ii++]=pChan->rxCtcss->tdet[pChan->rxCtcss->testIndex].pDebug2[i]; + + //pChan->prxDebug[ii++]=pChan->rxCtcss->tdet[pChan->rxCtcss->testIndex-1].pDebug0[i]; // Lower Adjacent CTCSS Code + + pChan->prxDebug[ii++]=pChan->prxDebug1[i]; // Measure Output for VOX + pChan->prxDebug[ii++]=pChan->prxDebug2[i]; // Measure Output for Tuning + } + } + #endif + + return 0; +} +/* + PmrTx does the whole buffer +*/ +i16 PmrTx(t_pmr_chan *pChan, i16 *input, i16 *output) +{ + int i, hit=0; + t_pmr_sps *pmr_sps; + + pChan->frameCountTx++; + + TRACEX(("PmrTx() %i\n",pChan->frameCountTx)); + + if(pChan==NULL){ + printf("PmrTx() pChan == NULL\n"); + return 1; + } + + if(pChan->b.startSpecialTone) + { + pChan->b.startSpecialTone=0; + pChan->spsSigGen1->option=1; + pChan->spsSigGen1->enabled=1; + pChan->b.doingSpecialTone=1; + } else if(pChan->b.stopSpecialTone) + { + pChan->b.stopSpecialTone=0; + pChan->spsSigGen1->option=0; + pChan->b.doingSpecialTone=0; + pChan->spsSigGen1->enabled=0; + } else if(pChan->b.doingSpecialTone) + { + pChan->spsSigGen1->sink=output; + pChan->spsSigGen1->sigProc(pChan->spsSigGen1); + for(i=0;i<(pChan->nSamplesTx*2*6);i+=2)output[i+1]=output[i]; + return 0; + } + + // handle transmitter ptt input + hit=0; + if( pChan->txPttIn && pChan->txState==0) + { + pChan->txState = 2; + pChan->txPttOut=1; + pChan->spsSigGen0->freq=pChan->txCtcssFreq*10; + pChan->spsSigGen0->option=1; + pChan->spsSigGen0->enabled=1; + if(pChan->spsTxOutA)pChan->spsTxOutA->enabled=1; + if(pChan->spsTxOutB)pChan->spsTxOutB->enabled=1; + if(pChan->spsTxLsdLpf)pChan->spsTxLsdLpf->enabled=1; + TRACEX((" TxOn\n")); + } + else if(!pChan->txPttIn && pChan->txState==2) + { + if( pChan->txTocType==TOC_NONE || !pChan->txCtcssFreq ) + { + hit=1; + TRACEX((" Tx Off Immediate.\n")); + } + else if(pChan->txCtcssFreq && pChan->txTocType==TOC_NOTONE) + { + pChan->txState=3; + pChan->txHangTime=TOC_NOTONE_TIME/MS_PER_FRAME; + pChan->spsSigGen0->option=3; + TRACEX((" Tx Turn Off No Tone Start.\n")); + } + else + { + pChan->txState=3; + pChan->txHangTime=0; + pChan->spsSigGen0->option=2; + TRACEX((" Tx Turn Off Phase Shift Start.\n")); + } + } + else if(pChan->txState==3) + { + if(pChan->txHangTime) + { + if(--pChan->txHangTime==0)hit=1; + + } + else if(pChan->txHangTime<=0 && pChan->spsSigGen0->state==0) + { + hit=1; + TRACEX((" Tx Off TOC.\n")); + } + if(pChan->txPttIn) + { + TRACEX((" Tx Key During HangTime\n")); + if((pChan->txTocType==TOC_PHASE)||(pChan->txTocType==TOC_NONE)) + { + pChan->txState = 2; + hit=0; + } + } + } + + if( pChan->txCpuSaver && !hit && !pChan->txPttIn && !pChan->txPttOut && pChan->txState==0 ) return (1); + + if(hit) + { + pChan->txPttOut=0; + pChan->txState=0; + if(pChan->spsTxLsdLpf)pChan->spsTxLsdLpf->option=3; + if(pChan->spsTxOutA)pChan->spsTxOutA->option=3; + if(pChan->spsTxOutB)pChan->spsTxOutB->option=3; + TRACEX((" Tx Off hit.\n")); + } + + if(pChan->spsSigGen0) + { + pChan->spsSigGen0->sigProc(pChan->spsSigGen0); + pmr_sps=pChan->spsSigGen0->nextSps; + i=0; + while(pmr_sps!=NULL && pmr_sps!=0) + { + TRACEX((" PmrTx() subaudible sps %i\n",i++)); + //printf(" CTCSS ENCODE %i %i\n",pChan->spsSigGen0->freq,pChan->spsSigGen0->outputGain); + pmr_sps->sigProc(pmr_sps); + pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps); + } + } + + if(pChan->spsSigGen1 && pChan->spsSigGen1->enabled) + { + pChan->spsSigGen1->sigProc(pChan->spsSigGen1); + } + + // Do Voice + pmr_sps=pChan->spsTx; + if(!pChan->spsSigGen1->enabled)pmr_sps->source=input; + else input=pmr_sps->source; + + if(output!=NULL) + { + if(pChan->spsTxOutA)pChan->spsTxOutA->sink=output; + if(pChan->spsTxOutB)pChan->spsTxOutB->sink=output; + } + + i=0; + while(pmr_sps!=NULL && pmr_sps!=0) + { + TRACEX((" PmrTx() sps %i\n",i++)); + pmr_sps->sigProc(pmr_sps); + pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps); + } + + + if(pChan->txMixA==TX_OUT_OFF || !pChan->txPttOut){ + for(i=0;i<pChan->nSamplesTx*2*6;i+=2)output[i]=0; + } + + if(pChan->txMixB==TX_OUT_OFF || !pChan->txPttOut ){ + for(i=0;i<pChan->nSamplesTx*2*6;i+=2)output[i+1]=0; + } + + #if XPMR_DEBUG0 == 1 + if(pChan->b.txCapture) + { + i16 ii=0; + for(i=0;i<pChan->nSamplesTx;i++) + { + pChan->ptxDebug[ii++]=input[i]; + pChan->ptxDebug[ii++]=output[i*2*6]; + pChan->ptxDebug[ii++]=output[(i*2*6)+1]; + pChan->ptxDebug[ii++]=pChan->txPttIn*8192; + + pChan->ptxDebug[ii++]=pChan->txPttOut*8192; + if(pChan->txHpfEnable)pChan->ptxDebug[ii++]=pChan->pTxHpf[i]; + else pChan->ptxDebug[ii++]=0; + if(pChan->txPreEmpEnable)pChan->ptxDebug[ii++]=pChan->pTxPreEmp[i]; + else pChan->ptxDebug[ii++]=0; + if(pChan->txLimiterEnable)pChan->ptxDebug[ii++]=pChan->pTxLimiter[i]; + else pChan->ptxDebug[ii++]=0; + + pChan->ptxDebug[ii++]=pChan->pTxLsd[i]; + pChan->ptxDebug[ii++]=pChan->pTxLsdLpf[i]; + pChan->ptxDebug[ii++]=pChan->pTxComposite[i]; + pChan->ptxDebug[ii++]=pChan->pSigGen1[i]; + + #if 1 + pChan->ptxDebug[ii++]=pChan->ptxDebug0[i]; + pChan->ptxDebug[ii++]=pChan->ptxDebug1[i]; + pChan->ptxDebug[ii++]=pChan->ptxDebug2[i]; + pChan->ptxDebug[ii++]=pChan->ptxDebug3[i]; + #else + pChan->ptxDebug[ii++]=0; + pChan->ptxDebug[ii++]=0; + pChan->ptxDebug[ii++]=0; + pChan->ptxDebug[ii++]=0; + #endif + } + } + #endif + + return 0; +} +/* end of file */ diff --git a/channels/xpmr/xpmr.h b/channels/xpmr/xpmr.h new file mode 100755 index 000000000..d51aa6dca --- /dev/null +++ b/channels/xpmr/xpmr.h @@ -0,0 +1,553 @@ +/* + * xpmr.h - for Xelatec Private Mobile Radio Processes + * + * All Rights Reserved. Copyright (C)2007, Xelatec, LLC + * + * 20070808 1235 Steven Henke, W9SH, sph@xelatec.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This version may be optionally licenced under the GNU LGPL licence. + * + * A license has been granted to Digium (via disclaimer) for the use of + * this code. + * + */ + +/*! \file + * + * \brief Private Land Mobile Radio Channel Voice and Signaling Processor + * + * \author Steven Henke, W9SH <sph@xelatec.com> Xelatec, LLC + */ + +#ifndef XPMR_H +#define XPMR_H 1 + +#ifdef CHAN_USBRADIO +#define XPMR_DEBUG0 1 +#define XPMR_TRACE 0 +#else +#define XPMR_DEBUG0 1 +#define XPMR_TRACE 1 +#endif + +#if(XPMR_TRACE == 1) +#define TRACEX(a) {printf a;} +#define TRACEXL(a) {printf("%s @ %u : ",__FILE__ ,__LINE__); printf a; } +#define TRACEXT(a) { struct timeval hack; gettimeofday(&hack,NULL); printf("%ld.",hack.tv_sec%100000); printf("%i : ",(int)hack.tv_usec); printf a; } +#else +#define TRACEX(a) +#define TRACEXL(a) +#define TRACEXT(a) +#endif + +#define i8 int8_t +#define u8 u_int8_t +#define i16 int16_t +#define u16 u_int16_t +#define i32 int32_t +#define u32 u_int32_t +#define i64 int64_t +#define u64 u_int64_t + +#define M_Q24 0x01000000 // +#define M_Q23 0x00800000 // +#define M_Q22 0x00400000 // +#define M_Q21 0x00200000 // +#define M_Q20 0x00100000 // 1048576 +#define M_Q19 0x00080000 // 524288 +#define M_Q18 0x00040000 // 262144 +#define M_Q17 0x00020000 // 131072 +#define M_Q16 0x00010000 // 65536 +#define M_Q15 0x00008000 // 32768 +#define M_Q14 0x00004000 // 16384 +#define M_Q13 0x00002000 // 8182 +#define M_Q12 0x00001000 // 4096 +#define M_Q11 0x00000800 // 2048 +#define M_Q10 0x00000400 // 1024 +#define M_Q9 0x00000200 // 512 +#define M_Q8 0x00000100 // 256 +#define M_Q7 0x00000080 // 128 +#define M_Q6 0x00000040 // 64 +#define M_Q5 0x00000020 // 32 +#define M_Q4 0x00000010 // 16 +#define M_Q3 0x00000008 // 16 +#define M_Q2 0x00000004 // 16 +#define M_Q1 0x00000002 // 16 +#define M_Q0 0x00000001 // 16 + +#define RADIANS_PER_CYCLE (2*M_PI) + +#define SAMPLE_RATE_INPUT 48000 +#define SAMPLE_RATE_NETWORK 8000 + +#define SAMPLES_PER_BLOCK 160 +#define MS_PER_FRAME 20 + +#define CTCSS_NUM_CODES 38 +#define CTCSS_SCOUNT_MUL 100 +#define CTCSS_INTEGRATE 3932 // 32767*.120 // 120/1000 // 0.120 +#define CTCSS_INPUT_LIMIT 1000 +#define CTCSS_DETECT_POINT 1989 +#define CTCSS_HYSTERSIS 200 + +#define CTCSS_TURN_OFF_TIME 160 // ms +#define CTCSS_TURN_OFF_SHIFT 240 // degrees +#define TOC_NOTONE_TIME 600 // ms + +#ifndef CHAN_USBRADIO +enum {RX_AUDIO_NONE,RX_AUDIO_SPEAKER,RX_AUDIO_FLAT}; +enum {TX_AUDIO_NONE,TX_AUDIO_FLAT,TX_AUDIO_FILTERED,TX_AUDIO_PROC}; +enum {CD_IGNORE,CD_XPMR_NOISE,CD_XPMR_VOX,CD_HID,CD_HID_INVERT}; +enum {SD_IGNORE,SD_HID,SD_HID_INVERT,SD_XPMR}; // no,external,externalinvert,software +enum {RX_KEY_CARRIER,RX_KEY_CARRIER_CODE}; +enum {TX_OUT_OFF,TX_OUT_VOICE,TX_OUT_LSD,TX_OUT_COMPOSITE,TX_OUT_AUX}; +enum {TOC_NONE,TOC_PHASE,TOC_NOTONE}; +#endif + +/* + one structure for each ctcss tone to decode +*/ +typedef struct +{ + i16 counter; // counter to next sample + i16 counterFactor; // full divisor used to increment counter + i16 binFactor; + i16 fudgeFactor; + i16 peak; // peak amplitude now maw sph now + i16 enabled; + i16 state; // dead, running, error + i16 zIndex; // z bucket index + i16 z[4]; // maw sph today + i16 zi; + i16 dvu; + i16 dvd; + i16 zd; + i16 setpt; + i16 hyst; + i16 decode; + i16 diffpeak; + i16 debug; // value held from last pass + i16 *pDebug0; // pointer to debug output + i16 *pDebug1; // pointer to debug output + i16 *pDebug2; // pointer to debug output + +} t_tdet; + +typedef struct +{ + i16 enabled; // if 0 none, 0xFFFF all tones, or single tone + i16 *input; + i16 clamplitude; + i16 center; + i16 decode; // current ctcss decode index + i32 BlankingTimer; + u32 TurnOffTimer; + t_tdet tdet[CTCSS_NUM_CODES]; + i16 gain; + i16 limit; + i16 *pDebug0; + i16 *pDebug1; + i16 *pDebug2; + i16 testIndex; + i16 multiFreq; + i8 relax; + +} t_dec_ctcss; + +typedef struct +{ + i16 enabled; // if 0 none, 0xFFFF all tones, or single tone + i16 clamplitude; + i16 center; + i16 decode; // current ctcss decode value + i32 BlankingTimer; + u32 TurnOffTimer; + i16 gain; + i16 limit; + i16 *pDebug0; + i16 *pDebug1; + i16 rxPolarity; +} t_dec_dcs; + +/* + Low Speed Data decoding both polarities +*/ +typedef struct +{ + i16 counter; // counter to next sample + i16 synced; + u32 syncCorr[2]; + u32 data[2]; + i16 state; // disabled, enabled, + i16 decode; + i16 debug; + + i16 polarity; + u32 frameNum; + + u16 area; + u16 chan; + u16 home; + u16 id; + u16 free; + + u16 crc; + i16 rssi; + +} t_decLsd; + + +/* general purpose pmr signal processing element */ + +struct t_pmr_chan; + +typedef struct t_pmr_sps +{ + i16 index; // unique to each instance + + i16 enabled; // enabled/disabled + + struct t_pmr_chan *parentChan; + + i16 *source; // source buffer + i16 *sourceB; // source buffer B + i16 *sink; // sink buffer + + i16 numChanOut; // allows output direct to interleaved buffer + i16 selChanOut; + + u32 ticks; + + void *buff; // this structure's internal buffer + + i16 *debugBuff0; // debug buffer + i16 *debugBuff1; // debug buffer + i16 *debugBuff2; // debug buffer + i16 *debugBuff3; // debug buffer + + i16 nSamples; // number of samples in the buffer + + u32 buffSize; // buffer maximum index + u32 buffInIndex; // index to current input point + u32 buffOutIndex; // index to current output point + u32 buffLead; // lead of input over output through cb + + i16 decimate; // decimation or interpolation factor (could be put in coef's) + i16 interpolate; + i16 decimator; // like the state this must be saved between calls (could be put in x's) + + u32 sampleRate; // in Hz for elements in this structure + u32 freq; // in 0.1 Hz + + i16 measPeak; // do measure Peak + i16 amax; // buffer amplitude maximum + i16 amin; // buffer amplitude minimum + i16 apeak; // buffer amplitude peak value (peak to peak)/2 + i16 setpt; // amplitude set point for amplitude comparator + i16 hyst; // hysterysis for amplitude comparator + i16 compOut; // amplitude comparator output + + i32 discounteru; // amplitude detector integrator discharge counter upper + i32 discounterl; // amplitude detector integrator discharge counter lower + i32 discfactor; // amplitude detector integrator discharge factor + + i16 err; // error condition + i16 option; // option / request zero + i16 state; // stopped, start, stopped assumes zero'd + + i16 cleared; // output buffer cleared + + i16 delay; + i16 decode; + + i32 inputGain; // apply to input data ? in Q7.8 format + i32 inputGainB; // apply to input data ? in Q7.8 format + i32 outputGain; // apply to output data ? in Q7.8 format + i16 mixOut; + i16 monoOut; + + i16 filterType; // iir, fir, 1, 2, 3, 4 ... + + i16 (*sigProc)(struct t_pmr_sps *sps); // function to call + + i32 calcAdjust; // final adjustment + i16 nx; // number of x history elements + i16 ncoef; // number of coefficients + i16 size_x; // size of each x history element + i16 size_coef; // size of each coefficient + void *x; // history registers + void *x2; // history registers, 2nd bank + void *coef; // coefficients + void *coef2; // coefficients 2 + + void *nextSps; // next Sps function + +} t_pmr_sps; + +/* + pmr channel +*/ +typedef struct t_pmr_chan +{ + i16 index; // which one + i16 enabled; // enabled/disabled + i16 status; // ok, error, busy, idle, initializing + + i16 nSamplesRx; // max frame size + i16 nSamplesTx; + + i32 inputSampleRate; // in S/s 48000 + i32 baseSampleRate; // in S/s 8000 + + i16 inputGain; + i16 inputOffset; + + u32 frameCountRx; // number processed + u32 frameCountTx; + + i32 txHangTime; + i32 txTurnOff; + + i16 rxDC; // average DC value of input + i16 rxSqSet; // carrier squelch threshold + i16 rxSqHyst; // carrier squelch hysterysis + i16 rxRssi; // current Rssi level + i16 rxQuality; // signal quality metric + i16 rxCarrierDetect; // carrier detect + i16 rxCdType; + i16 rxExtCarrierDetect; + i32 inputBlanking; // Tx pulse eliminator + + i16 rxDemod; // see enum + i16 txMod; // + + i16 rxNoiseSquelchEnable; + i16 rxHpfEnable; + i16 rxDeEmpEnable; + i16 rxCenterSlicerEnable; + i16 rxCtcssDecodeEnable; + i16 rxDcsDecodeEnable; + i16 rxDelayLineEnable; + + i16 txHpfEnable; + i16 txLimiterEnable; + i16 txPreEmpEnable; + i16 txLpfEnable; + + char radioDuplex; + + struct { + unsigned pmrNoiseSquelch:1; + unsigned rxHpf:1; + unsigned txHpf:1; + unsigned txLpf:1; + unsigned rxDeEmphasis:1; + unsigned txPreEmphasis:1; + unsigned startSpecialTone:1; + unsigned stopSpecialTone:1; + unsigned doingSpecialTone:1; + unsigned extCarrierDetect:1; + unsigned txCapture:1; + unsigned rxCapture:1; + }b; + + i16 dummy; + + i32 txScramFreq; + i32 rxScramFreq; + + i16 gainVoice; + i16 gainSubAudible; + + i16 txMixA; // Off, Ctcss, Voice, Composite + i16 txMixB; // Off, Ctcss, Voice, Composite + + i16 rxMuting; + + i16 rxCpuSaver; + i16 txCpuSaver; + + i8 rxSqMode; // 0 open, 1 carrier, 2 coded + + i8 cdMethod; + + i16 rxSquelchPoint; + + i16 rxCarrierPoint; + i16 rxCarrierHyst; + + i16 rxCtcssMap[CTCSS_NUM_CODES]; + + i16 txCtcssTocShift; + i16 txCtcssTocTime; + i8 txTocType; + + float txCtcssFreq; + float rxCtcssFreq; + float rxInputGain; + + i16 rxCtcssIndex; + + i16 txPttIn; // from external request + i16 txPttOut; // to radio hardware + + i16 bandwidth; // wide/narrow + i16 txCompand; // type + i16 rxCompand; // + + i16 txEqRight; // muted, flat, pre-emp limited filtered + i16 txEqLeft; + + i16 txPotRight; // + i16 txPotLeft; // + + i16 rxPotRight; // + i16 rxPotLeft; // + + i16 function; + + i16 txState; // off,settling,on,hangtime,turnoff + + t_pmr_sps *spsMeasure; // measurement block + + t_pmr_sps *spsRx; // 1st signal processing struct + t_pmr_sps *spsRxLsd; + t_pmr_sps *spsRxDeEmp; + t_pmr_sps *spsRxHpf; + t_pmr_sps *spsRxVox; + t_pmr_sps *spsDelayLine; // Last signal processing struct + t_pmr_sps *spsRxOut; // Last signal processing struct + + t_pmr_sps *spsTx; // 1st signal processing struct + + t_pmr_sps *spsTxLsdLpf; + t_pmr_sps *spsTxOutA; // Last signal processing struct + + t_pmr_sps *spsTxOutB; // Last signal processing struct + + t_pmr_sps *spsSigGen0; // ctcss + t_pmr_sps *spsSigGen1; // test and other tones + + // tune tweaks + + i32 rxVoxTimer; // Vox Hang Timer + + i16 *prxSquelchAdjust; + + // i16 *prxNoiseMeasure; // for autotune + // i32 *prxNoiseAdjust; + + i16 *prxVoiceMeasure; + i32 *prxVoiceAdjust; + + i16 *prxCtcssMeasure; + i32 *prxCtcssAdjust; + + i16 *ptxVoiceAdjust; // from calling application + i32 *ptxCtcssAdjust; // from calling application + + i32 *ptxLimiterAdjust; // from calling application + + i16 *pRxDemod; // buffers + i16 *pRxBase; // decimated lpf input + i16 *pRxNoise; + i16 *pRxLsd; // subaudible only + i16 *pRxHpf; // subaudible removed + i16 *pRxDeEmp; // EIA Audio + i16 *pRxSpeaker; // EIA Audio + i16 *pRxDcTrack; // DC Restored LSD + i16 *pRxLsdLimit; // LSD Limited + i16 *pRxCtcss; // + i16 *pRxSquelch; + + i16 *pTxBase; // input data + i16 *pTxHpf; + i16 *pTxPreEmp; + i16 *pTxLimiter; + i16 *pTxLsd; + i16 *pTxLsdLpf; + i16 *pTxComposite; + i16 *pTxMod; // upsampled, low pass filtered + + i16 *pTxOut; // + + i16 *pTxPttIn; + i16 *pTxPttOut; + i16 *pTxHang; + i16 *pTxCode; + + i16 *pSigGen0; + i16 *pSigGen1; + + i16 *pAlt0; + i16 *pAlt1; + + i16 *pNull; + + i16 *prxDebug; // consolidated debug buffer + i16 *ptxDebug; // consolidated debug buffer + + i16 *prxDebug0; + i16 *prxDebug1; + i16 *prxDebug2; + i16 *prxDebug3; + + i16 *ptxDebug0; + i16 *ptxDebug1; + i16 *ptxDebug2; + i16 *ptxDebug3; + + t_dec_ctcss *rxCtcss; + + i16 clamplitudeDcs; + i16 centerDcs; + u32 dcsBlankingTimer; + i16 dcsDecode; // current dcs decode value + + i16 clamplitudeLsd; + i16 centerLsd; + t_decLsd decLsd[2]; // for both polarities + +} t_pmr_chan; + +static i16 TxTestTone(t_pmr_chan *pChan, i16 function); + +t_pmr_chan *createPmrChannel(t_pmr_chan *tChan, i16 numSamples); +t_pmr_sps *createPmrSps(void); +i16 destroyPmrChannel(t_pmr_chan *pChan); +i16 destroyPmrSps(t_pmr_sps *pSps); +i16 pmr_rx_frontend(t_pmr_sps *mySps); +i16 pmr_gp_fir(t_pmr_sps *mySps); +i16 pmr_gp_iir(t_pmr_sps *mySps); +i16 gp_inte_00(t_pmr_sps *mySps); +i16 gp_diff(t_pmr_sps *mySps); +i16 CenterSlicer(t_pmr_sps *mySps); +i16 ctcss_detect(t_pmr_chan *pmrChan); +i16 SoftLimiter(t_pmr_sps *mySps); +i16 SigGen(t_pmr_sps *mySps); +i16 pmrMixer(t_pmr_sps *mySps); +i16 DelayLine(t_pmr_sps *mySps); +i16 PmrRx(t_pmr_chan *PmrChan, i16 *input, i16 *output); +i16 PmrTx(t_pmr_chan *PmrChan, i16 *input, i16 *output); +i16 CtcssFreqIndex(float freq); +i16 MeasureBlock(t_pmr_sps *mySps); +#endif /* ! XPMR_H */ + +/* end of file */ + + + diff --git a/channels/xpmr/xpmr_coef.h b/channels/xpmr/xpmr_coef.h new file mode 100755 index 000000000..4b7274e5a --- /dev/null +++ b/channels/xpmr/xpmr_coef.h @@ -0,0 +1,963 @@ +/* + * xpmr_coef.h - for Xelatec Private Mobile Radio Processes + * + * All Rights Reserved. Copyright (C)2007, Xelatec, LLC + * + * 20070808 1235 Steven Henke, W9SH, sph@xelatec.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This version may be optionally licenced under the GNU LGPL licence. + * + * A license has been granted to Digium (via disclaimer) for the use of + * this code. + * + * Some filter coeficients via 'WinFilter' http://www.winfilter.20m.com. + * + */ + +/*! \file + * + * \brief Private Land Mobile Radio Channel Voice and Signaling Processor + * + * \author Steven Henke, W9SH <sph@xelatec.com> Xelatec, LLC + */ + +#ifndef XPMR_COEF_H +#define XMPR_COEF_H 1 + +// frequencies in 0.1 Hz +const u32 dtmf_row[] = +{ + 6970, 7700, 8520, 9410 +}; +const u32 dtmf_col[] = +{ + 12090, 13360, 14770, 16330 +}; + +const i16 coef_dcs_rx = 1488; // dcs rx data divisor for oversampling 8000/134.4 +const i16 coef_dcs_tx = 5952; // dcs tx data divisor + +const i16 coef_lsd_div = 672; // low speed data divisor +const u32 coef_lsd_sync = 0x158; // 000101011000 +const u32 coef_lsd_sync_pattern[] = {0x0000000F, 0x0F0FF000}; + +#define CTCSS_COEF_INT 120 +#define CTCSS_SAMPLE_RATE 8000 +#define TDIV(x) ((CTCSS_SAMPLE_RATE*1000/x)+5)/10 + +i32 coef_ctcss[4][5]= +{ + // freq, divisor, integrator, filter + {770,TDIV(770),CTCSS_COEF_INT,0,0}, + {1000,TDIV(1000),CTCSS_COEF_INT,0,0}, + {1035,TDIV(1035),CTCSS_COEF_INT,0,0}, + {0,0,0,0} +}; + + +i16 coef_ctcss_div[]= +{ +2985, // 00 067.0 +2782, // 01 071.9 +2688, // 02 074.4 +2597, // 03 077.0 +2509, // 04 079.7 +2424, // 05 082.5 +2342, // 06 085.4 +2260, // 07 088.5 +2186, // 08 091.5 +2110, // 09 094.8 +2053, // 10 097.4 +2000, // 11 100.0 +1932, // 12 103.5 +1866, // 13 107.2 +1803, // 14 110.9 +1742, // 15 114.8 +1684, // 16 118.8 +1626, // 17 123.0 +1571, // 18 127.3 +1517, // 19 131.8 +1465, // 20 136.5 +1415, // 21 141.3 +1368, // 22 146.2 +1321, // 23 151.4 +1276, // 24 156.7 +1233, // 25 162.2 +1191, // 26 167.9 +1151, // 27 173.8 +1112, // 28 179.9 +1074, // 29 186.2 +1037, // 30 192.8 +983, // 31 203.5 +949, // 32 210.7 +917, // 33 218.1 +886, // 34 225.7 +856, // 35 233.6 +827, // 36 241.8 +799 // 37 250.3 +}; + +float freq_ctcss[]= +{ +067.0, // 00 +071.9, // 01 +074.4, // 02 +077.0, // 03 +079.7, // 04 +082.5, // 05 +085.4, // 06 +088.5, // 07 +091.5, // 08 +094.8, // 09 +097.4, // 10 +100.0, // 11 +103.5, // 12 +107.2, // 13 +110.9, // 14 +114.8, // 15 +118.8, // 16 +123.0, // 17 +127.3, // 18 +131.8, // 19 +136.5, // 20 +141.3, // 21 +146.2, // 22 +151.4, // 23 +156.7, // 24 +162.2, // 25 +167.9, // 26 +173.8, // 27 +179.9, // 28 +186.2, // 29 +192.8, // 30 +203.5, // 31 +210.7 , // 32 +218.1 , // 33 +225.7 , // 34 +233.6 , // 35 +241.8 , // 36 +250.3 // 37 +}; + +/* + noise squelch carrier detect filter +*/ +static const int16_t taps_fir_bpf_noise_1 = 66; +static const int32_t gain_fir_bpf_noise_1 = 65536; +static const int16_t coef_fir_bpf_noise_1[] = { + 139, + -182, + -269, + -66, + 56, + 59, + 250, + 395, + -80, + -775, + -557, + 437, + 779, + 210, + -17, + 123, + -692, + -1664, + -256, + 2495, + 2237, + -1018, + -2133, + -478, + -1134, + -2711, + 2642, + 10453, + 4010, + -14385, + -16488, + 6954, + 23030, + 6954, + -16488, + -14385, + 4010, + 10453, + 2642, + -2711, + -1134, + -478, + -2133, + -1018, + 2237, + 2495, + -256, + -1664, + -692, + 123, + -17, + 210, + 779, + 437, + -557, + -775, + -80, + 395, + 250, + 59, + 56, + -66, + -269, + -182, + 139, + 257 +}; +/* + tbd +*/ +static const int16_t taps_fir_lpf_3K_1 = 66; +static const int32_t gain_fir_lpf_3K_1 = 131072; +static const int16_t coef_fir_lpf_3K_1[] = { + 259, + 58, + -185, + -437, + -654, + -793, + -815, + -696, + -434, + -48, + 414, + 886, + 1284, + 1523, + 1529, + 1254, + 691, + -117, + -1078, + -2049, + -2854, + -3303, + -3220, + -2472, + -995, + 1187, + 3952, + 7086, + 10300, + 13270, + 15672, + 17236, + 17778, + 17236, + 15672, + 13270, + 10300, + 7086, + 3952, + 1187, + -995, + -2472, + -3220, + -3303, + -2854, + -2049, + -1078, + -117, + 691, + 1254, + 1529, + 1523, + 1284, + 886, + 414, + -48, + -434, + -696, + -815, + -793, + -654, + -437, + -185, + 58, + 259, + 393 +}; + +/************************************************************** +Filter type: Low Pass +Filter model: Butterworth +Filter order: 9 +Sampling Frequency: 8 KHz +Cut Frequency: 0.250000 KHz +Coefficents Quantization: 16-bit +***************************************************************/ +static const int16_t taps_fir_lpf_250_11_64 = 64; +static const int32_t gain_fir_lpf_250_11_64 = 262144; +static const int16_t coef_fir_lpf_250_11_64[] = +{ + 366, + -3, + -418, + -865, + -1328, + -1788, + -2223, + -2609, + -2922, + -3138, + -3232, + -3181, + -2967, + -2573, + -1988, + -1206, + -228, + 937, + 2277, + 3767, + 5379, + 7077, + 8821, + 10564, + 12259, + 13855, + 15305, + 16563, + 17588, + 18346, + 18812, + 18968, + 18812, + 18346, + 17588, + 16563, + 15305, + 13855, + 12259, + 10564, + 8821, + 7077, + 5379, + 3767, + 2277, + 937, + -228, + -1206, + -1988, + -2573, + -2967, + -3181, + -3232, + -3138, + -2922, + -2609, + -2223, + -1788, + -1328, + -865, + -418, + -3, + 366, + 680 +}; + +// de-emphasis integrator 300 Hz with 8KS/s +// a0, b1 +static const int16_t taps_int_lpf_300_1_2 = 2; +static const int32_t gain_int_lpf_300_1_2 = 8182; +static const int16_t coef_int_lpf_300_1_2[]={ +6878, +25889 +}; + +// pre-emphasis differentiator 4000 Hz with 8KS/s +// a0,a1,b0, +static const int16_t taps_int_hpf_4000_1_2 = 2; +static const int32_t gain_int_hpf_4000_1_2 = 16384; +static const int16_t coef_int_hpf_4000_1_2[]={ +17610, +-17610, +2454 +}; + + +/* + ltr crc table + from http://www.radioreference.com/forums/showthread.php?t=24126 +*/ + +static const u8 ltr_table[]= +{ +0x38, // 00 Area 0111000 +0x1c, // 01 Channel 4 0011100 +0x0e, // 02 Channel 3 0001110 +0x46, // 03 Channel 2 1000110 +0x23, // 04 Channel 1 0100011 +0x51, // 05 Channel 0 1010001 +0x68, // 06 Home 4 1101000 +0x75, // 07 Home 3 1110101 +0x7a, // 08 Home 2 1111010 +0x3d, // 09 Home 1 0111101 +0x1f, // 10 Home 0 0011111 +0x4f, // 11 Group 7 1001111 +0x26, // 12 Group 6 0100110 +0x52, // 13 Group 5 1010010 +0x29, // 14 Group 4 0101001 +0x15, // 15 Group 3 0010101 +0x0d, // 16 Group 2 0001101 +0x45, // 17 Group 1 1000101 +0x62, // 18 Group 0 1100010 +0x31, // 19 Free 4 0110001 +0x19, // 20 Free 3 0011001 +0x0d, // 21 Free 2 0001101 +0x07, // 22 Free 1 0000111 +0x43 // 23 Free 0 1000011 +}; + +static const i16 bitWeight[]= +{ +0, // 0 +1, // 1 +1, // 2 +2, // 3 +1, // 4 +2, // 5 +2, // 6 +3, // 7 +1, // 8 +2, // 9 +2, // 10 +3, // 11 +2, // 12 +3, // 13 +3, // 14 +4, // 15 +1, // 16 +2, // 17 +2, // 18 +3, // 19 +2, // 20 +3, // 21 +3, // 22 +4, // 23 +2, // 24 +3, // 25 +3, // 26 +4, // 27 +3, // 28 +4, // 29 +4, // 30 +5, // 31 +1, // 32 +2, // 33 +2, // 34 +3, // 35 +2, // 36 +3, // 37 +3, // 38 +4, // 39 +2, // 40 +3, // 41 +3, // 42 +4, // 43 +3, // 44 +4, // 45 +4, // 46 +5, // 47 +2, // 48 +3, // 49 +3, // 50 +4, // 51 +3, // 52 +4, // 53 +4, // 54 +5, // 55 +3, // 56 +4, // 57 +4, // 58 +5, // 59 +4, // 60 +5, // 61 +5, // 62 +6, // 63 +1, // 64 +2, // 65 +2, // 66 +3, // 67 +2, // 68 +3, // 69 +3, // 70 +4, // 71 +2, // 72 +3, // 73 +3, // 74 +4, // 75 +3, // 76 +4, // 77 +4, // 78 +5, // 79 +2, // 80 +3, // 81 +3, // 82 +4, // 83 +3, // 84 +4, // 85 +4, // 86 +5, // 87 +3, // 88 +4, // 89 +4, // 90 +5, // 91 +4, // 92 +5, // 93 +5, // 94 +6, // 95 +2, // 96 +3, // 97 +3, // 98 +4, // 99 +3, // 100 +4, // 101 +4, // 102 +5, // 103 +3, // 104 +4, // 105 +4, // 106 +5, // 107 +4, // 108 +5, // 109 +5, // 110 +6, // 111 +3, // 112 +4, // 113 +4, // 114 +5, // 115 +4, // 116 +5, // 117 +5, // 118 +6, // 119 +4, // 120 +5, // 121 +5, // 122 +6, // 123 +5, // 124 +6, // 125 +6, // 126 +7, // 127 +1, // 128 +2, // 129 +2, // 130 +3, // 131 +2, // 132 +3, // 133 +3, // 134 +4, // 135 +2, // 136 +3, // 137 +3, // 138 +4, // 139 +3, // 140 +4, // 141 +4, // 142 +5, // 143 +2, // 144 +3, // 145 +3, // 146 +4, // 147 +3, // 148 +4, // 149 +4, // 150 +5, // 151 +3, // 152 +4, // 153 +4, // 154 +5, // 155 +4, // 156 +5, // 157 +5, // 158 +6, // 159 +2, // 160 +3, // 161 +3, // 162 +4, // 163 +3, // 164 +4, // 165 +4, // 166 +5, // 167 +3, // 168 +4, // 169 +4, // 170 +5, // 171 +4, // 172 +5, // 173 +5, // 174 +6, // 175 +3, // 176 +4, // 177 +4, // 178 +5, // 179 +4, // 180 +5, // 181 +5, // 182 +6, // 183 +4, // 184 +5, // 185 +5, // 186 +6, // 187 +5, // 188 +6, // 189 +6, // 190 +7, // 191 +2, // 192 +3, // 193 +3, // 194 +4, // 195 +3, // 196 +4, // 197 +4, // 198 +5, // 199 +3, // 200 +4, // 201 +4, // 202 +5, // 203 +4, // 204 +5, // 205 +5, // 206 +6, // 207 +3, // 208 +4, // 209 +4, // 210 +5, // 211 +4, // 212 +5, // 213 +5, // 214 +6, // 215 +4, // 216 +5, // 217 +5, // 218 +6, // 219 +5, // 220 +6, // 221 +6, // 222 +7, // 223 +3, // 224 +4, // 225 +4, // 226 +5, // 227 +4, // 228 +5, // 229 +5, // 230 +6, // 231 +4, // 232 +5, // 233 +5, // 234 +6, // 235 +5, // 236 +6, // 237 +6, // 238 +7, // 239 +4, // 240 +5, // 241 +5, // 242 +6, // 243 +5, // 244 +6, // 245 +6, // 246 +7, // 247 +5, // 248 +6, // 249 +6, // 250 +7, // 251 +6, // 252 +7, // 253 +7, // 254 +8 // 255 +}; + + +/* + ctcss decode filter +*/ +/************************************************************** +Filter type: Low Pass +Filter model: Butterworth +Filter order: 9 +Sampling Frequency: 8 KHz +Cut Frequency: 0.250000 KHz +Coefficents Quantization: 16-bit +***************************************************************/ +static const int16_t taps_fir_lpf_250_9_66 = 66; +static const int32_t gain_fir_lpf_250_9_66 = 262144; +static const int16_t coef_fir_lpf_250_9_66[] = +{ + 676, + 364, + -3, + -415, + -860, +-1320, +-1777, +-2209, +-2593, +-2904, +-3119, +-3212, +-3162, +-2949, +-2557, +-1975, +-1198, + -226, + 932, + 2263, + 3744, + 5346, + 7034, + 8767, +10499, +12184, +13770, +15211, +16462, +17480, +18234, +18696, +18852, +18696, +18234, +17480, +16462, +15211, +13770, +12184, +10499, + 8767, + 7034, + 5346, + 3744, + 2263, + 932, + -226, +-1198, +-1975, +-2557, +-2949, +-3162, +-3212, +-3119, +-2904, +-2593, +-2209, +-1777, +-1320, + -860, + -415, + -3, + 364, + 676, + 927 +}; +/* ************************************************************* +Filter type: Low Pass +Filter model: Butterworth +Filter order: 9 +Sampling Frequency: 8 KHz +Cut Frequency: 0.215 KHz +Coefficents Quantization: 16-bit +***************************************************************/ +static const int16_t taps_fir_lpf_215_9_88 = 88; +static const int32_t gain_fir_lpf_215_9_88 = 524288; +static const int16_t coef_fir_lpf_215_9_88[] = { + 2038, + 2049, + 1991, + 1859, + 1650, + 1363, + 999, + 562, + 58, + -502, +-1106, +-1739, +-2382, +-3014, +-3612, +-4153, +-4610, +-4959, +-5172, +-5226, +-5098, +-4769, +-4222, +-3444, +-2430, +-1176, + 310, + 2021, + 3937, + 6035, + 8284, +10648, +13086, +15550, +17993, +20363, +22608, +24677, +26522, +28099, +29369, +30299, +30867, +31058, +30867, +30299, +29369, +28099, +26522, +24677, +22608, +20363, +17993, +15550, +13086, +10648, + 8284, + 6035, + 3937, + 2021, + 310, +-1176, +-2430, +-3444, +-4222, +-4769, +-5098, +-5226, +-5172, +-4959, +-4610, +-4153, +-3612, +-3014, +-2382, +-1739, +-1106, + -502, + 58, + 562, + 999, + 1363, + 1650, + 1859, + 1991, + 2049, + 2038, + 1966 +}; +// end coef fir_lpf_215_9_88 +// +/************************************************************** +Filter type: High Pass +Filter model: Butterworth +Filter order: 9 +Sampling Frequency: 8 KHz +Cut Frequency: 0.300000 KHz +Coefficents Quantization: 16-bit +***************************************************************/ +static const int16_t taps_fir_hpf_300_9_66 = 66; +static const int32_t gain_fir_hpf_300_9_66 = 32768; +static const int16_t coef_fir_hpf_300_9_66[] = +{ + -141, + -114, + -77, + -30, + 23, + 83, + 147, + 210, + 271, + 324, + 367, + 396, + 407, + 396, + 362, + 302, + 216, + 102, + -36, + -199, + -383, + -585, + -798, +-1017, +-1237, +-1452, +-1653, +-1836, +-1995, +-2124, +-2219, +-2278, +30463, +-2278, +-2219, +-2124, +-1995, +-1836, +-1653, +-1452, +-1237, +-1017, + -798, + -585, + -383, + -199, + -36, + 102, + 216, + 302, + 362, + 396, + 407, + 396, + 367, + 324, + 271, + 210, + 147, + 83, + 23, + -30, + -77, + -114, + -141, + -158 + }; +#endif /* !XPMR_COEF_H */ +/* end of file */ + + + + |