├── .gitattributes ├── .gitignore ├── AndroidManifest.xml ├── COPYING ├── README.md ├── project.properties ├── res └── xml │ └── device_filter.xml └── src └── com ├── hoho └── android │ └── usbserial │ ├── driver │ ├── CdcAcmSerialDriver.java │ ├── CommonUsbSerialPort.java │ ├── Cp21xxSerialDriver.java │ ├── FtdiSerialDriver.java │ ├── ProbeTable.java │ ├── ProlificSerialDriver.java │ ├── UsbId.java │ ├── UsbSerialDriver.java │ ├── UsbSerialPort.java │ ├── UsbSerialProber.java │ └── UsbSerialRuntimeException.java │ └── util │ ├── HexDump.java │ └── SerialInputOutputManager.java └── rtlsdr └── android ├── SdrSerialDriver.java ├── SdrSerialDriverOrig.java ├── SdrUsbId.java └── tuners ├── E4K.java ├── FC0012.java ├── FC0013.java ├── FC2580.java ├── IRtlSdrTuner.java └── R820T.java /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | gen/ 10 | tmp/ 11 | *.tmp 12 | *.bak 13 | *.swp 14 | *~.nib 15 | local.properties 16 | .classpath 17 | .settings/ 18 | .loadpath 19 | 20 | # External tool builders 21 | .externalToolBuilders/ 22 | 23 | # Locally stored "Eclipse launch configurations" 24 | *.launch 25 | 26 | # CDT-specific 27 | .cproject 28 | 29 | # PDT-specific 30 | .buildpath 31 | 32 | 33 | ################# 34 | ## Visual Studio 35 | ################# 36 | 37 | ## Ignore Visual Studio temporary files, build results, and 38 | ## files generated by popular Visual Studio add-ons. 39 | 40 | # User-specific files 41 | *.suo 42 | *.user 43 | *.sln.docstates 44 | 45 | # Build results 46 | 47 | [Dd]ebug/ 48 | [Rr]elease/ 49 | x64/ 50 | build/ 51 | [Bb]in/ 52 | [Oo]bj/ 53 | 54 | # MSTest test Results 55 | [Tt]est[Rr]esult*/ 56 | [Bb]uild[Ll]og.* 57 | 58 | *_i.c 59 | *_p.c 60 | *.ilk 61 | *.meta 62 | *.obj 63 | *.pch 64 | *.pdb 65 | *.pgc 66 | *.pgd 67 | *.rsp 68 | *.sbr 69 | *.tlb 70 | *.tli 71 | *.tlh 72 | *.tmp 73 | *.tmp_proj 74 | *.log 75 | *.vspscc 76 | *.vssscc 77 | .builds 78 | *.pidb 79 | *.log 80 | *.scc 81 | 82 | # Visual C++ cache files 83 | ipch/ 84 | *.aps 85 | *.ncb 86 | *.opensdf 87 | *.sdf 88 | *.cachefile 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | 102 | # TeamCity is a build add-in 103 | _TeamCity* 104 | 105 | # DotCover is a Code Coverage Tool 106 | *.dotCover 107 | 108 | # NCrunch 109 | *.ncrunch* 110 | .*crunch*.local.xml 111 | 112 | # Installshield output folder 113 | [Ee]xpress/ 114 | 115 | # DocProject is a documentation generator add-in 116 | DocProject/buildhelp/ 117 | DocProject/Help/*.HxT 118 | DocProject/Help/*.HxC 119 | DocProject/Help/*.hhc 120 | DocProject/Help/*.hhk 121 | DocProject/Help/*.hhp 122 | DocProject/Help/Html2 123 | DocProject/Help/html 124 | 125 | # Click-Once directory 126 | publish/ 127 | 128 | # Publish Web Output 129 | *.Publish.xml 130 | *.pubxml 131 | 132 | # NuGet Packages Directory 133 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 134 | #packages/ 135 | 136 | # Windows Azure Build Output 137 | csx 138 | *.build.csdef 139 | 140 | # Windows Store app package directory 141 | AppPackages/ 142 | 143 | # Others 144 | sql/ 145 | *.Cache 146 | ClientBin/ 147 | [Ss]tyle[Cc]op.* 148 | ~$* 149 | *~ 150 | *.dbmdl 151 | *.[Pp]ublish.xml 152 | *.pfx 153 | *.publishsettings 154 | 155 | # RIA/Silverlight projects 156 | Generated_Code/ 157 | 158 | # Backup & report files from converting an old project file to a newer 159 | # Visual Studio version. Backup files are not needed, because we have git ;-) 160 | _UpgradeReport_Files/ 161 | Backup*/ 162 | UpgradeLog*.XML 163 | UpgradeLog*.htm 164 | 165 | # SQL Server files 166 | App_Data/*.mdf 167 | App_Data/*.ldf 168 | 169 | ############# 170 | ## Windows detritus 171 | ############# 172 | 173 | # Windows image file caches 174 | Thumbs.db 175 | ehthumbs.db 176 | 177 | # Folder config file 178 | Desktop.ini 179 | 180 | # Recycle Bin used on file shares 181 | $RECYCLE.BIN/ 182 | 183 | # Mac crap 184 | .DS_Store 185 | 186 | 187 | ############# 188 | ## Python 189 | ############# 190 | 191 | *.py[co] 192 | 193 | # Packages 194 | *.egg 195 | *.egg-info 196 | dist/ 197 | build/ 198 | eggs/ 199 | parts/ 200 | var/ 201 | sdist/ 202 | develop-eggs/ 203 | .installed.cfg 204 | 205 | # Installer logs 206 | pip-log.txt 207 | 208 | # Unit test / coverage reports 209 | .coverage 210 | .tox 211 | 212 | #Translations 213 | *.mo 214 | 215 | #Mr Developer 216 | .mr.developer.cfg -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin Street, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) 19yy name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | flightfeeder-android 2 | ==================== 3 | 4 | FlightFeeder app for Android 5 | 6 | An Android app to send ADSB data back to FA. This app currently depends on the Avare ADSB Pro app to feed the ADSB frames over for decoding and conversion to ADEPT format before sending to FA. 7 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | android.library=true 16 | -------------------------------------------------------------------------------- /res/xml/device_filter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.hardware.usb.UsbConstants; 25 | import android.hardware.usb.UsbDevice; 26 | import android.hardware.usb.UsbDeviceConnection; 27 | import android.hardware.usb.UsbEndpoint; 28 | import android.hardware.usb.UsbInterface; 29 | import android.hardware.usb.UsbRequest; 30 | import android.os.Build; 31 | import android.util.Log; 32 | 33 | import java.io.IOException; 34 | import java.nio.ByteBuffer; 35 | import java.util.Collections; 36 | import java.util.LinkedHashMap; 37 | import java.util.List; 38 | import java.util.Map; 39 | 40 | /** 41 | * USB CDC/ACM serial driver implementation. 42 | * 43 | * @author mike wakerly (opensource@hoho.com) 44 | * @see Universal 46 | * Serial Bus Class Definitions for Communication Devices, v1.1 47 | */ 48 | public class CdcAcmSerialDriver implements UsbSerialDriver { 49 | 50 | private final String TAG = CdcAcmSerialDriver.class.getSimpleName(); 51 | 52 | private final UsbDevice mDevice; 53 | private final UsbSerialPort mPort; 54 | 55 | public CdcAcmSerialDriver(UsbDevice device) { 56 | mDevice = device; 57 | mPort = new CdcAcmSerialPort(device, 0); 58 | } 59 | 60 | @Override 61 | public UsbDevice getDevice() { 62 | return mDevice; 63 | } 64 | 65 | @Override 66 | public List getPorts() { 67 | return Collections.singletonList(mPort); 68 | } 69 | 70 | class CdcAcmSerialPort extends CommonUsbSerialPort { 71 | 72 | private final boolean mEnableAsyncReads; 73 | private UsbInterface mControlInterface; 74 | private UsbInterface mDataInterface; 75 | 76 | private UsbEndpoint mControlEndpoint; 77 | private UsbEndpoint mReadEndpoint; 78 | private UsbEndpoint mWriteEndpoint; 79 | 80 | private boolean mRts = false; 81 | private boolean mDtr = false; 82 | 83 | private static final int USB_RECIP_INTERFACE = 0x01; 84 | private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE; 85 | 86 | private static final int SET_LINE_CODING = 0x20; // USB CDC 1.1 section 6.2 87 | private static final int GET_LINE_CODING = 0x21; 88 | private static final int SET_CONTROL_LINE_STATE = 0x22; 89 | private static final int SEND_BREAK = 0x23; 90 | 91 | public CdcAcmSerialPort(UsbDevice device, int portNumber) { 92 | super(device, portNumber); 93 | mEnableAsyncReads = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1); 94 | } 95 | 96 | @Override 97 | public UsbSerialDriver getDriver() { 98 | return CdcAcmSerialDriver.this; 99 | } 100 | 101 | @Override 102 | public void open(UsbDeviceConnection connection) throws IOException { 103 | if (mConnection != null) { 104 | throw new IOException("Already open"); 105 | } 106 | 107 | mConnection = connection; 108 | boolean opened = false; 109 | try { 110 | Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount()); 111 | mControlInterface = mDevice.getInterface(0); 112 | Log.d(TAG, "Control iface=" + mControlInterface); 113 | // class should be USB_CLASS_COMM 114 | 115 | if (!mConnection.claimInterface(mControlInterface, true)) { 116 | throw new IOException("Could not claim control interface."); 117 | } 118 | mControlEndpoint = mControlInterface.getEndpoint(0); 119 | Log.d(TAG, "Control endpoint direction: " + mControlEndpoint.getDirection()); 120 | 121 | Log.d(TAG, "Claiming data interface."); 122 | mDataInterface = mDevice.getInterface(1); 123 | Log.d(TAG, "data iface=" + mDataInterface); 124 | // class should be USB_CLASS_CDC_DATA 125 | 126 | if (!mConnection.claimInterface(mDataInterface, true)) { 127 | throw new IOException("Could not claim data interface."); 128 | } 129 | mReadEndpoint = mDataInterface.getEndpoint(1); 130 | Log.d(TAG, "Read endpoint direction: " + mReadEndpoint.getDirection()); 131 | mWriteEndpoint = mDataInterface.getEndpoint(0); 132 | Log.d(TAG, "Write endpoint direction: " + mWriteEndpoint.getDirection()); 133 | if (mEnableAsyncReads) { 134 | Log.d(TAG, "Async reads enabled"); 135 | } else { 136 | Log.d(TAG, "Async reads disabled."); 137 | } 138 | opened = true; 139 | } finally { 140 | if (!opened) { 141 | mConnection = null; 142 | } 143 | } 144 | } 145 | 146 | private int sendAcmControlMessage(int request, int value, byte[] buf) { 147 | return mConnection.controlTransfer( 148 | USB_RT_ACM, request, value, 0, buf, buf != null ? buf.length : 0, 5000); 149 | } 150 | 151 | @Override 152 | public void close() throws IOException { 153 | if (mConnection == null) { 154 | throw new IOException("Already closed"); 155 | } 156 | mConnection.close(); 157 | mConnection = null; 158 | } 159 | 160 | @Override 161 | public int read(byte[] dest, int timeoutMillis) throws IOException { 162 | if (mEnableAsyncReads) { 163 | final UsbRequest request = new UsbRequest(); 164 | try { 165 | request.initialize(mConnection, mReadEndpoint); 166 | final ByteBuffer buf = ByteBuffer.wrap(dest); 167 | if (!request.queue(buf, dest.length)) { 168 | throw new IOException("Error queueing request."); 169 | } 170 | 171 | final UsbRequest response = mConnection.requestWait(); 172 | if (response == null) { 173 | throw new IOException("Null response"); 174 | } 175 | 176 | final int nread = buf.position(); 177 | if (nread > 0) { 178 | //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length))); 179 | return nread; 180 | } else { 181 | return 0; 182 | } 183 | } finally { 184 | request.close(); 185 | } 186 | } 187 | 188 | final int numBytesRead; 189 | synchronized (mReadBufferLock) { 190 | int readAmt = Math.min(dest.length, mReadBuffer.length); 191 | numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt, 192 | timeoutMillis); 193 | if (numBytesRead < 0) { 194 | // This sucks: we get -1 on timeout, not 0 as preferred. 195 | // We *should* use UsbRequest, except it has a bug/api oversight 196 | // where there is no way to determine the number of bytes read 197 | // in response :\ -- http://b.android.com/28023 198 | if (timeoutMillis == Integer.MAX_VALUE) { 199 | // Hack: Special case "~infinite timeout" as an error. 200 | return -1; 201 | } 202 | return 0; 203 | } 204 | System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead); 205 | } 206 | return numBytesRead; 207 | } 208 | 209 | @Override 210 | public int write(byte[] src, int timeoutMillis) throws IOException { 211 | // TODO(mikey): Nearly identical to FtdiSerial write. Refactor. 212 | int offset = 0; 213 | 214 | while (offset < src.length) { 215 | final int writeLength; 216 | final int amtWritten; 217 | 218 | synchronized (mWriteBufferLock) { 219 | final byte[] writeBuffer; 220 | 221 | writeLength = Math.min(src.length - offset, mWriteBuffer.length); 222 | if (offset == 0) { 223 | writeBuffer = src; 224 | } else { 225 | // bulkTransfer does not support offsets, make a copy. 226 | System.arraycopy(src, offset, mWriteBuffer, 0, writeLength); 227 | writeBuffer = mWriteBuffer; 228 | } 229 | 230 | amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength, 231 | timeoutMillis); 232 | } 233 | if (amtWritten <= 0) { 234 | throw new IOException("Error writing " + writeLength 235 | + " bytes at offset " + offset + " length=" + src.length); 236 | } 237 | 238 | Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength); 239 | offset += amtWritten; 240 | } 241 | return offset; 242 | } 243 | 244 | @Override 245 | public void setParameters(int baudRate, int dataBits, int stopBits, int parity) { 246 | byte stopBitsByte; 247 | switch (stopBits) { 248 | case STOPBITS_1: stopBitsByte = 0; break; 249 | case STOPBITS_1_5: stopBitsByte = 1; break; 250 | case STOPBITS_2: stopBitsByte = 2; break; 251 | default: throw new IllegalArgumentException("Bad value for stopBits: " + stopBits); 252 | } 253 | 254 | byte parityBitesByte; 255 | switch (parity) { 256 | case PARITY_NONE: parityBitesByte = 0; break; 257 | case PARITY_ODD: parityBitesByte = 1; break; 258 | case PARITY_EVEN: parityBitesByte = 2; break; 259 | case PARITY_MARK: parityBitesByte = 3; break; 260 | case PARITY_SPACE: parityBitesByte = 4; break; 261 | default: throw new IllegalArgumentException("Bad value for parity: " + parity); 262 | } 263 | 264 | byte[] msg = { 265 | (byte) ( baudRate & 0xff), 266 | (byte) ((baudRate >> 8 ) & 0xff), 267 | (byte) ((baudRate >> 16) & 0xff), 268 | (byte) ((baudRate >> 24) & 0xff), 269 | stopBitsByte, 270 | parityBitesByte, 271 | (byte) dataBits}; 272 | sendAcmControlMessage(SET_LINE_CODING, 0, msg); 273 | } 274 | 275 | @Override 276 | public boolean getCD() throws IOException { 277 | return false; // TODO 278 | } 279 | 280 | @Override 281 | public boolean getCTS() throws IOException { 282 | return false; // TODO 283 | } 284 | 285 | @Override 286 | public boolean getDSR() throws IOException { 287 | return false; // TODO 288 | } 289 | 290 | @Override 291 | public boolean getDTR() throws IOException { 292 | return mDtr; 293 | } 294 | 295 | @Override 296 | public void setDTR(boolean value) throws IOException { 297 | mDtr = value; 298 | setDtrRts(); 299 | } 300 | 301 | @Override 302 | public boolean getRI() throws IOException { 303 | return false; // TODO 304 | } 305 | 306 | @Override 307 | public boolean getRTS() throws IOException { 308 | return mRts; 309 | } 310 | 311 | @Override 312 | public void setRTS(boolean value) throws IOException { 313 | mRts = value; 314 | setDtrRts(); 315 | } 316 | 317 | private void setDtrRts() { 318 | int value = (mRts ? 0x2 : 0) | (mDtr ? 0x1 : 0); 319 | sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null); 320 | } 321 | 322 | } 323 | 324 | public static Map getSupportedDevices() { 325 | final Map supportedDevices = new LinkedHashMap(); 326 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ARDUINO), 327 | new int[] { 328 | UsbId.ARDUINO_UNO, 329 | UsbId.ARDUINO_UNO_R3, 330 | UsbId.ARDUINO_MEGA_2560, 331 | UsbId.ARDUINO_MEGA_2560_R3, 332 | UsbId.ARDUINO_SERIAL_ADAPTER, 333 | UsbId.ARDUINO_SERIAL_ADAPTER_R3, 334 | UsbId.ARDUINO_MEGA_ADK, 335 | UsbId.ARDUINO_MEGA_ADK_R3, 336 | UsbId.ARDUINO_LEONARDO, 337 | }); 338 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_VAN_OOIJEN_TECH), 339 | new int[] { 340 | UsbId.VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL, 341 | }); 342 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ATMEL), 343 | new int[] { 344 | UsbId.ATMEL_LUFA_CDC_DEMO_APP, 345 | }); 346 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_LEAFLABS), 347 | new int[] { 348 | UsbId.LEAFLABS_MAPLE, 349 | }); 350 | return supportedDevices; 351 | } 352 | 353 | } 354 | -------------------------------------------------------------------------------- /src/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.hardware.usb.UsbDevice; 25 | import android.hardware.usb.UsbDeviceConnection; 26 | 27 | import java.io.IOException; 28 | 29 | /** 30 | * A base class shared by several driver implementations. 31 | * 32 | * @author mike wakerly (opensource@hoho.com) 33 | */ 34 | public abstract class CommonUsbSerialPort implements UsbSerialPort { 35 | 36 | public static final int DEFAULT_READ_BUFFER_SIZE = 16 * 1024; 37 | public static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024; 38 | 39 | protected final UsbDevice mDevice; 40 | protected final int mPortNumber; 41 | 42 | // non-null when open() 43 | protected UsbDeviceConnection mConnection = null; 44 | 45 | protected final Object mReadBufferLock = new Object(); 46 | protected final Object mWriteBufferLock = new Object(); 47 | 48 | /** Internal read buffer. Guarded by {@link #mReadBufferLock}. */ 49 | protected byte[] mReadBuffer; 50 | 51 | /** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */ 52 | protected byte[] mWriteBuffer; 53 | 54 | public CommonUsbSerialPort(UsbDevice device, int portNumber) { 55 | mDevice = device; 56 | mPortNumber = portNumber; 57 | 58 | mReadBuffer = new byte[DEFAULT_READ_BUFFER_SIZE]; 59 | mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE]; 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return String.format("<%s device_name=%s device_id=%s port_number=%s>", 65 | getClass().getSimpleName(), mDevice.getDeviceName(), 66 | mDevice.getDeviceId(), mPortNumber); 67 | } 68 | 69 | /** 70 | * Returns the currently-bound USB device. 71 | * 72 | * @return the device 73 | */ 74 | public final UsbDevice getDevice() { 75 | return mDevice; 76 | } 77 | 78 | @Override 79 | public int getPortNumber() { 80 | return mPortNumber; 81 | } 82 | 83 | /** 84 | * Returns the device serial number 85 | * @return serial number 86 | */ 87 | @Override 88 | public String getSerial() { 89 | return mConnection.getSerial(); 90 | } 91 | 92 | /** 93 | * Sets the size of the internal buffer used to exchange data with the USB 94 | * stack for read operations. Most users should not need to change this. 95 | * 96 | * @param bufferSize the size in bytes 97 | */ 98 | public final void setReadBufferSize(int bufferSize) { 99 | synchronized (mReadBufferLock) { 100 | if (bufferSize == mReadBuffer.length) { 101 | return; 102 | } 103 | mReadBuffer = new byte[bufferSize]; 104 | } 105 | } 106 | 107 | /** 108 | * Sets the size of the internal buffer used to exchange data with the USB 109 | * stack for write operations. Most users should not need to change this. 110 | * 111 | * @param bufferSize the size in bytes 112 | */ 113 | public final void setWriteBufferSize(int bufferSize) { 114 | synchronized (mWriteBufferLock) { 115 | if (bufferSize == mWriteBuffer.length) { 116 | return; 117 | } 118 | mWriteBuffer = new byte[bufferSize]; 119 | } 120 | } 121 | 122 | @Override 123 | public abstract void open(UsbDeviceConnection connection) throws IOException; 124 | 125 | @Override 126 | public abstract void close() throws IOException; 127 | 128 | @Override 129 | public abstract int read(final byte[] dest, final int timeoutMillis) throws IOException; 130 | 131 | @Override 132 | public abstract int write(final byte[] src, final int timeoutMillis) throws IOException; 133 | 134 | @Override 135 | public abstract void setParameters( 136 | int baudRate, int dataBits, int stopBits, int parity) throws IOException; 137 | 138 | @Override 139 | public abstract boolean getCD() throws IOException; 140 | 141 | @Override 142 | public abstract boolean getCTS() throws IOException; 143 | 144 | @Override 145 | public abstract boolean getDSR() throws IOException; 146 | 147 | @Override 148 | public abstract boolean getDTR() throws IOException; 149 | 150 | @Override 151 | public abstract void setDTR(boolean value) throws IOException; 152 | 153 | @Override 154 | public abstract boolean getRI() throws IOException; 155 | 156 | @Override 157 | public abstract boolean getRTS() throws IOException; 158 | 159 | @Override 160 | public abstract void setRTS(boolean value) throws IOException; 161 | 162 | @Override 163 | public boolean purgeHwBuffers(boolean flushReadBuffers, boolean flushWriteBuffers) throws IOException { 164 | return !flushReadBuffers && !flushWriteBuffers; 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /src/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.hardware.usb.UsbConstants; 25 | import android.hardware.usb.UsbDevice; 26 | import android.hardware.usb.UsbDeviceConnection; 27 | import android.hardware.usb.UsbEndpoint; 28 | import android.hardware.usb.UsbInterface; 29 | import android.util.Log; 30 | 31 | import java.io.IOException; 32 | import java.util.Collections; 33 | import java.util.LinkedHashMap; 34 | import java.util.List; 35 | import java.util.Map; 36 | 37 | public class Cp21xxSerialDriver implements UsbSerialDriver { 38 | 39 | private static final String TAG = Cp21xxSerialDriver.class.getSimpleName(); 40 | 41 | private final UsbDevice mDevice; 42 | private final UsbSerialPort mPort; 43 | 44 | public Cp21xxSerialDriver(UsbDevice device) { 45 | mDevice = device; 46 | mPort = new Cp21xxSerialPort(mDevice, 0); 47 | } 48 | 49 | @Override 50 | public UsbDevice getDevice() { 51 | return mDevice; 52 | } 53 | 54 | @Override 55 | public List getPorts() { 56 | return Collections.singletonList(mPort); 57 | } 58 | 59 | public class Cp21xxSerialPort extends CommonUsbSerialPort { 60 | 61 | private static final int DEFAULT_BAUD_RATE = 9600; 62 | 63 | private static final int USB_WRITE_TIMEOUT_MILLIS = 5000; 64 | 65 | /* 66 | * Configuration Request Types 67 | */ 68 | private static final int REQTYPE_HOST_TO_DEVICE = 0x41; 69 | 70 | /* 71 | * Configuration Request Codes 72 | */ 73 | private static final int SILABSER_IFC_ENABLE_REQUEST_CODE = 0x00; 74 | private static final int SILABSER_SET_BAUDDIV_REQUEST_CODE = 0x01; 75 | private static final int SILABSER_SET_LINE_CTL_REQUEST_CODE = 0x03; 76 | private static final int SILABSER_SET_MHS_REQUEST_CODE = 0x07; 77 | private static final int SILABSER_SET_BAUDRATE = 0x1E; 78 | private static final int SILABSER_FLUSH_REQUEST_CODE = 0x12; 79 | 80 | private static final int FLUSH_READ_CODE = 0x0a; 81 | private static final int FLUSH_WRITE_CODE = 0x05; 82 | 83 | /* 84 | * SILABSER_IFC_ENABLE_REQUEST_CODE 85 | */ 86 | private static final int UART_ENABLE = 0x0001; 87 | private static final int UART_DISABLE = 0x0000; 88 | 89 | /* 90 | * SILABSER_SET_BAUDDIV_REQUEST_CODE 91 | */ 92 | private static final int BAUD_RATE_GEN_FREQ = 0x384000; 93 | 94 | /* 95 | * SILABSER_SET_MHS_REQUEST_CODE 96 | */ 97 | private static final int MCR_DTR = 0x0001; 98 | private static final int MCR_RTS = 0x0002; 99 | private static final int MCR_ALL = 0x0003; 100 | 101 | private static final int CONTROL_WRITE_DTR = 0x0100; 102 | private static final int CONTROL_WRITE_RTS = 0x0200; 103 | 104 | private UsbEndpoint mReadEndpoint; 105 | private UsbEndpoint mWriteEndpoint; 106 | 107 | public Cp21xxSerialPort(UsbDevice device, int portNumber) { 108 | super(device, portNumber); 109 | } 110 | 111 | @Override 112 | public UsbSerialDriver getDriver() { 113 | return Cp21xxSerialDriver.this; 114 | } 115 | 116 | private int setConfigSingle(int request, int value) { 117 | return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, value, 118 | 0, null, 0, USB_WRITE_TIMEOUT_MILLIS); 119 | } 120 | 121 | @Override 122 | public void open(UsbDeviceConnection connection) throws IOException { 123 | if (mConnection != null) { 124 | throw new IOException("Already opened."); 125 | } 126 | 127 | mConnection = connection; 128 | boolean opened = false; 129 | try { 130 | for (int i = 0; i < mDevice.getInterfaceCount(); i++) { 131 | UsbInterface usbIface = mDevice.getInterface(i); 132 | if (mConnection.claimInterface(usbIface, true)) { 133 | Log.d(TAG, "claimInterface " + i + " SUCCESS"); 134 | } else { 135 | Log.d(TAG, "claimInterface " + i + " FAIL"); 136 | } 137 | } 138 | 139 | UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1); 140 | for (int i = 0; i < dataIface.getEndpointCount(); i++) { 141 | UsbEndpoint ep = dataIface.getEndpoint(i); 142 | if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) { 143 | if (ep.getDirection() == UsbConstants.USB_DIR_IN) { 144 | mReadEndpoint = ep; 145 | } else { 146 | mWriteEndpoint = ep; 147 | } 148 | } 149 | } 150 | 151 | setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_ENABLE); 152 | setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, MCR_ALL | CONTROL_WRITE_DTR | CONTROL_WRITE_RTS); 153 | setConfigSingle(SILABSER_SET_BAUDDIV_REQUEST_CODE, BAUD_RATE_GEN_FREQ / DEFAULT_BAUD_RATE); 154 | // setParameters(DEFAULT_BAUD_RATE, DEFAULT_DATA_BITS, DEFAULT_STOP_BITS, DEFAULT_PARITY); 155 | opened = true; 156 | } finally { 157 | if (!opened) { 158 | try { 159 | close(); 160 | } catch (IOException e) { 161 | // Ignore IOExceptions during close() 162 | } 163 | } 164 | } 165 | } 166 | 167 | @Override 168 | public void close() throws IOException { 169 | if (mConnection == null) { 170 | throw new IOException("Already closed"); 171 | } 172 | try { 173 | setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE); 174 | mConnection.close(); 175 | } finally { 176 | mConnection = null; 177 | } 178 | } 179 | 180 | @Override 181 | public int read(byte[] dest, int timeoutMillis) throws IOException { 182 | final int numBytesRead; 183 | synchronized (mReadBufferLock) { 184 | int readAmt = Math.min(dest.length, mReadBuffer.length); 185 | numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt, 186 | timeoutMillis); 187 | if (numBytesRead < 0) { 188 | // This sucks: we get -1 on timeout, not 0 as preferred. 189 | // We *should* use UsbRequest, except it has a bug/api oversight 190 | // where there is no way to determine the number of bytes read 191 | // in response :\ -- http://b.android.com/28023 192 | return 0; 193 | } 194 | System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead); 195 | } 196 | return numBytesRead; 197 | } 198 | 199 | @Override 200 | public int write(byte[] src, int timeoutMillis) throws IOException { 201 | int offset = 0; 202 | 203 | while (offset < src.length) { 204 | final int writeLength; 205 | final int amtWritten; 206 | 207 | synchronized (mWriteBufferLock) { 208 | final byte[] writeBuffer; 209 | 210 | writeLength = Math.min(src.length - offset, mWriteBuffer.length); 211 | if (offset == 0) { 212 | writeBuffer = src; 213 | } else { 214 | // bulkTransfer does not support offsets, make a copy. 215 | System.arraycopy(src, offset, mWriteBuffer, 0, writeLength); 216 | writeBuffer = mWriteBuffer; 217 | } 218 | 219 | amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength, 220 | timeoutMillis); 221 | } 222 | if (amtWritten <= 0) { 223 | throw new IOException("Error writing " + writeLength 224 | + " bytes at offset " + offset + " length=" + src.length); 225 | } 226 | 227 | Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength); 228 | offset += amtWritten; 229 | } 230 | return offset; 231 | } 232 | 233 | private void setBaudRate(int baudRate) throws IOException { 234 | byte[] data = new byte[] { 235 | (byte) ( baudRate & 0xff), 236 | (byte) ((baudRate >> 8 ) & 0xff), 237 | (byte) ((baudRate >> 16) & 0xff), 238 | (byte) ((baudRate >> 24) & 0xff) 239 | }; 240 | int ret = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SILABSER_SET_BAUDRATE, 241 | 0, 0, data, 4, USB_WRITE_TIMEOUT_MILLIS); 242 | if (ret < 0) { 243 | throw new IOException("Error setting baud rate."); 244 | } 245 | } 246 | 247 | @Override 248 | public void setParameters(int baudRate, int dataBits, int stopBits, int parity) 249 | throws IOException { 250 | setBaudRate(baudRate); 251 | 252 | int configDataBits = 0; 253 | switch (dataBits) { 254 | case DATABITS_5: 255 | configDataBits |= 0x0500; 256 | break; 257 | case DATABITS_6: 258 | configDataBits |= 0x0600; 259 | break; 260 | case DATABITS_7: 261 | configDataBits |= 0x0700; 262 | break; 263 | case DATABITS_8: 264 | configDataBits |= 0x0800; 265 | break; 266 | default: 267 | configDataBits |= 0x0800; 268 | break; 269 | } 270 | 271 | switch (parity) { 272 | case PARITY_ODD: 273 | configDataBits |= 0x0010; 274 | break; 275 | case PARITY_EVEN: 276 | configDataBits |= 0x0020; 277 | break; 278 | } 279 | 280 | switch (stopBits) { 281 | case STOPBITS_1: 282 | configDataBits |= 0; 283 | break; 284 | case STOPBITS_2: 285 | configDataBits |= 2; 286 | break; 287 | } 288 | setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configDataBits); 289 | } 290 | 291 | @Override 292 | public boolean getCD() throws IOException { 293 | return false; 294 | } 295 | 296 | @Override 297 | public boolean getCTS() throws IOException { 298 | return false; 299 | } 300 | 301 | @Override 302 | public boolean getDSR() throws IOException { 303 | return false; 304 | } 305 | 306 | @Override 307 | public boolean getDTR() throws IOException { 308 | return true; 309 | } 310 | 311 | @Override 312 | public void setDTR(boolean value) throws IOException { 313 | } 314 | 315 | @Override 316 | public boolean getRI() throws IOException { 317 | return false; 318 | } 319 | 320 | @Override 321 | public boolean getRTS() throws IOException { 322 | return true; 323 | } 324 | 325 | @Override 326 | public void setRTS(boolean value) throws IOException { 327 | } 328 | 329 | @Override 330 | public boolean purgeHwBuffers(boolean purgeReadBuffers, 331 | boolean purgeWriteBuffers) throws IOException { 332 | int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0) 333 | | (purgeWriteBuffers ? FLUSH_WRITE_CODE : 0); 334 | 335 | if (value != 0) { 336 | setConfigSingle(SILABSER_FLUSH_REQUEST_CODE, value); 337 | } 338 | 339 | return true; 340 | } 341 | 342 | } 343 | 344 | public static Map getSupportedDevices() { 345 | final Map supportedDevices = new LinkedHashMap(); 346 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SILABS), 347 | new int[] { 348 | UsbId.SILABS_CP2102, 349 | UsbId.SILABS_CP2105, 350 | UsbId.SILABS_CP2108, 351 | UsbId.SILABS_CP2110 352 | }); 353 | return supportedDevices; 354 | } 355 | 356 | } 357 | -------------------------------------------------------------------------------- /src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.hardware.usb.UsbConstants; 25 | import android.hardware.usb.UsbDevice; 26 | import android.hardware.usb.UsbDeviceConnection; 27 | import android.hardware.usb.UsbEndpoint; 28 | import android.hardware.usb.UsbRequest; 29 | import android.util.Log; 30 | 31 | import com.hoho.android.usbserial.util.HexDump; 32 | 33 | import java.io.IOException; 34 | import java.nio.ByteBuffer; 35 | import java.util.Collections; 36 | import java.util.LinkedHashMap; 37 | import java.util.List; 38 | import java.util.Map; 39 | 40 | /** 41 | * A {@link CommonUsbSerialPort} implementation for a variety of FTDI devices 42 | *

43 | * This driver is based on libftdi, and is 45 | * copyright and subject to the following terms: 46 | * 47 | *

 48 |  *   Copyright (C) 2003 by Intra2net AG
 49 |  *
 50 |  *   This program is free software; you can redistribute it and/or modify
 51 |  *   it under the terms of the GNU Lesser General Public License
 52 |  *   version 2.1 as published by the Free Software Foundation;
 53 |  *
 54 |  *   opensource@intra2net.com
 55 |  *   http://www.intra2net.com/en/developer/libftdi
 56 |  * 
57 | * 58 | *

59 | *

60 | * Some FTDI devices have not been tested; see later listing of supported and 61 | * unsupported devices. Devices listed as "supported" support the following 62 | * features: 63 | *

    64 | *
  • Read and write of serial data (see 65 | * {@link CommonUsbSerialPort#read(byte[], int)} and 66 | * {@link CommonUsbSerialPort#write(byte[], int)}.
  • 67 | *
  • Setting serial line parameters (see 68 | * {@link CommonUsbSerialPort#setParameters(int, int, int, int)}.
  • 69 | *
70 | *

71 | *

72 | * Supported and tested devices: 73 | *

    74 | *
  • {@value DeviceType#TYPE_R}
  • 75 | *
76 | *

77 | *

78 | * Unsupported but possibly working devices (please contact the author with 79 | * feedback or patches): 80 | *

    81 | *
  • {@value DeviceType#TYPE_2232C}
  • 82 | *
  • {@value DeviceType#TYPE_2232H}
  • 83 | *
  • {@value DeviceType#TYPE_4232H}
  • 84 | *
  • {@value DeviceType#TYPE_AM}
  • 85 | *
  • {@value DeviceType#TYPE_BM}
  • 86 | *
87 | *

88 | * 89 | * @author mike wakerly (opensource@hoho.com) 90 | * @see USB Serial 91 | * for Android project page 92 | * @see FTDI Homepage 93 | * @see libftdi 94 | */ 95 | public class FtdiSerialDriver implements UsbSerialDriver { 96 | 97 | private final UsbDevice mDevice; 98 | private final UsbSerialPort mPort; 99 | 100 | /** 101 | * FTDI chip types. 102 | */ 103 | private static enum DeviceType { 104 | TYPE_BM, TYPE_AM, TYPE_2232C, TYPE_R, TYPE_2232H, TYPE_4232H; 105 | } 106 | 107 | public FtdiSerialDriver(UsbDevice device) { 108 | mDevice = device; 109 | mPort = new FtdiSerialPort(mDevice, 0); 110 | } 111 | @Override 112 | public UsbDevice getDevice() { 113 | return mDevice; 114 | } 115 | 116 | @Override 117 | public List getPorts() { 118 | return Collections.singletonList(mPort); 119 | } 120 | 121 | private class FtdiSerialPort extends CommonUsbSerialPort { 122 | 123 | public static final int USB_TYPE_STANDARD = 0x00 << 5; 124 | public static final int USB_TYPE_CLASS = 0x00 << 5; 125 | public static final int USB_TYPE_VENDOR = 0x00 << 5; 126 | public static final int USB_TYPE_RESERVED = 0x00 << 5; 127 | 128 | public static final int USB_RECIP_DEVICE = 0x00; 129 | public static final int USB_RECIP_INTERFACE = 0x01; 130 | public static final int USB_RECIP_ENDPOINT = 0x02; 131 | public static final int USB_RECIP_OTHER = 0x03; 132 | 133 | public static final int USB_ENDPOINT_IN = 0x80; 134 | public static final int USB_ENDPOINT_OUT = 0x00; 135 | 136 | public static final int USB_WRITE_TIMEOUT_MILLIS = 5000; 137 | public static final int USB_READ_TIMEOUT_MILLIS = 5000; 138 | 139 | // From ftdi.h 140 | /** 141 | * Reset the port. 142 | */ 143 | private static final int SIO_RESET_REQUEST = 0; 144 | 145 | /** 146 | * Set the modem control register. 147 | */ 148 | private static final int SIO_MODEM_CTRL_REQUEST = 1; 149 | 150 | /** 151 | * Set flow control register. 152 | */ 153 | private static final int SIO_SET_FLOW_CTRL_REQUEST = 2; 154 | 155 | /** 156 | * Set baud rate. 157 | */ 158 | private static final int SIO_SET_BAUD_RATE_REQUEST = 3; 159 | 160 | /** 161 | * Set the data characteristics of the port. 162 | */ 163 | private static final int SIO_SET_DATA_REQUEST = 4; 164 | 165 | private static final int SIO_RESET_SIO = 0; 166 | private static final int SIO_RESET_PURGE_RX = 1; 167 | private static final int SIO_RESET_PURGE_TX = 2; 168 | 169 | public static final int FTDI_DEVICE_OUT_REQTYPE = 170 | UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT; 171 | 172 | public static final int FTDI_DEVICE_IN_REQTYPE = 173 | UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN; 174 | 175 | /** 176 | * Length of the modem status header, transmitted with every read. 177 | */ 178 | private static final int MODEM_STATUS_HEADER_LENGTH = 2; 179 | 180 | private final String TAG = FtdiSerialDriver.class.getSimpleName(); 181 | 182 | private DeviceType mType; 183 | 184 | private int mInterface = 0; /* INTERFACE_ANY */ 185 | 186 | private int mMaxPacketSize = 64; // TODO(mikey): detect 187 | 188 | /** 189 | * Due to http://b.android.com/28023 , we cannot use UsbRequest async reads 190 | * since it gives no indication of number of bytes read. Set this to 191 | * {@code true} on platforms where it is fixed. 192 | */ 193 | private static final boolean ENABLE_ASYNC_READS = false; 194 | 195 | public FtdiSerialPort(UsbDevice device, int portNumber) { 196 | super(device, portNumber); 197 | } 198 | 199 | @Override 200 | public UsbSerialDriver getDriver() { 201 | return FtdiSerialDriver.this; 202 | } 203 | 204 | /** 205 | * Filter FTDI status bytes from buffer 206 | * @param src The source buffer (which contains status bytes) 207 | * @param dest The destination buffer to write the status bytes into (can be src) 208 | * @param totalBytesRead Number of bytes read to src 209 | * @param maxPacketSize The USB endpoint max packet size 210 | * @return The number of payload bytes 211 | */ 212 | private final int filterStatusBytes(byte[] src, byte[] dest, int totalBytesRead, int maxPacketSize) { 213 | final int packetsCount = totalBytesRead / maxPacketSize + (totalBytesRead % maxPacketSize == 0 ? 0 : 1); 214 | for (int packetIdx = 0; packetIdx < packetsCount; ++packetIdx) { 215 | final int count = (packetIdx == (packetsCount - 1)) 216 | ? (totalBytesRead % maxPacketSize) - MODEM_STATUS_HEADER_LENGTH 217 | : maxPacketSize - MODEM_STATUS_HEADER_LENGTH; 218 | if (count > 0) { 219 | System.arraycopy(src, 220 | packetIdx * maxPacketSize + MODEM_STATUS_HEADER_LENGTH, 221 | dest, 222 | packetIdx * (maxPacketSize - MODEM_STATUS_HEADER_LENGTH), 223 | count); 224 | } 225 | } 226 | 227 | return totalBytesRead - (packetsCount * 2); 228 | } 229 | 230 | public void reset() throws IOException { 231 | int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, 232 | SIO_RESET_SIO, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS); 233 | if (result != 0) { 234 | throw new IOException("Reset failed: result=" + result); 235 | } 236 | 237 | // TODO(mikey): autodetect. 238 | mType = DeviceType.TYPE_R; 239 | } 240 | 241 | @Override 242 | public void open(UsbDeviceConnection connection) throws IOException { 243 | if (mConnection != null) { 244 | throw new IOException("Already open"); 245 | } 246 | mConnection = connection; 247 | 248 | boolean opened = false; 249 | try { 250 | for (int i = 0; i < mDevice.getInterfaceCount(); i++) { 251 | if (connection.claimInterface(mDevice.getInterface(i), true)) { 252 | Log.d(TAG, "claimInterface " + i + " SUCCESS"); 253 | } else { 254 | throw new IOException("Error claiming interface " + i); 255 | } 256 | } 257 | reset(); 258 | opened = true; 259 | } finally { 260 | if (!opened) { 261 | close(); 262 | mConnection = null; 263 | } 264 | } 265 | } 266 | 267 | @Override 268 | public void close() throws IOException { 269 | if (mConnection == null) { 270 | throw new IOException("Already closed"); 271 | } 272 | try { 273 | mConnection.close(); 274 | } finally { 275 | mConnection = null; 276 | } 277 | } 278 | 279 | @Override 280 | public int read(byte[] dest, int timeoutMillis) throws IOException { 281 | final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(0); 282 | 283 | if (ENABLE_ASYNC_READS) { 284 | final int readAmt; 285 | synchronized (mReadBufferLock) { 286 | // mReadBuffer is only used for maximum read size. 287 | readAmt = Math.min(dest.length, mReadBuffer.length); 288 | } 289 | 290 | final UsbRequest request = new UsbRequest(); 291 | request.initialize(mConnection, endpoint); 292 | 293 | final ByteBuffer buf = ByteBuffer.wrap(dest); 294 | if (!request.queue(buf, readAmt)) { 295 | throw new IOException("Error queueing request."); 296 | } 297 | 298 | final UsbRequest response = mConnection.requestWait(); 299 | if (response == null) { 300 | throw new IOException("Null response"); 301 | } 302 | 303 | final int payloadBytesRead = buf.position() - MODEM_STATUS_HEADER_LENGTH; 304 | if (payloadBytesRead > 0) { 305 | Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length))); 306 | return payloadBytesRead; 307 | } else { 308 | return 0; 309 | } 310 | } else { 311 | final int totalBytesRead; 312 | 313 | synchronized (mReadBufferLock) { 314 | final int readAmt = Math.min(dest.length, mReadBuffer.length); 315 | totalBytesRead = mConnection.bulkTransfer(endpoint, mReadBuffer, 316 | readAmt, timeoutMillis); 317 | 318 | if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) { 319 | throw new IOException("Expected at least " + MODEM_STATUS_HEADER_LENGTH + " bytes"); 320 | } 321 | 322 | return filterStatusBytes(mReadBuffer, dest, totalBytesRead, endpoint.getMaxPacketSize()); 323 | } 324 | } 325 | } 326 | 327 | @Override 328 | public int write(byte[] src, int timeoutMillis) throws IOException { 329 | final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(1); 330 | int offset = 0; 331 | 332 | while (offset < src.length) { 333 | final int writeLength; 334 | final int amtWritten; 335 | 336 | synchronized (mWriteBufferLock) { 337 | final byte[] writeBuffer; 338 | 339 | writeLength = Math.min(src.length - offset, mWriteBuffer.length); 340 | if (offset == 0) { 341 | writeBuffer = src; 342 | } else { 343 | // bulkTransfer does not support offsets, make a copy. 344 | System.arraycopy(src, offset, mWriteBuffer, 0, writeLength); 345 | writeBuffer = mWriteBuffer; 346 | } 347 | 348 | amtWritten = mConnection.bulkTransfer(endpoint, writeBuffer, writeLength, 349 | timeoutMillis); 350 | } 351 | 352 | if (amtWritten <= 0) { 353 | throw new IOException("Error writing " + writeLength 354 | + " bytes at offset " + offset + " length=" + src.length); 355 | } 356 | 357 | Log.d(TAG, "Wrote amtWritten=" + amtWritten + " attempted=" + writeLength); 358 | offset += amtWritten; 359 | } 360 | return offset; 361 | } 362 | 363 | private int setBaudRate(int baudRate) throws IOException { 364 | long[] vals = convertBaudrate(baudRate); 365 | long actualBaudrate = vals[0]; 366 | long index = vals[1]; 367 | long value = vals[2]; 368 | int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, 369 | SIO_SET_BAUD_RATE_REQUEST, (int) value, (int) index, 370 | null, 0, USB_WRITE_TIMEOUT_MILLIS); 371 | if (result != 0) { 372 | throw new IOException("Setting baudrate failed: result=" + result); 373 | } 374 | return (int) actualBaudrate; 375 | } 376 | 377 | @Override 378 | public void setParameters(int baudRate, int dataBits, int stopBits, int parity) 379 | throws IOException { 380 | setBaudRate(baudRate); 381 | 382 | int config = dataBits; 383 | 384 | switch (parity) { 385 | case PARITY_NONE: 386 | config |= (0x00 << 8); 387 | break; 388 | case PARITY_ODD: 389 | config |= (0x01 << 8); 390 | break; 391 | case PARITY_EVEN: 392 | config |= (0x02 << 8); 393 | break; 394 | case PARITY_MARK: 395 | config |= (0x03 << 8); 396 | break; 397 | case PARITY_SPACE: 398 | config |= (0x04 << 8); 399 | break; 400 | default: 401 | throw new IllegalArgumentException("Unknown parity value: " + parity); 402 | } 403 | 404 | switch (stopBits) { 405 | case STOPBITS_1: 406 | config |= (0x00 << 11); 407 | break; 408 | case STOPBITS_1_5: 409 | config |= (0x01 << 11); 410 | break; 411 | case STOPBITS_2: 412 | config |= (0x02 << 11); 413 | break; 414 | default: 415 | throw new IllegalArgumentException("Unknown stopBits value: " + stopBits); 416 | } 417 | 418 | int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, 419 | SIO_SET_DATA_REQUEST, config, 0 /* index */, 420 | null, 0, USB_WRITE_TIMEOUT_MILLIS); 421 | if (result != 0) { 422 | throw new IOException("Setting parameters failed: result=" + result); 423 | } 424 | } 425 | 426 | private long[] convertBaudrate(int baudrate) { 427 | // TODO(mikey): Braindead transcription of libfti method. Clean up, 428 | // using more idiomatic Java where possible. 429 | int divisor = 24000000 / baudrate; 430 | int bestDivisor = 0; 431 | int bestBaud = 0; 432 | int bestBaudDiff = 0; 433 | int fracCode[] = { 434 | 0, 3, 2, 4, 1, 5, 6, 7 435 | }; 436 | 437 | for (int i = 0; i < 2; i++) { 438 | int tryDivisor = divisor + i; 439 | int baudEstimate; 440 | int baudDiff; 441 | 442 | if (tryDivisor <= 8) { 443 | // Round up to minimum supported divisor 444 | tryDivisor = 8; 445 | } else if (mType != DeviceType.TYPE_AM && tryDivisor < 12) { 446 | // BM doesn't support divisors 9 through 11 inclusive 447 | tryDivisor = 12; 448 | } else if (divisor < 16) { 449 | // AM doesn't support divisors 9 through 15 inclusive 450 | tryDivisor = 16; 451 | } else { 452 | if (mType == DeviceType.TYPE_AM) { 453 | // TODO 454 | } else { 455 | if (tryDivisor > 0x1FFFF) { 456 | // Round down to maximum supported divisor value (for 457 | // BM) 458 | tryDivisor = 0x1FFFF; 459 | } 460 | } 461 | } 462 | 463 | // Get estimated baud rate (to nearest integer) 464 | baudEstimate = (24000000 + (tryDivisor / 2)) / tryDivisor; 465 | 466 | // Get absolute difference from requested baud rate 467 | if (baudEstimate < baudrate) { 468 | baudDiff = baudrate - baudEstimate; 469 | } else { 470 | baudDiff = baudEstimate - baudrate; 471 | } 472 | 473 | if (i == 0 || baudDiff < bestBaudDiff) { 474 | // Closest to requested baud rate so far 475 | bestDivisor = tryDivisor; 476 | bestBaud = baudEstimate; 477 | bestBaudDiff = baudDiff; 478 | if (baudDiff == 0) { 479 | // Spot on! No point trying 480 | break; 481 | } 482 | } 483 | } 484 | 485 | // Encode the best divisor value 486 | long encodedDivisor = (bestDivisor >> 3) | (fracCode[bestDivisor & 7] << 14); 487 | // Deal with special cases for encoded value 488 | if (encodedDivisor == 1) { 489 | encodedDivisor = 0; // 3000000 baud 490 | } else if (encodedDivisor == 0x4001) { 491 | encodedDivisor = 1; // 2000000 baud (BM only) 492 | } 493 | 494 | // Split into "value" and "index" values 495 | long value = encodedDivisor & 0xFFFF; 496 | long index; 497 | if (mType == DeviceType.TYPE_2232C || mType == DeviceType.TYPE_2232H 498 | || mType == DeviceType.TYPE_4232H) { 499 | index = (encodedDivisor >> 8) & 0xffff; 500 | index &= 0xFF00; 501 | index |= 0 /* TODO mIndex */; 502 | } else { 503 | index = (encodedDivisor >> 16) & 0xffff; 504 | } 505 | 506 | // Return the nearest baud rate 507 | return new long[] { 508 | bestBaud, index, value 509 | }; 510 | } 511 | 512 | @Override 513 | public boolean getCD() throws IOException { 514 | return false; 515 | } 516 | 517 | @Override 518 | public boolean getCTS() throws IOException { 519 | return false; 520 | } 521 | 522 | @Override 523 | public boolean getDSR() throws IOException { 524 | return false; 525 | } 526 | 527 | @Override 528 | public boolean getDTR() throws IOException { 529 | return false; 530 | } 531 | 532 | @Override 533 | public void setDTR(boolean value) throws IOException { 534 | } 535 | 536 | @Override 537 | public boolean getRI() throws IOException { 538 | return false; 539 | } 540 | 541 | @Override 542 | public boolean getRTS() throws IOException { 543 | return false; 544 | } 545 | 546 | @Override 547 | public void setRTS(boolean value) throws IOException { 548 | } 549 | 550 | @Override 551 | public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException { 552 | if (purgeReadBuffers) { 553 | int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, 554 | SIO_RESET_PURGE_RX, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS); 555 | if (result != 0) { 556 | throw new IOException("Flushing RX failed: result=" + result); 557 | } 558 | } 559 | 560 | if (purgeWriteBuffers) { 561 | int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, 562 | SIO_RESET_PURGE_TX, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS); 563 | if (result != 0) { 564 | throw new IOException("Flushing RX failed: result=" + result); 565 | } 566 | } 567 | return true; 568 | } 569 | } 570 | 571 | public static Map getSupportedDevices() { 572 | final Map supportedDevices = new LinkedHashMap(); 573 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_FTDI), 574 | new int[] { 575 | UsbId.FTDI_FT232R, 576 | UsbId.FTDI_FT231X, 577 | }); 578 | return supportedDevices; 579 | } 580 | 581 | } 582 | -------------------------------------------------------------------------------- /src/com/hoho/android/usbserial/driver/ProbeTable.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.util.Pair; 25 | 26 | import java.lang.reflect.InvocationTargetException; 27 | import java.lang.reflect.Method; 28 | import java.util.LinkedHashMap; 29 | import java.util.Map; 30 | 31 | /** 32 | * Maps (vendor id, product id) pairs to the corresponding serial driver. 33 | * 34 | * @author mike wakerly (opensource@hoho.com) 35 | */ 36 | public class ProbeTable { 37 | 38 | private final Map, Class> mProbeTable = 39 | new LinkedHashMap, Class>(); 40 | 41 | /** 42 | * Adds or updates a (vendor, product) pair in the table. 43 | * 44 | * @param vendorId the USB vendor id 45 | * @param productId the USB product id 46 | * @param driverClass the driver class responsible for this pair 47 | * @return {@code this}, for chaining 48 | */ 49 | public ProbeTable addProduct(int vendorId, int productId, 50 | Class driverClass) { 51 | mProbeTable.put(Pair.create(vendorId, productId), driverClass); 52 | return this; 53 | } 54 | 55 | /** 56 | * Internal method to add all supported products from 57 | * {@code getSupportedProducts} static method. 58 | * 59 | * @param driverClass 60 | * @return 61 | */ 62 | @SuppressWarnings("unchecked") 63 | public ProbeTable addDriver(Class driverClass) { 64 | final Method method; 65 | 66 | try { 67 | method = driverClass.getMethod("getSupportedDevices"); 68 | } catch (SecurityException e) { 69 | throw new RuntimeException(e); 70 | } catch (NoSuchMethodException e) { 71 | throw new RuntimeException(e); 72 | } 73 | 74 | final Map devices; 75 | try { 76 | devices = (Map) method.invoke(null); 77 | } catch (IllegalArgumentException e) { 78 | throw new RuntimeException(e); 79 | } catch (IllegalAccessException e) { 80 | throw new RuntimeException(e); 81 | } catch (InvocationTargetException e) { 82 | throw new RuntimeException(e); 83 | } 84 | 85 | for (Map.Entry entry : devices.entrySet()) { 86 | final int vendorId = entry.getKey().intValue(); 87 | for (int productId : entry.getValue()) { 88 | addProduct(vendorId, productId, driverClass); 89 | } 90 | } 91 | 92 | return this; 93 | } 94 | 95 | /** 96 | * Returns the driver for the given (vendor, product) pair, or {@code null} 97 | * if no match. 98 | * 99 | * @param vendorId the USB vendor id 100 | * @param productId the USB product id 101 | * @return the driver class matching this pair, or {@code null} 102 | */ 103 | public Class findDriver(int vendorId, int productId) { 104 | final Pair pair = Pair.create(vendorId, productId); 105 | return mProbeTable.get(pair); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/com/hoho/android/usbserial/driver/ProlificSerialDriver.java: -------------------------------------------------------------------------------- 1 | /* This library is free software; you can redistribute it and/or 2 | * modify it under the terms of the GNU Lesser General Public 3 | * License as published by the Free Software Foundation; either 4 | * version 2.1 of the License, or (at your option) any later version. 5 | * 6 | * This library is distributed in the hope that it will be useful, 7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | * Lesser General Public License for more details. 10 | * 11 | * You should have received a copy of the GNU Lesser General Public 12 | * License along with this library; if not, write to the Free Software 13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 14 | * USA. 15 | * 16 | * Project home page: https://github.com/mik3y/usb-serial-for-android 17 | */ 18 | 19 | /* 20 | * Ported to usb-serial-for-android 21 | * by Felix Hädicke 22 | * 23 | * Based on the pyprolific driver written 24 | * by Emmanuel Blot 25 | * See https://github.com/eblot/pyftdi 26 | */ 27 | 28 | package com.hoho.android.usbserial.driver; 29 | 30 | import android.hardware.usb.UsbConstants; 31 | import android.hardware.usb.UsbDevice; 32 | import android.hardware.usb.UsbDeviceConnection; 33 | import android.hardware.usb.UsbEndpoint; 34 | import android.hardware.usb.UsbInterface; 35 | import android.util.Log; 36 | 37 | import java.io.IOException; 38 | import java.lang.reflect.Method; 39 | import java.util.Collections; 40 | import java.util.LinkedHashMap; 41 | import java.util.List; 42 | import java.util.Map; 43 | 44 | public class ProlificSerialDriver implements UsbSerialDriver { 45 | 46 | private final String TAG = ProlificSerialDriver.class.getSimpleName(); 47 | 48 | private final UsbDevice mDevice; 49 | private final UsbSerialPort mPort; 50 | 51 | public ProlificSerialDriver(UsbDevice device) { 52 | mDevice = device; 53 | mPort = new ProlificSerialPort(mDevice, 0); 54 | } 55 | 56 | @Override 57 | public List getPorts() { 58 | return Collections.singletonList(mPort); 59 | } 60 | 61 | @Override 62 | public UsbDevice getDevice() { 63 | return mDevice; 64 | } 65 | 66 | class ProlificSerialPort extends CommonUsbSerialPort { 67 | 68 | private static final int USB_READ_TIMEOUT_MILLIS = 1000; 69 | private static final int USB_WRITE_TIMEOUT_MILLIS = 5000; 70 | 71 | private static final int USB_RECIP_INTERFACE = 0x01; 72 | 73 | private static final int PROLIFIC_VENDOR_READ_REQUEST = 0x01; 74 | private static final int PROLIFIC_VENDOR_WRITE_REQUEST = 0x01; 75 | 76 | private static final int PROLIFIC_VENDOR_OUT_REQTYPE = UsbConstants.USB_DIR_OUT 77 | | UsbConstants.USB_TYPE_VENDOR; 78 | 79 | private static final int PROLIFIC_VENDOR_IN_REQTYPE = UsbConstants.USB_DIR_IN 80 | | UsbConstants.USB_TYPE_VENDOR; 81 | 82 | private static final int PROLIFIC_CTRL_OUT_REQTYPE = UsbConstants.USB_DIR_OUT 83 | | UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE; 84 | 85 | private static final int WRITE_ENDPOINT = 0x02; 86 | private static final int READ_ENDPOINT = 0x83; 87 | private static final int INTERRUPT_ENDPOINT = 0x81; 88 | 89 | private static final int FLUSH_RX_REQUEST = 0x08; 90 | private static final int FLUSH_TX_REQUEST = 0x09; 91 | 92 | private static final int SET_LINE_REQUEST = 0x20; 93 | private static final int SET_CONTROL_REQUEST = 0x22; 94 | 95 | private static final int CONTROL_DTR = 0x01; 96 | private static final int CONTROL_RTS = 0x02; 97 | 98 | private static final int STATUS_FLAG_CD = 0x01; 99 | private static final int STATUS_FLAG_DSR = 0x02; 100 | private static final int STATUS_FLAG_RI = 0x08; 101 | private static final int STATUS_FLAG_CTS = 0x80; 102 | 103 | private static final int STATUS_BUFFER_SIZE = 10; 104 | private static final int STATUS_BYTE_IDX = 8; 105 | 106 | private static final int DEVICE_TYPE_HX = 0; 107 | private static final int DEVICE_TYPE_0 = 1; 108 | private static final int DEVICE_TYPE_1 = 2; 109 | 110 | private int mDeviceType = DEVICE_TYPE_HX; 111 | 112 | private UsbEndpoint mReadEndpoint; 113 | private UsbEndpoint mWriteEndpoint; 114 | private UsbEndpoint mInterruptEndpoint; 115 | 116 | private int mControlLinesValue = 0; 117 | 118 | private int mBaudRate = -1, mDataBits = -1, mStopBits = -1, mParity = -1; 119 | 120 | private int mStatus = 0; 121 | private volatile Thread mReadStatusThread = null; 122 | private final Object mReadStatusThreadLock = new Object(); 123 | boolean mStopReadStatusThread = false; 124 | private IOException mReadStatusException = null; 125 | 126 | 127 | public ProlificSerialPort(UsbDevice device, int portNumber) { 128 | super(device, portNumber); 129 | } 130 | 131 | @Override 132 | public UsbSerialDriver getDriver() { 133 | return ProlificSerialDriver.this; 134 | } 135 | 136 | private final byte[] inControlTransfer(int requestType, int request, 137 | int value, int index, int length) throws IOException { 138 | byte[] buffer = new byte[length]; 139 | int result = mConnection.controlTransfer(requestType, request, value, 140 | index, buffer, length, USB_READ_TIMEOUT_MILLIS); 141 | if (result != length) { 142 | throw new IOException( 143 | String.format("ControlTransfer with value 0x%x failed: %d", 144 | value, result)); 145 | } 146 | return buffer; 147 | } 148 | 149 | private final void outControlTransfer(int requestType, int request, 150 | int value, int index, byte[] data) throws IOException { 151 | int length = (data == null) ? 0 : data.length; 152 | int result = mConnection.controlTransfer(requestType, request, value, 153 | index, data, length, USB_WRITE_TIMEOUT_MILLIS); 154 | if (result != length) { 155 | throw new IOException( 156 | String.format("ControlTransfer with value 0x%x failed: %d", 157 | value, result)); 158 | } 159 | } 160 | 161 | private final byte[] vendorIn(int value, int index, int length) 162 | throws IOException { 163 | return inControlTransfer(PROLIFIC_VENDOR_IN_REQTYPE, 164 | PROLIFIC_VENDOR_READ_REQUEST, value, index, length); 165 | } 166 | 167 | private final void vendorOut(int value, int index, byte[] data) 168 | throws IOException { 169 | outControlTransfer(PROLIFIC_VENDOR_OUT_REQTYPE, 170 | PROLIFIC_VENDOR_WRITE_REQUEST, value, index, data); 171 | } 172 | 173 | private void resetDevice() throws IOException { 174 | purgeHwBuffers(true, true); 175 | } 176 | 177 | private final void ctrlOut(int request, int value, int index, byte[] data) 178 | throws IOException { 179 | outControlTransfer(PROLIFIC_CTRL_OUT_REQTYPE, request, value, index, 180 | data); 181 | } 182 | 183 | private void doBlackMagic() throws IOException { 184 | vendorIn(0x8484, 0, 1); 185 | vendorOut(0x0404, 0, null); 186 | vendorIn(0x8484, 0, 1); 187 | vendorIn(0x8383, 0, 1); 188 | vendorIn(0x8484, 0, 1); 189 | vendorOut(0x0404, 1, null); 190 | vendorIn(0x8484, 0, 1); 191 | vendorIn(0x8383, 0, 1); 192 | vendorOut(0, 1, null); 193 | vendorOut(1, 0, null); 194 | vendorOut(2, (mDeviceType == DEVICE_TYPE_HX) ? 0x44 : 0x24, null); 195 | } 196 | 197 | private void setControlLines(int newControlLinesValue) throws IOException { 198 | ctrlOut(SET_CONTROL_REQUEST, newControlLinesValue, 0, null); 199 | mControlLinesValue = newControlLinesValue; 200 | } 201 | 202 | private final void readStatusThreadFunction() { 203 | try { 204 | while (!mStopReadStatusThread) { 205 | byte[] buffer = new byte[STATUS_BUFFER_SIZE]; 206 | int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint, 207 | buffer, 208 | STATUS_BUFFER_SIZE, 209 | 500); 210 | if (readBytesCount > 0) { 211 | if (readBytesCount == STATUS_BUFFER_SIZE) { 212 | mStatus = buffer[STATUS_BYTE_IDX] & 0xff; 213 | } else { 214 | throw new IOException( 215 | String.format("Invalid CTS / DSR / CD / RI status buffer received, expected %d bytes, but received %d", 216 | STATUS_BUFFER_SIZE, 217 | readBytesCount)); 218 | } 219 | } 220 | } 221 | } catch (IOException e) { 222 | mReadStatusException = e; 223 | } 224 | } 225 | 226 | private final int getStatus() throws IOException { 227 | if ((mReadStatusThread == null) && (mReadStatusException == null)) { 228 | synchronized (mReadStatusThreadLock) { 229 | if (mReadStatusThread == null) { 230 | byte[] buffer = new byte[STATUS_BUFFER_SIZE]; 231 | int readBytes = mConnection.bulkTransfer(mInterruptEndpoint, 232 | buffer, 233 | STATUS_BUFFER_SIZE, 234 | 100); 235 | if (readBytes != STATUS_BUFFER_SIZE) { 236 | Log.w(TAG, "Could not read initial CTS / DSR / CD / RI status"); 237 | } else { 238 | mStatus = buffer[STATUS_BYTE_IDX] & 0xff; 239 | } 240 | 241 | mReadStatusThread = new Thread(new Runnable() { 242 | @Override 243 | public void run() { 244 | readStatusThreadFunction(); 245 | } 246 | }); 247 | mReadStatusThread.setDaemon(true); 248 | mReadStatusThread.start(); 249 | } 250 | } 251 | } 252 | 253 | /* throw and clear an exception which occured in the status read thread */ 254 | IOException readStatusException = mReadStatusException; 255 | if (mReadStatusException != null) { 256 | mReadStatusException = null; 257 | throw readStatusException; 258 | } 259 | 260 | return mStatus; 261 | } 262 | 263 | private final boolean testStatusFlag(int flag) throws IOException { 264 | return ((getStatus() & flag) == flag); 265 | } 266 | 267 | @Override 268 | public void open(UsbDeviceConnection connection) throws IOException { 269 | if (mConnection != null) { 270 | throw new IOException("Already open"); 271 | } 272 | 273 | UsbInterface usbInterface = mDevice.getInterface(0); 274 | 275 | if (!connection.claimInterface(usbInterface, true)) { 276 | throw new IOException("Error claiming Prolific interface 0"); 277 | } 278 | 279 | mConnection = connection; 280 | boolean opened = false; 281 | try { 282 | for (int i = 0; i < usbInterface.getEndpointCount(); ++i) { 283 | UsbEndpoint currentEndpoint = usbInterface.getEndpoint(i); 284 | 285 | switch (currentEndpoint.getAddress()) { 286 | case READ_ENDPOINT: 287 | mReadEndpoint = currentEndpoint; 288 | break; 289 | 290 | case WRITE_ENDPOINT: 291 | mWriteEndpoint = currentEndpoint; 292 | break; 293 | 294 | case INTERRUPT_ENDPOINT: 295 | mInterruptEndpoint = currentEndpoint; 296 | break; 297 | } 298 | } 299 | 300 | if (mDevice.getDeviceClass() == 0x02) { 301 | mDeviceType = DEVICE_TYPE_0; 302 | } else { 303 | try { 304 | Method getRawDescriptorsMethod 305 | = mConnection.getClass().getMethod("getRawDescriptors"); 306 | byte[] rawDescriptors 307 | = (byte[]) getRawDescriptorsMethod.invoke(mConnection); 308 | byte maxPacketSize0 = rawDescriptors[7]; 309 | if (maxPacketSize0 == 64) { 310 | mDeviceType = DEVICE_TYPE_HX; 311 | } else if ((mDevice.getDeviceClass() == 0x00) 312 | || (mDevice.getDeviceClass() == 0xff)) { 313 | mDeviceType = DEVICE_TYPE_1; 314 | } else { 315 | Log.w(TAG, "Could not detect PL2303 subtype, " 316 | + "Assuming that it is a HX device"); 317 | mDeviceType = DEVICE_TYPE_HX; 318 | } 319 | } catch (NoSuchMethodException e) { 320 | Log.w(TAG, "Method UsbDeviceConnection.getRawDescriptors, " 321 | + "required for PL2303 subtype detection, not " 322 | + "available! Assuming that it is a HX device"); 323 | mDeviceType = DEVICE_TYPE_HX; 324 | } catch (Exception e) { 325 | Log.e(TAG, "An unexpected exception occured while trying " 326 | + "to detect PL2303 subtype", e); 327 | } 328 | } 329 | 330 | setControlLines(mControlLinesValue); 331 | resetDevice(); 332 | 333 | doBlackMagic(); 334 | opened = true; 335 | } finally { 336 | if (!opened) { 337 | mConnection = null; 338 | connection.releaseInterface(usbInterface); 339 | } 340 | } 341 | } 342 | 343 | @Override 344 | public void close() throws IOException { 345 | if (mConnection == null) { 346 | throw new IOException("Already closed"); 347 | } 348 | try { 349 | mStopReadStatusThread = true; 350 | synchronized (mReadStatusThreadLock) { 351 | if (mReadStatusThread != null) { 352 | try { 353 | mReadStatusThread.join(); 354 | } catch (Exception e) { 355 | Log.w(TAG, "An error occured while waiting for status read thread", e); 356 | } 357 | } 358 | } 359 | resetDevice(); 360 | } finally { 361 | try { 362 | mConnection.releaseInterface(mDevice.getInterface(0)); 363 | } finally { 364 | mConnection = null; 365 | } 366 | } 367 | } 368 | 369 | @Override 370 | public int read(byte[] dest, int timeoutMillis) throws IOException { 371 | synchronized (mReadBufferLock) { 372 | int readAmt = Math.min(dest.length, mReadBuffer.length); 373 | int numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, 374 | readAmt, timeoutMillis); 375 | if (numBytesRead < 0) { 376 | return 0; 377 | } 378 | System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead); 379 | return numBytesRead; 380 | } 381 | } 382 | 383 | @Override 384 | public int write(byte[] src, int timeoutMillis) throws IOException { 385 | int offset = 0; 386 | 387 | while (offset < src.length) { 388 | final int writeLength; 389 | final int amtWritten; 390 | 391 | synchronized (mWriteBufferLock) { 392 | final byte[] writeBuffer; 393 | 394 | writeLength = Math.min(src.length - offset, mWriteBuffer.length); 395 | if (offset == 0) { 396 | writeBuffer = src; 397 | } else { 398 | // bulkTransfer does not support offsets, make a copy. 399 | System.arraycopy(src, offset, mWriteBuffer, 0, writeLength); 400 | writeBuffer = mWriteBuffer; 401 | } 402 | 403 | amtWritten = mConnection.bulkTransfer(mWriteEndpoint, 404 | writeBuffer, writeLength, timeoutMillis); 405 | } 406 | 407 | if (amtWritten <= 0) { 408 | throw new IOException("Error writing " + writeLength 409 | + " bytes at offset " + offset + " length=" 410 | + src.length); 411 | } 412 | 413 | offset += amtWritten; 414 | } 415 | return offset; 416 | } 417 | 418 | @Override 419 | public void setParameters(int baudRate, int dataBits, int stopBits, 420 | int parity) throws IOException { 421 | if ((mBaudRate == baudRate) && (mDataBits == dataBits) 422 | && (mStopBits == stopBits) && (mParity == parity)) { 423 | // Make sure no action is performed if there is nothing to change 424 | return; 425 | } 426 | 427 | byte[] lineRequestData = new byte[7]; 428 | 429 | lineRequestData[0] = (byte) (baudRate & 0xff); 430 | lineRequestData[1] = (byte) ((baudRate >> 8) & 0xff); 431 | lineRequestData[2] = (byte) ((baudRate >> 16) & 0xff); 432 | lineRequestData[3] = (byte) ((baudRate >> 24) & 0xff); 433 | 434 | switch (stopBits) { 435 | case STOPBITS_1: 436 | lineRequestData[4] = 0; 437 | break; 438 | 439 | case STOPBITS_1_5: 440 | lineRequestData[4] = 1; 441 | break; 442 | 443 | case STOPBITS_2: 444 | lineRequestData[4] = 2; 445 | break; 446 | 447 | default: 448 | throw new IllegalArgumentException("Unknown stopBits value: " + stopBits); 449 | } 450 | 451 | switch (parity) { 452 | case PARITY_NONE: 453 | lineRequestData[5] = 0; 454 | break; 455 | 456 | case PARITY_ODD: 457 | lineRequestData[5] = 1; 458 | break; 459 | 460 | case PARITY_MARK: 461 | lineRequestData[5] = 3; 462 | break; 463 | 464 | case PARITY_SPACE: 465 | lineRequestData[5] = 4; 466 | break; 467 | 468 | default: 469 | throw new IllegalArgumentException("Unknown parity value: " + parity); 470 | } 471 | 472 | lineRequestData[6] = (byte) dataBits; 473 | 474 | ctrlOut(SET_LINE_REQUEST, 0, 0, lineRequestData); 475 | 476 | resetDevice(); 477 | 478 | mBaudRate = baudRate; 479 | mDataBits = dataBits; 480 | mStopBits = stopBits; 481 | mParity = parity; 482 | } 483 | 484 | @Override 485 | public boolean getCD() throws IOException { 486 | return testStatusFlag(STATUS_FLAG_CD); 487 | } 488 | 489 | @Override 490 | public boolean getCTS() throws IOException { 491 | return testStatusFlag(STATUS_FLAG_CTS); 492 | } 493 | 494 | @Override 495 | public boolean getDSR() throws IOException { 496 | return testStatusFlag(STATUS_FLAG_DSR); 497 | } 498 | 499 | @Override 500 | public boolean getDTR() throws IOException { 501 | return ((mControlLinesValue & CONTROL_DTR) == CONTROL_DTR); 502 | } 503 | 504 | @Override 505 | public void setDTR(boolean value) throws IOException { 506 | int newControlLinesValue; 507 | if (value) { 508 | newControlLinesValue = mControlLinesValue | CONTROL_DTR; 509 | } else { 510 | newControlLinesValue = mControlLinesValue & ~CONTROL_DTR; 511 | } 512 | setControlLines(newControlLinesValue); 513 | } 514 | 515 | @Override 516 | public boolean getRI() throws IOException { 517 | return testStatusFlag(STATUS_FLAG_RI); 518 | } 519 | 520 | @Override 521 | public boolean getRTS() throws IOException { 522 | return ((mControlLinesValue & CONTROL_RTS) == CONTROL_RTS); 523 | } 524 | 525 | @Override 526 | public void setRTS(boolean value) throws IOException { 527 | int newControlLinesValue; 528 | if (value) { 529 | newControlLinesValue = mControlLinesValue | CONTROL_RTS; 530 | } else { 531 | newControlLinesValue = mControlLinesValue & ~CONTROL_RTS; 532 | } 533 | setControlLines(newControlLinesValue); 534 | } 535 | 536 | @Override 537 | public boolean purgeHwBuffers(boolean purgeReadBuffers, boolean purgeWriteBuffers) throws IOException { 538 | if (purgeReadBuffers) { 539 | vendorOut(FLUSH_RX_REQUEST, 0, null); 540 | } 541 | 542 | if (purgeWriteBuffers) { 543 | vendorOut(FLUSH_TX_REQUEST, 0, null); 544 | } 545 | 546 | return purgeReadBuffers || purgeWriteBuffers; 547 | } 548 | } 549 | 550 | public static Map getSupportedDevices() { 551 | final Map supportedDevices = new LinkedHashMap(); 552 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_PROLIFIC), 553 | new int[] { UsbId.PROLIFIC_PL2303, }); 554 | return supportedDevices; 555 | } 556 | } 557 | -------------------------------------------------------------------------------- /src/com/hoho/android/usbserial/driver/UsbId.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | /** 25 | * Registry of USB vendor/product ID constants. 26 | * 27 | * Culled from various sources; see usb.ids for one listing. 29 | * 30 | * @author mike wakerly (opensource@hoho.com) 31 | */ 32 | public final class UsbId { 33 | 34 | public static final int VENDOR_FTDI = 0x0403; 35 | public static final int FTDI_FT232R = 0x6001; 36 | public static final int FTDI_FT231X = 0x6015; 37 | 38 | public static final int VENDOR_ATMEL = 0x03EB; 39 | public static final int ATMEL_LUFA_CDC_DEMO_APP = 0x2044; 40 | 41 | public static final int VENDOR_ARDUINO = 0x2341; 42 | public static final int ARDUINO_UNO = 0x0001; 43 | public static final int ARDUINO_MEGA_2560 = 0x0010; 44 | public static final int ARDUINO_SERIAL_ADAPTER = 0x003b; 45 | public static final int ARDUINO_MEGA_ADK = 0x003f; 46 | public static final int ARDUINO_MEGA_2560_R3 = 0x0042; 47 | public static final int ARDUINO_UNO_R3 = 0x0043; 48 | public static final int ARDUINO_MEGA_ADK_R3 = 0x0044; 49 | public static final int ARDUINO_SERIAL_ADAPTER_R3 = 0x0044; 50 | public static final int ARDUINO_LEONARDO = 0x8036; 51 | 52 | public static final int VENDOR_VAN_OOIJEN_TECH = 0x16c0; 53 | public static final int VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL = 0x0483; 54 | 55 | public static final int VENDOR_LEAFLABS = 0x1eaf; 56 | public static final int LEAFLABS_MAPLE = 0x0004; 57 | 58 | public static final int VENDOR_SILABS = 0x10c4; 59 | public static final int SILABS_CP2102 = 0xea60; 60 | public static final int SILABS_CP2105 = 0xea70; 61 | public static final int SILABS_CP2108 = 0xea71; 62 | public static final int SILABS_CP2110 = 0xea80; 63 | 64 | public static final int VENDOR_PROLIFIC = 0x067b; 65 | public static final int PROLIFIC_PL2303 = 0x2303; 66 | 67 | private UsbId() { 68 | throw new IllegalAccessError("Non-instantiable class."); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/com/hoho/android/usbserial/driver/UsbSerialDriver.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.hardware.usb.UsbDevice; 25 | 26 | import java.util.List; 27 | 28 | /** 29 | * 30 | * @author mike wakerly (opensource@hoho.com) 31 | */ 32 | public interface UsbSerialDriver { 33 | 34 | /** 35 | * Returns the raw {@link UsbDevice} backing this port. 36 | * 37 | * @return the device 38 | */ 39 | public UsbDevice getDevice(); 40 | 41 | /** 42 | * Returns all available ports for this device. This list must have at least 43 | * one entry. 44 | * 45 | * @return the ports 46 | */ 47 | public List getPorts(); 48 | } 49 | -------------------------------------------------------------------------------- /src/com/hoho/android/usbserial/driver/UsbSerialPort.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.hardware.usb.UsbDeviceConnection; 25 | import android.hardware.usb.UsbManager; 26 | 27 | import java.io.IOException; 28 | 29 | /** 30 | * Interface for a single serial port. 31 | * 32 | * @author mike wakerly (opensource@hoho.com) 33 | */ 34 | public interface UsbSerialPort { 35 | 36 | /** 5 data bits. */ 37 | public static final int DATABITS_5 = 5; 38 | 39 | /** 6 data bits. */ 40 | public static final int DATABITS_6 = 6; 41 | 42 | /** 7 data bits. */ 43 | public static final int DATABITS_7 = 7; 44 | 45 | /** 8 data bits. */ 46 | public static final int DATABITS_8 = 8; 47 | 48 | /** No flow control. */ 49 | public static final int FLOWCONTROL_NONE = 0; 50 | 51 | /** RTS/CTS input flow control. */ 52 | public static final int FLOWCONTROL_RTSCTS_IN = 1; 53 | 54 | /** RTS/CTS output flow control. */ 55 | public static final int FLOWCONTROL_RTSCTS_OUT = 2; 56 | 57 | /** XON/XOFF input flow control. */ 58 | public static final int FLOWCONTROL_XONXOFF_IN = 4; 59 | 60 | /** XON/XOFF output flow control. */ 61 | public static final int FLOWCONTROL_XONXOFF_OUT = 8; 62 | 63 | /** No parity. */ 64 | public static final int PARITY_NONE = 0; 65 | 66 | /** Odd parity. */ 67 | public static final int PARITY_ODD = 1; 68 | 69 | /** Even parity. */ 70 | public static final int PARITY_EVEN = 2; 71 | 72 | /** Mark parity. */ 73 | public static final int PARITY_MARK = 3; 74 | 75 | /** Space parity. */ 76 | public static final int PARITY_SPACE = 4; 77 | 78 | /** 1 stop bit. */ 79 | public static final int STOPBITS_1 = 1; 80 | 81 | /** 1.5 stop bits. */ 82 | public static final int STOPBITS_1_5 = 3; 83 | 84 | /** 2 stop bits. */ 85 | public static final int STOPBITS_2 = 2; 86 | 87 | public UsbSerialDriver getDriver(); 88 | 89 | /** 90 | * Port number within driver. 91 | */ 92 | public int getPortNumber(); 93 | 94 | /** 95 | * The serial number of the underlying UsbDeviceConnection, or {@code null}. 96 | */ 97 | public String getSerial(); 98 | 99 | /** 100 | * Opens and initializes the port. Upon success, caller must ensure that 101 | * {@link #close()} is eventually called. 102 | * 103 | * @param connection an open device connection, acquired with 104 | * {@link UsbManager#openDevice(android.hardware.usb.UsbDevice)} 105 | * @throws IOException on error opening or initializing the port. 106 | */ 107 | public void open(UsbDeviceConnection connection) throws IOException; 108 | 109 | /** 110 | * Closes the port. 111 | * 112 | * @throws IOException on error closing the port. 113 | */ 114 | public void close() throws IOException; 115 | 116 | /** 117 | * Reads as many bytes as possible into the destination buffer. 118 | * 119 | * @param dest the destination byte buffer 120 | * @param timeoutMillis the timeout for reading 121 | * @return the actual number of bytes read 122 | * @throws IOException if an error occurred during reading 123 | */ 124 | public int read(final byte[] dest, final int timeoutMillis) throws IOException; 125 | 126 | /** 127 | * Writes as many bytes as possible from the source buffer. 128 | * 129 | * @param src the source byte buffer 130 | * @param timeoutMillis the timeout for writing 131 | * @return the actual number of bytes written 132 | * @throws IOException if an error occurred during writing 133 | */ 134 | public int write(final byte[] src, final int timeoutMillis) throws IOException; 135 | 136 | /** 137 | * Sets various serial port parameters. 138 | * 139 | * @param baudRate baud rate as an integer, for example {@code 115200}. 140 | * @param dataBits one of {@link #DATABITS_5}, {@link #DATABITS_6}, 141 | * {@link #DATABITS_7}, or {@link #DATABITS_8}. 142 | * @param stopBits one of {@link #STOPBITS_1}, {@link #STOPBITS_1_5}, or 143 | * {@link #STOPBITS_2}. 144 | * @param parity one of {@link #PARITY_NONE}, {@link #PARITY_ODD}, 145 | * {@link #PARITY_EVEN}, {@link #PARITY_MARK}, or 146 | * {@link #PARITY_SPACE}. 147 | * @throws IOException on error setting the port parameters 148 | */ 149 | public void setParameters( 150 | int baudRate, int dataBits, int stopBits, int parity) throws IOException; 151 | 152 | /** 153 | * Gets the CD (Carrier Detect) bit from the underlying UART. 154 | * 155 | * @return the current state, or {@code false} if not supported. 156 | * @throws IOException if an error occurred during reading 157 | */ 158 | public boolean getCD() throws IOException; 159 | 160 | /** 161 | * Gets the CTS (Clear To Send) bit from the underlying UART. 162 | * 163 | * @return the current state, or {@code false} if not supported. 164 | * @throws IOException if an error occurred during reading 165 | */ 166 | public boolean getCTS() throws IOException; 167 | 168 | /** 169 | * Gets the DSR (Data Set Ready) bit from the underlying UART. 170 | * 171 | * @return the current state, or {@code false} if not supported. 172 | * @throws IOException if an error occurred during reading 173 | */ 174 | public boolean getDSR() throws IOException; 175 | 176 | /** 177 | * Gets the DTR (Data Terminal Ready) bit from the underlying UART. 178 | * 179 | * @return the current state, or {@code false} if not supported. 180 | * @throws IOException if an error occurred during reading 181 | */ 182 | public boolean getDTR() throws IOException; 183 | 184 | /** 185 | * Sets the DTR (Data Terminal Ready) bit on the underlying UART, if 186 | * supported. 187 | * 188 | * @param value the value to set 189 | * @throws IOException if an error occurred during writing 190 | */ 191 | public void setDTR(boolean value) throws IOException; 192 | 193 | /** 194 | * Gets the RI (Ring Indicator) bit from the underlying UART. 195 | * 196 | * @return the current state, or {@code false} if not supported. 197 | * @throws IOException if an error occurred during reading 198 | */ 199 | public boolean getRI() throws IOException; 200 | 201 | /** 202 | * Gets the RTS (Request To Send) bit from the underlying UART. 203 | * 204 | * @return the current state, or {@code false} if not supported. 205 | * @throws IOException if an error occurred during reading 206 | */ 207 | public boolean getRTS() throws IOException; 208 | 209 | /** 210 | * Sets the RTS (Request To Send) bit on the underlying UART, if 211 | * supported. 212 | * 213 | * @param value the value to set 214 | * @throws IOException if an error occurred during writing 215 | */ 216 | public void setRTS(boolean value) throws IOException; 217 | 218 | /** 219 | * Flush non-transmitted output data and / or non-read input data 220 | * @param flushRX {@code true} to flush non-transmitted output data 221 | * @param flushTX {@code true} to flush non-read input data 222 | * @return {@code true} if the operation was successful, or 223 | * {@code false} if the operation is not supported by the driver or device 224 | * @throws IOException if an error occurred during flush 225 | */ 226 | public boolean purgeHwBuffers(boolean flushRX, boolean flushTX) throws IOException; 227 | 228 | } 229 | -------------------------------------------------------------------------------- /src/com/hoho/android/usbserial/driver/UsbSerialProber.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.driver; 23 | 24 | import android.hardware.usb.UsbDevice; 25 | import android.hardware.usb.UsbManager; 26 | 27 | import java.lang.reflect.Constructor; 28 | import java.lang.reflect.InvocationTargetException; 29 | import java.util.ArrayList; 30 | import java.util.List; 31 | 32 | /** 33 | * 34 | * @author mike wakerly (opensource@hoho.com) 35 | */ 36 | public class UsbSerialProber { 37 | 38 | private final ProbeTable mProbeTable; 39 | 40 | public UsbSerialProber(ProbeTable probeTable) { 41 | mProbeTable = probeTable; 42 | } 43 | 44 | public static UsbSerialProber getDefaultProber() { 45 | return new UsbSerialProber(getDefaultProbeTable()); 46 | } 47 | 48 | public static ProbeTable getDefaultProbeTable() { 49 | final ProbeTable probeTable = new ProbeTable(); 50 | probeTable.addDriver(CdcAcmSerialDriver.class); 51 | probeTable.addDriver(Cp21xxSerialDriver.class); 52 | probeTable.addDriver(FtdiSerialDriver.class); 53 | probeTable.addDriver(ProlificSerialDriver.class); 54 | return probeTable; 55 | } 56 | 57 | /** 58 | * Finds and builds all possible {@link UsbSerialDriver UsbSerialDrivers} 59 | * from the currently-attached {@link UsbDevice} hierarchy. This method does 60 | * not require permission from the Android USB system, since it does not 61 | * open any of the devices. 62 | * 63 | * @param usbManager 64 | * @return a list, possibly empty, of all compatible drivers 65 | */ 66 | public List findAllDrivers(final UsbManager usbManager) { 67 | final List result = new ArrayList(); 68 | 69 | for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) { 70 | final UsbSerialDriver driver = probeDevice(usbDevice); 71 | if (driver != null) { 72 | result.add(driver); 73 | } 74 | } 75 | return result; 76 | } 77 | 78 | /** 79 | * Probes a single device for a compatible driver. 80 | * 81 | * @param usbDevice the usb device to probe 82 | * @return a new {@link UsbSerialDriver} compatible with this device, or 83 | * {@code null} if none available. 84 | */ 85 | public UsbSerialDriver probeDevice(final UsbDevice usbDevice) { 86 | final int vendorId = usbDevice.getVendorId(); 87 | final int productId = usbDevice.getProductId(); 88 | 89 | final Class driverClass = 90 | mProbeTable.findDriver(vendorId, productId); 91 | if (driverClass != null) { 92 | final UsbSerialDriver driver; 93 | try { 94 | final Constructor ctor = 95 | driverClass.getConstructor(UsbDevice.class); 96 | driver = ctor.newInstance(usbDevice); 97 | } catch (NoSuchMethodException e) { 98 | throw new RuntimeException(e); 99 | } catch (IllegalArgumentException e) { 100 | throw new RuntimeException(e); 101 | } catch (InstantiationException e) { 102 | throw new RuntimeException(e); 103 | } catch (IllegalAccessException e) { 104 | throw new RuntimeException(e); 105 | } catch (InvocationTargetException e) { 106 | throw new RuntimeException(e); 107 | } 108 | return driver; 109 | } 110 | return null; 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/com/hoho/android/usbserial/driver/UsbSerialRuntimeException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Google Inc. 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | */ 19 | 20 | package com.hoho.android.usbserial.driver; 21 | 22 | /** 23 | * Generic unchecked exception for the usbserial package. 24 | * 25 | * @author mike wakerly (opensource@hoho.com) 26 | */ 27 | @SuppressWarnings("serial") 28 | public class UsbSerialRuntimeException extends RuntimeException { 29 | 30 | public UsbSerialRuntimeException() { 31 | super(); 32 | } 33 | 34 | public UsbSerialRuntimeException(String detailMessage, Throwable throwable) { 35 | super(detailMessage, throwable); 36 | } 37 | 38 | public UsbSerialRuntimeException(String detailMessage) { 39 | super(detailMessage); 40 | } 41 | 42 | public UsbSerialRuntimeException(Throwable throwable) { 43 | super(throwable); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/com/hoho/android/usbserial/util/HexDump.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2006 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.hoho.android.usbserial.util; 18 | 19 | /** 20 | * Clone of Android's HexDump class, for use in debugging. Cosmetic changes 21 | * only. 22 | */ 23 | public class HexDump { 24 | private final static char[] HEX_DIGITS = { 25 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 26 | }; 27 | 28 | public static String dumpHexString(byte[] array) { 29 | return dumpHexString(array, 0, array.length); 30 | } 31 | 32 | public static String dumpHexString(byte[] array, int offset, int length) { 33 | StringBuilder result = new StringBuilder(); 34 | 35 | byte[] line = new byte[16]; 36 | int lineIndex = 0; 37 | 38 | result.append("\n0x"); 39 | result.append(toHexString(offset)); 40 | 41 | for (int i = offset; i < offset + length; i++) { 42 | if (lineIndex == 16) { 43 | result.append(" "); 44 | 45 | for (int j = 0; j < 16; j++) { 46 | if (line[j] > ' ' && line[j] < '~') { 47 | result.append(new String(line, j, 1)); 48 | } else { 49 | result.append("."); 50 | } 51 | } 52 | 53 | result.append("\n0x"); 54 | result.append(toHexString(i)); 55 | lineIndex = 0; 56 | } 57 | 58 | byte b = array[i]; 59 | result.append(" "); 60 | result.append(HEX_DIGITS[(b >>> 4) & 0x0F]); 61 | result.append(HEX_DIGITS[b & 0x0F]); 62 | 63 | line[lineIndex++] = b; 64 | } 65 | 66 | if (lineIndex != 16) { 67 | int count = (16 - lineIndex) * 3; 68 | count++; 69 | for (int i = 0; i < count; i++) { 70 | result.append(" "); 71 | } 72 | 73 | for (int i = 0; i < lineIndex; i++) { 74 | if (line[i] > ' ' && line[i] < '~') { 75 | result.append(new String(line, i, 1)); 76 | } else { 77 | result.append("."); 78 | } 79 | } 80 | } 81 | 82 | return result.toString(); 83 | } 84 | 85 | public static String toHexString(byte b) { 86 | return toHexString(toByteArray(b)); 87 | } 88 | 89 | public static String toHexString(byte[] array) { 90 | return toHexString(array, 0, array.length); 91 | } 92 | 93 | public static String toHexString(byte[] array, int offset, int length) { 94 | char[] buf = new char[length * 2]; 95 | 96 | int bufIndex = 0; 97 | for (int i = offset; i < offset + length; i++) { 98 | byte b = array[i]; 99 | buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F]; 100 | buf[bufIndex++] = HEX_DIGITS[b & 0x0F]; 101 | } 102 | 103 | return new String(buf); 104 | } 105 | 106 | public static String toHexString(int i) { 107 | return toHexString(toByteArray(i)); 108 | } 109 | 110 | public static String toHexString(short i) { 111 | return toHexString(toByteArray(i)); 112 | } 113 | 114 | public static byte[] toByteArray(byte b) { 115 | byte[] array = new byte[1]; 116 | array[0] = b; 117 | return array; 118 | } 119 | 120 | public static byte[] toByteArray(int i) { 121 | byte[] array = new byte[4]; 122 | 123 | array[3] = (byte) (i & 0xFF); 124 | array[2] = (byte) ((i >> 8) & 0xFF); 125 | array[1] = (byte) ((i >> 16) & 0xFF); 126 | array[0] = (byte) ((i >> 24) & 0xFF); 127 | 128 | return array; 129 | } 130 | 131 | public static byte[] toByteArray(short i) { 132 | byte[] array = new byte[2]; 133 | 134 | array[1] = (byte) (i & 0xFF); 135 | array[0] = (byte) ((i >> 8) & 0xFF); 136 | 137 | return array; 138 | } 139 | 140 | private static int toByte(char c) { 141 | if (c >= '0' && c <= '9') 142 | return (c - '0'); 143 | if (c >= 'A' && c <= 'F') 144 | return (c - 'A' + 10); 145 | if (c >= 'a' && c <= 'f') 146 | return (c - 'a' + 10); 147 | 148 | throw new RuntimeException("Invalid hex char '" + c + "'"); 149 | } 150 | 151 | public static byte[] hexStringToByteArray(String hexString) { 152 | int length = hexString.length(); 153 | byte[] buffer = new byte[length / 2]; 154 | 155 | for (int i = 0; i < length; i += 2) { 156 | buffer[i / 2] = (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString 157 | .charAt(i + 1))); 158 | } 159 | 160 | return buffer; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/com/hoho/android/usbserial/util/SerialInputOutputManager.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2011-2013 Google Inc. 2 | * Copyright 2013 mike wakerly 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * Project home page: https://github.com/mik3y/usb-serial-for-android 20 | */ 21 | 22 | package com.hoho.android.usbserial.util; 23 | 24 | import android.hardware.usb.UsbRequest; 25 | import android.util.Log; 26 | 27 | import com.hoho.android.usbserial.driver.UsbSerialPort; 28 | 29 | import java.io.IOException; 30 | import java.nio.ByteBuffer; 31 | 32 | /** 33 | * Utility class which services a {@link UsbSerialPort} in its {@link #run()} 34 | * method. 35 | * 36 | * @author mike wakerly (opensource@hoho.com) 37 | */ 38 | public class SerialInputOutputManager implements Runnable { 39 | 40 | private static final String TAG = SerialInputOutputManager.class.getSimpleName(); 41 | private static final boolean DEBUG = true; 42 | 43 | private static final int READ_WAIT_MILLIS = 200; 44 | private static final int BUFSIZ = 4096; 45 | 46 | private final UsbSerialPort mDriver; 47 | 48 | private final ByteBuffer mReadBuffer = ByteBuffer.allocate(BUFSIZ); 49 | 50 | // Synchronized by 'mWriteBuffer' 51 | private final ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ); 52 | 53 | private enum State { 54 | STOPPED, 55 | RUNNING, 56 | STOPPING 57 | } 58 | 59 | // Synchronized by 'this' 60 | private State mState = State.STOPPED; 61 | 62 | // Synchronized by 'this' 63 | private Listener mListener; 64 | 65 | public interface Listener { 66 | /** 67 | * Called when new incoming data is available. 68 | */ 69 | public void onNewData(byte[] data); 70 | 71 | /** 72 | * Called when {@link SerialInputOutputManager#run()} aborts due to an 73 | * error. 74 | */ 75 | public void onRunError(Exception e); 76 | } 77 | 78 | /** 79 | * Creates a new instance with no listener. 80 | */ 81 | public SerialInputOutputManager(UsbSerialPort driver) { 82 | this(driver, null); 83 | } 84 | 85 | /** 86 | * Creates a new instance with the provided listener. 87 | */ 88 | public SerialInputOutputManager(UsbSerialPort driver, Listener listener) { 89 | mDriver = driver; 90 | mListener = listener; 91 | } 92 | 93 | public synchronized void setListener(Listener listener) { 94 | mListener = listener; 95 | } 96 | 97 | public synchronized Listener getListener() { 98 | return mListener; 99 | } 100 | 101 | public void writeAsync(byte[] data) { 102 | synchronized (mWriteBuffer) { 103 | mWriteBuffer.put(data); 104 | } 105 | } 106 | 107 | public synchronized void stop() { 108 | if (getState() == State.RUNNING) { 109 | Log.i(TAG, "Stop requested"); 110 | mState = State.STOPPING; 111 | } 112 | } 113 | 114 | private synchronized State getState() { 115 | return mState; 116 | } 117 | 118 | /** 119 | * Continuously services the read and write buffers until {@link #stop()} is 120 | * called, or until a driver exception is raised. 121 | * 122 | * NOTE(mikey): Uses inefficient read/write-with-timeout. 123 | * TODO(mikey): Read asynchronously with {@link UsbRequest#queue(ByteBuffer, int)} 124 | */ 125 | @Override 126 | public void run() { 127 | synchronized (this) { 128 | if (getState() != State.STOPPED) { 129 | throw new IllegalStateException("Already running."); 130 | } 131 | mState = State.RUNNING; 132 | } 133 | 134 | Log.i(TAG, "Running .."); 135 | try { 136 | while (true) { 137 | if (getState() != State.RUNNING) { 138 | Log.i(TAG, "Stopping mState=" + getState()); 139 | break; 140 | } 141 | step(); 142 | } 143 | } catch (Exception e) { 144 | Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e); 145 | final Listener listener = getListener(); 146 | if (listener != null) { 147 | listener.onRunError(e); 148 | } 149 | } finally { 150 | synchronized (this) { 151 | mState = State.STOPPED; 152 | Log.i(TAG, "Stopped."); 153 | } 154 | } 155 | } 156 | 157 | private void step() throws IOException { 158 | // Handle incoming data. 159 | int len = mDriver.read(mReadBuffer.array(), READ_WAIT_MILLIS); 160 | if (len > 0) { 161 | if (DEBUG) Log.d(TAG, "Read data len=" + len); 162 | final Listener listener = getListener(); 163 | if (listener != null) { 164 | final byte[] data = new byte[len]; 165 | mReadBuffer.get(data, 0, len); 166 | listener.onNewData(data); 167 | } 168 | mReadBuffer.clear(); 169 | } 170 | 171 | // Handle outgoing data. 172 | byte[] outBuff = null; 173 | synchronized (mWriteBuffer) { 174 | len = mWriteBuffer.position(); 175 | if (len > 0) { 176 | outBuff = new byte[len]; 177 | mWriteBuffer.rewind(); 178 | mWriteBuffer.get(outBuff, 0, len); 179 | mWriteBuffer.clear(); 180 | } 181 | } 182 | if (outBuff != null) { 183 | if (DEBUG) { 184 | Log.d(TAG, "Writing data len=" + len); 185 | } 186 | mDriver.write(outBuff, READ_WAIT_MILLIS); 187 | } 188 | } 189 | 190 | } 191 | -------------------------------------------------------------------------------- /src/com/rtlsdr/android/SdrSerialDriver.java: -------------------------------------------------------------------------------- 1 | package com.rtlsdr.android; 2 | 3 | import java.io.IOException; 4 | import java.util.Collections; 5 | import java.util.LinkedHashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import android.hardware.usb.UsbDevice; 10 | import android.hardware.usb.UsbDeviceConnection; 11 | 12 | import com.hoho.android.usbserial.driver.CommonUsbSerialPort; 13 | import com.hoho.android.usbserial.driver.UsbSerialDriver; 14 | import com.hoho.android.usbserial.driver.UsbSerialPort; 15 | 16 | public class SdrSerialDriver implements UsbSerialDriver { 17 | 18 | private class SdrSerialPort extends CommonUsbSerialPort { 19 | 20 | public SdrSerialPort(UsbDevice device, int portNumber) { 21 | super(device, portNumber); 22 | } 23 | 24 | @Override 25 | public void close() throws IOException { 26 | } 27 | 28 | @Override 29 | public boolean getCD() throws IOException { 30 | return false; 31 | } 32 | 33 | @Override 34 | public boolean getCTS() throws IOException { 35 | return false; 36 | } 37 | 38 | @Override 39 | public UsbSerialDriver getDriver() { 40 | return null; 41 | } 42 | 43 | @Override 44 | public boolean getDSR() throws IOException { 45 | return false; 46 | } 47 | 48 | @Override 49 | public boolean getDTR() throws IOException { 50 | return false; 51 | } 52 | 53 | @Override 54 | public boolean getRI() throws IOException { 55 | return false; 56 | } 57 | 58 | @Override 59 | public boolean getRTS() throws IOException { 60 | return false; 61 | } 62 | 63 | @Override 64 | public void open(UsbDeviceConnection connection) throws IOException { 65 | } 66 | 67 | @Override 68 | public int read(byte[] dest, int timeoutMillis) throws IOException { 69 | return 0; 70 | } 71 | 72 | @Override 73 | public void setDTR(boolean value) throws IOException { 74 | } 75 | 76 | @Override 77 | public void setParameters(int baudRate, int dataBits, int stopBits, 78 | int parity) throws IOException { 79 | } 80 | 81 | @Override 82 | public void setRTS(boolean value) throws IOException { 83 | } 84 | 85 | @Override 86 | public int write(byte[] src, int timeoutMillis) throws IOException { 87 | return 0; 88 | } 89 | } 90 | 91 | public static Map getSupportedDevices() { 92 | final Map supportedDevices = new LinkedHashMap(); 93 | 94 | supportedDevices.put(Integer.valueOf(SdrUsbId.VENDOR_KYE), 95 | new int[] { SdrUsbId.KYE_RTL2832_707F }); 96 | 97 | supportedDevices.put(Integer.valueOf(SdrUsbId.VENDOR_RTL), new int[] { 98 | SdrUsbId.RTL_RTL2832, SdrUsbId.RTL_RTL2838 }); 99 | 100 | supportedDevices.put(Integer.valueOf(SdrUsbId.VENDOR_TERRATEC), 101 | new int[] { SdrUsbId.TERRATEC_RTL2838_A9, 102 | SdrUsbId.TERRATEC_RTL2838_B3, 103 | SdrUsbId.TERRATEC_RTL2838_B4, 104 | SdrUsbId.TERRATEC_RTL2838_B7, 105 | SdrUsbId.TERRATEC_RTL2838_C6, 106 | SdrUsbId.TERRATEC_RTL2838_D3, 107 | SdrUsbId.TERRATEC_RTL2838_D7, 108 | SdrUsbId.TERRATEC_RTL2838_E0 }); 109 | 110 | supportedDevices.put(Integer.valueOf(SdrUsbId.VENDOR_COMPRO), 111 | new int[] { SdrUsbId.COMPRO_620, SdrUsbId.COMPRO_650, 112 | SdrUsbId.COMPRO_680 }); 113 | 114 | supportedDevices.put(Integer.valueOf(SdrUsbId.VENDOR_AFATECH), 115 | new int[] { SdrUsbId.AFATECH_RTL2838_D393, 116 | SdrUsbId.AFATECH_RTL2838_D394, 117 | SdrUsbId.AFATECH_RTL2838_D395, 118 | SdrUsbId.AFATECH_RTL2838_D395, 119 | SdrUsbId.AFATECH_RTL2838_D396, 120 | SdrUsbId.AFATECH_RTL2838_D397, 121 | SdrUsbId.AFATECH_RTL2838_D398, 122 | SdrUsbId.AFATECH_RTL2838_D39D, 123 | SdrUsbId.AFATECH_RTL2838_D3A4 }); 124 | 125 | supportedDevices.put(Integer.valueOf(SdrUsbId.VENDOR_DEXATEC), 126 | new int[] { SdrUsbId.DEXATEC_1101, SdrUsbId.DEXATEC_1102, 127 | SdrUsbId.DEXATEC_1103 }); 128 | 129 | supportedDevices.put(Integer.valueOf(SdrUsbId.VENDOR_GTEK), new int[] { 130 | SdrUsbId.GTEK_RTL2838_B803, SdrUsbId.GTEK_RTL2838_C803, 131 | SdrUsbId.GTEK_RTL2838_D286, SdrUsbId.GTEK_RTL2838_D803 }); 132 | 133 | return supportedDevices; 134 | } 135 | 136 | private final UsbDevice mDevice; 137 | 138 | private final UsbSerialPort mPort; 139 | 140 | public SdrSerialDriver(UsbDevice device) { 141 | mDevice = device; 142 | mPort = new SdrSerialPort(mDevice, 0); 143 | } 144 | 145 | @Override 146 | public UsbDevice getDevice() { 147 | return mDevice; 148 | } 149 | 150 | @Override 151 | public List getPorts() { 152 | return Collections.singletonList(mPort); 153 | } 154 | } -------------------------------------------------------------------------------- /src/com/rtlsdr/android/SdrSerialDriverOrig.java: -------------------------------------------------------------------------------- 1 | package com.rtlsdr.android; 2 | 3 | import java.io.IOException; 4 | import java.util.LinkedHashMap; 5 | import java.util.Map; 6 | 7 | //import android.hardware.usb.UsbConstants; 8 | import android.hardware.usb.UsbConstants; 9 | import android.hardware.usb.UsbDevice; 10 | import android.hardware.usb.UsbDeviceConnection; 11 | import android.hardware.usb.UsbEndpoint; 12 | import android.hardware.usb.UsbInterface; 13 | import android.util.Log; 14 | 15 | import com.hoho.android.usbserial.driver.CommonUsbSerialDriver; 16 | import com.hoho.android.usbserial.driver.UsbId; 17 | import com.rtlsdr.android.tuners.E4K; 18 | import com.rtlsdr.android.tuners.FC0012; 19 | import com.rtlsdr.android.tuners.FC0013; 20 | import com.rtlsdr.android.tuners.FC2580; 21 | import com.rtlsdr.android.tuners.IRtlSdrTuner; 22 | import com.rtlsdr.android.tuners.R820T; 23 | 24 | public class SdrSerialDriverOrig extends CommonUsbSerialDriver { 25 | private static final String TAG = SdrSerialDriverOrig.class.getSimpleName(); 26 | static IRtlSdrTuner myTuner = null; 27 | boolean set_gain_mode = true; 28 | /* 29 | * private static final int DEFAULT_BAUD_RATE = 9600; 30 | * 31 | * private static final int DEFAULT_BUF_LENGTH = 512;//(16 * 16384); private 32 | * static final char MESSAGEGO = 253; private static final char OVERWRITE = 33 | * 254; private static final char BADSAMPLE = 255; 34 | */ 35 | private final int MODES_DEFAULT_RATE = 2000000; 36 | private final int MODES_DEFAULT_FREQ = 1090000000; 37 | private final int MODES_AUTO_GAIN = -100; /* Use automatic gain. */ 38 | private final int MODES_MAX_GAIN = 999999; /* Use max available gain. */ 39 | // /private final long ADSB_FREQ = 1090000000; 40 | // private final int AUTO_GAIN = -100; 41 | // private final long ADSB_RATE = 2000000; 42 | private int gain = MODES_MAX_GAIN;// AUTO_GAIN; 43 | private boolean enable_agc = false; 44 | private long freq = MODES_DEFAULT_FREQ; 45 | // Buffersizes 46 | // private static final int MODES_PREAMBLE_US = 8; 47 | // private static final int MODES_LONG_MSG_BITS =112; 48 | // private static final int MODES_FULL_LEN 49 | // =(MODES_PREAMBLE_US+MODES_LONG_MSG_BITS); 50 | // private static final int MODES_DATA_LEN = (16*16384); /* 256k */ 51 | // private static final int BUFSIZ = MODES_DATA_LEN + (MODES_FULL_LEN-1)*4; 52 | 53 | // private byte [] input = new byte[BUFSIZ]; 54 | // private static char[] mag = new char[BUFSIZ *2]; 55 | 56 | // private int [] adsb_frame = new int[14]; 57 | // private final int preamble_len = 16; 58 | // private final int long_frame = 112; 59 | // private final int char_frame = 56; 60 | // private double quality = 1.0; 61 | // private int allowed_errors = 5; 62 | 63 | private static final int USB_WRITE_TIMEOUT_MILLIS = 5000;// was 5000 64 | 65 | /* 66 | * Configuration Request Types 67 | */ 68 | private static final int REQTYPE_HOST_TO_DEVICE = 0x41; 69 | // private static final int REQTYPE_DEVICE_TO_HOST = 0x80; 70 | 71 | /** In: device-to-host */ 72 | private static final int LIBUSB_ENDPOINT_IN = 0x80; 73 | 74 | /** Out: host-to-device */ 75 | private static final int LIBUSB_ENDPOINT_OUT = 0x00; 76 | 77 | /** Standard */ 78 | // private static final int LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5); 79 | 80 | /** Class */ 81 | // private static final int LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5); 82 | 83 | /** Vendor */ 84 | private static final int LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5); 85 | 86 | /** Reserved */ 87 | // private static final int LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5); 88 | 89 | private static final byte CTRL_IN = (byte) (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN); 90 | private static final byte CTRL_OUT = (byte) (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT); 91 | 92 | // private static final int DEFAULT_SAMPLE_RATE = 2048000; 93 | // private static final int DEFAULT_ASYNC_BUF_NUMBER = 32; 94 | // private static final int DEFAULT_BUF_LENGTH = (16 * 16384); 95 | // private static final int MINIMAL_BUF_LENGTH = 512; 96 | // static final int MAXIMAL_BUF_LENGTH = (256 * 16384); 97 | 98 | // private static final int DEFAULT_BUF_NUMBER = 32; 99 | // private static final int DEFAULT_BUF_LENGTH = (16 * 32 * 512); 100 | 101 | private static final int DEF_RTL_XTAL_FREQ = 28800000; 102 | private static final int MIN_RTL_XTAL_FREQ = (DEF_RTL_XTAL_FREQ - 1000); 103 | private static final int MAX_RTL_XTAL_FREQ = (DEF_RTL_XTAL_FREQ + 1000); 104 | 105 | private static final int MAX_SAMP_RATE = 3200000; 106 | 107 | // private static final int CTRL_TIMEOUT = 300; 108 | private static final int BULK_TIMEOUT = 0; 109 | private static final char EEPROM_ADDR = 0xa0; 110 | 111 | private static final char USB_SYSCTL = 0x2000; 112 | // private static final char USB_CTRL = 0x2010; 113 | // private static final char USB_STAT = 0x2014; 114 | // private static final char USB_EPA_CFG = 0x2144; 115 | private static final char USB_EPA_CTL = 0x2148; 116 | private static final char USB_EPA_MAXPKT = 0x2158; 117 | // private static final char USB_EPA_MAXPKT_2 = 0x215a; 118 | // private static final char USB_EPA_FIFO_CFG = 0x2160; 119 | 120 | private static final char DEMOD_CTL = 0x3000; 121 | private static final char GPO = 0x3001; 122 | // private static final char GPI = 0x3002; 123 | private static final char GPOE = 0x3003; 124 | private static final char GPD = 0x3004; 125 | // private static final char SYSINTE = 0x3005; 126 | // private static final char SYSINTS = 0x3006; 127 | // private static final char GP_CFG0 = 0x3007; 128 | // private static final char GP_CFG1 = 0x3008; 129 | // private static final char SYSINTE_1 = 0x3009; 130 | // private static final char SYSINTS_1 = 0x300a; 131 | private static final char DEMOD_CTL_1 = 0x300b; 132 | // private static final char IR_SUSPEND = 0x300c; 133 | 134 | // private static final byte DEMODB = 0; 135 | private static final byte USBB = 1; 136 | private static final byte SYSB = 2; 137 | // private static final byte TUNB = 3; 138 | // private static final byte ROMB = 4; 139 | // private static final byte IRB = 5; 140 | private static final byte IICB = 6; 141 | 142 | /* 143 | * Configuration Request Codes 144 | */ 145 | // private static final int SILABSER_IFC_ENABLE_REQUEST_CODE = 0x00; 146 | // private static final int SILABSER_SET_BAUDDIV_REQUEST_CODE = 0x01; 147 | // private static final int SILABSER_SET_LINE_CTL_REQUEST_CODE = 0x03; 148 | // private static final int SILABSER_SET_MHS_REQUEST_CODE = 0x07; 149 | // private static final int SILABSER_SET_BAUDRATE = 0x1E; 150 | 151 | /* 152 | * SILABSER_IFC_ENABLE_REQUEST_CODE 153 | */ 154 | // private static final int UART_ENABLE = 0x0001; 155 | // private static final int UART_DISABLE = 0x0000; 156 | 157 | /* 158 | * SILABSER_SET_BAUDDIV_REQUEST_CODE 159 | */ 160 | // private static final int BAUD_RATE_GEN_FREQ = 0x384000; 161 | 162 | private static final int E4K_I2C_ADDR = 0xc8; 163 | private static final int E4K_CHECK_ADDR = 0x02; 164 | private static final int E4K_CHECK_VAL = 0x40; 165 | 166 | private static final int FC0013_I2C_ADDR = 0xc6; 167 | private static final int FC0013_CHECK_ADDR = 0x00; 168 | private static final int FC0013_CHECK_VAL = 0xa3; 169 | 170 | private static final int R820T_I2C_ADDR = 0x34; 171 | private static final int R828D_I2C_ADDR = 0x74; 172 | private static final int R820T_CHECK_ADDR = 0x00; 173 | private static final int R820T_CHECK_VAL = 0x69; 174 | 175 | private static final int FC2580_I2C_ADDR = 0xac; 176 | private static final int FC2580_CHECK_ADDR = 0x01; 177 | private static final int FC2580_CHECK_VAL = 0x56; 178 | 179 | private static final int FC0012_I2C_ADDR = 0xc6; 180 | private static final int FC0012_CHECK_ADDR = 0x00; 181 | private static final int FC0012_CHECK_VAL = 0xa1; 182 | 183 | /* 184 | * SILABSER_SET_MHS_REQUEST_CODE 185 | */ 186 | // private static final int MCR_DTR = 0x0001; 187 | // private static final int MCR_RTS = 0x0002; 188 | // private static final int MCR_ALL = 0x0003; 189 | 190 | // private static final int CONTROL_WRITE_DTR = 0x0100; 191 | // private static final int CONTROL_WRITE_RTS = 0x0200; 192 | 193 | // private static final int TIMEOUT = 500; 194 | // private static final byte i2c_addr = 0; //FIXME 195 | // private static final long[] null = null; 196 | private static final int RTLSDR_TUNER_UNKNOWN = 0; 197 | private static final int RTLSDR_TUNER_E4000 = 1; 198 | private static final int RTLSDR_TUNER_FC0012 = 2; 199 | private static final int RTLSDR_TUNER_FC0013 = 3; 200 | private static final int RTLSDR_TUNER_FC2580 = 4; 201 | private static final int RTLSDR_TUNER_R820T = 5; 202 | private static final int RTLSDR_TUNER_R828D = 6; 203 | private static final long R820T_IF_FREQ = 3570000; 204 | // private static final String RTLSDR_INACTIVE = null; 205 | 206 | private UsbEndpoint mReadEndpoint; 207 | private boolean tuner = false; 208 | private boolean tuner_exit = false; 209 | private static long rtl_xtal = DEF_RTL_XTAL_FREQ; 210 | private long rate = MAX_SAMP_RATE; 211 | private static long tun_xtal = DEF_RTL_XTAL_FREQ; 212 | // private long freq=DEF_RTL_XTAL_FREQ; 213 | private static int corr = 0; 214 | // private Object e4k_s; 215 | private boolean direct_sampling = false; 216 | private long offs_freq = 0; 217 | private int tuner_type = 0; 218 | 219 | private int ppm_error = 0; 220 | private boolean tuner_set_gain = true; 221 | // private boolean tuner_set_if_gain=false; 222 | // private boolean tuner_set_gain_mode=false; 223 | private boolean tuner_set_bw = true; 224 | private boolean tuner_init = false; 225 | int erro_count = 0; 226 | 227 | // AdsbParse adsb; 228 | public SdrSerialDriverOrig(UsbDevice device, UsbDeviceConnection connection) { 229 | super(device, connection); 230 | } 231 | 232 | private int setConfigSingle(int request, int value) { 233 | return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, 234 | value, 0, null, 0, USB_WRITE_TIMEOUT_MILLIS); 235 | } 236 | 237 | @Override 238 | public void open() throws IOException { 239 | // inteface 0 has 1 bulktransfer read endpoint 240 | boolean opened = false; 241 | try { 242 | for (int i = 0; i < mDevice.getInterfaceCount(); i++) { 243 | UsbInterface usbIface = mDevice.getInterface(i); 244 | if (mConnection.claimInterface(usbIface, true)) { 245 | Log.e(TAG, "claimInterface " + i + " SUCCESS"); 246 | } else { 247 | Log.e(TAG, "claimInterface " + i + " FAIL"); 248 | } 249 | } 250 | int count = mDevice.getInterfaceCount(); 251 | for (int i = 0; i < count; i++) { 252 | UsbInterface intf = mDevice.getInterface(i); 253 | if (intf != null) { 254 | Log.e(TAG, 255 | "intf.getInterfaceClass()=" + i + " " 256 | + intf.getInterfaceClass() 257 | + " intf.getInterfaceSubclass()=" + i + " " 258 | + intf.getInterfaceSubclass() 259 | + " intf.getInterfaceProtocol()=" + i + " " 260 | + intf.getInterfaceProtocol()); 261 | Log.e(TAG, 262 | "dataIface.getEndpointCount " + i + " " 263 | + intf.getEndpointCount()); 264 | } 265 | int getEndpointCount = intf.getEndpointCount(); 266 | for (int j = 0; j < getEndpointCount; j++) { 267 | UsbEndpoint ep = intf.getEndpoint(j); 268 | Log.e(TAG, 269 | "found endpoint getEndpointNumber= " 270 | + ep.getEndpointNumber()); 271 | Log.e(TAG, "found endpoint type= " + ep.getType()); 272 | Log.e(TAG, 273 | "found endpoint getDirection= " + ep.getDirection()); 274 | Log.e(TAG, 275 | "found endpoint getMaxPacketSize= " 276 | + ep.getMaxPacketSize()); 277 | 278 | if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) { 279 | if (ep.getDirection() == UsbConstants.USB_DIR_IN) { 280 | mReadEndpoint = ep; 281 | Log.e(TAG, "found READ USB_ENDPOINT_XFER_BULK"); 282 | } else { 283 | Log.e(TAG, 284 | "found WRITE USB_DIR_OUT->USB_ENDPOINT_XFER_BULK"); 285 | } 286 | } 287 | } 288 | opened = true; 289 | 290 | } 291 | // if(myTuner == null) 292 | myTuner = rtlsdr_detect(); 293 | if (myTuner != null) { 294 | 295 | StartDevice(); 296 | 297 | } 298 | } finally { 299 | if (!opened) { 300 | close(); 301 | } 302 | } 303 | } 304 | 305 | @Override 306 | public void close() throws IOException { 307 | rtlsdr_deinit_baseband(); 308 | 309 | if (myTuner != null) 310 | myTuner.exit(0); 311 | mConnection.close(); 312 | } 313 | 314 | @Override 315 | public int read(byte[] dest, int timeoutMillis) throws IOException { 316 | final int totalBytesRead; 317 | 318 | synchronized (mReadBufferLock) { 319 | int readAmt = Math.min(dest.length, mReadBuffer.length); 320 | totalBytesRead = mConnection.bulkTransfer(mReadEndpoint, 321 | mReadBuffer, readAmt, timeoutMillis * 1000); 322 | // if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) { 323 | // throw new IOException("Expected at least " + 324 | // MODEM_STATUS_HEADER_LENGTH + " bytes"); 325 | // } 326 | if (totalBytesRead < 0) { 327 | Log.e(TAG, " mConnection.bulkTransfer ERROR totalBytesRead=" 328 | + totalBytesRead); 329 | 330 | } else { 331 | System.arraycopy(mReadBuffer, 0, dest, 0, totalBytesRead); 332 | } 333 | return totalBytesRead; 334 | } 335 | 336 | } 337 | 338 | @Override 339 | public int write(byte[] src, int timeoutMillis) throws IOException { 340 | 341 | Log.e(TAG, "Writes not support yet writeLength= " + src.length); 342 | 343 | return src.length; 344 | } 345 | 346 | private void StartDevice() { 347 | /* Set gain, frequency, sample rate, and reset the device. */ 348 | 349 | rtlsdr_set_tuner_gain_mode((gain == MODES_AUTO_GAIN) ? false : true); 350 | if (gain != MODES_AUTO_GAIN) { 351 | if (gain == MODES_MAX_GAIN) { 352 | /* Find the maximum gain available. */ 353 | int numgains; 354 | int[] gains = new int[100]; 355 | 356 | numgains = rtlsdr_get_tuner_gains(gains); 357 | gain = gains[numgains - 1]; 358 | Log.e(TAG, 359 | "Max available gain is: " 360 | + String.format("%.2f", gain / 10.0)); 361 | } 362 | rtlsdr_set_tuner_gain(gain); 363 | Log.e(TAG, "Setting gain to: " + String.format("%.2f", gain / 10.0)); 364 | } else { 365 | Log.e(TAG, "Using automatic gain control.\n"); 366 | } 367 | rtlsdr_set_freq_correction(ppm_error); 368 | if (enable_agc) 369 | rtlsdr_set_agc_mode(true); 370 | rtlsdr_set_center_freq(this.freq); 371 | // rtlsdr_set_tuner_gain_mode(true);//true == AGC 372 | rtlsdr_set_sample_rate(MODES_DEFAULT_RATE); 373 | rtlsdr_reset_buffer(); 374 | Log.e(TAG, 375 | "Gain reported by device: " 376 | + String.format("%.2f", rtlsdr_get_tuner_gain() / 10.0)); 377 | return; 378 | } 379 | 380 | public static Map getSupportedDevices() { 381 | final Map supportedDevices = new LinkedHashMap(); 382 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SDR), new int[] { 383 | UsbId.SDR_SDR2838, UsbId.SDR_SDR2832 }); 384 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_TERRACTEC), 385 | new int[] { UsbId.TER_00A9, UsbId.TER_00B3, UsbId.TER_00B4, 386 | UsbId.TER_00B5, UsbId.TER_00B7, UsbId.TER_00B8, 387 | UsbId.TER_00B9, UsbId.TER_00C0, UsbId.TER_00C6, 388 | UsbId.TER_00D3, UsbId.TER_00D7, UsbId.TER_00E0 }); 389 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SDR2), new int[] { 390 | UsbId.SDR2_SDR169, UsbId.SDR2_SDR179, UsbId.SDR2_SDR180, 391 | UsbId.SDR2_SDR183, UsbId.SDR2_SDR198, UsbId.SDR2_SDR211, 392 | UsbId.SDR2_SDR215, UsbId.SDR2_SDR224 }); 393 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SDR3), new int[] { 394 | UsbId.SDR3_SDR1568, UsbId.SDR3_SDR1616, UsbId.SDR3_SDR1664 }); 395 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SDR4), new int[] { 396 | UsbId.SDR4_SDR47107, UsbId.SDR4_SDR51203, UsbId.SDR4_SDR53894, 397 | UsbId.SDR4_SDR55299 }); 398 | supportedDevices 399 | .put(Integer.valueOf(UsbId.VENDOR_SDR5), new int[] { 400 | UsbId.SDR5_SDR54163, UsbId.SDR5_SDR54164, 401 | UsbId.SDR5_SDR54165, UsbId.SDR5_SDR54168, 402 | UsbId.SDR5_SDR54173, UsbId.SDR5_SDR54180 }); 403 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SDR6), 404 | new int[] { UsbId.SDR6_SDR28799 }); 405 | supportedDevices.put(Integer.valueOf(UsbId.VENDOR_SDR7), new int[] { 406 | UsbId.SDR7_SDR4353, UsbId.SDR7_SDR4354, UsbId.SDR7_SDR4355 }); 407 | return supportedDevices; 408 | } 409 | 410 | private static int libusb_control_transfer(byte requestType, byte request, 411 | char value, char index, byte[] buffer, char length, int timeout) { 412 | return mConnection.controlTransfer(requestType, request, value, index, 413 | buffer, length, timeout); 414 | } 415 | 416 | private static int rtlsdr_read_array(byte iicb2, char addr, byte[] data, 417 | byte len) { 418 | int r; 419 | char index = (char) (iicb2 << 8); 420 | 421 | r = libusb_control_transfer(CTRL_IN, (byte) 0, addr, index, data, 422 | (char) len, USB_WRITE_TIMEOUT_MILLIS); 423 | 424 | if (r < 0) { 425 | Log.e("rtlsdr_read_array", " error" + len); 426 | Log.e("rtlsdr_read_array", 427 | "addr 0x" + Integer.toHexString((int) addr) + " index 0x" 428 | + Integer.toHexString((int) index) + " array " 429 | + data[0] + " len " + len); 430 | } 431 | return r; 432 | } 433 | 434 | private static int rtlsdr_write_array(byte iicb2, char addr, byte[] array, 435 | byte len) { 436 | int r; 437 | char index = (char) ((iicb2 << 8) | 0x10); 438 | 439 | r = libusb_control_transfer(CTRL_OUT, (byte) 0, addr, index, array, 440 | (char) len, USB_WRITE_TIMEOUT_MILLIS); 441 | 442 | if (r < 0) { 443 | Log.e("rtlsdr_write_array", 444 | "addr 0x" + Integer.toHexString((int) addr) + " index 0x" 445 | + Integer.toHexString((int) index) + " array " 446 | + array[0] + " len " + len); 447 | Log.e("rtlsdr_write_array", " error byte count " + len); 448 | } 449 | return r; 450 | } 451 | 452 | public static int rtlsdr_i2c_write_reg(byte i2c_addr, char reg, char val) { 453 | char addr = (char) i2c_addr; 454 | byte[] data = new byte[2]; 455 | 456 | data[0] = (byte) reg; 457 | data[1] = (byte) val; 458 | return rtlsdr_write_array(IICB, addr, data, (byte) 2); 459 | } 460 | 461 | public static byte rtlsdr_i2c_read_reg(int e4kI2cAddr, int e4kCheckAddr) { 462 | char addr = (char) e4kI2cAddr; 463 | byte[] data = new byte[2]; 464 | byte[] out = new byte[2]; 465 | out[0] = (byte) e4kCheckAddr; 466 | rtlsdr_write_array(IICB, addr, out, (byte) 1); 467 | rtlsdr_read_array(IICB, addr, data, (byte) 1); 468 | 469 | return data[0]; 470 | } 471 | 472 | public static int rtlsdr_get_tuner_clock() { 473 | long[] tuner_freq = new long[1]; 474 | long[] xtal_freq = new long[1]; 475 | /* read corrected clock value */ 476 | if (rtlsdr_get_xtal_freq(xtal_freq, tuner_freq) < 0) 477 | return 0; 478 | 479 | return (int) tuner_freq[0]; 480 | } 481 | 482 | private static int rtlsdr_i2c_write(byte i2c_addr, byte[] buffer, byte len) { 483 | byte addr = i2c_addr; 484 | 485 | return rtlsdr_write_array(IICB, (char) addr, buffer, len); 486 | } 487 | 488 | private static int rtlsdr_i2c_read(byte i2c_addr, byte[] buffer, byte len) { 489 | byte addr = i2c_addr; 490 | 491 | return rtlsdr_read_array(IICB, (char) addr, buffer, (byte) len); 492 | } 493 | 494 | private char rtlsdr_read_reg(byte block, char addr, byte len) { 495 | int r = 0; 496 | byte[] data = new byte[2]; 497 | char index = (char) (block << 8); 498 | char reg; 499 | 500 | r = libusb_control_transfer(CTRL_IN, (byte) 0, addr, index, data, 501 | (char) len, USB_WRITE_TIMEOUT_MILLIS); 502 | 503 | if (r < 0) 504 | Log.e(TAG, "rtlsdr_read_reg failed " + r); 505 | 506 | reg = (char) ((data[1] << 8) | data[0]); 507 | 508 | return reg; 509 | } 510 | 511 | private int rtlsdr_write_reg(byte block, char addr, char val, byte len) { 512 | int r = 0; 513 | byte[] data = new byte[2]; 514 | 515 | char index = (char) ((block << 8) | 0x10); 516 | 517 | if (len == 1) 518 | data[0] = (byte) (val & 0xff); 519 | else 520 | data[0] = (byte) (val >> 8); 521 | 522 | data[1] = (byte) (val & 0xff); 523 | 524 | r = libusb_control_transfer(CTRL_OUT, (byte) 0, addr, index, data, 525 | (char) len, USB_WRITE_TIMEOUT_MILLIS); 526 | 527 | if (r < 0) { 528 | Log.e("rtlsdr_write_reg", "block " + block + " addr " + " val " 529 | + " len " + len); 530 | Log.e("rtlsdr_write_reg", "Line " 531 | + Thread.currentThread().getStackTrace()[2].getLineNumber()); 532 | } 533 | return r; 534 | } 535 | 536 | private char rtlsdr_demod_read_reg(byte page, char addr, byte len) { 537 | int r; 538 | byte[] data = new byte[2]; 539 | 540 | char index = (char) page; 541 | char reg; 542 | addr = (char) ((addr << 8) | 0x20); 543 | 544 | r = libusb_control_transfer(CTRL_IN, (byte) 0, addr, index, data, 545 | (char) len, USB_WRITE_TIMEOUT_MILLIS); 546 | 547 | if (r < 0) { 548 | Log.e(TAG, "rtlsdr_demod_read_reg error " + r); 549 | Log.e(TAG, 550 | " addr " + Integer.toHexString((int) addr) + " index " 551 | + Integer.toHexString((int) index) + " data[0] " 552 | + Integer.toHexString((int) data[0]) + " data[1] " 553 | + Integer.toHexString((int) data[1]) + " len " 554 | + Integer.toHexString((int) len)); 555 | } 556 | reg = (char) ((data[1] << 8) | data[0]); 557 | 558 | return ((char) r); 559 | } 560 | 561 | private int rtlsdr_demod_write_reg(byte page, char addr, char val, byte len) { 562 | int r; 563 | byte[] data = new byte[2]; 564 | char index = (char) (0x10 | page); 565 | addr = (char) ((addr << 8) | 0x20); 566 | 567 | if (len == 1) 568 | data[0] = (byte) (val & 0xff); 569 | else 570 | data[0] = (byte) (val >> 8); 571 | 572 | data[1] = (byte) (val & 0xff); 573 | 574 | r = libusb_control_transfer(CTRL_OUT, (byte) 0, addr, index, data, 575 | (char) len, USB_WRITE_TIMEOUT_MILLIS); 576 | 577 | if (r < 0) { 578 | Log.e(TAG, "rtlsdr_demod_write_reg failed " + r); 579 | Log.e(TAG, 580 | " addr " + Integer.toHexString((int) addr) + " index " 581 | + Integer.toHexString((int) index) + " data[0] " 582 | + Integer.toHexString((int) data[0]) + " data[1] " 583 | + Integer.toHexString((int) data[1]) + " len " 584 | + Integer.toHexString((int) len)); 585 | } 586 | rtlsdr_demod_read_reg((byte) 0x0a, (char) 0x01, (byte) 1); 587 | 588 | return (r == len) ? len : -1; 589 | } 590 | 591 | private void rtlsdr_set_gpio_bit(byte gpio, boolean val) { 592 | int r; 593 | 594 | gpio = (byte) (1 << gpio); 595 | r = rtlsdr_read_reg(SYSB, GPO, (byte) 1); 596 | r = (val ? (r | gpio) : (r & ~gpio)); 597 | rtlsdr_write_reg(SYSB, GPO, (char) r, (byte) 1); 598 | } 599 | 600 | private void rtlsdr_set_gpio_output(byte gpio) { 601 | int r; 602 | gpio = (byte) (1 << gpio); 603 | 604 | r = rtlsdr_read_reg(SYSB, GPD, (byte) 1); 605 | rtlsdr_write_reg(SYSB, GPO, (char) (r & ~gpio), (byte) 1); 606 | r = rtlsdr_read_reg(SYSB, GPOE, (byte) 1); 607 | rtlsdr_write_reg(SYSB, GPOE, (char) (r | gpio), (byte) 1); 608 | } 609 | 610 | private void rtlsdr_set_i2c_repeater(boolean on) { 611 | rtlsdr_demod_write_reg((byte) 1, (char) 0x01, 612 | (char) (on ? 0x18 : 0x10), (byte) 1); 613 | } 614 | 615 | private void rtlsdr_init_baseband() { 616 | int i = 0; 617 | int ret = 0; 618 | /* 619 | * default FIR coefficients used for DAB/FM by the Windows driver, the 620 | * DVB driver uses different ones 621 | */ 622 | char[] fir_coeff = { 0xca, 0xdc, 0xd7, 0xd8, 0xe0, 0xf2, 0x0e, 0x35, 623 | 0x06, 0x50, 0x9c, 0x0d, 0x71, 0x11, 0x14, 0x71, 0x74, 0x19, 624 | 0x41, 0xa5, }; 625 | 626 | /* initialize USB */ 627 | ret = rtlsdr_write_reg(USBB, USB_SYSCTL, (char) 0x09, (byte) 1); 628 | ret = rtlsdr_write_reg(USBB, USB_EPA_MAXPKT, (char) 0x0002, (byte) 2); 629 | ret = rtlsdr_write_reg(USBB, USB_EPA_CTL, (char) 0x1002, (byte) 2); 630 | 631 | /* poweron demod */ 632 | ret = rtlsdr_write_reg(SYSB, DEMOD_CTL_1, (char) 0x22, (byte) 1); 633 | ret = rtlsdr_write_reg(SYSB, DEMOD_CTL, (char) 0xe8, (byte) 1); 634 | 635 | /* reset demod (bit 3, soft_rst) */ 636 | ret = rtlsdr_demod_write_reg((byte) 1, (char) 0x01, (char) 0x14, 637 | (byte) 1); 638 | ret = rtlsdr_demod_write_reg((byte) 1, (char) 0x01, (char) 0x10, 639 | (byte) 1); 640 | 641 | /* disable spectrum inversion and adjacent channel rejection */ 642 | ret = rtlsdr_demod_write_reg((byte) 1, (char) 0x15, (char) 0x00, 643 | (byte) 1); 644 | ret = rtlsdr_demod_write_reg((byte) 1, (char) 0x16, (char) 0x0000, 645 | (byte) 2); 646 | 647 | /* clear both DDC shift and IF frequency registers */ 648 | for (i = 0; i < 6; i++) { 649 | ret = rtlsdr_demod_write_reg((byte) 1, (char) (0x16 + i), 650 | (char) 0x00, (byte) 1); 651 | } 652 | 653 | /* set FIR coefficients */ 654 | for (i = 0; i < fir_coeff.length; i++) { 655 | ret = rtlsdr_demod_write_reg((byte) 1, (char) (0x1c + i), 656 | fir_coeff[i], (byte) 1); 657 | } 658 | /* enable SDR mode, disable DAGC (bit 5) */ 659 | ret = rtlsdr_demod_write_reg((byte) 0, (char) 0x19, (char) 0x05, 660 | (byte) 1); 661 | 662 | /* init FSM state-holding register */ 663 | ret = rtlsdr_demod_write_reg((byte) 1, (char) 0x93, (char) 0xf0, 664 | (byte) 1); 665 | 666 | ret = rtlsdr_demod_write_reg((byte) 1, (char) 0x94, (char) 0x0f, 667 | (byte) 1); 668 | 669 | /* disable AGC (en_dagc, bit 0) (this seems to have no effect) */ 670 | ret = rtlsdr_demod_write_reg((byte) 1, (char) 0x11, (char) 0x00, 671 | (byte) 1); 672 | 673 | /* disable RF and IF AGC loop */ 674 | ret = rtlsdr_demod_write_reg((byte) 1, (char) 0x04, (char) 0x00, 675 | (byte) 1); 676 | 677 | /* disable PID filter (enable_PID = 0) */ 678 | ret = rtlsdr_demod_write_reg((byte) 0, (char) 0x61, (char) 0x60, 679 | (byte) 1); 680 | 681 | /* opt_adc_iq = 0, default ADC_I/ADC_Q datapath */ 682 | ret = rtlsdr_demod_write_reg((byte) 0, (char) 0x06, (char) 0x80, 683 | (byte) 1); 684 | 685 | /* 686 | * Enable Zero-IF mode (en_bbin bit), DC cancellation (en_dc_est), IQ 687 | * estimation/compensation (en_iq_comp, en_iq_est) 688 | */ 689 | ret = rtlsdr_demod_write_reg((byte) 1, (char) 0xb1, (char) 0x1b, 690 | (byte) 1); 691 | 692 | /* disable 4.096 MHz clock output on pin TP_CK0 */ 693 | ret = rtlsdr_demod_write_reg((byte) 0, (char) 0x0d, (char) 0x83, 694 | (byte) 1); 695 | 696 | } 697 | 698 | private int rtlsdr_deinit_baseband() { 699 | int r = 0; 700 | int ret = 0; 701 | 702 | if ((tuner) && (!this.tuner_exit)) { 703 | rtlsdr_set_i2c_repeater(true); 704 | 705 | rtlsdr_set_i2c_repeater(false); 706 | } 707 | 708 | /* poweroff demodulator and ADCs */ 709 | ret = rtlsdr_write_reg(SYSB, DEMOD_CTL, (char) 0x20, (byte) 1); 710 | if (ret != 0) 711 | Log.e(TAG, " ret " + ret + "Line " 712 | + Thread.currentThread().getStackTrace()[2].getLineNumber()); 713 | tuner_exit = true; 714 | tuner = false; 715 | return r; 716 | } 717 | 718 | private int rtlsdr_set_if_freq(long freq) { 719 | // long [] rtl_xtal = new long[1] ; 720 | // long [] rtl_dummy = new long[1] ; 721 | long if_freq = 0; 722 | char tmp; 723 | int r; 724 | 725 | /* read corrected clock value */ 726 | // if (rtlsdr_get_xtal_freq(rtl_xtal, rtl_dummy) < 0) return -2; 727 | 728 | if_freq = (long) (((freq * TWO_POW(22)) / rtl_xtal) * (-1)); 729 | // if(rtl_xtal !=0 ) if_freq = (freq/rtl_xtal) & 0x003fffff; 730 | tmp = (char) ((if_freq >> 16) & 0x3f); 731 | r = rtlsdr_demod_write_reg((byte) 1, (char) 0x19, tmp, (byte) 1); 732 | tmp = (char) ((if_freq >> 8) & 0xff); 733 | r |= rtlsdr_demod_write_reg((byte) 1, (char) 0x1a, tmp, (byte) 1); 734 | tmp = (char) (if_freq & 0xff); 735 | r |= rtlsdr_demod_write_reg((byte) 1, (char) 0x1b, tmp, (byte) 1); 736 | 737 | return r; 738 | } 739 | 740 | private double TWO_POW(int i) { 741 | return (1 << (i)); 742 | 743 | } 744 | 745 | private int rtlsdr_set_sample_freq_correction(int ppm) { 746 | int r = 0; 747 | char tmp; 748 | char offs = (char) (ppm * (-1) * TWO_POW(24) / 1000000); 749 | 750 | tmp = (char) (offs & 0xff); 751 | r |= rtlsdr_demod_write_reg((byte) 1, (char) 0x3f, tmp, (byte) 1); 752 | tmp = (char) ((offs >> 8) & 0x3f); 753 | r |= rtlsdr_demod_write_reg((byte) 1, (char) 0x3e, tmp, (byte) 1); 754 | 755 | return r; 756 | } 757 | 758 | private int rtlsdr_set_xtal_freq(long rtl_freq, long tuner_freq) { 759 | int r = 0; 760 | 761 | if (rtl_freq > 0 762 | && (rtl_freq < MIN_RTL_XTAL_FREQ || rtl_freq > MAX_RTL_XTAL_FREQ)) 763 | return -2; 764 | 765 | if (rtl_freq > 0 && rtl_xtal != rtl_freq) { 766 | rtl_xtal = rtl_freq; 767 | 768 | /* update xtal-dependent settings */ 769 | if (this.rate != 0) 770 | r = rtlsdr_set_sample_rate(this.rate); 771 | } 772 | 773 | if (tun_xtal != tuner_freq) { 774 | if (0 == tuner_freq) 775 | tun_xtal = rtl_xtal; 776 | else 777 | tun_xtal = tuner_freq; 778 | 779 | /* read corrected clock value into e4k structure */ 780 | // if (rtlsdr_get_xtal_freq(null, /*this.e4k_s.vco.fosc 781 | // fixxme*/null) < 0) return -3; 782 | 783 | /* update xtal-dependent settings */ 784 | if (this.freq != 0) 785 | r = rtlsdr_set_center_freq(this.freq); 786 | } 787 | 788 | return r; 789 | } 790 | 791 | private static double APPLY_PPM_CORR(long val, int ppm) { 792 | return (((val) * (1.0 + (ppm) / 1e6))); 793 | } 794 | 795 | private static int rtlsdr_get_xtal_freq(long[] rtl_xtal2, long[] tuner_freq) { 796 | 797 | // #define APPLY_PPM_CORR(val,ppm) (((val) * (1.0 + (ppm) / 1e6))) 798 | 799 | rtl_xtal2[0] = (long) APPLY_PPM_CORR(rtl_xtal, corr); 800 | 801 | tuner_freq[0] = (long) APPLY_PPM_CORR(tun_xtal, corr); 802 | 803 | return 0; 804 | } 805 | 806 | private int rtlsdr_write_eeprom(byte[] data, char offset, char len) 807 | throws InterruptedException { 808 | int r = 0; 809 | int i; 810 | byte[] cmd = new byte[2]; 811 | 812 | // if (!dev) return -1; 813 | 814 | if ((len + offset) > 256) 815 | return -2; 816 | 817 | for (i = 0; i < len; i++) { 818 | cmd[0] = (byte) (i + offset); 819 | r = rtlsdr_write_array(IICB, EEPROM_ADDR, cmd, (byte) 1); 820 | r = rtlsdr_read_array(IICB, EEPROM_ADDR, cmd, (byte) 1); 821 | 822 | /* only write the byte if it differs */ 823 | if (cmd[1] == data[i]) 824 | continue; 825 | 826 | cmd[1] = data[i]; 827 | r = rtlsdr_write_array(IICB, EEPROM_ADDR, cmd, (byte) 2); 828 | if (r != cmd.length) 829 | return -3; 830 | 831 | /* 832 | * for some EEPROMs (e.g. ATC 240LC02) we need a delay between write 833 | * operations, otherwise they will fail 834 | */ 835 | 836 | Thread.sleep(5000); 837 | 838 | // usleep(5000); 839 | 840 | } 841 | 842 | return 0; 843 | } 844 | 845 | private int rtlsdr_read_eeprom(byte[] data, byte[] offset, char len) { 846 | int r = 0; 847 | int i; 848 | byte[] output = new byte[2]; 849 | 850 | if ((len + offset[0]) > 256) { 851 | Log.e(TAG, " rtlsdr_read_eeprom offset + len > 256"); 852 | return -2; 853 | } 854 | 855 | r = rtlsdr_write_array(IICB, EEPROM_ADDR, offset, (byte) 1); 856 | if (r < 0) 857 | return -3; 858 | 859 | for (i = 0; i < len; i++) { 860 | output[0] = data[i]; 861 | r = rtlsdr_read_array(IICB, EEPROM_ADDR, output, (byte) 1); 862 | 863 | if (r < 0) { 864 | Log.e(TAG, " rtlsdr_read_eeprom FAILED"); 865 | return -3; 866 | } 867 | 868 | } 869 | 870 | return r; 871 | } 872 | 873 | private int rtlsdr_set_center_freq(long freq) { 874 | int r = -1; 875 | 876 | // if (this.tuner ==0) return -1; 877 | 878 | if (this.direct_sampling) { 879 | r = rtlsdr_set_if_freq(freq); 880 | } else if (myTuner != null) { 881 | 882 | rtlsdr_set_i2c_repeater(true); 883 | try { 884 | r = myTuner.set_freq(0, freq); 885 | } catch (IOException e) { 886 | 887 | e.printStackTrace(); 888 | 889 | Log.e(TAG, e.toString()); 890 | try { 891 | myTuner.set_freq(0, freq - this.offs_freq); 892 | } catch (IOException e1) { 893 | 894 | e1.printStackTrace(); 895 | Log.e(TAG, e.toString()); 896 | } 897 | } 898 | 899 | rtlsdr_set_i2c_repeater(false); 900 | } 901 | 902 | if (r <= 0) 903 | this.freq = freq; 904 | else 905 | this.freq = 0; 906 | return r; 907 | } 908 | 909 | private long rtlsdr_get_center_freq() { 910 | 911 | return this.freq; 912 | } 913 | 914 | private int rtlsdr_set_freq_correction(int ppm) { 915 | int r = 0; 916 | long[] xtal_freq = new long[1]; 917 | long[] tuner_freq2 = new long[1]; 918 | 919 | if (corr == ppm) 920 | return -2; 921 | 922 | corr = ppm; 923 | 924 | r |= rtlsdr_set_sample_freq_correction(ppm); 925 | 926 | /* read corrected clock value into e4k structure */ 927 | if (rtlsdr_get_xtal_freq(xtal_freq, tuner_freq2) < 0) 928 | return -3; 929 | 930 | if (this.freq != 0) /* retune to apply new correction value */ 931 | r |= rtlsdr_set_center_freq(this.freq); 932 | 933 | return r; 934 | } 935 | 936 | private int rtlsdr_get_freq_correction() { 937 | 938 | return corr; 939 | } 940 | 941 | // int rtlsdr_tuner 942 | private int rtlsdr_get_tuner_type() { 943 | // return RTLSDR_TUNER_UNKNOWN; 944 | 945 | return (this.tuner_type); 946 | } 947 | 948 | private int rtlsdr_get_tuner_gains(int[] dst) { 949 | int len; 950 | /* all gain values are expressed in tenths of a dB */ 951 | int[] e4k_gains = { -10, 15, 40, 65, 90, 115, 140, 165, 190, 215, 240, 952 | 290, 340, 420 }; 953 | int[] fc0012_gains = { -99, -40, 71, 179, 192 }; 954 | int[] fc0013_gains = { -99, -73, -65, -63, -60, -58, -54, 58, 61, 63, 955 | 65, 67, 68, 70, 71, 179, 181, 182, 184, 186, 188, 191, 197 }; 956 | int[] fc2580_gains = { 0 /* no gain values */}; 957 | int[] r820t_gains = { 0, 9, 14, 27, 37, 77, 87, 125, 144, 157, 166, 958 | 197, 207, 229, 254, 280, 297, 328, 338, 364, 372, 386, 402, 959 | 421, 434, 439, 445, 480, 496 }; 960 | int[] unknown_gains = { 0 /* no gain values */}; 961 | 962 | switch (this.tuner_type) { 963 | case RTLSDR_TUNER_E4000: 964 | len = e4k_gains.length; 965 | System.arraycopy(e4k_gains, 0, dst, 0, e4k_gains.length); 966 | break; 967 | case RTLSDR_TUNER_FC0012: 968 | len = fc0012_gains.length; 969 | System.arraycopy(fc0012_gains, 0, dst, 0, fc0012_gains.length); 970 | break; 971 | case RTLSDR_TUNER_FC0013: 972 | len = fc0013_gains.length; 973 | System.arraycopy(fc0013_gains, 0, dst, 0, fc0013_gains.length); 974 | break; 975 | case RTLSDR_TUNER_FC2580: 976 | len = fc2580_gains.length; 977 | System.arraycopy(fc2580_gains, 0, dst, 0, fc2580_gains.length); 978 | break; 979 | case RTLSDR_TUNER_R820T: 980 | len = r820t_gains.length; 981 | System.arraycopy(r820t_gains, 0, dst, 0, r820t_gains.length); 982 | break; 983 | default: 984 | 985 | len = unknown_gains.length; 986 | System.arraycopy(unknown_gains, 0, dst, 0, unknown_gains.length); 987 | break; 988 | } 989 | 990 | return (len); 991 | } 992 | 993 | private int rtlsdr_set_tuner_gain(int inputGain) { 994 | int r = 0; 995 | if (this.tuner_set_gain) { 996 | rtlsdr_set_i2c_repeater(true); 997 | try { 998 | myTuner.set_gain(0, inputGain); 999 | } catch (IOException e) { 1000 | Log.e(TAG, "set_gain error " + e.toString()); 1001 | e.printStackTrace(); 1002 | } 1003 | rtlsdr_set_i2c_repeater(false); 1004 | } 1005 | gain = inputGain; 1006 | return r; 1007 | } 1008 | 1009 | private long rtlsdr_get_tuner_gain() { 1010 | return this.gain; 1011 | } 1012 | 1013 | private int rtlsdr_set_tuner_if_gain(int stage, int gain) { 1014 | int r = 0; 1015 | if (myTuner != null) 1016 | return -1; 1017 | if (myTuner != null) { 1018 | rtlsdr_set_i2c_repeater(true); 1019 | try { 1020 | myTuner.set_if_gain(0, stage, gain); 1021 | } catch (IOException e) { 1022 | Log.e(TAG, e.toString()); 1023 | e.printStackTrace(); 1024 | } 1025 | rtlsdr_set_i2c_repeater(false); 1026 | } 1027 | 1028 | return r; 1029 | } 1030 | 1031 | private int rtlsdr_set_tuner_gain_mode(boolean mode) { 1032 | int r = 0; 1033 | // if(myTuner == null) return -1; 1034 | 1035 | if (this.set_gain_mode) { 1036 | rtlsdr_set_i2c_repeater(true); 1037 | try { 1038 | myTuner.set_gain_mode(0, mode); 1039 | } catch (IOException e) { 1040 | Log.e(TAG, e.toString()); 1041 | e.printStackTrace(); 1042 | } 1043 | rtlsdr_set_i2c_repeater(false); 1044 | } 1045 | 1046 | return r; 1047 | } 1048 | 1049 | private int rtlsdr_set_sample_rate(long samp_rate) { 1050 | int r = 0; 1051 | char tmp; 1052 | long rsamp_ratio; 1053 | double real_rate; 1054 | 1055 | // if (!dev) return -1; 1056 | 1057 | /* check for the maximum rate the resampler supports */ 1058 | if (samp_rate > MAX_SAMP_RATE) 1059 | samp_rate = MAX_SAMP_RATE; 1060 | 1061 | rsamp_ratio = (long) ((rtl_xtal * TWO_POW(22)) / samp_rate); 1062 | rsamp_ratio &= ~3; 1063 | 1064 | real_rate = (rtl_xtal * TWO_POW(22)) / rsamp_ratio; 1065 | 1066 | if (samp_rate != real_rate) 1067 | Log.e(TAG, "Exact sample rate is: " + real_rate + " Hz"); 1068 | 1069 | if ((myTuner != null) && this.tuner_set_bw) { 1070 | rtlsdr_set_i2c_repeater(true); 1071 | try { 1072 | myTuner.set_bw(0, (int) real_rate); 1073 | } catch (IOException e1) { 1074 | Log.e(TAG, e1.toString()); 1075 | e1.printStackTrace(); 1076 | } 1077 | if (myTuner != null) 1078 | try { 1079 | myTuner.set_bw(0, (int) real_rate); 1080 | } catch (IOException e) { 1081 | Log.e(TAG, "error set_bw " + real_rate); 1082 | e.printStackTrace(); 1083 | } 1084 | rtlsdr_set_i2c_repeater(false); 1085 | } 1086 | 1087 | this.rate = (long) real_rate; 1088 | 1089 | tmp = (char) ((char) (rsamp_ratio >> 16) & 0x0000ffff); 1090 | r |= rtlsdr_demod_write_reg((byte) 1, (char) 0x9f, tmp, (byte) 2); 1091 | tmp = (char) (rsamp_ratio & 0x0ffff); 1092 | r |= rtlsdr_demod_write_reg((byte) 1, (char) 0xa1, tmp, (byte) 2); 1093 | 1094 | r |= rtlsdr_set_sample_freq_correction(corr); 1095 | 1096 | /* reset demod (bit 3, soft_rst) */ 1097 | r |= rtlsdr_demod_write_reg((byte) 1, (char) 0x01, (char) 0x14, 1098 | (byte) 1); 1099 | r |= rtlsdr_demod_write_reg((byte) 1, (char) 0x01, (char) 0x10, 1100 | (byte) 1); 1101 | 1102 | /* recalculate offset frequency if offset tuning is enabled */ 1103 | if (this.offs_freq != 0) 1104 | rtlsdr_set_offset_tuning(true); 1105 | 1106 | return r; 1107 | } 1108 | 1109 | private long rtlsdr_get_sample_rate() { 1110 | 1111 | return this.rate; 1112 | } 1113 | 1114 | private int rtlsdr_set_testmode(boolean on) { 1115 | 1116 | return rtlsdr_demod_write_reg((byte) 0, (char) 0x19, (char) (on ? 0x03 1117 | : 0x05), (byte) 1); 1118 | } 1119 | 1120 | private int rtlsdr_set_agc_mode(boolean on) { 1121 | 1122 | return rtlsdr_demod_write_reg((byte) 0, (char) 0x19, (char) (on ? 0x25 1123 | : 0x05), (byte) 1); 1124 | } 1125 | 1126 | private int rtlsdr_set_direct_sampling(boolean on) { 1127 | int r = 0; 1128 | 1129 | // if (!dev) return -1; 1130 | 1131 | if (on) { 1132 | if ((this.tuner) && this.tuner_exit) { 1133 | rtlsdr_set_i2c_repeater(true); 1134 | // r = this.tuner->exit(); 1135 | if (myTuner != null) 1136 | try { 1137 | myTuner.exit(0); 1138 | } catch (IOException e) { 1139 | Log.e(TAG, "myTuner.exit(0) FAILED " + e.toString()); 1140 | e.printStackTrace(); 1141 | } 1142 | rtlsdr_set_i2c_repeater(false); 1143 | } 1144 | 1145 | /* disable Zero-IF mode */ 1146 | r |= rtlsdr_demod_write_reg((byte) 1, (char) 0xb1, (char) 0x1a, 1147 | (byte) 1); 1148 | 1149 | /* disable spectrum inversion */ 1150 | r |= rtlsdr_demod_write_reg((byte) 1, (char) 0x15, (char) 0x00, 1151 | (byte) 1); 1152 | 1153 | /* only enable In-phase ADC input */ 1154 | r |= rtlsdr_demod_write_reg((byte) 0, (char) 0x08, (char) 0x4d, 1155 | (byte) 1); 1156 | 1157 | /* swap I and Q ADC, this allows to select between two inputs */ 1158 | r |= rtlsdr_demod_write_reg((byte) 0, (char) 0x06, 1159 | (char) (on ? 0x90 : 0x80), (byte) 1); 1160 | 1161 | Log.e(TAG, 1162 | "rtlsdr_set_direct_sampling Enabled direct sampling mode, input " 1163 | + on); 1164 | this.direct_sampling = on; 1165 | } else { 1166 | if ((this.myTuner != null) && this.tuner_init) { 1167 | rtlsdr_set_i2c_repeater(true); 1168 | try { 1169 | r |= myTuner.init(0); 1170 | } catch (IOException e) { 1171 | 1172 | e.printStackTrace(); 1173 | Log.e(TAG, e.toString()); 1174 | } 1175 | rtlsdr_set_i2c_repeater(true); 1176 | } 1177 | 1178 | if (this.tuner_type == RTLSDR_TUNER_R820T) { 1179 | r |= rtlsdr_set_if_freq(R820T_IF_FREQ); 1180 | 1181 | /* enable spectrum inversion */ 1182 | r |= rtlsdr_demod_write_reg((byte) 1, (char) 0x15, (char) 0x01, 1183 | (byte) 1); 1184 | } else { 1185 | r |= rtlsdr_set_if_freq(0); 1186 | 1187 | /* enable In-phase + Quadrature ADC input */ 1188 | r |= rtlsdr_demod_write_reg((byte) 0, (char) 0x08, (char) 0xcd, 1189 | (byte) 1); 1190 | 1191 | /* Enable Zero-IF mode */ 1192 | r |= rtlsdr_demod_write_reg((byte) 1, (char) 0xb1, (char) 0x1b, 1193 | (byte) 1); 1194 | } 1195 | 1196 | /* opt_adc_iq = 0, default ADC_I/ADC_Q datapath */ 1197 | r |= rtlsdr_demod_write_reg((byte) 0, (char) 0x06, (char) 0x80, 1198 | (byte) 1); 1199 | 1200 | Log.e(TAG, "Disabled direct sampling mode\n"); 1201 | this.direct_sampling = false; 1202 | } 1203 | 1204 | r |= rtlsdr_set_center_freq(this.freq); 1205 | 1206 | return r; 1207 | } 1208 | 1209 | private boolean rtlsdr_get_direct_sampling() { 1210 | return this.direct_sampling; 1211 | } 1212 | 1213 | private int rtlsdr_set_offset_tuning(boolean on) { 1214 | int r = 0; 1215 | 1216 | if (this.tuner_type == RTLSDR_TUNER_R820T) 1217 | return -2; 1218 | 1219 | if (this.direct_sampling) 1220 | return -3; 1221 | 1222 | /* based on keenerds 1/f noise measurements */ 1223 | this.offs_freq = on ? ((this.rate / 2) * 170 / 100) : 0; 1224 | // r |= rtlsdr_set_if_freq(this.offs_freq); 1225 | 1226 | if ((this.tuner) && /* this.tuner.set_bw */true) { 1227 | rtlsdr_set_i2c_repeater(true); 1228 | // this.tuner.set_bw(on ? (2 * this.offs_freq) : this. rate); 1229 | rtlsdr_set_i2c_repeater(false); 1230 | } 1231 | 1232 | if (this.freq > this.offs_freq) 1233 | r |= rtlsdr_set_center_freq(this.freq); 1234 | 1235 | return r; 1236 | } 1237 | 1238 | private int rtlsdr_get_offset_tuning() { 1239 | return (this.offs_freq < 0) ? 1 : 0; 1240 | } 1241 | 1242 | private IRtlSdrTuner rtlsdr_detect() throws IOException { 1243 | int reg = 0; 1244 | int ret = 0; 1245 | 1246 | if (myTuner != null) { 1247 | Log.e(TAG, "Error Already called rtlsdr_open()"); 1248 | // return (myTuner); 1249 | } 1250 | 1251 | Log.e(TAG, "rtlsdr_open()"); 1252 | 1253 | /* perform a dummy write, if it fails, reset the device */ 1254 | if ((ret = rtlsdr_write_reg(USBB, USB_SYSCTL, (char) 0x09, (byte) 1)) < 0) { 1255 | if (ret != 0) 1256 | Log.e(TAG, 1257 | "ERROR ret " 1258 | + ret 1259 | + " Line " 1260 | + Thread.currentThread().getStackTrace()[2] 1261 | .getLineNumber()); 1262 | Log.e(TAG, "Resetting device..."); 1263 | 1264 | } 1265 | 1266 | rtlsdr_init_baseband(); 1267 | /* Probe tuners */ 1268 | rtlsdr_set_i2c_repeater(true); 1269 | 1270 | reg = rtlsdr_i2c_read_reg(R820T_I2C_ADDR, R820T_CHECK_ADDR) & 0x0000FF; 1271 | if (reg == R820T_CHECK_VAL) { 1272 | Log.e(TAG, "Found Rafael Micro R820T tuner\n"); 1273 | this.tuner_type = RTLSDR_TUNER_R820T; 1274 | 1275 | /* disable Zero-IF mode */ 1276 | rtlsdr_demod_write_reg((byte) 1, (char) 0xb1, (char) 0x1a, (byte) 1); 1277 | 1278 | /* only enable In-phase ADC input */ 1279 | rtlsdr_demod_write_reg((byte) 0, (char) 0x08, (char) 0x4d, (byte) 1); 1280 | 1281 | /* 1282 | * the R820T uses 3.57 MHz IF for the DVB-T 6 MHz mode, and 4.57 MHz 1283 | * for the 8 MHz mode 1284 | */ 1285 | rtlsdr_set_if_freq(R820T_IF_FREQ); 1286 | 1287 | /* enable spectrum inversion */ 1288 | rtlsdr_demod_write_reg((byte) 1, (char) 0x15, (char) 0x01, (byte) 1); 1289 | 1290 | myTuner = new R820T(); 1291 | if (myTuner != null) 1292 | Log.e(TAG, "Error on tuner init"); 1293 | myTuner.init(0); 1294 | 1295 | rtlsdr_set_i2c_repeater(false); 1296 | 1297 | tun_xtal = rtl_xtal; /* use the rtl clock value by default */ 1298 | 1299 | return myTuner; 1300 | } 1301 | 1302 | reg = rtlsdr_i2c_read_reg(R828D_I2C_ADDR, R820T_CHECK_ADDR); 1303 | if (reg == R820T_CHECK_VAL) { 1304 | Log.e(TAG, "Found Rafael Micro R828D tuner\n"); 1305 | this.tuner_type = RTLSDR_TUNER_R828D; 1306 | myTuner = new R820T();// ?? 1307 | 1308 | myTuner.init(0); 1309 | rtlsdr_set_i2c_repeater(false); 1310 | } 1311 | 1312 | /* initialise GPIOs */ 1313 | reg = rtlsdr_i2c_read_reg(E4K_I2C_ADDR, E4K_CHECK_ADDR) & 0x000000FF; 1314 | if (reg == E4K_CHECK_VAL) { 1315 | Log.e(TAG, "Found Elonics E4000 tuner"); 1316 | this.tuner_type = RTLSDR_TUNER_E4000; 1317 | myTuner = new E4K(); 1318 | 1319 | myTuner.init(0); 1320 | 1321 | rtlsdr_set_i2c_repeater(false); 1322 | 1323 | tun_xtal = rtl_xtal; /* use the rtl clock value by default */ 1324 | 1325 | return myTuner; 1326 | } 1327 | 1328 | reg = rtlsdr_i2c_read_reg(FC0013_I2C_ADDR, FC0013_CHECK_ADDR) & 0x000000FF; 1329 | if (reg == FC0013_CHECK_VAL) { 1330 | Log.e(TAG, "Found Fitipower FC0013 tuner"); 1331 | 1332 | this.tuner_type = RTLSDR_TUNER_FC0013; 1333 | 1334 | tun_xtal = rtl_xtal; /* use the rtl clock value by default */ 1335 | 1336 | myTuner = new FC0013(); 1337 | 1338 | myTuner.init(0); 1339 | 1340 | rtlsdr_set_i2c_repeater(false); 1341 | 1342 | return myTuner; 1343 | } 1344 | 1345 | rtlsdr_set_gpio_output((byte) 5); 1346 | 1347 | /* reset tuner before probing */ 1348 | rtlsdr_tuner_reset(); 1349 | 1350 | reg = rtlsdr_i2c_read_reg(FC2580_I2C_ADDR, FC2580_CHECK_ADDR) & 0x000000FF; 1351 | if ((reg & 0x7f) == FC2580_CHECK_VAL) { 1352 | Log.e(TAG, "Found FCI 2580 tuner"); 1353 | this.tuner_type = RTLSDR_TUNER_FC2580; 1354 | myTuner = new FC2580(); 1355 | 1356 | myTuner.init(0); 1357 | 1358 | rtlsdr_set_i2c_repeater(false); 1359 | 1360 | tun_xtal = rtl_xtal; /* use the rtl clock value by default */ 1361 | 1362 | return myTuner; 1363 | } 1364 | 1365 | reg = rtlsdr_i2c_read_reg(FC0012_I2C_ADDR, FC0012_CHECK_ADDR) & 0x000000FF; 1366 | if (reg == FC0012_CHECK_VAL) { 1367 | Log.e(TAG, "Found Fitipower FC0012 tuner"); 1368 | rtlsdr_set_gpio_output((byte) 6); 1369 | this.tuner_type = RTLSDR_TUNER_FC0012; 1370 | 1371 | myTuner = new FC0012(); 1372 | 1373 | myTuner.init(0); 1374 | 1375 | rtlsdr_set_i2c_repeater(false); 1376 | 1377 | tun_xtal = rtl_xtal; /* use the rtl clock value by default */ 1378 | 1379 | return myTuner; 1380 | } 1381 | 1382 | if (this.tuner_type == RTLSDR_TUNER_UNKNOWN) { 1383 | Log.e(TAG, "No supported tuner found\n"); 1384 | rtlsdr_set_direct_sampling(true); 1385 | return null; 1386 | } 1387 | 1388 | tun_xtal = rtl_xtal; /* use the rtl clock value by default */ 1389 | 1390 | rtlsdr_set_i2c_repeater(false); 1391 | 1392 | return myTuner; 1393 | } 1394 | 1395 | private void rtlsdr_tuner_led_on() { 1396 | /* reset tuner before probing */ 1397 | rtlsdr_set_gpio_bit((byte) 0, true); 1398 | // rtlsdr_set_gpio_bit((byte) 1, false); 1399 | } 1400 | 1401 | private void rtlsdr_tuner_reset() { 1402 | /* reset tuner before probing */ 1403 | rtlsdr_set_gpio_bit((byte) 5, true); 1404 | rtlsdr_set_gpio_bit((byte) 5, false); 1405 | } 1406 | 1407 | private int rtlsdr_reset_buffer() { 1408 | 1409 | rtlsdr_write_reg(USBB, USB_EPA_CTL, (char) 0x1002, (byte) 2); 1410 | rtlsdr_write_reg(USBB, USB_EPA_CTL, (char) 0x0000, (byte) 2); 1411 | 1412 | return 0; 1413 | } 1414 | 1415 | private int rtlsdr_read_sync(byte[] buf, int len, int n_read) 1416 | throws IOException { 1417 | return (read(buf, BULK_TIMEOUT)); 1418 | // return libusb_bulk_transfer(0x81, buf, len, n_read, BULK_TIMEOUT); 1419 | } 1420 | 1421 | /* 1422 | * @Override public int setBaudRate(int baudRate) throws IOException { // 1423 | * TODO Auto-generated method stub return 0; } 1424 | */ 1425 | 1426 | @Override 1427 | public void settings(boolean agc, int mygain, int ppm) { 1428 | enable_agc = agc; 1429 | ppm_error = ppm; 1430 | gain = mygain; 1431 | } 1432 | 1433 | @Override 1434 | public void setParameters(int baudRate, int dataBits, int stopBits, 1435 | int parity) throws IOException { 1436 | 1437 | } 1438 | 1439 | @Override 1440 | public boolean getCD() throws IOException { 1441 | return false; 1442 | } 1443 | 1444 | @Override 1445 | public boolean getCTS() throws IOException { 1446 | return false; 1447 | } 1448 | 1449 | @Override 1450 | public boolean getDSR() throws IOException { 1451 | return false; 1452 | } 1453 | 1454 | @Override 1455 | public boolean getDTR() throws IOException { 1456 | return false; 1457 | } 1458 | 1459 | @Override 1460 | public void setDTR(boolean value) throws IOException { 1461 | } 1462 | 1463 | @Override 1464 | public boolean getRI() throws IOException { 1465 | return false; 1466 | } 1467 | 1468 | @Override 1469 | public boolean getRTS() throws IOException { 1470 | return false; 1471 | } 1472 | 1473 | @Override 1474 | public void setRTS(boolean value) throws IOException { 1475 | } 1476 | 1477 | public static int rtlsdr_i2c_write_fn(byte addr, byte[] buf, byte len) { 1478 | return rtlsdr_i2c_write(addr, buf, len); 1479 | 1480 | } 1481 | 1482 | public static int rtlsdr_i2c_read_fn(byte addr, byte[] buf, byte len) { 1483 | return rtlsdr_i2c_read(addr, buf, len); 1484 | 1485 | } 1486 | 1487 | } 1488 | -------------------------------------------------------------------------------- /src/com/rtlsdr/android/SdrUsbId.java: -------------------------------------------------------------------------------- 1 | package com.rtlsdr.android; 2 | 3 | public class SdrUsbId { 4 | 5 | public static final int VENDOR_KYE = 0x0458; 6 | public static final int KYE_RTL2832_707F = 0x707f; 7 | 8 | public static final int VENDOR_RTL = 0x0bda; 9 | public static final int RTL_RTL2832 = 0x2832; 10 | public static final int RTL_RTL2838 = 0x2838; 11 | 12 | public static final int VENDOR_TERRATEC = 0x0ccd; 13 | public static final int TERRATEC_RTL2838_A9 = 0x00a9; 14 | public static final int TERRATEC_RTL2838_B3 = 0x00b3; 15 | public static final int TERRATEC_RTL2838_B4 = 0x00b4; 16 | public static final int TERRATEC_RTL2838_B7 = 0x00b7; 17 | public static final int TERRATEC_RTL2838_C6 = 0x00c6; 18 | public static final int TERRATEC_RTL2838_D3 = 0x00d3; 19 | public static final int TERRATEC_RTL2838_D7 = 0x00d7; 20 | public static final int TERRATEC_RTL2838_E0 = 0x00e0; 21 | 22 | public static final int VENDOR_COMPRO = 0x185b; 23 | public static final int COMPRO_620 = 0x0620;; 24 | public static final int COMPRO_650 = 0x0650; 25 | public static final int COMPRO_680 = 0x0680; 26 | 27 | public static final int VENDOR_AFATECH = 0x01b80; 28 | public static final int AFATECH_RTL2838_D393 = 0xd393; 29 | public static final int AFATECH_RTL2838_D394 = 0xd394; 30 | public static final int AFATECH_RTL2838_D395 = 0xd395; 31 | public static final int AFATECH_RTL2838_D396 = 0xd396; 32 | public static final int AFATECH_RTL2838_D397 = 0xd397; 33 | public static final int AFATECH_RTL2838_D398 = 0xd398; 34 | public static final int AFATECH_RTL2838_D39D = 0xd39d; 35 | public static final int AFATECH_RTL2838_D3A4 = 0xd3a4; 36 | 37 | public static final int VENDOR_DEXATEC = 0x01d19; 38 | public static final int DEXATEC_1101 = 0x1101; 39 | public static final int DEXATEC_1102 = 0x1102; 40 | public static final int DEXATEC_1103 = 0x1103; 41 | 42 | public static final int VENDOR_GTEK = 0x1f4d; 43 | public static final int GTEK_RTL2838_B803 = 0xb803; 44 | public static final int GTEK_RTL2838_C803 = 0xC803; 45 | public static final int GTEK_RTL2838_D286 = 0xd286; 46 | public static final int GTEK_RTL2838_D803 = 0xD803; 47 | 48 | private SdrUsbId() { 49 | throw new IllegalAccessError("Non-instantiable class."); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/com/rtlsdr/android/tuners/E4K.java: -------------------------------------------------------------------------------- 1 | package com.rtlsdr.android.tuners; 2 | 3 | import java.io.IOException; 4 | 5 | import com.rtlsdr.android.SdrSerialDriver; 6 | 7 | public class E4K implements IRtlSdrTuner { 8 | class e4k_if_filter { 9 | int E4K_IF_FILTER_MIX; 10 | int E4K_IF_FILTER_CHAN; 11 | int E4K_IF_FILTER_RC; 12 | }; 13 | 14 | class e4k_pll_params { 15 | int fosc; 16 | int intended_flo; 17 | int flo; 18 | char x; 19 | byte z; 20 | byte r; 21 | byte r_idx; 22 | byte threephase; 23 | }; 24 | 25 | class e4k_band { 26 | int E4K_BAND_VHF2 = 0; 27 | int E4K_BAND_VHF3 = 1; 28 | int E4K_BAND_UHF = 2; 29 | int E4K_BAND_L = 3; 30 | }; 31 | 32 | class e4k_state { 33 | 34 | byte i2c_addr; 35 | e4k_band band; 36 | e4k_pll_params vco; 37 | 38 | }; 39 | 40 | class reg_field { 41 | byte reg; 42 | byte shift; 43 | byte width; 44 | }; 45 | 46 | private final int E4K_I2C_ADDR = 0xC8; 47 | private final int E4K_REG_MASTER1 = 0x00, 48 | E4K_REG_MASTER2 = 0x01, 49 | E4K_REG_MASTER3 = 0x02, 50 | E4K_REG_MASTER4 = 0x03, 51 | E4K_REG_MASTER5 = 0x04, 52 | E4K_REG_CLK_INP = 0x05, 53 | E4K_REG_REF_CLK = 0x06, 54 | E4K_REG_SYNTH1 = 0x07, 55 | E4K_REG_SYNTH2 = 0x08, 56 | E4K_REG_SYNTH3 = 0x09, 57 | E4K_REG_SYNTH4 = 0x0a, 58 | E4K_REG_SYNTH5 = 0x0b, 59 | E4K_REG_SYNTH6 = 0x0c, 60 | E4K_REG_SYNTH7 = 0x0d, 61 | E4K_REG_SYNTH8 = 0x0e, 62 | E4K_REG_SYNTH9 = 0x0f, 63 | E4K_REG_FILT1 = 0x10, 64 | E4K_REG_FILT2 = 0x11, 65 | E4K_REG_FILT3 = 0x12, 66 | // gap 67 | E4K_REG_GAIN1 = 0x14, 68 | E4K_REG_GAIN2 = 0x15, 69 | E4K_REG_GAIN3 = 0x16, 70 | E4K_REG_GAIN4 = 0x17, 71 | // gap 72 | E4K_REG_AGC1 = 0x1a, 73 | E4K_REG_AGC2 = 0x1b, 74 | E4K_REG_AGC3 = 0x1c, 75 | E4K_REG_AGC4 = 0x1d, 76 | E4K_REG_AGC5 = 0x1e, 77 | E4K_REG_AGC6 = 0x1f, 78 | E4K_REG_AGC7 = 0x20, 79 | E4K_REG_AGC8 = 0x21, 80 | // gap 81 | E4K_REG_AGC11 = 0x24, 82 | E4K_REG_AGC12 = 0x25, 83 | // gap 84 | E4K_REG_DC1 = 0x29, 85 | E4K_REG_DC2 = 0x2a, 86 | E4K_REG_DC3 = 0x2b, 87 | E4K_REG_DC4 = 0x2c, 88 | E4K_REG_DC5 = 0x2d, 89 | E4K_REG_DC6 = 0x2e, 90 | E4K_REG_DC7 = 0x2f, 91 | E4K_REG_DC8 = 0x30, 92 | // gap 93 | E4K_REG_QLUT0 = 0x50, 94 | E4K_REG_QLUT1 = 0x51, 95 | E4K_REG_QLUT2 = 0x52, 96 | E4K_REG_QLUT3 = 0x53, 97 | // gap 98 | E4K_REG_ILUT0 = 0x60, 99 | E4K_REG_ILUT1 = 0x61, 100 | E4K_REG_ILUT2 = 0x62, 101 | E4K_REG_ILUT3 = 0x63, 102 | // gap 103 | E4K_REG_DCTIME1 = 0x70, E4K_REG_DCTIME2 = 0x71, 104 | E4K_REG_DCTIME3 = 0x72, E4K_REG_DCTIME4 = 0x73, 105 | E4K_REG_PWM1 = 0x74, E4K_REG_PWM2 = 0x75, E4K_REG_PWM3 = 0x76, 106 | E4K_REG_PWM4 = 0x77, E4K_REG_BIAS = 0x78, 107 | E4K_REG_CLKOUT_PWDN = 0x7a, E4K_REG_CHFILT_CALIB = 0x7b, 108 | E4K_REG_I2C_REG_ADDR = 0x7d, E4K_AGC_MOD_SERIAL = 0x0, 109 | E4K_AGC_MOD_IF_PWM_LNA_SERIAL = 0x1, 110 | E4K_AGC_MOD_IF_PWM_LNA_AUTONL = 0x2, 111 | E4K_AGC_MOD_IF_PWM_LNA_SUPERV = 0x3, 112 | E4K_AGC_MOD_IF_SERIAL_LNA_PWM = 0x4, 113 | E4K_AGC_MOD_IF_PWM_LNA_PWM = 0x5, 114 | E4K_AGC_MOD_IF_DIG_LNA_SERIAL = 0x6, 115 | E4K_AGC_MOD_IF_DIG_LNA_AUTON = 0x7, 116 | E4K_AGC_MOD_IF_DIG_LNA_SUPERV = 0x8, 117 | E4K_AGC_MOD_IF_SERIAL_LNA_AUTON = 0x9, 118 | E4K_AGC_MOD_IF_SERIAL_LNA_SUPERV = 0xa, E4K_BAND_VHF2 = 0, 119 | E4K_BAND_VHF3 = 1, E4K_BAND_UHF = 2, E4K_BAND_L = 3, 120 | E4K_F_MIX_BW_27M = 0, E4K_F_MIX_BW_4M6 = 8, E4K_F_MIX_BW_4M2 = 9, 121 | E4K_F_MIX_BW_3M8 = 10, E4K_F_MIX_BW_3M4 = 11, E4K_F_MIX_BW_3M = 12, 122 | E4K_F_MIX_BW_2M7 = 13, E4K_F_MIX_BW_2M3 = 14, 123 | E4K_F_MIX_BW_1M9 = 15, E4K_IF_FILTER_MIX = 0, 124 | E4K_IF_FILTER_CHAN = 1, E4K_IF_FILTER_RC = 3; 125 | 126 | private final int E4K_MASTER1_RESET = (1 << 0); 127 | private final int E4K_MASTER1_NORM_STBY = (1 << 1); 128 | private final int E4K_MASTER1_POR_DET = (1 << 2); 129 | private final int E4K_SYNTH1_PLL_LOCK = (1 << 0); 130 | private final int E4K_SYNTH1_BAND_SHIF = 1; 131 | private final int E4K_SYNTH7_3PHASE_EN = (1 << 3); 132 | private final int E4K_SYNTH8_VCOCAL_UPD = (1 << 2); 133 | private final int E4K_FILT3_DISABLE = (1 << 5); 134 | private final int E4K_AGC1_LIN_MODE = (1 << 4); 135 | private final int E4K_AGC1_LNA_UPDATE = (1 << 5); 136 | private final int E4K_AGC1_LNA_G_LOW = (1 << 6); 137 | private final int E4K_AGC1_LNA_G_HIGH = (1 << 7); 138 | private final int E4K_AGC6_LNA_CAL_REQ = (1 << 4); 139 | private final int E4K_AGC7_MIX_GAIN_AUTO = (1 << 0); 140 | private final int E4K_AGC7_GAIN_STEP_5dB = (1 << 5); 141 | private final int E4K_AGC8_SENS_LIN_AUTO = (1 << 0); 142 | private final int E4K_AGC11_LNA_GAIN_ENH = (1 << 0); 143 | private final int E4K_DC1_CAL_REQ = (1 << 0); 144 | private final int E4K_DC5_I_LUT_EN = (1 << 0); 145 | private final int E4K_DC5_Q_LUT_EN = (1 << 1); 146 | private final int E4K_DC5_RANGE_DET_EN = (1 << 2); 147 | private final int E4K_DC5_RANGE_EN = (1 << 3); 148 | private final int E4K_DC5_TIMEVAR_EN = (1 << 4); 149 | private final int E4K_CLKOUT_DISABLE = 0x96; 150 | private final int E4K_CHFCALIB_CMD = (1 << 0); 151 | private final int E4K_AGC1_MOD_MASK = 0xF; 152 | 153 | private final byte[] if_stage1_gain = { -3, 6 }; 154 | 155 | private final byte[] if_stage23_gain = { 0, 3, 6, 9 }; 156 | 157 | private final byte[] if_stage4_gain = { 0, 1, 2, 2 }; 158 | 159 | private final byte[] if_stage56_gain = { 3, 6, 9, 12, 15, 15, 15, 15 }; 160 | 161 | private final byte[] if_stage_gain[] = { null, if_stage1_gain, 162 | if_stage23_gain, if_stage23_gain, if_stage4_gain, if_stage56_gain, 163 | if_stage56_gain }; 164 | 165 | private final int[] if_stage_gain_len = { 0, if_stage1_gain.length, 166 | if_stage23_gain.length, if_stage23_gain.length, 167 | if_stage4_gain.length, if_stage56_gain.length, 168 | if_stage56_gain.length }; 169 | 170 | @Override 171 | public int init(int param) throws IOException { 172 | // TODO Auto-generated method stub 173 | 174 | return e4k_init(); 175 | } 176 | 177 | @Override 178 | public int exit(int param) throws IOException { 179 | // TODO Auto-generated method stub 180 | return 0; 181 | } 182 | 183 | @Override 184 | public int set_freq(int param, long freq) throws IOException { 185 | // TODO Auto-generated method stub 186 | return 0; 187 | } 188 | 189 | @Override 190 | public int set_bw(int param, int bw) throws IOException { 191 | // TODO Auto-generated method stub 192 | return 0; 193 | } 194 | 195 | @Override 196 | public int set_gain(int param, int gain) throws IOException { 197 | // TODO Auto-generated method stub 198 | return 0; 199 | } 200 | 201 | @Override 202 | public int set_if_gain(int param, int stage, int gain) throws IOException { 203 | // TODO Auto-generated method stub 204 | return 0; 205 | } 206 | 207 | @Override 208 | public int set_gain_mode(int param, boolean manual) throws IOException { 209 | // TODO Auto-generated method stub 210 | return 0; 211 | } 212 | 213 | private int MHZ(int x) { 214 | return ((x) * 1000 * 1000); 215 | } 216 | 217 | private int KHZ(int x) { 218 | return ((x) * 1000); 219 | } 220 | 221 | byte e4k_reg_read(int reg) { 222 | return SdrSerialDriver.rtlsdr_i2c_read_reg((char) E4K_I2C_ADDR, reg); 223 | } 224 | 225 | int e4k_reg_write(int reg, int val) { 226 | return SdrSerialDriver.rtlsdr_i2c_write_reg((byte) E4K_I2C_ADDR, 227 | (char) reg, (char) val); 228 | } 229 | 230 | /* 231 | * ! \brief Set or clear some (masked) bits inside a register \param[in] e4k 232 | * reference to the tuner \param[in] reg number of the register \param[in] 233 | * mask bit-mask of the value \param[in] val data value to be written to 234 | * register \returns 0 on success, negative in case of error 235 | */ 236 | int e4k_reg_set_mask(byte reg, char mask, char val) { 237 | byte tmp = e4k_reg_read(reg); 238 | 239 | if ((tmp & mask) == val) 240 | return 0; 241 | 242 | return e4k_reg_write(reg, (tmp & ~mask) | (val & mask)); 243 | } 244 | 245 | /* 246 | * ! \brief Enables / Disables the channel filter \param[in] e4k reference 247 | * to the tuner chip \param[in] on 1=filter enabled, 0=filter disabled 248 | * \returns 0 success, negative errors 249 | */ 250 | int e4k_if_filter_chan_enable(boolean on) { 251 | return e4k_reg_set_mask((byte) E4K_REG_FILT3, (char) E4K_FILT3_DISABLE, 252 | (char) (on ? 0 : E4K_FILT3_DISABLE)); 253 | } 254 | 255 | /* 256 | * ! \brief Initialize the E4K tuner 257 | */ 258 | int e4k_init() { 259 | /* make a dummy i2c read or write command, will not be ACKed! */ 260 | e4k_reg_read((byte) 0); 261 | 262 | /* Make sure we reset everything and clear POR indicator */ 263 | e4k_reg_write((byte) E4K_REG_MASTER1, (byte) (E4K_MASTER1_RESET 264 | | E4K_MASTER1_NORM_STBY | E4K_MASTER1_POR_DET)); 265 | 266 | /* Configure clock input */ 267 | e4k_reg_write((byte) E4K_REG_CLK_INP, (byte) 0x00); 268 | 269 | /* Disable clock output */ 270 | e4k_reg_write((byte) E4K_REG_REF_CLK, (byte) 0x00); 271 | e4k_reg_write((byte) E4K_REG_CLKOUT_PWDN, (byte) 0x96); 272 | 273 | /* Write some magic values into registers */ 274 | magic_init(); 275 | /* 276 | * #if 0 /* Set common mode voltage a bit higher for more margin 850 mv 277 | * * / e4k_commonmode_set(e4k, 4); 278 | * 279 | * /* Initialize DC offset lookup tables * / 280 | * e4k_dc_offset_gen_table(e4k); 281 | * 282 | * / * Enable time variant DC correction * / e4k_reg_write(e4k, 283 | * E4K_REG_DCTIME1, 0x01); e4k_reg_write(e4k, E4K_REG_DCTIME2, 0x01); 284 | * #endif 285 | */ 286 | 287 | /* Set LNA mode to manual */ 288 | e4k_reg_write((byte) E4K_REG_AGC4, 0x10); /* High threshold */ 289 | e4k_reg_write((byte) E4K_REG_AGC5, 0x04); /* Low threshold */ 290 | e4k_reg_write((byte) E4K_REG_AGC6, 0x1a); /* LNA calib + loop rate */ 291 | 292 | e4k_reg_set_mask((byte) E4K_REG_AGC1, (char) E4K_AGC1_MOD_MASK, 293 | (char) E4K_AGC_MOD_SERIAL); 294 | 295 | /* Set Mixer Gain Control to manual */ 296 | e4k_reg_set_mask((byte) E4K_REG_AGC7, (char) E4K_AGC7_MIX_GAIN_AUTO, 297 | (char) 0); 298 | 299 | /* 300 | * #if 0/* Enable LNA Gain enhancement * / e4k_reg_set_mask(e4k, 301 | * E4K_REG_AGC11, 0x7, E4K_AGC11_LNA_GAIN_ENH | (2 << 1)); 302 | * 303 | * /* Enable automatic IF gain mode switching * / e4k_reg_set_mask(e4k, 304 | * E4K_REG_AGC8, 0x1, E4K_AGC8_SENS_LIN_AUTO); $infif 305 | */ 306 | 307 | /* Use auto-gain as default */ 308 | e4k_enable_manual_gain(false); 309 | 310 | /* Select moderate gain levels */ 311 | e4k_if_gain_set((byte) 1, (byte) 6); 312 | e4k_if_gain_set(2, 0); 313 | e4k_if_gain_set(3, 0); 314 | e4k_if_gain_set(4, 0); 315 | e4k_if_gain_set(5, 9); 316 | e4k_if_gain_set(6, 9); 317 | 318 | /* Set the most narrow filter we can possibly use */ 319 | // e4k_if_filter_bw_set(E4K_IF_FILTER_MIX, KHZ(1900)); 320 | // e4k_if_filter_bw_set( E4K_IF_FILTER_RC, KHZ(1000)); 321 | // e4k_if_filter_bw_set( E4K_IF_FILTER_CHAN, KHZ(2150)); 322 | // e4k_if_filter_chan_enable(true); 323 | 324 | /* Disable time variant DC correction and LUT */ 325 | e4k_reg_set_mask((byte) E4K_REG_DC5, (char) 0x03, (char) 0); 326 | e4k_reg_set_mask((byte) E4K_REG_DCTIME1, (char) 0x03, (char) 0); 327 | e4k_reg_set_mask((byte) E4K_REG_DCTIME2, (char) 0x03, (char) 0); 328 | 329 | return 0; 330 | } 331 | 332 | int find_stage_gain(byte stage, byte val) { 333 | byte[] arr; 334 | int i; 335 | 336 | if (stage >= (if_stage_gain.length)) 337 | return -1; 338 | 339 | arr = if_stage_gain[stage]; 340 | 341 | for (i = 0; i < if_stage_gain_len[stage]; i++) { 342 | if (arr[i] == val) 343 | return i; 344 | } 345 | return -1; 346 | } 347 | 348 | /* 349 | * ! \brief Set the gain of one of the IF gain stages \param [e4k] handle to 350 | * the tuner chip \param [stage] number of the stage (1..6) \param [value] 351 | * gain value in dB \returns 0 on success, negative in case of error 352 | */ 353 | int e4k_if_gain_set(int stage, int value) { 354 | int rc; 355 | byte mask; 356 | // const struct reg_field *field; 357 | 358 | rc = find_stage_gain((byte) stage, (byte) value); 359 | if (rc < 0) 360 | return rc; 361 | 362 | /* compute the bit-mask for the given gain field */ 363 | // field = if_stage_gain_regs[stage]; 364 | // mask = width2mask[field.width] << field->shift; 365 | 366 | return 0;// e4k_reg_set_mask( field.reg, mask, rc << field.shift); 367 | } 368 | 369 | private int e4k_enable_manual_gain(boolean manual) { 370 | if (manual) { 371 | /* Set LNA mode to manual */ 372 | e4k_reg_set_mask((byte) E4K_REG_AGC1, (char) E4K_AGC1_MOD_MASK, 373 | (char) E4K_AGC_MOD_SERIAL); 374 | 375 | /* Set Mixer Gain Control to manual */ 376 | e4k_reg_set_mask((byte) E4K_REG_AGC7, 377 | (char) E4K_AGC7_MIX_GAIN_AUTO, (char) 0); 378 | } else { 379 | /* Set LNA mode to auto */ 380 | e4k_reg_set_mask((byte) E4K_REG_AGC1, (char) E4K_AGC1_MOD_MASK, 381 | (char) E4K_AGC_MOD_IF_SERIAL_LNA_AUTON); 382 | /* Set Mixer Gain Control to auto */ 383 | e4k_reg_set_mask((byte) E4K_REG_AGC7, 384 | (char) E4K_AGC7_MIX_GAIN_AUTO, (char) 1); 385 | 386 | e4k_reg_set_mask((byte) E4K_REG_AGC11, (char) 0x7, (char) 0); 387 | } 388 | 389 | return 0; 390 | } 391 | 392 | int unsigned_delta(int a, int b) { 393 | if (a > b) 394 | return a - b; 395 | else 396 | return b - a; 397 | } 398 | 399 | int closest_arr_idx(int arr[], int arr_size, int freq) { 400 | int i, bi = 0; 401 | int best_delta = 0xffffffff; 402 | 403 | /* 404 | * iterate over the array containing a list of the center frequencies, 405 | * selecting the closest one 406 | */ 407 | for (i = 0; i < arr_size; i++) { 408 | int delta = unsigned_delta(freq, arr[i]); 409 | if (delta < best_delta) { 410 | best_delta = delta; 411 | bi = i; 412 | } 413 | } 414 | 415 | return bi; 416 | } 417 | 418 | int magic_init() { 419 | e4k_reg_write((byte) 0x7e, (byte) 0x01); 420 | e4k_reg_write((byte) 0x7f, (byte) 0xfe); 421 | e4k_reg_write((byte) 0x82, (byte) 0x00); 422 | e4k_reg_write((byte) 0x86, (byte) 0x50); /* polarity A */ 423 | e4k_reg_write((byte) 0x87, (byte) 0x20); 424 | e4k_reg_write((byte) 0x88, (byte) 0x01); 425 | e4k_reg_write((byte) 0x9f, (byte) 0x7f); 426 | e4k_reg_write((byte) 0xa0, (byte) 0x07); 427 | 428 | return 0; 429 | } 430 | } 431 | -------------------------------------------------------------------------------- /src/com/rtlsdr/android/tuners/FC0012.java: -------------------------------------------------------------------------------- 1 | package com.rtlsdr.android.tuners; 2 | 3 | import java.io.IOException; 4 | 5 | public class FC0012 implements IRtlSdrTuner { 6 | private static final String TAG = FC0012.class.getSimpleName(); 7 | 8 | @Override 9 | public int init(int param) throws IOException { 10 | // TODO Auto-generated method stub 11 | return 0; 12 | } 13 | 14 | @Override 15 | public int exit(int param) throws IOException { 16 | // TODO Auto-generated method stub 17 | return 0; 18 | } 19 | 20 | @Override 21 | public int set_freq(int param, long freq) throws IOException { 22 | // TODO Auto-generated method stub 23 | return 0; 24 | } 25 | 26 | @Override 27 | public int set_bw(int param, int bw) throws IOException { 28 | // TODO Auto-generated method stub 29 | return 0; 30 | } 31 | 32 | @Override 33 | public int set_gain(int param, int gain) throws IOException { 34 | // TODO Auto-generated method stub 35 | return 0; 36 | } 37 | 38 | @Override 39 | public int set_if_gain(int param, int stage, int gain) throws IOException { 40 | // TODO Auto-generated method stub 41 | return 0; 42 | } 43 | 44 | @Override 45 | public int set_gain_mode(int param, boolean manual) throws IOException { 46 | // TODO Auto-generated method stub 47 | return 0; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/com/rtlsdr/android/tuners/FC0013.java: -------------------------------------------------------------------------------- 1 | package com.rtlsdr.android.tuners; 2 | 3 | import java.io.IOException; 4 | 5 | import android.util.Log; 6 | 7 | import com.rtlsdr.android.SdrSerialDriver; 8 | 9 | public class FC0013 implements IRtlSdrTuner { 10 | private static final String TAG = FC0013.class.getSimpleName(); 11 | final int FC0013_I2C_ADDR = 0xc6; 12 | final int FC0013_CHECK_ADDR = 0x00; 13 | final int FC0013_CHECK_VAL = 0xa3; 14 | int[] fc0013_lna_gains = { -99, 0x02, -73, 0x03, -65, 0x05, -63, 0x04, -63, 15 | 0x00, -60, 0x07, -58, 0x01, -54, 0x06, 58, 0x0f, 61, 0x0e, 63, 16 | 0x0d, 65, 0x0c, 67, 0x0b, 68, 0x0a, 70, 0x09, 71, 0x08, 179, 0x17, 17 | 181, 0x16, 182, 0x15, 184, 0x14, 186, 0x13, 188, 0x12, 191, 0x11, 18 | 197, 0x10 }; 19 | 20 | @Override 21 | public int init(int param) throws IOException { 22 | fc0013_init(); 23 | return 0; 24 | } 25 | 26 | @Override 27 | public int exit(int param) throws IOException { 28 | // TODO Auto-generated method stub 29 | return 0; 30 | } 31 | 32 | @Override 33 | public int set_freq(int param, long freq) throws IOException { 34 | return fc0013_set_params((int) freq, 6000000); 35 | } 36 | 37 | @Override 38 | public int set_bw(int param, int bw) throws IOException { 39 | // TODO Auto-generated method stub 40 | return 0; 41 | } 42 | 43 | @Override 44 | public int set_gain(int param, int gain) throws IOException { 45 | return fc0013_set_lna_gain(gain); 46 | } 47 | 48 | @Override 49 | public int set_if_gain(int param, int stage, int gain) throws IOException { 50 | // TODO Auto-generated method stub 51 | return 0; 52 | } 53 | 54 | @Override 55 | public int set_gain_mode(int param, boolean manual) throws IOException { 56 | return fc0013_set_gain_mode(manual); 57 | 58 | } 59 | 60 | private int fc0013_writereg(byte reg, byte val) { 61 | byte[] data = new byte[2]; 62 | data[0] = reg; 63 | data[1] = val; 64 | 65 | if (SdrSerialDriver.rtlsdr_i2c_write_fn((byte) FC0013_I2C_ADDR, data, 66 | (byte) 2) < 0) 67 | return -1; 68 | 69 | return 0; 70 | } 71 | 72 | private int fc0013_readreg(byte reg, byte[] val) { 73 | byte[] data = new byte[2]; 74 | data[0] = reg; 75 | 76 | if (SdrSerialDriver.rtlsdr_i2c_write_fn((byte) FC0013_I2C_ADDR, data, 77 | (byte) 1) < 0) 78 | return -1; 79 | 80 | if (SdrSerialDriver.rtlsdr_i2c_read_fn((byte) FC0013_I2C_ADDR, data, 81 | (byte) 1) < 0) 82 | return -1; 83 | 84 | val[0] = data[0]; 85 | 86 | return 0; 87 | } 88 | 89 | int fc0013_set_gain_mode(boolean manual) { 90 | int ret = 0; 91 | byte[] tmp = new byte[2]; 92 | 93 | ret |= fc0013_readreg((byte) 0x0d, tmp); 94 | 95 | if (manual) 96 | tmp[0] |= (1 << 3); 97 | else 98 | tmp[0] &= ~(1 << 3); 99 | 100 | ret |= fc0013_writereg((byte) 0x0d, tmp[0]); 101 | 102 | /* set a fixed IF-gain for now */ 103 | ret |= fc0013_writereg((byte) 0x13, (byte) 0x0a); 104 | 105 | return ret; 106 | } 107 | 108 | int fc0013_init() { 109 | int ret = 0; 110 | int i; 111 | byte[] reg = { 0x00, /* reg. 0x00: dummy */ 112 | 0x09, /* reg. 0x01 */ 113 | 0x16, /* reg. 0x02 */ 114 | 0x00, /* reg. 0x03 */ 115 | 0x00, /* reg. 0x04 */ 116 | 0x17, /* reg. 0x05 */ 117 | 0x02, /* reg. 0x06: LPF bandwidth */ 118 | 0x0a, /* reg. 0x07: CHECK */ 119 | (byte) 0xff, /* 120 | * reg. 0x08: AGC Clock divide by 256, AGC gain 1/256, Loop 121 | * Bw 1/8 122 | */ 123 | 0x6e, /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */ 124 | (byte) 0xb8, /* reg. 0x0a: Disable LO Test Buffer */ 125 | (byte) 0x82, /* reg. 0x0b: CHECK */ 126 | (byte) 0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */ 127 | 0x01, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, may need 0x02 */ 128 | 0x00, /* reg. 0x0e */ 129 | 0x00, /* reg. 0x0f */ 130 | 0x00, /* reg. 0x10 */ 131 | 0x00, /* reg. 0x11 */ 132 | 0x00, /* reg. 0x12 */ 133 | 0x00, /* reg. 0x13 */ 134 | 0x50, /* 135 | * reg. 0x14: DVB-t High Gain, UHF. Middle Gain: 0x48, Low Gain: 136 | * 0x40 137 | */ 138 | 0x01, /* reg. 0x15 */ 139 | }; 140 | /* 141 | * #if 0 switch (rtlsdr_get_tuner_clock(dev)) { case FC_XTAL_27_MHZ: 142 | * case FC_XTAL_28_8_MHZ: reg[0x07] |= 0x20; break; case FC_XTAL_36_MHZ: 143 | * default: break; } #endif 144 | */ 145 | reg[0x07] |= 0x20; 146 | 147 | // if (dev->dual_master) 148 | reg[0x0c] |= 0x02; 149 | 150 | for (i = 1; i < reg.length; i++) { 151 | ret = fc0013_writereg((byte) i, reg[i]); 152 | if (ret < 0) 153 | break; 154 | } 155 | 156 | return ret; 157 | } 158 | 159 | int fc0013_set_lna_gain(int gain) { 160 | int ret = 0; 161 | int i; 162 | byte[] tmp = new byte[1]; 163 | 164 | ret |= fc0013_readreg((byte) 0x14, tmp); 165 | 166 | /* mask bits off */ 167 | tmp[0] &= 0xe0; 168 | 169 | for (i = 0; i < fc0013_lna_gains.length / 2; i++) { 170 | if ((fc0013_lna_gains[i * 2] >= gain) 171 | || (i + 1 == (fc0013_lna_gains.length / 2))) { 172 | tmp[0] |= fc0013_lna_gains[i * 2 + 1]; 173 | break; 174 | } 175 | } 176 | 177 | /* set gain */ 178 | ret |= fc0013_writereg((byte) 0x14, tmp[0]); 179 | 180 | return ret; 181 | } 182 | 183 | int fc0013_set_params(int freq, int bandwidth) { 184 | int i, ret = 0; 185 | char[] reg = new char[7]; 186 | byte am, pm, multi; 187 | long f_vco; 188 | int xtal_freq_div_2; 189 | char xin, xdiv; 190 | boolean vco_select = false; 191 | byte[] tmp = new byte[1]; 192 | 193 | xtal_freq_div_2 = SdrSerialDriver.rtlsdr_get_tuner_clock() / 2; 194 | 195 | /* set VHF track */ 196 | ret = fc0013_set_vhf_track(freq); 197 | if (ret < 0) 198 | return -1; 199 | 200 | if (freq < 300000000) { 201 | /* enable VHF filter */ 202 | ret = fc0013_readreg((byte) 0x07, tmp); 203 | if (ret < 0) 204 | return -1; 205 | ret = fc0013_writereg((byte) 0x07, (byte) (tmp[0] | 0x10)); 206 | if (ret < 0) 207 | return -1; 208 | 209 | /* disable UHF & disable GPS */ 210 | ret = fc0013_readreg((byte) 0x14, tmp); 211 | if (ret < 0) 212 | return -1; 213 | ret = fc0013_writereg((byte) 0x14, (byte) (tmp[0] & 0x1f)); 214 | if (ret < 0) 215 | return -1; 216 | } else if (freq <= 862000000) { 217 | /* disable VHF filter */ 218 | ret = fc0013_readreg((byte) 0x07, tmp); 219 | if (ret < 0) 220 | return -1; 221 | ret = fc0013_writereg((byte) 0x07, (byte) (tmp[0] & 0xef)); 222 | if (ret < 0) 223 | return -1; 224 | ; 225 | 226 | /* enable UHF & disable GPS */ 227 | ret = fc0013_readreg((byte) 0x14, tmp); 228 | if (ret < 0) 229 | return -1; 230 | ; 231 | ret = fc0013_writereg((byte) 0x14, (byte) ((tmp[0] & 0x1f) | 0x40)); 232 | if (ret < 0) 233 | return -1; 234 | ; 235 | } else { 236 | /* disable VHF filter */ 237 | ret = fc0013_readreg((byte) 0x07, tmp); 238 | if (ret < 0) 239 | return -1; 240 | ret = fc0013_writereg((byte) 0x07, (byte) (tmp[0] & 0xef)); 241 | if (ret < 0) 242 | return -1; 243 | 244 | /* disable UHF & enable GPS */ 245 | ret = fc0013_readreg((byte) 0x14, tmp); 246 | if (ret < 0) 247 | return -1; 248 | ; 249 | ret = fc0013_writereg((byte) 0x14, (byte) ((tmp[0] & 0x1f) | 0x20)); 250 | if (ret < 0) 251 | return -1; 252 | ; 253 | } 254 | 255 | /* select frequency divider and the frequency of VCO */ 256 | if (freq < 37084000) { /* freq * 96 < 3560000000 */ 257 | multi = 96; 258 | reg[5] = (char) 0x82; 259 | reg[6] = 0x00; 260 | } else if (freq < 55625000) { /* freq * 64 < 3560000000 */ 261 | multi = 64; 262 | reg[5] = 0x02; 263 | reg[6] = 0x02; 264 | } else if (freq < 74167000) { /* freq * 48 < 3560000000 */ 265 | multi = 48; 266 | reg[5] = 0x42; 267 | reg[6] = 0x00; 268 | } else if (freq < 111250000) { /* freq * 32 < 3560000000 */ 269 | multi = 32; 270 | reg[5] = (char) 0x82; 271 | reg[6] = 0x02; 272 | } else if (freq < 148334000) { /* freq * 24 < 3560000000 */ 273 | multi = 24; 274 | reg[5] = 0x22; 275 | reg[6] = 0x00; 276 | } else if (freq < 222500000) { /* freq * 16 < 3560000000 */ 277 | multi = 16; 278 | reg[5] = 0x42; 279 | reg[6] = 0x02; 280 | } else if (freq < 296667000) { /* freq * 12 < 3560000000 */ 281 | multi = 12; 282 | reg[5] = 0x12; 283 | reg[6] = 0x00; 284 | } else if (freq < 445000000) { /* freq * 8 < 3560000000 */ 285 | multi = 8; 286 | reg[5] = 0x22; 287 | reg[6] = 0x02; 288 | } else if (freq < 593334000) { /* freq * 6 < 3560000000 */ 289 | multi = 6; 290 | reg[5] = 0x0a; 291 | reg[6] = 0x00; 292 | } else if (freq < 950000000) { /* freq * 4 < 3800000000 */ 293 | multi = 4; 294 | reg[5] = 0x12; 295 | reg[6] = 0x02; 296 | } else { 297 | multi = 2; 298 | reg[5] = 0x0a; 299 | reg[6] = 0x02; 300 | } 301 | 302 | f_vco = freq * multi; 303 | 304 | if (f_vco >= 3060000000L) { 305 | reg[6] |= 0x08; 306 | vco_select = true; 307 | } 308 | 309 | /* From divided value (XDIV) determined the FA and FP value */ 310 | xdiv = (char) (f_vco / xtal_freq_div_2); 311 | if ((f_vco - xdiv * xtal_freq_div_2) >= (xtal_freq_div_2 / 2)) 312 | xdiv++; 313 | 314 | pm = (byte) (xdiv / 8); 315 | am = (byte) (xdiv - (8 * pm)); 316 | 317 | if (am < 2) { 318 | am += 8; 319 | pm--; 320 | } 321 | 322 | if (pm > 31) { 323 | reg[1] = (char) (am + (8 * (pm - 31))); 324 | reg[2] = 31; 325 | } else { 326 | reg[1] = (char) am; 327 | reg[2] = (char) pm; 328 | } 329 | 330 | if ((reg[1] > 15) || (reg[2] < 0x0b)) { 331 | Log.e("TAG", "[FC0013] no valid PLL combination found for " + freq 332 | + " HZ!"); 333 | return -1; 334 | } 335 | 336 | /* fix clock out */ 337 | reg[6] |= 0x20; 338 | 339 | /* 340 | * From VCO frequency determines the XIN ( fractional part of Delta 341 | * Sigma PLL) and divided value (XDIV) 342 | */ 343 | xin = (char) ((f_vco - (f_vco / xtal_freq_div_2) * xtal_freq_div_2) / 1000); 344 | xin = (char) ((xin << 15) / (xtal_freq_div_2 / 1000)); 345 | if (xin >= 16384) 346 | xin += 32768; 347 | 348 | reg[3] = (char) (xin >> 8); 349 | reg[4] = (char) (xin & 0xff); 350 | 351 | reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */ 352 | switch (bandwidth) { 353 | case 6000000: 354 | reg[6] |= 0x80; 355 | break; 356 | case 7000000: 357 | reg[6] |= 0x40; 358 | break; 359 | case 8000000: 360 | default: 361 | break; 362 | } 363 | 364 | /* modified for Realtek demod */ 365 | reg[5] |= 0x07; 366 | 367 | for (i = 1; i <= 6; i++) { 368 | ret = fc0013_writereg((byte) i, (byte) reg[i]); 369 | if (ret < 0) 370 | return -1; 371 | } 372 | 373 | ret = fc0013_readreg((byte) 0x11, tmp); 374 | if (ret < 0) 375 | return -1; 376 | if (multi == 64) 377 | ret = fc0013_writereg((byte) 0x11, (byte) (tmp[0] | 0x04)); 378 | else 379 | ret = fc0013_writereg((byte) 0x11, (byte) (tmp[0] & 0xfb)); 380 | if (ret < 0) 381 | return -1; 382 | 383 | /* VCO Calibration */ 384 | ret = fc0013_writereg((byte) 0x0e, (byte) 0x80); 385 | if (ret != 0) 386 | ret = fc0013_writereg((byte) 0x0e, (byte) 0x00); 387 | 388 | /* VCO Re-Calibration if needed */ 389 | if (ret != 0) 390 | ret = fc0013_writereg((byte) 0x0e, (byte) 0x00); 391 | 392 | if (ret != 0) { 393 | // msleep(10); 394 | ret = fc0013_readreg((byte) 0x0e, tmp); 395 | } 396 | if (ret < 0) 397 | return -1; 398 | 399 | /* vco selection */ 400 | tmp[0] &= 0x3f; 401 | 402 | if (vco_select) { 403 | if (tmp[0] > 0x3c) { 404 | reg[6] &= ~0x08; 405 | ret = fc0013_writereg((byte) 0x06, (byte) reg[6]); 406 | if (ret != 0) 407 | ret = fc0013_writereg((byte) 0x0e, (byte) 0x80); 408 | if (ret != 0) 409 | ret = fc0013_writereg((byte) 0x0e, (byte) 0x00); 410 | } 411 | } else { 412 | if (tmp[0] < 0x02) { 413 | reg[6] |= 0x08; 414 | ret = fc0013_writereg((byte) 0x06, (byte) reg[6]); 415 | if (ret != 0) 416 | ret = fc0013_writereg((byte) 0x0e, (byte) 0x80); 417 | if (ret != 0) 418 | ret = fc0013_writereg((byte) 0x0e, (byte) 0x00); 419 | } 420 | } 421 | 422 | // exit: 423 | return ret; 424 | } 425 | 426 | private int fc0013_set_vhf_track(int freq) { 427 | int ret; 428 | 429 | byte[] tmp = new byte[1]; 430 | 431 | ret = fc0013_readreg((byte) 0x1d, tmp); 432 | if (ret != 0) 433 | return -1; 434 | tmp[0] &= 0xe3; 435 | if (freq <= 177500000) { /* VHF Track: 7 */ 436 | ret = fc0013_writereg((byte) 0x1d, (byte) (tmp[0] | 0x1c)); 437 | } else if (freq <= 184500000) { /* VHF Track: 6 */ 438 | ret = fc0013_writereg((byte) 0x1d, (byte) (tmp[0] | 0x18)); 439 | } else if (freq <= 191500000) { /* VHF Track: 5 */ 440 | ret = fc0013_writereg((byte) 0x1d, (byte) (tmp[0] | 0x14)); 441 | } else if (freq <= 198500000) { /* VHF Track: 4 */ 442 | ret = fc0013_writereg((byte) 0x1d, (byte) (tmp[0] | 0x10)); 443 | } else if (freq <= 205500000) { /* VHF Track: 3 */ 444 | ret = fc0013_writereg((byte) 0x1d, (byte) (tmp[0] | 0x0c)); 445 | } else if (freq <= 219500000) { /* VHF Track: 2 */ 446 | ret = fc0013_writereg((byte) 0x1d, (byte) (tmp[0] | 0x08)); 447 | } else if (freq < 300000000) { /* VHF Track: 1 */ 448 | ret = fc0013_writereg((byte) 0x1d, (byte) (tmp[0] | 0x04)); 449 | } else { /* UHF and GPS */ 450 | ret = fc0013_writereg((byte) 0x1d, (byte) (tmp[0] | 0x1c)); 451 | } 452 | 453 | // error_out: 454 | return ret; 455 | } 456 | } 457 | -------------------------------------------------------------------------------- /src/com/rtlsdr/android/tuners/FC2580.java: -------------------------------------------------------------------------------- 1 | package com.rtlsdr.android.tuners; 2 | 3 | import java.io.IOException; 4 | 5 | public class FC2580 implements IRtlSdrTuner { 6 | 7 | @Override 8 | public int init(int param) throws IOException { 9 | // TODO Auto-generated method stub 10 | return 0; 11 | } 12 | 13 | @Override 14 | public int exit(int param) throws IOException { 15 | // TODO Auto-generated method stub 16 | return 0; 17 | } 18 | 19 | @Override 20 | public int set_freq(int param, long freq) throws IOException { 21 | // TODO Auto-generated method stub 22 | return 0; 23 | } 24 | 25 | @Override 26 | public int set_bw(int param, int bw) throws IOException { 27 | // TODO Auto-generated method stub 28 | return 0; 29 | } 30 | 31 | @Override 32 | public int set_gain(int param, int gain) throws IOException { 33 | // TODO Auto-generated method stub 34 | return 0; 35 | } 36 | 37 | @Override 38 | public int set_if_gain(int param, int stage, int gain) throws IOException { 39 | // TODO Auto-generated method stub 40 | return 0; 41 | } 42 | 43 | @Override 44 | public int set_gain_mode(int param, boolean manual) throws IOException { 45 | // TODO Auto-generated method stub 46 | return 0; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/com/rtlsdr/android/tuners/IRtlSdrTuner.java: -------------------------------------------------------------------------------- 1 | package com.rtlsdr.android.tuners; 2 | 3 | import java.io.IOException; 4 | 5 | public interface IRtlSdrTuner { 6 | int init(int param) throws IOException; 7 | 8 | int exit(int param) throws IOException; 9 | 10 | int set_freq(int param, long freq /* Hz */) throws IOException; 11 | 12 | int set_bw(int param, int bw /* Hz */) throws IOException; 13 | 14 | int set_gain(int param, int gain /* tenth dB */) throws IOException; 15 | 16 | int set_if_gain(int param, int stage, int gain /* tenth dB */) 17 | throws IOException; 18 | 19 | int set_gain_mode(int param, boolean manual) throws IOException; 20 | } 21 | --------------------------------------------------------------------------------