├── README.md ├── LICENSE.md └── webusb-ftdi.js /README.md: -------------------------------------------------------------------------------- 1 | # webusb-ftdi.js 2 | (C) 2021 Jai B / Shaped Technologies 3 | 4 | This is a basic WebUSB FTDI driver. It works on Chrome and Chromium-based browsers (currently Firefox doesn't support WebUSB). It also works on Android devices under Chrome. This will allow you to communicate with existing FTDI devices in a browser using the WebUSB API (the device does NOT need to be WebUSB aware - any old FTDI works). 5 | 6 | I wrote this because I wanted to interface with different automotive devices on my Android devices. On Windows, it's generally much easier to use the WebSerial API instead. 7 | 8 | Under Windows, if any FTDI driver has been installed, you can use `zadig` to switch to the `WinUSB driver` in order for the browser to be able to access the USB device. This will prevent the device from being used as a serial (COM) port until you've switched the driver back. 9 | 10 | Under Android, it should just work when a FTDI device is plugged into USB OTG. I haven't tested a ton of devices but it has worked everywhere I have tested it. 11 | 12 | I tried to get details about the protocol from FTDI for this project (as the Linux driver states they helped them out for it) but when I mentioned that I planned on releasing the driver as open source, I stopped receiving emails from FTDI unfortunately. The Linux driver was a great inspiration and help for this so I want to give a shout out to the developers of the Linux FTDI driver. 13 | 14 | This will allow you to send and receive TTL data over an FTDI device. This is not a complete driver and this advanced features are not implemented although I'm sure most use cases just simply need communication. By default, it currently sets the latency timer to 1 though you'll be able to change this in the future. I'm also planning on allowing changing of some other options if I find anyone needs it. 15 | 16 | # usage 17 | 18 | This is just some basic usage. This driver is `alpha` quality; thus the API is subject to change, I will probably rename and change some sh~t. Be warned! 19 | 20 | // get a device object 21 | var device = new WebUSBSerialDevice({ 22 | overridePortSettings: true, // TODO: not supported yet, always overrides baudrate 23 | // these are the defaults, this config is only used if above is true 24 | baudrate: 9600, 25 | bits: 8, // TODO: override not supported yet 26 | stop: 1, // TODO: override not supported yet 27 | parity: false, // TODO: override not supported yet 28 | deviceFilters : [ 29 | // example filtered device; see code for more examples 30 | { 'vendorId': 0x0403, 'productId': 0x6001}, // 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC 31 | ] 32 | }); 33 | 34 | // get available ports (ftdi devices) 35 | console.log(device.getAvailablePorts()); 36 | 37 | // shows browser request for usb device 38 | var port = await device.requestNewPort(); 39 | 40 | try { 41 | // try to connect, connect receives two parameters: data callback and error callback 42 | await port.connect((data) => { 43 | // this is data callback, print data to console 44 | console.log(data); 45 | // send/repeat received data back to port after 10ms 46 | setTimeout(()=>{ 47 | port.send(data); 48 | },10); 49 | }, (error) => { 50 | // called if error receiving data 51 | console.warn("Error receiving data: " + error) 52 | }); 53 | } catch (e) { 54 | // called if can't get a port 55 | console.warn("Error connecting to port: " + e.error) 56 | console.warn(e) 57 | } 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | GNU General Public License 2 | ========================== 3 | 4 | For web-usb-ftdi.js - this applies for personal / open source use only. 5 | 6 | Closed source / commercial uses require a commercial license. 7 | 8 | _Version 2, June 1991_ 9 | _Copyright © 1989, 1991 Free Software Foundation, Inc.,_ 10 | _51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA_ 11 | 12 | Everyone is permitted to copy and distribute verbatim copies 13 | of this license document, but changing it is not allowed. 14 | 15 | ### Preamble 16 | 17 | The licenses for most software are designed to take away your 18 | freedom to share and change it. By contrast, the GNU General Public 19 | License is intended to guarantee your freedom to share and change free 20 | software--to make sure the software is free for all its users. This 21 | General Public License applies to most of the Free Software 22 | Foundation's software and to any other program whose authors commit to 23 | using it. (Some other Free Software Foundation software is covered by 24 | the GNU Lesser General Public License instead.) You can apply it to 25 | your programs, too. 26 | 27 | When we speak of free software, we are referring to freedom, not 28 | price. Our General Public Licenses are designed to make sure that you 29 | have the freedom to distribute copies of free software (and charge for 30 | this service if you wish), that you receive source code or can get it 31 | if you want it, that you can change the software or use pieces of it 32 | in new free programs; and that you know you can do these things. 33 | 34 | To protect your rights, we need to make restrictions that forbid 35 | anyone to deny you these rights or to ask you to surrender the rights. 36 | These restrictions translate to certain responsibilities for you if you 37 | distribute copies of the software, or if you modify it. 38 | 39 | For example, if you distribute copies of such a program, whether 40 | gratis or for a fee, you must give the recipients all the rights that 41 | you have. You must make sure that they, too, receive or can get the 42 | source code. And you must show them these terms so they know their 43 | rights. 44 | 45 | We protect your rights with two steps: **(1)** copyright the software, and 46 | **(2)** offer you this license which gives you legal permission to copy, 47 | distribute and/or modify the software. 48 | 49 | Also, for each author's protection and ours, we want to make certain 50 | that everyone understands that there is no warranty for this free 51 | software. If the software is modified by someone else and passed on, we 52 | want its recipients to know that what they have is not the original, so 53 | that any problems introduced by others will not reflect on the original 54 | authors' reputations. 55 | 56 | Finally, any free program is threatened constantly by software 57 | patents. We wish to avoid the danger that redistributors of a free 58 | program will individually obtain patent licenses, in effect making the 59 | program proprietary. To prevent this, we have made it clear that any 60 | patent must be licensed for everyone's free use or not licensed at all. 61 | 62 | The precise terms and conditions for copying, distribution and 63 | modification follow. 64 | 65 | ### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 66 | 67 | **0.** This License applies to any program or other work which contains 68 | a notice placed by the copyright holder saying it may be distributed 69 | under the terms of this General Public License. The “Program”, below, 70 | refers to any such program or work, and a “work based on the Program” 71 | means either the Program or any derivative work under copyright law: 72 | that is to say, a work containing the Program or a portion of it, 73 | either verbatim or with modifications and/or translated into another 74 | language. (Hereinafter, translation is included without limitation in 75 | the term “modification”.) Each licensee is addressed as “you”. 76 | 77 | Activities other than copying, distribution and modification are not 78 | covered by this License; they are outside its scope. The act of 79 | running the Program is not restricted, and the output from the Program 80 | is covered only if its contents constitute a work based on the 81 | Program (independent of having been made by running the Program). 82 | Whether that is true depends on what the Program does. 83 | 84 | **1.** You may copy and distribute verbatim copies of the Program's 85 | source code as you receive it, in any medium, provided that you 86 | conspicuously and appropriately publish on each copy an appropriate 87 | copyright notice and disclaimer of warranty; keep intact all the 88 | notices that refer to this License and to the absence of any warranty; 89 | and give any other recipients of the Program a copy of this License 90 | along with the Program. 91 | 92 | You may charge a fee for the physical act of transferring a copy, and 93 | you may at your option offer warranty protection in exchange for a fee. 94 | 95 | **2.** You may modify your copy or copies of the Program or any portion 96 | of it, thus forming a work based on the Program, and copy and 97 | distribute such modifications or work under the terms of Section 1 98 | above, provided that you also meet all of these conditions: 99 | 100 | * **a)** You must cause the modified files to carry prominent notices 101 | stating that you changed the files and the date of any change. 102 | * **b)** You must cause any work that you distribute or publish, that in 103 | whole or in part contains or is derived from the Program or any 104 | part thereof, to be licensed as a whole at no charge to all third 105 | parties under the terms of this License. 106 | * **c)** If the modified program normally reads commands interactively 107 | when run, you must cause it, when started running for such 108 | interactive use in the most ordinary way, to print or display an 109 | announcement including an appropriate copyright notice and a 110 | notice that there is no warranty (or else, saying that you provide 111 | a warranty) and that users may redistribute the program under 112 | these conditions, and telling the user how to view a copy of this 113 | License. (Exception: if the Program itself is interactive but 114 | does not normally print such an announcement, your work based on 115 | the Program is not required to print an announcement.) 116 | 117 | These requirements apply to the modified work as a whole. If 118 | identifiable sections of that work are not derived from the Program, 119 | and can be reasonably considered independent and separate works in 120 | themselves, then this License, and its terms, do not apply to those 121 | sections when you distribute them as separate works. But when you 122 | distribute the same sections as part of a whole which is a work based 123 | on the Program, the distribution of the whole must be on the terms of 124 | this License, whose permissions for other licensees extend to the 125 | entire whole, and thus to each and every part regardless of who wrote it. 126 | 127 | Thus, it is not the intent of this section to claim rights or contest 128 | your rights to work written entirely by you; rather, the intent is to 129 | exercise the right to control the distribution of derivative or 130 | collective works based on the Program. 131 | 132 | In addition, mere aggregation of another work not based on the Program 133 | with the Program (or with a work based on the Program) on a volume of 134 | a storage or distribution medium does not bring the other work under 135 | the scope of this License. 136 | 137 | **3.** You may copy and distribute the Program (or a work based on it, 138 | under Section 2) in object code or executable form under the terms of 139 | Sections 1 and 2 above provided that you also do one of the following: 140 | 141 | * **a)** Accompany it with the complete corresponding machine-readable 142 | source code, which must be distributed under the terms of Sections 143 | 1 and 2 above on a medium customarily used for software interchange; or, 144 | * **b)** Accompany it with a written offer, valid for at least three 145 | years, to give any third party, for a charge no more than your 146 | cost of physically performing source distribution, a complete 147 | machine-readable copy of the corresponding source code, to be 148 | distributed under the terms of Sections 1 and 2 above on a medium 149 | customarily used for software interchange; or, 150 | * **c)** Accompany it with the information you received as to the offer 151 | to distribute corresponding source code. (This alternative is 152 | allowed only for noncommercial distribution and only if you 153 | received the program in object code or executable form with such 154 | an offer, in accord with Subsection b above.) 155 | 156 | The source code for a work means the preferred form of the work for 157 | making modifications to it. For an executable work, complete source 158 | code means all the source code for all modules it contains, plus any 159 | associated interface definition files, plus the scripts used to 160 | control compilation and installation of the executable. However, as a 161 | special exception, the source code distributed need not include 162 | anything that is normally distributed (in either source or binary 163 | form) with the major components (compiler, kernel, and so on) of the 164 | operating system on which the executable runs, unless that component 165 | itself accompanies the executable. 166 | 167 | If distribution of executable or object code is made by offering 168 | access to copy from a designated place, then offering equivalent 169 | access to copy the source code from the same place counts as 170 | distribution of the source code, even though third parties are not 171 | compelled to copy the source along with the object code. 172 | 173 | **4.** You may not copy, modify, sublicense, or distribute the Program 174 | except as expressly provided under this License. Any attempt 175 | otherwise to copy, modify, sublicense or distribute the Program is 176 | void, and will automatically terminate your rights under this License. 177 | However, parties who have received copies, or rights, from you under 178 | this License will not have their licenses terminated so long as such 179 | parties remain in full compliance. 180 | 181 | **5.** You are not required to accept this License, since you have not 182 | signed it. However, nothing else grants you permission to modify or 183 | distribute the Program or its derivative works. These actions are 184 | prohibited by law if you do not accept this License. Therefore, by 185 | modifying or distributing the Program (or any work based on the 186 | Program), you indicate your acceptance of this License to do so, and 187 | all its terms and conditions for copying, distributing or modifying 188 | the Program or works based on it. 189 | 190 | **6.** Each time you redistribute the Program (or any work based on the 191 | Program), the recipient automatically receives a license from the 192 | original licensor to copy, distribute or modify the Program subject to 193 | these terms and conditions. You may not impose any further 194 | restrictions on the recipients' exercise of the rights granted herein. 195 | You are not responsible for enforcing compliance by third parties to 196 | this License. 197 | 198 | **7.** If, as a consequence of a court judgment or allegation of patent 199 | infringement or for any other reason (not limited to patent issues), 200 | conditions are imposed on you (whether by court order, agreement or 201 | otherwise) that contradict the conditions of this License, they do not 202 | excuse you from the conditions of this License. If you cannot 203 | distribute so as to satisfy simultaneously your obligations under this 204 | License and any other pertinent obligations, then as a consequence you 205 | may not distribute the Program at all. For example, if a patent 206 | license would not permit royalty-free redistribution of the Program by 207 | all those who receive copies directly or indirectly through you, then 208 | the only way you could satisfy both it and this License would be to 209 | refrain entirely from distribution of the Program. 210 | 211 | If any portion of this section is held invalid or unenforceable under 212 | any particular circumstance, the balance of the section is intended to 213 | apply and the section as a whole is intended to apply in other 214 | circumstances. 215 | 216 | It is not the purpose of this section to induce you to infringe any 217 | patents or other property right claims or to contest validity of any 218 | such claims; this section has the sole purpose of protecting the 219 | integrity of the free software distribution system, which is 220 | implemented by public license practices. Many people have made 221 | generous contributions to the wide range of software distributed 222 | through that system in reliance on consistent application of that 223 | system; it is up to the author/donor to decide if he or she is willing 224 | to distribute software through any other system and a licensee cannot 225 | impose that choice. 226 | 227 | This section is intended to make thoroughly clear what is believed to 228 | be a consequence of the rest of this License. 229 | 230 | **8.** If the distribution and/or use of the Program is restricted in 231 | certain countries either by patents or by copyrighted interfaces, the 232 | original copyright holder who places the Program under this License 233 | may add an explicit geographical distribution limitation excluding 234 | those countries, so that distribution is permitted only in or among 235 | countries not thus excluded. In such case, this License incorporates 236 | the limitation as if written in the body of this License. 237 | 238 | **9.** The Free Software Foundation may publish revised and/or new versions 239 | of the General Public License from time to time. Such new versions will 240 | be similar in spirit to the present version, but may differ in detail to 241 | address new problems or concerns. 242 | 243 | Each version is given a distinguishing version number. If the Program 244 | specifies a version number of this License which applies to it and “any 245 | later version”, you have the option of following the terms and conditions 246 | either of that version or of any later version published by the Free 247 | Software Foundation. If the Program does not specify a version number of 248 | this License, you may choose any version ever published by the Free Software 249 | Foundation. 250 | 251 | **10.** If you wish to incorporate parts of the Program into other free 252 | programs whose distribution conditions are different, write to the author 253 | to ask for permission. For software which is copyrighted by the Free 254 | Software Foundation, write to the Free Software Foundation; we sometimes 255 | make exceptions for this. Our decision will be guided by the two goals 256 | of preserving the free status of all derivatives of our free software and 257 | of promoting the sharing and reuse of software generally. 258 | 259 | ### NO WARRANTY 260 | 261 | **11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 262 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 263 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 264 | PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 265 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 266 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 267 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 268 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 269 | REPAIR OR CORRECTION. 270 | 271 | **12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 272 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 273 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 274 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 275 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 276 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 277 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 278 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 279 | POSSIBILITY OF SUCH DAMAGES. 280 | 281 | END OF TERMS AND CONDITIONS 282 | 283 | ### How to Apply These Terms to Your New Programs 284 | 285 | If you develop a new program, and you want it to be of the greatest 286 | possible use to the public, the best way to achieve this is to make it 287 | free software which everyone can redistribute and change under these terms. 288 | 289 | To do so, attach the following notices to the program. It is safest 290 | to attach them to the start of each source file to most effectively 291 | convey the exclusion of warranty; and each file should have at least 292 | the “copyright” line and a pointer to where the full notice is found. 293 | 294 | 295 | Copyright (C) 296 | 297 | This program is free software; you can redistribute it and/or modify 298 | it under the terms of the GNU General Public License as published by 299 | the Free Software Foundation; either version 2 of the License, or 300 | (at your option) any later version. 301 | 302 | This program is distributed in the hope that it will be useful, 303 | but WITHOUT ANY WARRANTY; without even the implied warranty of 304 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 305 | GNU General Public License for more details. 306 | 307 | You should have received a copy of the GNU General Public License along 308 | with this program; if not, write to the Free Software Foundation, Inc., 309 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 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) year 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 Lesser General 340 | Public License instead of this License. 341 | 342 | -------------------------------------------------------------------------------- /webusb-ftdi.js: -------------------------------------------------------------------------------- 1 | /* 2 | WebUSB FTDI Driver v0.01a 3 | (C) 2020 Shaped Technologies (Jai B.) 4 | 5 | GPL v2 free for personal use / commercial or closed source use requires commercial license - contact us. 6 | 7 | This wouldn't have been possible without the Linux driver, so shoutout to the developers of that! 8 | 9 | Data Transfer Efficiency / Bulk Transfers Technical Note 10 | https://www.ftdichip.com/Support/Documents/TechnicalNotes/TN_103_FTDI_USB_Data_Transfer_Efficiency(FT_000097).pdf 11 | 12 | Chipset feature comparison: 13 | https://www.ftdichip.com/Support/Documents/TechnicalNotes/TN_107%20FTDI_Chipset_Feature_Comparison.pdf 14 | 15 | https://www.ftdichip.com/Support/Documents/AppNotes/AN232B-04_DataLatencyFlow.pdf 16 | 17 | */ 18 | 19 | /* 20 | 21 | USB_SETUP_HOST_TO_DEVICE 0x00 Transfer direction: host to device 22 | USB_SETUP_DEVICE_TO_HOST 0x80 Transfer direction: device to host 23 | USB_SETUP_TYPE_STANDARD 0x00 Type: standard 24 | USB_SETUP_TYPE_CLASS 0x20 Type: class 25 | USB_SETUP_TYPE_VENDOR 0x40 Type: vendor 26 | USB_SETUP_RECIPIENT_DEVICE 0x00 Recipient: device 27 | USB_SETUP_RECIPIENT_INTERFACE 0x01 Recipient: interface 28 | USB_SETUP_RECIPIENT_ENDPOINT 0x02 Recipient: endpoint 29 | USB_SETUP_RECIPIENT_OTHER 0x03 Recipient: other 30 | 31 | */ 32 | 33 | class WebUSBSerialPort { 34 | /* Commands */ 35 | #FTDI_SIO_RESET = 0x00; /* Reset the port */ 36 | #FTDI_SIO_MODEM_CTRL = 0x01; /* Set the modem control register */ 37 | #FTDI_SIO_SET_FLOW_CTRL = 0x02; /* Set flow control register */ 38 | #FTDI_SIO_SET_BAUD_RATE = 0x03; /* Set baud rate */ 39 | #FTDI_SIO_SET_DATA = 0x04; /* Set the data characteristics of the port */ 40 | #FTDI_SIO_GET_MODEM_STATUS = 0x05; /* Retrieve current value of modem status register */ 41 | #FTDI_SIO_SET_EVENT_CHAR = 0x06; /* Set the event character */ 42 | #FTDI_SIO_SET_ERROR_CHAR = 0x07; /* Set the error character */ 43 | #FTDI_SIO_SET_LATENCY_TIMER = 0x09; /* Set the latency timer */ 44 | #FTDI_SIO_GET_LATENCY_TIMER = 0x0a; /* Get the latency timer */ 45 | #FTDI_SIO_SET_BITMODE = 0x0b; /* Set bitbang mode */ 46 | #FTDI_SIO_READ_PINS = 0x0c; /* Read immediate value of pins */ 47 | #FTDI_SIO_READ_EEPROM = 0x90; /* Read EEPROM */ 48 | 49 | /* not in linux driver? */ 50 | #FTDI_BitMode_Reset = 0x00; 51 | #FTDI_BitMode_BitBang = 0x01; 52 | #FTDI_BitMode_MPSSE = 0x02; 53 | #FTDI_BitMode_SyncBitBang = 0x04; 54 | #FTDI_BitMode_MCU = 0x08; 55 | #FTDI_BitMode_Opto = 0x10; 56 | #FTDI_BitMode_CBus = 0x20; 57 | #FTDI_BitMode_SyncFIFO = 0x40; 58 | 59 | /* Interface indices for FT2232, FT2232H and FT4232H devices */ 60 | #INTERFACE_A = 1; 61 | #INTERFACE_B = 2; 62 | #INTERFACE_C = 3; 63 | #INTERFACE_D = 4; 64 | 65 | /* Port Identifier Table */ 66 | #PIT_DEFAULT = 0; /* SIOA */ 67 | #PIT_SIOA = 1; /* SIOA */ 68 | 69 | /* The device this driver is tested with one has only one port */ 70 | #PIT_SIOB = 2; /* SIOB */ 71 | #PIT_PARALLEL = 3; /* Parallel */ 72 | 73 | /* FTDI_SIO_RESET 74 | BmRequestType: 0100 0000B 75 | bRequest: FTDI_SIO_RESET 76 | wValue: Control Value 77 | 0 = Reset SIO 78 | 1 = Purge RX buffer 79 | 2 = Purge TX buffer 80 | wIndex: Port 81 | wLength: 0 82 | Data: None 83 | 84 | The Reset SIO command has this effect: 85 | 86 | Sets flow control set to 'none' 87 | Event char = $0D 88 | Event trigger = disabled 89 | Purge RX buffer 90 | Purge TX buffer 91 | Clear DTR 92 | Clear RTS 93 | baud and data format not reset 94 | 95 | The Purge RX and TX buffer commands affect nothing except the buffers 96 | 97 | */ 98 | #FTDI_SIO_RESET_REQUEST = this.#FTDI_SIO_RESET; 99 | #FTDI_SIO_RESET_REQUEST_TYPE = 'vendor'; 100 | #FTDI_SIO_RESET_SIO = 0; 101 | #FTDI_SIO_RESET_PURGE_RX = 1; 102 | #FTDI_SIO_RESET_PURGE_TX = 2; 103 | 104 | /* FTDI_SIO_SET_BAUDRATE */ 105 | #FTDI_SIO_SET_BAUDRATE_REQUEST = 0x03; 106 | 107 | 108 | #ftdi_chip_type = { 109 | SIO : 1, 110 | FT8U232AM : 2, 111 | FT232BM : 3, 112 | FT2232C : 4, 113 | FT232RL : 5, 114 | FT2232H : 6, 115 | FT4232H : 7, 116 | FT232H : 8, 117 | FTX : 9 118 | }; 119 | 120 | /* 121 | BmRequestType: 0100 0000B 122 | bRequest: FTDI_SIO_SET_BAUDRATE 123 | wValue: BaudDivisor value - see below 124 | wIndex: Port 125 | wLength: 0 126 | Data: None 127 | The BaudDivisor values are calculated as follows: 128 | - BaseClock is either 12000000 or 48000000 depending on the device. 129 | FIXME: I wish I knew how to detect old chips to select proper base clock! 130 | - BaudDivisor is a fixed point number encoded in a funny way. 131 | (--WRONG WAY OF THINKING--) 132 | BaudDivisor is a fixed point number encoded with following bit weighs: 133 | (-2)(-1)(13..0). It is a radical with a denominator of 4, so values 134 | end with 0.0 (00...), 0.25 (10...), 0.5 (01...), and 0.75 (11...). 135 | (--THE REALITY--) 136 | The both-bits-set has quite different meaning from 0.75 - the chip 137 | designers have decided it to mean 0.125 instead of 0.75. 138 | This info looked up in FTDI application note "FT8U232 DEVICES \ Data Rates 139 | and Flow Control Consideration for USB to RS232". 140 | - BaudDivisor = (BaseClock / 16) / BaudRate, where the (=) operation should 141 | automagically re-encode the resulting value to take fractions into 142 | consideration. 143 | As all values are integers, some bit twiddling is in order: 144 | BaudDivisor = (BaseClock / 16 / BaudRate) | 145 | (((BaseClock / 2 / BaudRate) & 4) ? 0x4000 // 0.5 146 | : ((BaseClock / 2 / BaudRate) & 2) ? 0x8000 // 0.25 147 | : ((BaseClock / 2 / BaudRate) & 1) ? 0xc000 // 0.125 148 | : 0) 149 | 150 | For the FT232BM, a 17th divisor bit was introduced to encode the multiples 151 | of 0.125 missing from the FT8U232AM. Bits 16 to 14 are coded as follows 152 | (the first four codes are the same as for the FT8U232AM, where bit 16 is 153 | always 0): 154 | 000 - add .000 to divisor 155 | 001 - add .500 to divisor 156 | 010 - add .250 to divisor 157 | 011 - add .125 to divisor 158 | 100 - add .375 to divisor 159 | 101 - add .625 to divisor 160 | 110 - add .750 to divisor 161 | 111 - add .875 to divisor 162 | Bits 15 to 0 of the 17-bit divisor are placed in the urb value. Bit 16 is 163 | placed in bit 0 of the urb index. 164 | 165 | Note that there are a couple of special cases to support the highest baud 166 | rates. If the calculated divisor value is 1, this needs to be replaced with 167 | 0. Additionally for the FT232BM, if the calculated divisor value is 0x4001 168 | (1.5), this needs to be replaced with 0x0001 (1) (but this divisor value is 169 | not supported by the FT8U232AM). 170 | */ 171 | #ftdi_sio_baudrate = { 172 | ftdi_sio_b300 : 0, 173 | ftdi_sio_b600 : 1, 174 | ftdi_sio_b1200 : 2, 175 | ftdi_sio_b2400 : 3, 176 | ftdi_sio_b4800 : 4, 177 | ftdi_sio_b9600 : 5, 178 | ftdi_sio_b19200 : 6, 179 | ftdi_sio_b38400 : 7, 180 | ftdi_sio_b57600 : 8, 181 | ftdi_sio_b115200 : 9 182 | }; 183 | 184 | /* FTDI_SIO_SET_DATA 185 | BmRequestType: 0100 0000B 186 | bRequest: FTDI_SIO_SET_DATA 187 | wValue: Data characteristics (see below) 188 | wIndex: Port 189 | wLength: 0 190 | Data: No 191 | 192 | Data characteristics 193 | 194 | B0..7 Number of data bits 195 | B8..10 Parity 196 | 0 = None 197 | 1 = Odd 198 | 2 = Even 199 | 3 = Mark 200 | 4 = Space 201 | B11..13 Stop Bits 202 | 0 = 1 203 | 1 = 1.5 204 | 2 = 2 205 | B14 206 | 1 = TX ON (break) 207 | 0 = TX OFF (normal state) 208 | B15 Reserved 209 | 210 | */ 211 | #FTDI_SIO_SET_DATA_REQUEST = this.#FTDI_SIO_SET_DATA; 212 | #FTDI_SIO_SET_DATA_PARITY_NONE = (0x0 << 8); 213 | #FTDI_SIO_SET_DATA_PARITY_ODD = (0x1 << 8); 214 | #FTDI_SIO_SET_DATA_PARITY_EVEN = (0x2 << 8); 215 | #FTDI_SIO_SET_DATA_PARITY_MARK = (0x3 << 8); 216 | #FTDI_SIO_SET_DATA_PARITY_SPACE = (0x4 << 8); 217 | #FTDI_SIO_SET_DATA_STOP_BITS_1 = (0x0 << 11); 218 | #FTDI_SIO_SET_DATA_STOP_BITS_15 = (0x1 << 11); 219 | #FTDI_SIO_SET_DATA_STOP_BITS_2 = (0x2 << 11); 220 | #FTDI_SIO_SET_BREAK = (0x1 << 14); 221 | 222 | /* FTDI_SIO_MODEM_CTRL 223 | 224 | BmRequestType: 0100 0000B 225 | bRequest: FTDI_SIO_MODEM_CTRL 226 | wValue: ControlValue (see below) 227 | wIndex: Port 228 | wLength: 0 229 | Data: None 230 | 231 | NOTE: If the device is in RTS/CTS flow control, the RTS set by this 232 | command will be IGNORED without an error being returned 233 | Also - you can not set DTR and RTS with one control message 234 | */ 235 | #FTDI_SIO_SET_MODEM_CTRL_REQUEST = this.#FTDI_SIO_MODEM_CTRL; 236 | 237 | /* 238 | ControlValue 239 | B0 DTR state 240 | 0 = reset 241 | 1 = set 242 | B1 RTS state 243 | 0 = reset 244 | 1 = set 245 | B2..7 Reserved 246 | B8 DTR state enable 247 | 0 = ignore 248 | 1 = use DTR state 249 | B9 RTS state enable 250 | 0 = ignore 251 | 1 = use RTS state 252 | B10..15 Reserved 253 | */ 254 | 255 | #FTDI_SIO_SET_DTR_MASK = 0x1; 256 | #FTDI_SIO_SET_DTR_HIGH = ((this.#FTDI_SIO_SET_DTR_MASK << 8) | 1); 257 | #FTDI_SIO_SET_DTR_LOW = ((this.#FTDI_SIO_SET_DTR_MASK << 8) | 0); 258 | #FTDI_SIO_SET_RTS_MASK = 0x2; 259 | #FTDI_SIO_SET_RTS_HIGH = ((this.#FTDI_SIO_SET_RTS_MASK << 8) | 2); 260 | #FTDI_SIO_SET_RTS_LOW = ((this.#FTDI_SIO_SET_RTS_MASK << 8) | 0); 261 | 262 | /* FTDI_SIO_SET_FLOW_CTRL 263 | BmRequestType: 0100 0000b 264 | bRequest: FTDI_SIO_SET_FLOW_CTRL 265 | wValue: Xoff/Xon 266 | wIndex: Protocol/Port - hIndex is protocol / lIndex is port 267 | wLength: 0 268 | Data: None 269 | 270 | hIndex protocol is: 271 | B0 Output handshaking using RTS/CTS 272 | 0 = disabled 273 | 1 = enabled 274 | B1 Output handshaking using DTR/DSR 275 | 0 = disabled 276 | 1 = enabled 277 | B2 Xon/Xoff handshaking 278 | 0 = disabled 279 | 1 = enabled 280 | 281 | A value of zero in the hIndex field disables handshaking 282 | 283 | If Xon/Xoff handshaking is specified, the hValue field should contain the 284 | XOFF character and the lValue field contains the XON character. 285 | */ 286 | #FTDI_SIO_SET_FLOW_CTRL_REQUEST = this.#FTDI_SIO_SET_FLOW_CTRL; 287 | #FTDI_SIO_DISABLE_FLOW_CTRL = 0x0; 288 | #FTDI_SIO_RTS_CTS_HS = (0x1 << 8); 289 | #FTDI_SIO_DTR_DSR_HS = (0x2 << 8); 290 | #FTDI_SIO_XON_XOFF_HS = (0x4 << 8); 291 | 292 | /* 293 | FTDI_SIO_GET_LATENCY_TIMER 294 | 295 | Set the timeout interval. The FTDI collects data from the 296 | device, transmitting it to the host when either A) 62 bytes are 297 | received, or B) the timeout interval has elapsed and the buffer 298 | contains at least 1 byte. Setting this value to a small number 299 | can dramatically improve performance for applications which send 300 | small packets, since the default value is 16ms. 301 | 302 | BmRequestType: 1100 0000b 303 | bRequest: FTDI_SIO_GET_LATENCY_TIMER 304 | wValue: 0 305 | wIndex: Port 306 | wLength: 0 307 | Data: latency (on return) 308 | */ 309 | #FTDI_SIO_GET_LATENCY_TIMER_REQUEST = this.#FTDI_SIO_GET_LATENCY_TIMER; 310 | 311 | /* 312 | FTDI_SIO_SET_LATENCY_TIMER 313 | 314 | Set the timeout interval. The FTDI collects data from the 315 | device, transmitting it to the host when either A) 62 bytes are 316 | received, or B) the timeout interval has elapsed and the buffer 317 | contains at least 1 byte. Setting this value to a small number 318 | can dramatically improve performance for applications which send 319 | small packets, since the default value is 16ms. 320 | 321 | BmRequestType: 0100 0000b 322 | bRequest: FTDI_SIO_SET_LATENCY_TIMER 323 | wValue: Latency (milliseconds) 324 | wIndex: Port 325 | wLength: 0 326 | Data: None 327 | 328 | wValue: 329 | B0..7 Latency timer 330 | B8..15 0 331 | 332 | */ 333 | #FTDI_SIO_SET_LATENCY_TIMER_REQUEST = this.#FTDI_SIO_SET_LATENCY_TIMER; 334 | 335 | 336 | /* 337 | FTDI_SIO_SET_EVENT_CHAR 338 | 339 | Set the special event character for the specified communications port. 340 | If the device sees this character it will immediately return the 341 | data read so far - rather than wait 40ms or until 62 bytes are read 342 | which is what normally happens. 343 | 344 | BmRequestType: 0100 0000b 345 | bRequest: FTDI_SIO_SET_EVENT_CHAR 346 | wValue: EventChar 347 | wIndex: Port 348 | wLength: 0 349 | Data: None 350 | 351 | wValue: 352 | B0..7 Event Character 353 | B8 Event Character Processing 354 | 0 = disabled 355 | 1 = enabled 356 | B9..15 Reserved 357 | 358 | FTDI_SIO_SET_ERROR_CHAR 359 | Set the parity error replacement character for the specified communications 360 | port 361 | BmRequestType: 0100 0000b 362 | bRequest: FTDI_SIO_SET_EVENT_CHAR 363 | wValue: Error Char 364 | wIndex: Port 365 | wLength: 0 366 | Data: None 367 | 368 | Error Char 369 | B0..7 Error Character 370 | B8 Error Character Processing 371 | 0 = disabled 372 | 1 = enabled 373 | B9..15 Reserved 374 | 375 | */ 376 | 377 | #FTDI_SIO_SET_EVENT_CHAR_REQUEST = this.#FTDI_SIO_SET_EVENT_CHAR; 378 | 379 | 380 | /* FTDI_SIO_GET_MODEM_STATUS 381 | Retrieve the current value of the modem status register 382 | BmRequestType: 1100 0000b 383 | bRequest: FTDI_SIO_GET_MODEM_STATUS 384 | wValue: zero 385 | wIndex: Port 386 | wLength: 1 387 | Data: Status 388 | 389 | One byte of data is returned 390 | B0..3 0 391 | B4 CTS 392 | 0 = inactive 393 | 1 = active 394 | B5 DSR 395 | 0 = inactive 396 | 1 = active 397 | B6 Ring Indicator (RI) 398 | 0 = inactive 399 | 1 = active 400 | B7 Receive Line Signal Detect (RLSD) 401 | 0 = inactive 402 | 1 = active 403 | */ 404 | 405 | #FTDI_SIO_GET_MODEM_STATUS_REQUEST = this.#FTDI_SIO_GET_MODEM_STATUS; 406 | #FTDI_SIO_CTS_MASK = 0x10; 407 | #FTDI_SIO_DSR_MASK = 0x20; 408 | #FTDI_SIO_RI_MASK = 0x40; 409 | #FTDI_SIO_RLSD_MASK = 0x80; 410 | 411 | /* FTDI_SIO_SET_BITMODE */ 412 | #FTDI_SIO_SET_BITMODE_REQUEST = this.#FTDI_SIO_SET_BITMODE; 413 | 414 | /* Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST */ 415 | #FTDI_SIO_BITMODE_RESET = 0x00; 416 | #FTDI_SIO_BITMODE_CBUS = 0x20; 417 | 418 | /* FTDI_SIO_READ_PINS */ 419 | #FTDI_SIO_READ_PINS_REQUEST = this.#FTDI_SIO_READ_PINS; 420 | 421 | /* 422 | * FTDI_SIO_READ_EEPROM 423 | * 424 | * EEPROM format found in FTDI AN_201, "FT-X MTP memory Configuration", 425 | * http://www.ftdichip.com/Support/Documents/AppNotes/AN_201_FT-X%20MTP%20Memory%20Configuration.pdf 426 | */ 427 | #FTDI_SIO_READ_EEPROM_REQUEST = this.#FTDI_SIO_READ_EEPROM; 428 | 429 | #FTDI_FTX_CBUS_MUX_GPIO = 0x8; 430 | #FTDI_FT232R_CBUS_MUX_GPIO = 0xa; 431 | 432 | /* Descriptors returned by the device 433 | 434 | Device Descriptor 435 | 436 | Offset Field Size Value Description 437 | 0 bLength 1 0x12 Size of descriptor in bytes 438 | 1 bDescriptorType 1 0x01 DEVICE Descriptor Type 439 | 2 bcdUSB 2 0x0110 USB Spec Release Number 440 | 4 bDeviceClass 1 0x00 Class Code 441 | 5 bDeviceSubClass 1 0x00 SubClass Code 442 | 6 bDeviceProtocol 1 0x00 Protocol Code 443 | 7 bMaxPacketSize0 1 0x08 Maximum packet size for endpoint 0 444 | 8 idVendor 2 0x0403 Vendor ID 445 | 10 idProduct 2 0x8372 Product ID (FTDI_SIO_PID) 446 | 12 bcdDevice 2 0x0001 Device release number 447 | 14 iManufacturer 1 0x01 Index of man. string desc 448 | 15 iProduct 1 0x02 Index of prod string desc 449 | 16 iSerialNumber 1 0x02 Index of serial nmr string desc 450 | 17 bNumConfigurations 1 0x01 Number of possible configurations 451 | 452 | Configuration Descriptor 453 | 454 | Offset Field Size Value 455 | 0 bLength 1 0x09 Size of descriptor in bytes 456 | 1 bDescriptorType 1 0x02 CONFIGURATION Descriptor Type 457 | 2 wTotalLength 2 0x0020 Total length of data 458 | 4 bNumInterfaces 1 0x01 Number of interfaces supported 459 | 5 bConfigurationValue 1 0x01 Argument for SetCOnfiguration() req 460 | 6 iConfiguration 1 0x02 Index of config string descriptor 461 | 7 bmAttributes 1 0x20 Config characteristics Remote Wakeup 462 | 8 MaxPower 1 0x1E Max power consumption 463 | 464 | Interface Descriptor 465 | 466 | Offset Field Size Value 467 | 0 bLength 1 0x09 Size of descriptor in bytes 468 | 1 bDescriptorType 1 0x04 INTERFACE Descriptor Type 469 | 2 bInterfaceNumber 1 0x00 Number of interface 470 | 3 bAlternateSetting 1 0x00 Value used to select alternate 471 | 4 bNumEndpoints 1 0x02 Number of endpoints 472 | 5 bInterfaceClass 1 0xFF Class Code 473 | 6 bInterfaceSubClass 1 0xFF Subclass Code 474 | 7 bInterfaceProtocol 1 0xFF Protocol Code 475 | 8 iInterface 1 0x02 Index of interface string description 476 | 477 | IN Endpoint Descriptor 478 | 479 | Offset Field Size Value 480 | 0 bLength 1 0x07 Size of descriptor in bytes 481 | 1 bDescriptorType 1 0x05 ENDPOINT descriptor type 482 | 2 bEndpointAddress 1 0x82 Address of endpoint 483 | 3 bmAttributes 1 0x02 Endpoint attributes - Bulk 484 | 4 bNumEndpoints 2 0x0040 maximum packet size 485 | 5 bInterval 1 0x00 Interval for polling endpoint 486 | 487 | OUT Endpoint Descriptor 488 | 489 | Offset Field Size Value 490 | 0 bLength 1 0x07 Size of descriptor in bytes 491 | 1 bDescriptorType 1 0x05 ENDPOINT descriptor type 492 | 2 bEndpointAddress 1 0x02 Address of endpoint 493 | 3 bmAttributes 1 0x02 Endpoint attributes - Bulk 494 | 4 bNumEndpoints 2 0x0040 maximum packet size 495 | 5 bInterval 1 0x00 Interval for polling endpoint 496 | 497 | DATA FORMAT 498 | 499 | IN Endpoint 500 | 501 | The device reserves the first two bytes of data on this endpoint to contain 502 | the current values of the modem and line status registers. In the absence of 503 | data, the device generates a message consisting of these two status bytes 504 | every 40 ms *** (maybe 16ms for newer/higher clkd dev?) 505 | 506 | *** According to TN103: 507 | 508 | FTDI devices will return data to the host in 2 cases: 509 | •The IC has a full buffer of data to send back to the host. (64 bytes minus 2 status bytes) 510 | •The latency timer has expired. (default 16ms on windows driver; don't konw if this is device default) 511 | - 16ms latency timer fucks with ISR (maybe others?) datalogging normally with HTS 512 | 513 | The latency timer acts as a timeout on the receive buffer which will trigger the transmission 514 | of any data in the chip’s receive buffer back to the host. 515 | 516 | The latency timer acts as a timeout on the receive buffer which will trigger the transmission 517 | of any data in the chip’s receive buffer back to the host. In cases when the amount of data 518 | being received is minimal, this prevents applications from having to wait a long time for a 519 | full packet. 520 | 521 | If the receive buffer of the chip is empty when the latency timer expires, 2 status 522 | bytes are returned which contain the modem status and line status of the UART. For FT245 523 | devices, these bytes are still returned but have no meaning. If the latency timer is expiring 524 | before the receive buffer is full, short USB packets will be returned to the host. As this is 525 | not the most efficient packet size, this may be unsuitable for some applications. 526 | 527 | For example, a UART receiving data at 9600 baud with a default latency timer value (16ms) will 528 | generate USB packets of around 16 bytes before the latency timer expires and transmits the 529 | data available back to the PC. If 64 byte IN packets were desired to minimise the number of 530 | INs required to complete a read,the packet size could be increased by increasing the value of 531 | the latency timer. In this case, a value greater than 64ms would be sufficient for the chip to 532 | transmit full USB packets back to the host assuming data was constantly being received by the 533 | UART. 534 | 535 | In the case of FTDI’s USB-UART devices, the IN packet size may appear to be dependent 536 | on baud rate. This is not the case: it is simply that the UART may receive data faster at a 537 | higher baud rate and thus has a better chance of filling the buffer before the latency 538 | timer expires 539 | 540 | When optimising data throughput for FTDI devices, the following factors should be considered: 541 | •Send as much data to the IC from the host application as possible in a single write. 542 | This will maximise the size of the data packets being sent to the device and hence minimise 543 | the number of packets required and time to transfer an amount of data. 544 | 545 | •Set the latency timer to a value appropriate for the application. Note that a low latency 546 | timer value may result in many short incoming USB packets rather than a single large packet, 547 | thus diminishing performance 548 | 549 | Byte 0: Modem Status 550 | 551 | Offset Description 552 | B0 Reserved - must be 1 553 | B1 Reserved - must be 0 554 | B2 Reserved - must be 0 555 | B3 Reserved - must be 0 556 | B4 Clear to Send (CTS) 557 | B5 Data Set Ready (DSR) 558 | B6 Ring Indicator (RI) 559 | B7 Receive Line Signal Detect (RLSD) 560 | 561 | Byte 1: Line Status 562 | 563 | Offset Description 564 | B0 Data Ready (DR) 565 | B1 Overrun Error (OE) 566 | B2 Parity Error (PE) 567 | B3 Framing Error (FE) 568 | B4 Break Interrupt (BI) 569 | B5 Transmitter Holding Register (THRE) 570 | B6 Transmitter Empty (TEMT) 571 | B7 Error in RCVR FIFO 572 | 573 | */ 574 | #FTDI_RS0_CTS = (1 << 4); 575 | #FTDI_RS0_DSR = (1 << 5); 576 | #FTDI_RS0_RI = (1 << 6); 577 | #FTDI_RS0_RLSD = (1 << 7); 578 | 579 | #FTDI_RS_DR = 1; 580 | #FTDI_RS_OE = (1 << 1); 581 | #FTDI_RS_PE = (1 << 2); 582 | #FTDI_RS_FE = (1 << 3); 583 | #FTDI_RS_BI = (1 << 4); 584 | #FTDI_RS_THRE = (1 << 5); 585 | #FTDI_RS_TEMT = (1 << 6); 586 | #FTDI_RS_FIFO = (1 << 7); 587 | 588 | /* 589 | * OUT Endpoint 590 | * 591 | * This device reserves the first bytes of data on this endpoint contain the 592 | * length and port identifier of the message. For the FTDI USB Serial converter 593 | * the port identifier is always 1. 594 | * 595 | * Byte 0: Line Status 596 | * 597 | * Offset Description 598 | * B0 Reserved - must be 1 599 | * B1 Reserved - must be 0 600 | * B2..7 Length of message - (not including Byte 0) 601 | * 602 | */ 603 | 604 | constructor(device, portConfiguration) { 605 | this.device = device; 606 | this.portConfiguration = portConfiguration; 607 | 608 | this.interfaceNumber = 0; 609 | this.endpointIn = 0; 610 | this.endpointOut = 0; 611 | 612 | this.modemStatusByte = 0; 613 | this.lineStatusByte = 0; 614 | 615 | this.packetsReceived = 0; 616 | } 617 | 618 | connect(receiveCallback, errorCallback) { 619 | this.onReceive = receiveCallback; 620 | this.onReceiveError = errorCallback; 621 | 622 | let readLoop = () => { 623 | this.device.transferIn(this.endpointIn, 64).then(result => { 624 | //console.log("Modem Status Byte:"+this.result.data[0]) 625 | //console.log("Line Status Byte:"+this.result.data[1]) 626 | let resultArray = new Uint8Array(result.data.buffer); 627 | 628 | if (resultArray[0] != this.modemStatusByte) 629 | this.modemStatusByte = resultArray[0]; 630 | 631 | if (resultArray[1] != this.lineStatusByte) 632 | this.lineStatusByte = resultArray[1]; 633 | 634 | if (resultArray.length > 2) { 635 | let dataArray = new Uint8Array(resultArray.length - 2); 636 | for (let x=2;x { 647 | this.onReceiveError(error); 648 | }); 649 | }; 650 | 651 | return this.device.open() 652 | .then(() => { 653 | 654 | if (this.device.configuration === null) { 655 | return this.device.selectConfiguration(1); 656 | } 657 | }) 658 | .then(() => { 659 | var interfaces = this.device.configuration.interfaces; 660 | /*console.log("interfaces:") 661 | console.log(interfaces)*/ 662 | interfaces.forEach(element => { 663 | element.alternates.forEach(elementalt => { 664 | console.log(elementalt); 665 | if (elementalt.interfaceClass==0xFF) { 666 | this.interfaceNumber = element.interfaceNumber; 667 | elementalt.endpoints.forEach(elementendpoint => { 668 | if (elementendpoint.direction == "out") { 669 | this.endpointOut = elementendpoint.endpointNumber; 670 | } 671 | if (elementendpoint.direction=="in") { 672 | this.endpointIn = elementendpoint.endpointNumber; 673 | } 674 | }) 675 | } 676 | }) 677 | }) 678 | /*console.log("in out"); 679 | console.log(this.endpointIn) 680 | console.log(this.endpointOut)*/ 681 | }) 682 | .then(() => this.device.claimInterface(this.interfaceNumber)) 683 | .then(() => this.device.selectAlternateInterface(this.interfaceNumber, 0)) 684 | .then(() => { 685 | 686 | let baud = this.portConfiguration.baudrate; 687 | 688 | /* console.log("controlTransfer out now for " + this.interfaceNumber) 689 | console.log("req: " + this.#FTDI_SIO_SET_BAUD_RATE) 690 | console.log("val: " + this.getBaudDivisor(baud) + '(' + baud + ')') 691 | console.log("ind: " + this.getBaudBase())*/ 692 | 693 | this.device.controlTransferOut({ 694 | requestType: 'vendor', 695 | recipient: "device", 696 | request: this.#FTDI_SIO_SET_BAUD_RATE, 697 | value: this.getBaudDivisor(baud), // divisor_value 698 | index: this.getBaudBase() // divisor_index 699 | }); 700 | }) 701 | .then(() => { 702 | 703 | return this.device.controlTransferIn({ 704 | requestType: 'vendor', 705 | recipient: 'device', 706 | request: this.#FTDI_SIO_GET_LATENCY_TIMER_REQUEST, 707 | value: 0, 708 | index: 0 709 | },1); 710 | 711 | }) 712 | .then((res) => { 713 | this.device.latencyTimer = new Uint8Array(res.data.buffer)[0]; 714 | 715 | /*console.log("Current Latency Timer: "); 716 | console.log(this.device.latencyTimer);*/ 717 | 718 | if (this.device.latencyTimer != 1) { 719 | /*console.log("Setting latency timer to 1")*/ 720 | return this.device.controlTransferOut({ 721 | requestType: 'vendor', 722 | recipient: "device", 723 | request: this.#FTDI_SIO_SET_LATENCY_TIMER_REQUEST, 724 | value: 1, 725 | index: 0 726 | }); 727 | } 728 | }) 729 | .then((res) => { 730 | return this.device.latencyTimer = this.device.controlTransferIn({ 731 | requestType: 'vendor', 732 | recipient: 'device', 733 | request: this.#FTDI_SIO_GET_LATENCY_TIMER_REQUEST, 734 | value: 0, 735 | index: 0 736 | },1); 737 | 738 | /* console.log(this.device.controlTransferOut({ 739 | 'requestType': 'class', 740 | 'recipient': 'interface', 741 | 'request': 0x22, 742 | 'value': 0x01, 743 | 'index': this.interfaceNumber 744 | }))*/ 745 | }) 746 | .then((res) => { 747 | this.device.latencyTimer = new Uint8Array(res.data.buffer)[0]; 748 | 749 | console.log("Current Latency Timer: "); 750 | console.log(this.device.latencyTimer); 751 | readLoop(); 752 | return this.device; 753 | }); 754 | } 755 | 756 | DIV_ROUND_CLOSEST(x, divisor) 757 | { 758 | let __x = x; 759 | let __d = divisor; 760 | return ((((x))-1) > 0 || 761 | (((divisor))-1) > 0 || 762 | (((__x) > 0) == ((__d) > 0))) ? 763 | (((__x) + ((__d) / 2)) / (__d)) : 764 | (((__x) - ((__d) / 2)) / (__d)); 765 | } 766 | 767 | getBaudBase() { 768 | // older devices = 12000000 ? 769 | return 48000000; 770 | } 771 | 772 | getBaudDivisor(baud) { 773 | /* 774 | works for 232bm, 2232c, 232rl, ftx 775 | */ 776 | 777 | let base = this.getBaudBase(); 778 | 779 | // static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; 780 | 781 | let divfrac = new Uint8Array(8); 782 | divfrac = [ 0, 3, 2, 4, 1, 5, 6, 7 ]; 783 | 784 | let divisor = 0; 785 | 786 | let divisor3 = this.DIV_ROUND_CLOSEST(base, 2 * baud); 787 | divisor = divisor3 >> 3; 788 | divisor |= divfrac[divisor3 & 0x7] << 14; 789 | /* Deal with special cases for highest baud rates. */ 790 | if (divisor == 1) 791 | divisor = 0; 792 | else if (divisor == 0x4001) 793 | divisor = 1; 794 | return divisor; 795 | 796 | } 797 | 798 | /* The SIO requires the first byte to have: 799 | * B0 1 800 | * B1 0 801 | * B2..7 length of message excluding byte 0 802 | * 803 | * The new devices do not require this byte 804 | */ 805 | 806 | send(data) { 807 | return this.device.transferOut(this.endpointOut, data); 808 | } 809 | 810 | disconnect() { 811 | /*return console.log(this.device.controlTransferOut({ 812 | 'requestType': 'class', 813 | 'recipient': 'interface', 814 | 'request': 0x22, 815 | 'value': 0x01, 816 | 'index': this.interfaceNumber 817 | }).then(()=> 818 | this.device.close()))*/ 819 | this.device.close(); 820 | } 821 | } 822 | 823 | class WebUSBSerialDevice { 824 | constructor(configuration) { 825 | if (!('usb' in navigator)) { 826 | throw new Error('USB Support not available!'); 827 | } 828 | 829 | this.configuration = configuration || { 830 | // Whether or not to override/specify baud/bits/stop/parity 831 | overridePortSettings: false, 832 | 833 | // Default settings, only used when overridden 834 | baudrate: 9600, 835 | bits: 8, 836 | stop: 1, 837 | parity: false, 838 | 839 | // Some default FTDI device IDs 840 | // you can replace these with any device that has 841 | // an ftdi chip. 842 | deviceFilters: [ 843 | /*{ 'vendorId' : 0x0403, 'productId' : 0x6000 }, 844 | { 'vendorId' : 0x0403, 'productId' : 0x6001 }, 845 | { 'vendorId' : 0x0403, 'productId' : 0x6010 }, 846 | { 'vendorId' : 0x0403, 'productId' : 0x6011 }, 847 | { 'vendorId' : 0x0403, 'productId' : 0x6014 }*/ 848 | ] 849 | } 850 | 851 | this.devices = []; 852 | //this.ports = []; 853 | } 854 | 855 | async getAvailablePorts() { 856 | this.devices = await navigator.usb.getDevices(); 857 | 858 | return this.devices.map(device => new WebUSBSerialPort(device)); 859 | } 860 | 861 | async requestNewPort() { 862 | try { 863 | let device = await navigator.usb.requestDevice({ 864 | filters : this.configuration.deviceFilters 865 | }); 866 | 867 | if (!(device in this.devices)) 868 | this.devices.push(device); 869 | 870 | return new WebUSBSerialPort(device, this.configuration); 871 | } catch (e) { 872 | throw new Error(e); 873 | } 874 | } 875 | 876 | } --------------------------------------------------------------------------------