├── Girino ├── COPYING.txt ├── Girino.h ├── Girino.ino ├── ISR.cpp ├── Inits.cpp ├── Interface.cpp └── Settings.cpp ├── Girinoscope ├── .classpath ├── .project ├── .settings │ └── org.eclipse.jdt.core.prefs ├── LICENSE ├── README.md ├── build.xml ├── doc │ ├── Ramp signal acquired on Linux.png │ ├── Random signal acquired on Linux.png │ ├── Relay oscillator signal acquired on Linux with higher sampling.png │ ├── Relay oscillator signal acquired on Linux.png │ ├── Relay oscillator signal acquired on Mac.png │ ├── Sine signal acquired on Linux with higher sampling.png │ ├── Sine signal acquired on Mac.png │ ├── Sine signal acquired on Windows.png │ ├── Slow relay oscillator signal acquired on Linux.png │ ├── Triangle signal acquired on Mac.png │ └── girino_optimization.md ├── lib │ ├── README.md │ ├── RXTXcomm.jar │ └── quaqua.jar ├── native │ ├── girinoscope │ ├── girinoscope.bat │ ├── linux │ │ ├── lib │ │ │ └── librxtxSerial.so │ │ └── lib64 │ │ │ └── librxtxSerial.so │ ├── macosx │ │ └── lib │ │ │ ├── libquaqua.jnilib │ │ │ └── librxtxSerial.jnilib │ └── windows │ │ └── lib │ │ └── rxtxSerial.dll └── src │ └── org │ └── hihan │ └── girinoscope │ ├── Native.java │ ├── comm │ ├── Girino.java │ └── Serial.java │ └── ui │ ├── AboutDialog.java │ ├── Axis.java │ ├── GraphPane.java │ ├── StatusBar.java │ ├── UI.java │ ├── about.html │ └── images │ ├── Icon.java │ ├── application-exit.png │ ├── help-about.png │ ├── icon.png │ ├── media-playback-stop.png │ └── media-record.png ├── LTSpice ├── LM324.txt ├── girino.asc └── pwm-threshold.asc ├── README.md ├── arduino-oscilloscope.txt └── pass ├── AITENDO-ARDU.bmp ├── AITENDO-ARDU_.bmp ├── POWER-JACK.bmp ├── backside-blue.png ├── backside-green.png ├── frontside-blue.png ├── frontside-green.png ├── universal-pcb-board-memo.txt └── universal-pcb-oscilloscope.pas /Girino/COPYING.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /Girino/Girino.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Girino.h 3 | //----------------------------------------------------------------------------- 4 | // Copyright 2012 Cristiano Lino Fontana 5 | // 6 | // This file is part of Girino. 7 | // 8 | // Girino is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // Girino is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with Girino. If not, see . 20 | // 21 | //----------------------------------------------------------------------------- 22 | // Includes 23 | //----------------------------------------------------------------------------- 24 | 25 | #include 26 | 27 | //----------------------------------------------------------------------------- 28 | // Defines and Typedefs 29 | //----------------------------------------------------------------------------- 30 | 31 | #define DEBUG 0 32 | 33 | #define ADCBUFFERSIZE 512 //1280 34 | 35 | #define ADCPIN 0 36 | #define errorPin 13 37 | #define thresholdPin 3 38 | #define defThreshold 200 39 | 40 | #define BAUDRATE 115200 // Baud rate of UART in bps 41 | #define COMMANDDELAY 10 // ms to wait for the filling of Serial buffer 42 | #define COMBUFFERSIZE 4 // Size of buffer for incoming numbers 43 | 44 | #if DEBUG == 1 45 | #define dprint(expression) Serial.print("# "); Serial.print( #expression ); Serial.print( ": " ); Serial.println( expression ) 46 | #define dshow(expression) Serial.println( expression ) 47 | #else 48 | #define dprint(expression) 49 | #define dshow(expression) 50 | #endif 51 | 52 | // Defines for setting and clearing register bits 53 | #ifndef cbi 54 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 55 | #endif 56 | #ifndef sbi 57 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 58 | #endif 59 | 60 | //----------------------------------------------------------------------------- 61 | // Global Constants 62 | //----------------------------------------------------------------------------- 63 | 64 | //----------------------------------------------------------------------------- 65 | // Function Prototypes 66 | //----------------------------------------------------------------------------- 67 | void initPins(void); 68 | void initADC(void); 69 | void initAnalogComparator(void); 70 | 71 | void startADC( void ); 72 | void stopADC( void ); 73 | void startAnalogComparator( void ); 74 | void stopAnalogComparator( void ); 75 | 76 | void setADCPrescaler( uint8_t prescaler ); 77 | void setVoltageReference( uint8_t reference ); 78 | void setTriggerEvent( uint8_t event ); 79 | 80 | void error (void); 81 | // Fills the given buffer with bufferSize chars from a Serial object 82 | void fillBuffer( \ 83 | char *buffer, \ 84 | byte bufferSize, \ 85 | HardwareSerial* serial = &Serial ); 86 | void printStatus(void); 87 | 88 | //----------------------------------------------------------------------------- 89 | // Global Variables 90 | //----------------------------------------------------------------------------- 91 | extern uint16_t waitDuration; 92 | extern volatile uint16_t stopIndex; 93 | extern volatile uint16_t ADCCounter; 94 | extern volatile uint8_t ADCBuffer[ADCBUFFERSIZE]; 95 | extern volatile boolean freeze; 96 | 97 | extern uint8_t prescaler; 98 | extern uint8_t triggerEvent; 99 | extern uint8_t threshold; 100 | 101 | extern char commandBuffer[COMBUFFERSIZE+1]; 102 | 103 | -------------------------------------------------------------------------------- /Girino/Girino.ino: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Girino.ino 3 | //----------------------------------------------------------------------------- 4 | // Copyright 2012 Cristiano Lino Fontana 5 | // 6 | // This file is part of Girino. 7 | // 8 | // Girino is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // Girino is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with Girino. If not, see . 20 | // 21 | //----------------------------------------------------------------------------- 22 | // Includes 23 | //----------------------------------------------------------------------------- 24 | 25 | #include "Girino.h" 26 | 27 | //----------------------------------------------------------------------------- 28 | // Global Constants 29 | //----------------------------------------------------------------------------- 30 | 31 | //----------------------------------------------------------------------------- 32 | // Global Variables 33 | //----------------------------------------------------------------------------- 34 | 35 | uint16_t waitDuration; 36 | volatile uint16_t stopIndex; 37 | volatile uint16_t ADCCounter; 38 | volatile uint8_t ADCBuffer[ADCBUFFERSIZE]; 39 | volatile boolean freeze; 40 | 41 | uint8_t prescaler; 42 | uint8_t triggerEvent; 43 | uint8_t threshold; 44 | 45 | char commandBuffer[COMBUFFERSIZE+1]; 46 | 47 | //----------------------------------------------------------------------------- 48 | // Main routines 49 | //----------------------------------------------------------------------------- 50 | // 51 | // The setup function initializes registers. 52 | // 53 | void setup (void) { // Setup of the microcontroller 54 | // Open serial port with a baud rate of BAUDRATE b/s 55 | Serial.begin(BAUDRATE); 56 | 57 | dshow("# setup()"); 58 | // Clear buffers 59 | memset( (void *)ADCBuffer, 0, sizeof(ADCBuffer) ); 60 | memset( (void *)commandBuffer, 0, sizeof(commandBuffer) ); 61 | ADCCounter = 0; 62 | waitDuration = ADCBUFFERSIZE - 32; 63 | stopIndex = -1; 64 | freeze = false; 65 | 66 | prescaler = 128; 67 | triggerEvent = 3; 68 | 69 | threshold = defThreshold; 70 | 71 | // Activate interrupts 72 | sei(); 73 | 74 | initPins(); 75 | initADC(); 76 | initAnalogComparator(); 77 | 78 | Serial.println("Girino ready"); 79 | //printStatus(); 80 | } 81 | 82 | void loop (void) { 83 | dprint(ADCCounter); 84 | dprint(stopIndex); 85 | dprint(freeze); 86 | #if DEBUG == 1 87 | Serial.println( ADCSRA, BIN ); 88 | Serial.println( ADCSRB, BIN ); 89 | #endif 90 | 91 | // If freeze flag is set, then it is time to send the buffer to the serial port 92 | if ( freeze ) 93 | { 94 | dshow("# Frozen"); 95 | 96 | // Send buffer through serial port in the right order 97 | //Serial.print("Buffer: "); 98 | //Serial.write( ADCBuffer, ADCBUFFERSIZE ); 99 | //Serial.print("End of Buffer"); 100 | Serial.write( (uint8_t *)ADCBuffer + ADCCounter, ADCBUFFERSIZE - ADCCounter ); 101 | Serial.write( (uint8_t *)ADCBuffer, ADCCounter ); 102 | 103 | // Turn off errorPin 104 | //digitalWrite( errorPin, LOW ); 105 | cbi(PORTB,PORTB5); 106 | 107 | stopIndex = ADCBUFFERSIZE + 1; 108 | freeze = false; 109 | 110 | // Clear buffer 111 | //memset( (void *)ADCBuffer, 0, sizeof(ADCBuffer) ); 112 | 113 | // Let the ADC fill the buffer a little bit 114 | // [Note] uncomment the following for continuous coversions 115 | //startADC(); 116 | //delay(1); 117 | //startAnalogComparator(); 118 | 119 | #if DEBUG == 1 120 | delay(3000); 121 | #endif 122 | } 123 | 124 | if ( Serial.available() > 0 ) { 125 | // Read the incoming byte 126 | char theChar = Serial.read(); 127 | // Parse character 128 | switch (theChar) { 129 | case 's': // 's' for starting ADC conversions 130 | //Serial.println("ADC conversions started"); 131 | 132 | // Clear buffer 133 | memset( (void *)ADCBuffer, 0, sizeof(ADCBuffer) ); 134 | 135 | startADC(); 136 | // Let the ADC fill the buffer a little bit 137 | //delay(1); 138 | startAnalogComparator(); 139 | break; 140 | case 'S': // 'S' for stopping ADC conversions 141 | //Serial.println("ADC conversions stopped"); 142 | stopAnalogComparator(); 143 | stopADC(); 144 | break; 145 | case 'p': // 'p' for new prescaler setting 146 | case 'P': { 147 | // Wait for COMMANDDELAY ms to be sure that the Serial buffer is filled 148 | delay(COMMANDDELAY); 149 | 150 | fillBuffer( commandBuffer, COMBUFFERSIZE ); 151 | 152 | // Convert buffer to integer 153 | uint8_t newP = atoi( commandBuffer ); 154 | 155 | // Display moving status indicator 156 | Serial.print("Setting prescaler to: "); 157 | Serial.println(newP); 158 | 159 | prescaler = newP; 160 | setADCPrescaler(newP); 161 | } 162 | break; 163 | 164 | case 'r': // 'r' for new voltage reference setting 165 | case 'R': { 166 | // Wait for COMMANDDELAY ms to be sure that the Serial buffer is filled 167 | delay(COMMANDDELAY * 2); 168 | 169 | fillBuffer( commandBuffer, COMBUFFERSIZE ); 170 | 171 | // Convert buffer to integer 172 | uint16_t newR = atoi( commandBuffer ); 173 | 174 | // Display moving status indicator 175 | Serial.print("Setting voltage reference to: "); 176 | Serial.println(newR); 177 | 178 | setVoltageReference(newR); 179 | } 180 | break; 181 | 182 | case 'e': // 'e' for new trigger event setting 183 | case 'E': { 184 | // Wait for COMMANDDELAY ms to be sure that the Serial buffer is filled 185 | delay(COMMANDDELAY); 186 | 187 | fillBuffer( commandBuffer, COMBUFFERSIZE ); 188 | 189 | // Convert buffer to integer 190 | uint8_t newE = atoi( commandBuffer ); 191 | 192 | // Display moving status indicator 193 | Serial.print("Setting trigger event to: "); 194 | Serial.println(newE); 195 | 196 | triggerEvent = newE; 197 | setTriggerEvent(newE); 198 | } 199 | break; 200 | 201 | case 'w': // 'w' for new wait setting 202 | case 'W': { 203 | // Wait for COMMANDDELAY ms to be sure that the Serial buffer is filled 204 | delay(COMMANDDELAY); 205 | 206 | fillBuffer( commandBuffer, COMBUFFERSIZE ); 207 | 208 | // Convert buffer to integer 209 | uint8_t newW = atoi( commandBuffer ); 210 | 211 | // Display moving status indicator 212 | Serial.print("Setting waitDuration to: "); 213 | Serial.println(newW); 214 | 215 | waitDuration = newW; 216 | } 217 | break; 218 | 219 | case 't': // 'w' for new threshold setting 220 | case 'T': { 221 | // Wait for COMMANDDELAY ms to be sure that the Serial buffer is filled 222 | delay(COMMANDDELAY); 223 | 224 | fillBuffer( commandBuffer, COMBUFFERSIZE ); 225 | 226 | // Convert buffer to integer 227 | uint8_t newT = atoi( commandBuffer ); 228 | 229 | // Display moving status indicator 230 | Serial.print("Setting threshold to: "); 231 | Serial.println(newT); 232 | 233 | threshold = newT; 234 | analogWrite( thresholdPin, threshold ); 235 | } 236 | break; 237 | 238 | case 'd': // 'd' for display status 239 | case 'D': 240 | printStatus(); 241 | break; 242 | 243 | default: 244 | // Display error message 245 | Serial.print("ERROR: Command not found, it was: "); 246 | Serial.println(theChar); 247 | error(); 248 | } 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /Girino/ISR.cpp: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // ISR.cpp 3 | //----------------------------------------------------------------------------- 4 | // Copyright 2012 Cristiano Lino Fontana 5 | // 6 | // This file is part of Girino. 7 | // 8 | // Girino is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // Girino is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with Girino. If not, see . 20 | // 21 | //----------------------------------------------------------------------------- 22 | // Includes 23 | //----------------------------------------------------------------------------- 24 | 25 | #include "Girino.h" 26 | 27 | //----------------------------------------------------------------------------- 28 | // ADC Conversion Complete Interrupt 29 | //----------------------------------------------------------------------------- 30 | ISR(ADC_vect) 31 | { 32 | // When ADCL is read, the ADC Data Register is not updated until ADCH 33 | // is read. Consequently, if the result is left adjusted and no more 34 | // than 8-bit precision is required, it is sufficient to read ADCH. 35 | // Otherwise, ADCL must be read first, then ADCH. 36 | ADCBuffer[ADCCounter] = ADCH; 37 | 38 | if (++ADCCounter >= ADCBUFFERSIZE) ADCCounter = 0; 39 | 40 | if ( stopIndex == ADCCounter ) 41 | { 42 | // Freeze situation 43 | // Disable ADC and stop Free Running Conversion Mode 44 | cbi( ADCSRA, ADEN ); 45 | freeze = true; 46 | } 47 | } 48 | 49 | //----------------------------------------------------------------------------- 50 | // Analog Comparator interrupt 51 | //----------------------------------------------------------------------------- 52 | ISR(ANALOG_COMP_vect) 53 | { 54 | // Disable Analog Comparator interrupt 55 | cbi( ACSR,ACIE ); 56 | 57 | // Turn on errorPin 58 | //digitalWrite( errorPin, HIGH ); 59 | sbi( PORTB, PORTB5 ); 60 | 61 | stopIndex = ( ADCCounter + waitDuration ) % ADCBUFFERSIZE; 62 | } 63 | -------------------------------------------------------------------------------- /Girino/Inits.cpp: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Inits.cpp 3 | //----------------------------------------------------------------------------- 4 | // Copyright 2012 Cristiano Lino Fontana 5 | // 6 | // This file is part of Girino. 7 | // 8 | // Girino is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // Girino is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with Girino. If not, see . 20 | // 21 | //----------------------------------------------------------------------------- 22 | // Includes 23 | //----------------------------------------------------------------------------- 24 | 25 | #include "Girino.h" 26 | 27 | //----------------------------------------------------------------------------- 28 | // initPins() 29 | //----------------------------------------------------------------------------- 30 | void initPins(void) 31 | { 32 | //--------------------------------------------------------------------- 33 | // TCCR2A settings 34 | //--------------------------------------------------------------------- 35 | // These bits control the Output Compare pin (OC2A) behavior. If one or 36 | // both of the COM2A1:0 bits are set, the OC2A output overrides the 37 | // normal port functionality of the I/O pin it is connected to. 38 | // However, note that the Data Direction Register (DDR) bit 39 | // corresponding to the OC2A pin must be set in order to enable the 40 | // output driver. 41 | // When OC2A is connected to the pin, the function of the COM2A1:0 bits 42 | // depends on the WGM22:0 bit setting. 43 | // 44 | // Fast PWM Mode 45 | // COM2A1 COM2A0 46 | // 0 0 Normal port operation, OC2A disconnected. 47 | // 0 1 WGM22 = 0: Normal Port Operation, OC0A Disconnected. 48 | // WGM22 = 1: Toggle OC2A on Compare Match. 49 | // 1 0 Clear OC2A on Compare Match, set OC2A at BOTTOM 50 | // 1 1 Clear OC2A on Compare Match, clear OC2A at BOTTOM 51 | cbi(TCCR2A,COM2A1); 52 | cbi(TCCR2A,COM2A0); 53 | sbi(TCCR2A,COM2B1); 54 | cbi(TCCR2A,COM2B0); 55 | 56 | // Combined with the WGM22 bit found in the TCCR2B Register, these bits 57 | // control the counting sequence of the counter, the source for maximum 58 | // (TOP) counter value, and what type of waveform generation to be used 59 | // Modes of operation supported by the Timer/Counter unit are: 60 | // - Normal mode (counter), 61 | // - Clear Timer on Compare Match (CTC) mode, 62 | // - two types of Pulse Width Modulation (PWM) modes. 63 | // 64 | // Mode WGM22 WGM21 WGM20 Operation TOP 65 | // 0 0 0 0 Normal 0xFF 66 | // 1 0 0 1 PWM 0xFF 67 | // 2 0 1 0 CTC OCRA 68 | // 3 0 1 1 Fast PWM 0xFF 69 | // 4 1 0 0 Reserved - 70 | // 5 1 0 1 PWM OCRA 71 | // 6 1 1 0 Reserved - 72 | // 7 1 1 1 Fast PWM OCRA 73 | cbi(TCCR2B,WGM22); 74 | sbi(TCCR2A,WGM21); 75 | sbi(TCCR2A,WGM20); 76 | 77 | //--------------------------------------------------------------------- 78 | // TCCR2B settings 79 | //--------------------------------------------------------------------- 80 | // The FOC2A bit is only active when the WGM bits specify a non-PWM 81 | // mode. 82 | // However, for ensuring compatibility with future devices, this bit 83 | // must be set to zero when TCCR2B is written when operating in PWM 84 | // mode. When writing a logical one to the FOC2A bit, an immediate 85 | // Compare Match is forced on the Waveform Generation unit. The OC2A 86 | // output is changed according to its COM2A1:0 bits setting. Note that 87 | // the FOC2A bit is implemented as a strobe. Therefore it is the value 88 | // present in the COM2A1:0 bits that determines the effect of the 89 | // forced compare. 90 | // A FOC2A strobe will not generate any interrupt, nor will it clear 91 | // the timer in CTC mode using OCR2A as TOP. 92 | // The FOC2A bit is always read as zero. 93 | cbi(TCCR2B,FOC2A); 94 | cbi(TCCR2B,FOC2B); 95 | 96 | // The three Clock Select bits select the clock source to be used by 97 | // the Timer/Counter. 98 | // CS22 CS21 CS20 Prescaler 99 | // 0 0 0 No clock source (Timer/Counter stopped). 100 | // 0 0 1 No prescaling 101 | // 0 1 0 8 102 | // 0 1 1 32 103 | // 1 0 0 64 104 | // 1 0 1 128 105 | // 1 1 0 256 106 | // 1 1 1 1024 107 | cbi(TCCR2B,CS22); 108 | cbi(TCCR2B,CS21); 109 | sbi(TCCR2B,CS20); 110 | 111 | pinMode( errorPin, OUTPUT ); 112 | pinMode( thresholdPin, OUTPUT ); 113 | 114 | analogWrite( thresholdPin, defThreshold ); 115 | } 116 | 117 | //----------------------------------------------------------------------------- 118 | // initADC() 119 | //----------------------------------------------------------------------------- 120 | void initADC(void) 121 | { 122 | //--------------------------------------------------------------------- 123 | // ADMUX settings 124 | //--------------------------------------------------------------------- 125 | // These bits select the voltage reference for the ADC. If these bits 126 | // are changed during a conversion, the change will not go in effect 127 | // until this conversion is complete (ADIF in ADCSRA is set). The 128 | // internal voltage reference options may not be used if an external 129 | // reference voltage is being applied to the AREF pin. 130 | // REFS1 REFS0 Voltage reference 131 | // 0 0 AREF, Internal Vref turned off 132 | // 0 1 AVCC with external capacitor at AREF pin 133 | // 1 0 Reserved 134 | // 1 1 Internal 1.1V Voltage Reference with external 135 | // capacitor at AREF pin 136 | cbi(ADMUX,REFS1); 137 | sbi(ADMUX,REFS0); 138 | // The ADLAR bit affects the presentation of the ADC conversion result 139 | // in the ADC Data Register. Write one to ADLAR to left adjust the 140 | // result. Otherwise, the result is right adjusted. Changing the ADLAR 141 | // bit will affect the ADC Data Register immediately, regardless of any 142 | // ongoing conversions. 143 | sbi(ADMUX,ADLAR); 144 | // The value of these bits selects which analog inputs are connected to 145 | // the ADC. If these bits are changed during a conversion, the change 146 | // will not go in effect until this conversion is complete (ADIF in 147 | // ADCSRA is set). 148 | ADMUX |= ( ADCPIN & 0x07 ); 149 | 150 | //--------------------------------------------------------------------- 151 | // ADCSRA settings 152 | //--------------------------------------------------------------------- 153 | // Writing this bit to one enables the ADC. By writing it to zero, the 154 | // ADC is turned off. Turning the ADC off while a conversion is in 155 | // progress, will terminate this conversion. 156 | cbi(ADCSRA,ADEN); 157 | // In Single Conversion mode, write this bit to one to start each 158 | // conversion. In Free Running mode, write this bit to one to start the 159 | // first conversion. The first conversion after ADSC has been written 160 | // after the ADC has been enabled, or if ADSC is written at the same 161 | // time as the ADC is enabled, will take 25 ADC clock cycles instead of 162 | // the normal 13. This first conversion performs initialization of the 163 | // ADC. ADSC will read as one as long as a conversion is in progress. 164 | // When the conversion is complete, it returns to zero. Writing zero to 165 | // this bit has no effect. 166 | cbi(ADCSRA,ADSC); 167 | // When this bit is written to one, Auto Triggering of the ADC is 168 | // enabled. The ADC will start a conversion on a positive edge of the 169 | // selected trigger signal. The trigger source is selected by setting 170 | // the ADC Trigger Select bits, ADTS in ADCSRB. 171 | sbi(ADCSRA,ADATE); 172 | // When this bit is written to one and the I-bit in SREG is set, the 173 | // ADC Conversion Complete Interrupt is activated. 174 | sbi(ADCSRA,ADIE); 175 | // These bits determine the division factor between the system clock 176 | // frequency and the input clock to the ADC. 177 | // ADPS2 ADPS1 ADPS0 Division Factor 178 | // 0 0 0 2 179 | // 0 0 1 2 180 | // 0 1 0 4 181 | // 0 1 1 8 182 | // 1 0 0 16 183 | // 1 0 1 32 184 | // 1 1 0 64 185 | // 1 1 1 128 186 | sbi(ADCSRA,ADPS2); 187 | sbi(ADCSRA,ADPS1); 188 | sbi(ADCSRA,ADPS0); 189 | 190 | //--------------------------------------------------------------------- 191 | // ADCSRB settings 192 | //--------------------------------------------------------------------- 193 | // When this bit is written logic one and the ADC is switched off 194 | // (ADEN in ADCSRA is zero), the ADC multiplexer selects the negative 195 | // input to the Analog Comparator. When this bit is written logic zero, 196 | // AIN1 is applied to the negative input of the Analog Comparator. 197 | cbi(ADCSRB,ACME); 198 | // If ADATE in ADCSRA is written to one, the value of these bits 199 | // selects which source will trigger an ADC conversion. If ADATE is 200 | // cleared, the ADTS2:0 settings will have no effect. A conversion will 201 | // be triggered by the rising edge of the selected Interrupt Flag. Note 202 | // that switching from a trigger source that is cleared to a trigger 203 | // source that is set, will generate a positive edge on the trigger 204 | // signal. If ADEN in ADCSRA is set, this will start a conversion. 205 | // Switching to Free Running mode (ADTS[2:0]=0) will not cause a 206 | // trigger event, even if the ADC Interrupt Flag is set. 207 | // ADTS2 ADTS1 ADTS0 Trigger source 208 | // 0 0 0 Free Running mode 209 | // 0 0 1 Analog Comparator 210 | // 0 1 0 External Interrupt Request 0 211 | // 0 1 1 Timer/Counter0 Compare Match A 212 | // 1 0 0 Timer/Counter0 Overflow 213 | // 1 0 1 Timer/Counter1 Compare Match B 214 | // 1 1 0 Timer/Counter1 Overflow 215 | // 1 1 1 Timer/Counter1 Capture Event 216 | cbi(ADCSRB,ADTS2); 217 | cbi(ADCSRB,ADTS1); 218 | cbi(ADCSRB,ADTS0); 219 | 220 | //--------------------------------------------------------------------- 221 | // DIDR0 settings 222 | //--------------------------------------------------------------------- 223 | // When this bit is written logic one, the digital input buffer on the 224 | // corresponding ADC pin is disabled. The corresponding PIN Register 225 | // bit will always read as zero when this bit is set. When an analog 226 | // signal is applied to the ADC5..0 pin and the digital input from this 227 | // pin is not needed, this bit should be written logic one to reduce 228 | // power consumption in the digital input buffer. 229 | // Note that ADC pins ADC7 and ADC6 do not have digital input buffers, 230 | // and therefore do not require Digital Input Disable bits. 231 | sbi(DIDR0,ADC5D); 232 | sbi(DIDR0,ADC4D); 233 | sbi(DIDR0,ADC3D); 234 | sbi(DIDR0,ADC2D); 235 | sbi(DIDR0,ADC1D); 236 | sbi(DIDR0,ADC0D); 237 | } 238 | 239 | //----------------------------------------------------------------------------- 240 | // initAnalogComparator() 241 | //----------------------------------------------------------------------------- 242 | void initAnalogComparator(void) 243 | { 244 | //--------------------------------------------------------------------- 245 | // ACSR settings 246 | //--------------------------------------------------------------------- 247 | // When this bit is written logic one, the power to the Analog 248 | // Comparator is switched off. This bit can be set at any time to turn 249 | // off the Analog Comparator. This will reduce power consumption in 250 | // Active and Idle mode. When changing the ACD bit, the Analog 251 | // Comparator Interrupt must be disabled by clearing the ACIE bit in 252 | // ACSR. Otherwise an interrupt can occur when the bit is changed. 253 | cbi(ACSR,ACD); 254 | // When this bit is set, a fixed bandgap reference voltage replaces the 255 | // positive input to the Analog Comparator. When this bit is cleared, 256 | // AIN0 is applied to the positive input of the Analog Comparator. When 257 | // the bandgap referance is used as input to the Analog Comparator, it 258 | // will take a certain time for the voltage to stabilize. If not 259 | // stabilized, the first conversion may give a wrong value. 260 | cbi(ACSR,ACBG); 261 | // When the ACIE bit is written logic one and the I-bit in the Status 262 | // Register is set, the Analog Comparator interrupt is activated. 263 | // When written logic zero, the interrupt is disabled. 264 | cbi(ACSR,ACIE); 265 | // When written logic one, this bit enables the input capture function 266 | // in Timer/Counter1 to be triggered by the Analog Comparator. The 267 | // comparator output is in this case directly connected to the input 268 | // capture front-end logic, making the comparator utilize the noise 269 | // canceler and edge select features of the Timer/Counter1 Input 270 | // Capture interrupt. When written logic zero, no connection between 271 | // the Analog Comparator and the input capture function exists. To 272 | // make the comparator trigger the Timer/Counter1 Input Capture 273 | // interrupt, the ICIE1 bit in the Timer Interrupt Mask Register 274 | // (TIMSK1) must be set. 275 | cbi(ACSR,ACIC); 276 | // These bits determine which comparator events that trigger the Analog 277 | // Comparator interrupt. 278 | // ACIS1 ACIS0 Mode 279 | // 0 0 Toggle 280 | // 0 1 Reserved 281 | // 1 0 Falling edge 282 | // 1 1 Rising edge 283 | sbi(ACSR,ACIS1); 284 | sbi(ACSR,ACIS0); 285 | 286 | //--------------------------------------------------------------------- 287 | // DIDR1 settings 288 | //--------------------------------------------------------------------- 289 | // When this bit is written logic one, the digital input buffer on the 290 | // AIN1/0 pin is disabled. The corresponding PIN Register bit will 291 | // always read as zero when this bit is set. When an analog signal is 292 | // applied to the AIN1/0 pin and the digital input from this pin is not 293 | // needed, this bit should be written logic one to reduce power 294 | // consumption in the digital input buffer. 295 | sbi(DIDR1,AIN1D); 296 | sbi(DIDR1,AIN0D); 297 | } 298 | -------------------------------------------------------------------------------- /Girino/Interface.cpp: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Interface.cpp 3 | //----------------------------------------------------------------------------- 4 | // Copyright 2012 Cristiano Lino Fontana 5 | // 6 | // This file is part of Girino. 7 | // 8 | // Girino is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // Girino is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with Girino. If not, see . 20 | // 21 | //----------------------------------------------------------------------------- 22 | // Includes 23 | //----------------------------------------------------------------------------- 24 | 25 | #include "Girino.h" 26 | 27 | //----------------------------------------------------------------------------- 28 | void error (void) { 29 | digitalWrite( errorPin, HIGH ); 30 | delay( 500 ); 31 | digitalWrite( errorPin, LOW ); 32 | delay( 250 ); 33 | digitalWrite( errorPin, HIGH ); 34 | delay( 500 ); 35 | digitalWrite( errorPin, LOW ); 36 | } 37 | 38 | //----------------------------------------------------------------------------- 39 | // fillBuffer 40 | //----------------------------------------------------------------------------- 41 | // Fills the given buffer with bufferSize chars from a Serial object 42 | 43 | void fillBuffer( char *buffer, byte bufferSize, HardwareSerial* serial ) 44 | { 45 | // Clean buffer 46 | memset( (void *)buffer, '\0', sizeof(char) * bufferSize ); 47 | 48 | dprint(serial->available()); 49 | 50 | byte limit = ( bufferSize < serial->available() ) ? bufferSize : serial->available(); 51 | 52 | dprint(serial->available()); 53 | dprint(bufferSize); 54 | dprint(limit); 55 | 56 | // Fill buffer 57 | for ( byte i = 0; i < limit; i++ ) { 58 | dprint(serial->available()); 59 | dprint(i); 60 | dprint(buffer); 61 | 62 | buffer[i] = serial->read(); 63 | } 64 | } 65 | 66 | void printStatus( void ) 67 | { 68 | Serial.print("Buffer size: "); 69 | Serial.println(ADCBUFFERSIZE); 70 | Serial.print("Baud rate: "); 71 | Serial.println(BAUDRATE); 72 | Serial.print("Wait duration: "); 73 | Serial.println(waitDuration); 74 | Serial.print("Prescaler: "); 75 | Serial.println(prescaler); 76 | Serial.print("Trigger event: "); 77 | Serial.println(triggerEvent); 78 | Serial.print("Threshold: "); 79 | Serial.println(threshold); 80 | } 81 | -------------------------------------------------------------------------------- /Girino/Settings.cpp: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Settings.cpp 3 | //----------------------------------------------------------------------------- 4 | // Copyright 2012 Cristiano Lino Fontana 5 | // 6 | // This file is part of Girino. 7 | // 8 | // Girino is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | // 13 | // Girino is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with Girino. If not, see . 20 | // 21 | //----------------------------------------------------------------------------- 22 | // Includes 23 | //----------------------------------------------------------------------------- 24 | 25 | #include "Girino.h" 26 | 27 | //----------------------------------------------------------------------------- 28 | // Start elements 29 | //----------------------------------------------------------------------------- 30 | void startADC( void ) 31 | { 32 | // Enable ADC 33 | sbi(ADCSRA,ADEN); 34 | // Start conversion 35 | sbi(ADCSRA,ADSC); 36 | } 37 | void stopADC( void ) 38 | { 39 | // Disable ADC and stop Free Running Conversion Mode 40 | cbi(ADCSRA,ADEN); 41 | } 42 | 43 | //----------------------------------------------------------------------------- 44 | // startAnalogComparator() 45 | //----------------------------------------------------------------------------- 46 | void startAnalogComparator( void ) 47 | { 48 | // Enable Analog Comparator Interrupt 49 | sbi(ACSR,ACIE); 50 | } 51 | void stopAnalogComparator( void ) 52 | { 53 | // Disable Analog Comparator interrupt 54 | cbi( ACSR,ACIE ); 55 | } 56 | 57 | //----------------------------------------------------------------------------- 58 | // Set and modify ADC prescaler 59 | //----------------------------------------------------------------------------- 60 | void setADCPrescaler( uint8_t Prescaler ) 61 | { 62 | dshow("# setADCPrescaler()"); 63 | dprint(Prescaler); 64 | // These bits determine the division factor between the system clock 65 | // frequency and the input clock to the ADC. 66 | // ADPS2 ADPS1 ADPS0 Division Factor 67 | // 0 0 0 2 68 | // 0 0 1 2 69 | // 0 1 0 4 70 | // 0 1 1 8 71 | // 1 0 0 16 72 | // 1 0 1 32 73 | // 1 1 0 64 74 | // 1 1 1 128 75 | switch (Prescaler) 76 | { 77 | case 2: 78 | cbi(ADCSRA,ADPS2); 79 | cbi(ADCSRA,ADPS1); 80 | sbi(ADCSRA,ADPS0); 81 | break; 82 | case 4: 83 | cbi(ADCSRA,ADPS2); 84 | sbi(ADCSRA,ADPS1); 85 | cbi(ADCSRA,ADPS0); 86 | break; 87 | case 8: 88 | cbi(ADCSRA,ADPS2); 89 | sbi(ADCSRA,ADPS1); 90 | sbi(ADCSRA,ADPS0); 91 | break; 92 | case 16: 93 | sbi(ADCSRA,ADPS2); 94 | cbi(ADCSRA,ADPS1); 95 | cbi(ADCSRA,ADPS0); 96 | break; 97 | case 32: 98 | sbi(ADCSRA,ADPS2); 99 | cbi(ADCSRA,ADPS1); 100 | sbi(ADCSRA,ADPS0); 101 | break; 102 | case 64: 103 | sbi(ADCSRA,ADPS2); 104 | sbi(ADCSRA,ADPS1); 105 | cbi(ADCSRA,ADPS0); 106 | break; 107 | case 128: 108 | sbi(ADCSRA,ADPS2); 109 | sbi(ADCSRA,ADPS1); 110 | sbi(ADCSRA,ADPS0); 111 | break; 112 | default: // Set 128 113 | sbi(ADCSRA,ADPS2); 114 | sbi(ADCSRA,ADPS1); 115 | sbi(ADCSRA,ADPS0); 116 | } 117 | } 118 | 119 | //----------------------------------------------------------------------------- 120 | // Set and modify Voltage Reference 121 | //----------------------------------------------------------------------------- 122 | void setVoltageReference( uint8_t reference ) 123 | { 124 | dshow("# setVoltageReference()"); 125 | dprint(reference); 126 | // These bits select the voltage reference for the ADC. If these bits 127 | // are changed during a conversion, the change will not go in effect 128 | // until this conversion is complete (ADIF in ADCSRA is set). The 129 | // internal voltage reference options may not be used if an external 130 | // reference voltage is being applied to the AREF pin. 131 | // REFS1 REFS0 Voltage reference 132 | // 0 0 AREF, Internal Vref turned off 133 | // 0 1 AVCC with external capacitor at AREF pin 134 | // 1 0 Reserved 135 | // 1 1 Internal 1.1V Voltage Reference with external 136 | // capacitor at AREF pin 137 | switch (reference) 138 | { 139 | case 0: 140 | cbi(ADMUX,REFS1); 141 | cbi(ADMUX,REFS0); 142 | break; 143 | case 2: 144 | sbi(ADMUX,REFS1); 145 | sbi(ADMUX,REFS0); 146 | break; 147 | case 1: 148 | default: 149 | cbi(ADMUX,REFS1); 150 | sbi(ADMUX,REFS0); 151 | } 152 | } 153 | 154 | //----------------------------------------------------------------------------- 155 | void setTriggerEvent( uint8_t TriggerEvent ) 156 | { 157 | dshow("# setTriggerEvent()"); 158 | dprint(event); 159 | // These bits determine which comparator events that trigger the Analog 160 | // Comparator interrupt. 161 | // ACIS1 ACIS0 Mode 162 | // 0 0 Toggle 163 | // 0 1 Reserved 164 | // 1 0 Falling edge 165 | // 1 1 Rising edge 166 | switch (TriggerEvent) 167 | { 168 | case 0: 169 | cbi(ACSR,ACIS1); 170 | cbi(ACSR,ACIS0); 171 | break; 172 | case 2: 173 | sbi(ACSR,ACIS1); 174 | cbi(ACSR,ACIS0); 175 | break; 176 | case 3: 177 | default: 178 | sbi(ACSR,ACIS1); 179 | sbi(ACSR,ACIS0); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /Girinoscope/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Girinoscope/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Girinoscope 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /Girinoscope/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.6 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.source=1.6 12 | -------------------------------------------------------------------------------- /Girinoscope/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Girinoscope/README.md: -------------------------------------------------------------------------------- 1 | [Note] the original source is at https://github.com/Chatanga/Girinoscope, I 2 | only patched the buffer size for ATmega168 3 | -- Daniel Sangorrin 4 | 5 | Girinoscope 6 | =========== 7 | 8 | A simple graphical user interface for 9 | [Girino, a Fast Arduino Oscilloscope](http://www.instructables.com/id/Girino-Fast-Arduino-Oscilloscope/) 10 | running on Linux, Mac OS X and Windows. 11 | The screen capture below, as well as the others in the `doc` folder, 12 | displays the acquisition of a signal generated by various circuits including another DIY project: 13 | [Skill Builder: Advanced Arduino Sound Synthesis](http://makezine.com/projects/make-35/advanced-arduino-sound-synthesis/). 14 | 15 | ![Screen capture of a relay oscillator signal acquisition](doc/Slow relay oscillator signal acquired on Linux.png "Acquiring a relay oscillator signal") 16 | 17 | Usage 18 | ----- 19 | 20 | Since this little application is intimately bound to Girino, 21 | the various settings provided by Girinoscope are not detailled here. 22 | If you have already built your own Girino and studied the firmware, 23 | you should already be familiar with them. 24 | 25 | **Wait duration parameter** 26 | 27 | The Arduino code provided in the [Girino Instructable] 28 | (http://www.instructables.com/id/Girino-Fast-Arduino-Oscilloscope/) 29 | doesn't handle very well the `wait duration` parameter that you can set using the vertical green rule 30 | (the horizontal orange rule is for the threshold to trigger the acquisition). 31 | There are a small bug when changing the value through the serial interface 32 | which can easily be solved by applying the following patch manually: 33 | 34 | _Girino.h, line 41:_ 35 | 36 | // Replaced 3 by 4 since the wait duration range is [0, 1280[. 37 | #define COMBUFFERSIZE 4 // Size of buffer for incoming numbers 38 | 39 | _Girino.ino, line 224:_ 40 | 41 | // Added a necessary x2 factor since we read 16 bits now. 42 | delay(COMMANDDELAY * 2); 43 | 44 | _Girino.ino, line 229:_ 45 | 46 | // Replaced 'uint8' by 'uint16' for the same reason. 47 | uint16_t newT = atoi( commandBuffer ); 48 | 49 | With this simple correction, you should now be able to change the `wait duration` without problem. 50 | However, remember that this duration is the time spent (or, more exactly, the number of data samples measured) by Girino _after_ the trigger. 51 | Per instance, a `wait duration` of `580` gives you `1280 - 580` data measures before the trigger and `580` after. 52 | If this trigger occurs too early, you will not see much from the past. 53 | In fact, since Girino resets its data buffer on each acquisition, you will mostly get zeros. 54 | The screen captures in the `doc` folder show some cases of such missing data 55 | (since the observed signals are periodic, Girino can’t catch more than a period before a trigger occurs). 56 | 57 | **Prescaler parameter** 58 | 59 | The prescaler parameter also suffers some limitations signaled by the UI using the following colors: 60 | - black if it should work without problem, 61 | - orange if it won’t work without optimizing the Girino code, 62 | - red if it won’t work at all (at least, it never did at home). 63 | 64 | The code optimization consists in applying the [advices](doc/girino_optimization.md) given by [womai](http://www.instructables.com/member/womai/) 65 | in the [Girino Instructable] (http://www.instructables.com/id/Girino-Fast-Arduino-Oscilloscope/). 66 | 67 | Install 68 | ------- 69 | 70 | Just unzip the [latest release](https://github.com/Chatanga/Girinoscope/releases) somewhere 71 | and launch the application using the appropriate script at the root 72 | (`girino` for Linux / Mac and `girino.bat` for Windows). 73 | Of course, since this is a Java application, you need a [JRE 1.6 or higher](https://www.java.com/fr) 74 | installed on your system (64 bits is currently only supported for the Linux version). 75 | It shouldn’t be a problem on Linux and Mac, however, if you are an unfortunate Windows user 76 | who don’t have it installed and don’t want to use the [shameful Oracle’s installer] 77 | (http://news.techworld.com/applications/3423193/oracle-to-keep-bundling-crapware-with-java-installer/), 78 | a fine solution is to use the one provided by the Arduino IDE. 79 | In fact, provided you installed it in the default place, the launch script should find it. 80 | If not, just edit the appropriate variable in the `girinoscope.bat` file. 81 | 82 | Dependencies 83 | ------------ 84 | 85 | Girinoscope uses the same native library than the Arduino IDE 1.0.5 to manage serial port: the RXTX library. 86 | It is not necessarily the perfect solution 87 | and the latest Arduino IDE version (1.5.7 BETA) has droped it in favor of something more elaborate. 88 | Whatever, the RXTX works well enough for our purposes and, if you have already successfully installed the Arduino IDE, 89 | Girinoscope should work out of the crafting table. 90 | Otherwise, there is all the informations you need on the [Arduino web site](http://arduino.cc/en/Guide/HomePage). 91 | 92 | Build 93 | ----- 94 | 95 | You just need a [JDK 1.6 or higher](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 96 | and [Ant](http://ant.apache.org/bindownload.cgi). 97 | Nothing particular exotic in the Java world. 98 | Once these tools installed, a simple `ant build` at the root of this project will do the job. 99 | On success, you can run the application the same way by issuing a `ant run`. 100 | 101 | Author 102 | ------ 103 | 104 | Florent Lioult 105 | 106 | -------------------------------------------------------------------------------- /Girinoscope/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /Girinoscope/doc/Ramp signal acquired on Linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/doc/Ramp signal acquired on Linux.png -------------------------------------------------------------------------------- /Girinoscope/doc/Random signal acquired on Linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/doc/Random signal acquired on Linux.png -------------------------------------------------------------------------------- /Girinoscope/doc/Relay oscillator signal acquired on Linux with higher sampling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/doc/Relay oscillator signal acquired on Linux with higher sampling.png -------------------------------------------------------------------------------- /Girinoscope/doc/Relay oscillator signal acquired on Linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/doc/Relay oscillator signal acquired on Linux.png -------------------------------------------------------------------------------- /Girinoscope/doc/Relay oscillator signal acquired on Mac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/doc/Relay oscillator signal acquired on Mac.png -------------------------------------------------------------------------------- /Girinoscope/doc/Sine signal acquired on Linux with higher sampling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/doc/Sine signal acquired on Linux with higher sampling.png -------------------------------------------------------------------------------- /Girinoscope/doc/Sine signal acquired on Mac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/doc/Sine signal acquired on Mac.png -------------------------------------------------------------------------------- /Girinoscope/doc/Sine signal acquired on Windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/doc/Sine signal acquired on Windows.png -------------------------------------------------------------------------------- /Girinoscope/doc/Slow relay oscillator signal acquired on Linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/doc/Slow relay oscillator signal acquired on Linux.png -------------------------------------------------------------------------------- /Girinoscope/doc/Triangle signal acquired on Mac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/doc/Triangle signal acquired on Mac.png -------------------------------------------------------------------------------- /Girinoscope/doc/girino_optimization.md: -------------------------------------------------------------------------------- 1 | [womai](http://www.instructables.com/member/womai/) 2 | 3 | Two ideas to make the code more efficient (run faster): 4 | 5 | The calculation 6 | 7 | ADCCounter = ( ADCCounter + 1 ) % ADCBUFFERSIZE; 8 | 9 | involves an integer division which tends to be time consuming (at least on a Microchip PIC - I do not know Atmel as well). Instead, try 10 | 11 | if (++ADCCounter >= ADCBUFFERSIZE) ADCCounter = 0; 12 | 13 | Second, you can completely avoid the time required to evaluate 14 | 15 | if(wait) 16 | 17 | and live without the wait variable if you simply set stopIndex to a value that the counter never reaches, as long as you aren't yet in the post-trigger phase. I.e. during initialization (when starting a new sweep) set 18 | 19 | stopIndex = ADCBUFFERSIZE + 1; 20 | 21 | and when the trigger event happens then just do as you did so far, but without the boolean wait variable: 22 | 23 | ISR(ANALOG_COMP_vect) 24 | { 25 | // Disable Analog Comparator interrupt 26 | cbi( ACSR,ACIE ); 27 | 28 | // Turn on errorPin 29 | //digitalWrite( errorPin, HIGH ); 30 | sbi( PORTB, PORTB5 ); 31 | 32 | stopIndex = ( ADCCounter + waitDuration ) % ADCBUFFERSIZE; 33 | } 34 | 35 | and the ADC ISR routine becomes 36 | 37 | ISR(ADC_vect) 38 | { 39 | if (++ADCCounter >= ADCBUFFERSIZE) ADCCounter = 0; 40 | 41 | if ( stopIndex == ADCCounter ) 42 | { 43 | cbi( ADCSRA, ADEN ); 44 | freeze = true; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Girinoscope/lib/README.md: -------------------------------------------------------------------------------- 1 | The `quaqua.jar` for the [Quaqua Look and Feel](http://www.randelshofer.ch/quaqua/) 2 | is optional and meant to be used on Mac OS X to achieve a better integration 3 | (but it doesn’t hurt to have it in the classpath on other platforms). 4 | 5 | -------------------------------------------------------------------------------- /Girinoscope/lib/RXTXcomm.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/lib/RXTXcomm.jar -------------------------------------------------------------------------------- /Girinoscope/lib/quaqua.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/lib/quaqua.jar -------------------------------------------------------------------------------- /Girinoscope/native/girinoscope: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$JAVA_HOME" ]; then 4 | PATH="$JAVA_HOME/bin:$PATH" 5 | fi 6 | 7 | java -version 2> /dev/null 8 | if [ $? -gt 0 ]; then 9 | echo 1 > truc.txt 10 | echo "No Java instance has been found." 11 | fi 12 | 13 | if [[ "$OSTYPE" = "darwin"* ]]; then 14 | SCRIPT_DIR=$(dirname `stat -f "$0"`) 15 | JVMARG="-d32" 16 | java $JVMARG -version 2> /dev/null 17 | if [[ $? > 0 ]]; then 18 | echo "Your Java instance does not support a 32-bit JVM." 19 | exit 1 20 | fi 21 | else 22 | SCRIPT_DIR=$(dirname `readlink -f "$0"`) 23 | fi 24 | 25 | java $JVMARG -cp "$SCRIPT_DIR/lib/*" -Dgirinoscope.native.path="$SCRIPT_DIR" org.hihan.girinoscope.ui.UI 26 | -------------------------------------------------------------------------------- /Girinoscope/native/girinoscope.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set SCRIPT_PATH=%~dp0 3 | set SCRIPT_DIR=%SCRIPT_PATH:~0,-1% 4 | 5 | set PATH=C:\Program Files (x86)\Arduino\java\bin;%JAVA_HOME%\bin;%PATH% 6 | java -cp "%SCRIPT_DIR%\lib\Girinoscope.jar;%SCRIPT_DIR%\lib\RXTXcomm.jar" ^ 7 | -Dgirinoscope.native.path="%SCRIPT_DIR%" ^ 8 | org.hihan.girinoscope.ui.UI 9 | -------------------------------------------------------------------------------- /Girinoscope/native/linux/lib/librxtxSerial.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/native/linux/lib/librxtxSerial.so -------------------------------------------------------------------------------- /Girinoscope/native/linux/lib64/librxtxSerial.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/native/linux/lib64/librxtxSerial.so -------------------------------------------------------------------------------- /Girinoscope/native/macosx/lib/libquaqua.jnilib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/native/macosx/lib/libquaqua.jnilib -------------------------------------------------------------------------------- /Girinoscope/native/macosx/lib/librxtxSerial.jnilib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/native/macosx/lib/librxtxSerial.jnilib -------------------------------------------------------------------------------- /Girinoscope/native/windows/lib/rxtxSerial.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/native/windows/lib/rxtxSerial.dll -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/Native.java: -------------------------------------------------------------------------------- 1 | package org.hihan.girinoscope; 2 | 3 | import java.io.File; 4 | import java.lang.reflect.Field; 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | 8 | import javax.swing.UIManager; 9 | import javax.swing.UnsupportedLookAndFeelException; 10 | 11 | public class Native { 12 | 13 | private static final Logger logger = Logger.getLogger(Native.class.getName()); 14 | 15 | public enum OS { 16 | 17 | Linux("linux"), MacOSX("mac"), Windows("win"); 18 | 19 | String[] names; 20 | 21 | OS(String... names) { 22 | this.names = names; 23 | } 24 | 25 | public static OS resolve(String osName) { 26 | for (OS os : values()) { 27 | for (String name : os.names) { 28 | if (osName.toLowerCase().contains(name)) { 29 | return os; 30 | } 31 | } 32 | } 33 | return null; 34 | } 35 | } 36 | 37 | public static void setLibraryPath() { 38 | String osName = System.getProperty("os.name"); 39 | OS os = OS.resolve(osName); 40 | if (os != null) { 41 | boolean is64bits = "64".equals(System.getProperty("sun.arch.data.model")); 42 | 43 | String nativePath = System.getProperty("girinoscope.native.path"); 44 | if (nativePath == null) { 45 | nativePath = "native"; 46 | } 47 | logger.log(Level.INFO, "Native path is '{0}'.", nativePath); 48 | 49 | File libPath = new File(nativePath); 50 | libPath = new File(libPath, os.name().toLowerCase()); 51 | libPath = new File(libPath, is64bits ? "lib64" : "lib"); 52 | 53 | if (libPath.exists()) { 54 | /* 55 | * http://blog.cedarsoft.com/2010/11/setting-java-library-path- 56 | * programmatically 57 | */ 58 | try { 59 | System.setProperty("java.library.path", libPath.getAbsolutePath()); 60 | Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths"); 61 | fieldSysPath.setAccessible(true); 62 | fieldSysPath.set(null, null); 63 | } catch (Exception e) { 64 | throw new RuntimeException("Fail to force the reload of system paths property.", e); 65 | } 66 | } else { 67 | throw new RuntimeException("Unsupported architecture: " + (is64bits ? "64" : "32") + " bits"); 68 | } 69 | } else { 70 | throw new RuntimeException("Unsupported operating system: " + osName); 71 | } 72 | } 73 | 74 | public static void setBestLookAndFeel() { 75 | String osName = System.getProperty("os.name"); 76 | OS os = OS.resolve(osName); 77 | 78 | boolean lafSet = false; 79 | try { 80 | /* 81 | * Could work on other platform actually, but not intended to. 82 | */ 83 | if (os == OS.MacOSX) { 84 | /* 85 | * set system properties here that affect Quaqua for example the 86 | * default layout policy for tabbed panes. 87 | */ 88 | System.setProperty("Quaqua.tabLayoutPolicy", "wrap"); 89 | lafSet = setLookAndFeelIfAvailable("ch.randelshofer.quaqua.QuaquaLookAndFeel"); 90 | } 91 | /* 92 | * The GTK+ would probably be the system LaF in Linux, which is not 93 | * necessarily a good idea considering how is broken (in our case: 94 | * menu without shadows and with unreadable highlighting). 95 | */ 96 | else if (os == OS.Linux) { 97 | lafSet = setLookAndFeelIfAvailable("javax.swing.plaf.nimbus.NimbusLookAndFeel"); 98 | if (!lafSet) { 99 | lafSet = setLookAndFeelIfAvailable("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); 100 | } 101 | } 102 | } catch (Exception e) { 103 | logger.log(Level.WARNING, "Failed to load the best LaF.", e); 104 | } 105 | 106 | if (!lafSet) { 107 | try { 108 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 109 | } catch (Exception e) { 110 | logger.log(Level.WARNING, "Failed to load the system LaF.", e); 111 | } 112 | } 113 | } 114 | 115 | private static boolean setLookAndFeelIfAvailable(String className) throws InstantiationException, 116 | IllegalAccessException, UnsupportedLookAndFeelException { 117 | try { 118 | if (Native.class.getClassLoader().loadClass(className) != null) { 119 | UIManager.setLookAndFeel(className); 120 | return true; 121 | } else { 122 | return false; 123 | } 124 | } catch (ClassNotFoundException e) { 125 | return false; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/comm/Girino.java: -------------------------------------------------------------------------------- 1 | package org.hihan.girinoscope.comm; 2 | 3 | import gnu.io.CommPortIdentifier; 4 | 5 | import java.io.IOException; 6 | import java.util.AbstractMap; 7 | import java.util.HashMap; 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | public class Girino { 13 | 14 | public enum Parameter { 15 | BUFFER_SIZE(null, true), // 16 | BAUD_RATE(null, true), // 17 | PRESCALER("p", true), // 18 | VOLTAGE_REFERENCE("r", false), // 19 | TRIGGER_EVENT("e", true), // 20 | WAIT_DURATION("w", true), // 21 | THRESHOLD("t", true); 22 | 23 | private String command; 24 | private boolean readable; 25 | 26 | Parameter(String command, boolean readable) { 27 | this.command = command; 28 | this.readable = readable; 29 | } 30 | 31 | public String getIdentifier() { 32 | if (this == WAIT_DURATION) { 33 | return "waitDuration"; 34 | } else { 35 | return name().toLowerCase().replace('_', ' '); 36 | } 37 | } 38 | 39 | public String getDescription() { 40 | return name().charAt(0) + name().substring(1).toLowerCase().replace('_', ' '); 41 | } 42 | 43 | public static Parameter findByDescription(String description) { 44 | for (Parameter parameter : values()) { 45 | if (parameter.getDescription().equals(description)) { 46 | return parameter; 47 | } 48 | } 49 | return null; 50 | } 51 | 52 | private static Map.Entry read(Serial serial) throws IOException { 53 | String data = serial.readLine(); 54 | if (READY_MESSAGE.equals(data)) { 55 | data = serial.readLine(); 56 | } 57 | String[] items = data.split(":"); 58 | String name = items[0].trim(); 59 | int value = Integer.parseInt(items[1].trim()); 60 | Parameter parameter = Parameter.findByDescription(name); 61 | return new AbstractMap.SimpleEntry(parameter, value); 62 | } 63 | 64 | private int apply(Serial serial, int newValue) throws IOException { 65 | if (command != null) { 66 | serial.writeLine(command + newValue); 67 | String data = serial.readLine(); 68 | String[] items = data.split(":"); 69 | if (items.length > 1) { 70 | String message = items[0].trim(); 71 | String identifier = getIdentifier(); 72 | if (message.equals(String.format("Setting %s to", identifier))) { 73 | return Integer.parseInt(items[1].trim()); 74 | } else { 75 | throw new IOException("Not matching returned parameter " + identifier); 76 | } 77 | } else { 78 | throw new IOException("Unknown parameter " + getDescription()); 79 | } 80 | } else { 81 | throw new IllegalArgumentException("Read only parameter " + getDescription()); 82 | } 83 | } 84 | } 85 | 86 | public static class PrescalerInfo { 87 | 88 | public final int value; 89 | public final double frequency; 90 | public final double timeframe; 91 | public final String description; 92 | public final boolean tooFast; 93 | public final boolean reallyTooFast; 94 | 95 | private PrescalerInfo(int n) { 96 | value = (int) Math.pow(2, n); 97 | double baseFrequency = 16 * 1000 * 1000; 98 | double clockCycleCountPerConversion = 13; 99 | frequency = baseFrequency / value / clockCycleCountPerConversion; 100 | timeframe = 512 / frequency; 101 | tooFast = n < 5; 102 | reallyTooFast = n < 3; 103 | description = String.format("%.1f kHz / %.1f ms", frequency / 1000, timeframe * 1000); 104 | } 105 | 106 | public static List values() { 107 | List infos = new LinkedList(); 108 | for (int i = 2; i < 8; ++i) { 109 | infos.add(new PrescalerInfo(i)); 110 | } 111 | return infos; 112 | } 113 | } 114 | 115 | public enum TriggerEventMode { 116 | 117 | TOGGLE(0, "Toggle"), // 118 | FALLING_EDGE(2, "Falling edge"), // 119 | RISING_EDGE(3, "Rising edge"); 120 | 121 | public int value; 122 | public String description; 123 | 124 | private TriggerEventMode(int value, String description) { 125 | this.value = value; 126 | this.description = description; 127 | } 128 | } 129 | 130 | public enum VoltageReference { 131 | 132 | AREF(0, "AREF, Internal Vref turned off"), // 133 | AVCC(1, "AVCC with external capacitor at AREF pin"), // 134 | /* 135 | * The value is misleading since it sets [REFS1, REFS0] to 11 (10 is 136 | * reserved). At least, the trigger event mode always uses the [ACI1, 137 | * ACI0] value (hence the gap since 2 is also a reserved value). 138 | */ 139 | INTERNAL(2, "Internal 1.1V Vref with external capacitor at AREF pin"); 140 | 141 | public int value; 142 | public String description; 143 | 144 | private VoltageReference(int value, String description) { 145 | this.value = value; 146 | this.description = description; 147 | } 148 | } 149 | 150 | /** Milliseconds to wait once a new connection has been etablished. */ 151 | private static final int SETUP_DELAY_ON_RESET = 2000; 152 | 153 | private static final String READY_MESSAGE = "Girino ready"; 154 | 155 | private static final String START_ACQUIRING_COMMAND = "s"; 156 | 157 | private static final String STOP_ACQUIRING_COMMAND = "S"; 158 | 159 | private static final String DUMP_COMMAND = "d"; 160 | 161 | private Serial serial; 162 | 163 | private CommPortIdentifier portId; 164 | 165 | private Map parameters = new HashMap(); 166 | 167 | public static Map getDefaultParameters(Map parameters) { 168 | parameters.put(Parameter.BUFFER_SIZE, 512); 169 | parameters.put(Parameter.PRESCALER, 32); 170 | parameters.put(Parameter.VOLTAGE_REFERENCE, VoltageReference.AVCC.value); 171 | parameters.put(Parameter.TRIGGER_EVENT, TriggerEventMode.TOGGLE.value); 172 | parameters.put(Parameter.WAIT_DURATION, 512 - 32); 173 | parameters.put(Parameter.THRESHOLD, 200); 174 | return parameters; 175 | } 176 | 177 | private void connect(CommPortIdentifier newPortId) throws Exception { 178 | if (newPortId != null) { 179 | if (serial == null || !same(portId, newPortId)) { 180 | portId = newPortId; 181 | if (serial != null) { 182 | disconnect(); 183 | } 184 | 185 | serial = new Serial(portId); 186 | try { 187 | /* 188 | * Note that the USB to serial adapter is usually configured 189 | * to reset the AVR each time a connection is etablish. The 190 | * delay here is to give some time to the controller to set 191 | * itself up. 192 | */ 193 | Thread.sleep(SETUP_DELAY_ON_RESET); 194 | 195 | String data; 196 | do { 197 | data = serial.readLine(); 198 | } while (!data.endsWith(READY_MESSAGE)); 199 | 200 | readParameters(); 201 | } catch (InterruptedException e) { 202 | disconnect(); 203 | } 204 | } 205 | } else { 206 | throw new IllegalArgumentException("No serial port"); 207 | } 208 | } 209 | 210 | public void disconnect() throws IOException { 211 | if (serial != null) { 212 | serial.close(); 213 | serial = null; 214 | } 215 | } 216 | 217 | private void readParameters() throws IOException { 218 | int readableParameterCount = 0; 219 | for (Parameter parameter : Parameter.values()) { 220 | if (parameter.readable) { 221 | ++readableParameterCount; 222 | } 223 | } 224 | 225 | serial.writeLine(DUMP_COMMAND); 226 | for (int i = 0; i < readableParameterCount; ++i) { 227 | Map.Entry entry = Parameter.read(serial); 228 | if (entry.getKey() != null) { 229 | parameters.put(entry.getKey(), entry.getValue()); 230 | } 231 | } 232 | } 233 | 234 | /** 235 | * @throws IOException 236 | * Provided parameters shall be verified by the caller since 237 | * some parameters could have been set back to a different value 238 | * than asked. 239 | */ 240 | private void applyParameters(Map newParameters) throws IOException { 241 | for (Map.Entry entry : newParameters.entrySet()) { 242 | Parameter parameter = entry.getKey(); 243 | Integer newValue = entry.getValue(); 244 | 245 | // We only update modified parameters. 246 | if (!same(newValue, parameters.get(parameter))) { 247 | int returnedValue = parameter.apply(serial, newValue); 248 | parameters.put(parameter, returnedValue); 249 | if (!same(newValue, parameters.get(parameter))) { 250 | throw new IOException("Change has been rejected for parameter " + parameter.getDescription() + ": " 251 | + newValue + " =/= " + returnedValue); 252 | } 253 | } 254 | } 255 | } 256 | 257 | public void setConnection(final CommPortIdentifier newPortId, final Map newParameters) 258 | throws Exception { 259 | connect(newPortId); 260 | if (serial != null) { 261 | applyParameters(newParameters); 262 | } 263 | } 264 | 265 | public byte[] acquireData() throws Exception { 266 | serial.writeLine(START_ACQUIRING_COMMAND); 267 | /* 268 | * Note that the Girino reset its buffer (with zeros), meaning we won’t 269 | * catch a lot of the signal before the trigger if it happens too fast. 270 | */ 271 | try { 272 | byte[] buffer = new byte[512]; 273 | int size = serial.readBytes(buffer); 274 | return size == buffer.length ? buffer : null; 275 | } finally { 276 | /* 277 | * We can only acquire a single buffer and need to stop / start to 278 | * get the next one. That’s how the Girino code works, but it was 279 | * probably a bit different during its development. In practise, 280 | * this 'stop' is only required when we cancel a trigger waiting. 281 | */ 282 | serial.writeLine(STOP_ACQUIRING_COMMAND); 283 | } 284 | } 285 | 286 | private static boolean same(Object o1, Object o2) { 287 | if (o1 == o2) { 288 | return true; 289 | } else if (o1 == null || o2 == null) { 290 | return false; 291 | } else { 292 | return o1.equals(o2); 293 | } 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/comm/Serial.java: -------------------------------------------------------------------------------- 1 | package org.hihan.girinoscope.comm; 2 | 3 | import gnu.io.CommPortIdentifier; 4 | import gnu.io.SerialPort; 5 | 6 | import java.io.Closeable; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.OutputStream; 10 | import java.util.Enumeration; 11 | import java.util.LinkedList; 12 | import java.util.List; 13 | import java.util.logging.Level; 14 | import java.util.logging.Logger; 15 | import java.util.regex.Pattern; 16 | 17 | import org.hihan.girinoscope.Native; 18 | 19 | /** 20 | * Reading operations are semi-interruptible here. As long as nothing as been 21 | * read, it can be interrupted, but once something has been read, it continues 22 | * up to the line / buffer completion. This behavior is here to avoid to stop 23 | * reading a bunch of data sent by the Girino. It do it fast enough not to 24 | * bother us. The only delay we want to interrupt is when nothing is coming, per 25 | * instance when we wait for the trigger to happen. A crossover can still occur 26 | * - the trigger happening the same time the user cancel the operation - but it 27 | * is not likely to happen and the Girino doesn’t support a complex enough 28 | * protocol to prevent this kind of problem anyway. On the other hand, the 29 | * consequence is not fatal. We will read garbage the next time, display some 30 | * error to the user and move along. 31 | */ 32 | public class Serial implements Closeable { 33 | 34 | private static final Logger logger = Logger.getLogger(Serial.class.getName()); 35 | 36 | static { 37 | Native.setLibraryPath(); 38 | } 39 | 40 | /** The port we're normally going to use. */ 41 | private static final Pattern[] ACCEPTABLE_PORT_NAMES = { 42 | // 43 | Pattern.compile("/dev/tty\\.usbserial-.+"), // Mac OS X 44 | Pattern.compile("/dev/tty\\.usbmodem.+"), // Mac OS X 45 | Pattern.compile("/dev/ttyACM\\d+"), // Raspberry Pi 46 | Pattern.compile("/dev/ttyUSB\\d+"), // Linux 47 | Pattern.compile("COM\\d+"), // Windows 48 | }; 49 | 50 | /** Milliseconds to block while waiting for port open. */ 51 | private static final int TIME_OUT = 2000; 52 | 53 | /** Default bits per second for COM port. */ 54 | private static final int DATA_RATE = 115200; 55 | 56 | /** Milliseconds to wait when no input is available. */ 57 | private static final int READ_DELAY = 200; 58 | 59 | private SerialPort serialPort; 60 | 61 | /** The output stream to the port. */ 62 | private InputStream input; 63 | 64 | /** 65 | * A BufferedReader which will be fed by a InputStreamReader converting the 66 | * bytes into characters making the displayed results codepage independent. 67 | */ 68 | private OutputStream output; 69 | 70 | public Serial(CommPortIdentifier portId) throws Exception { 71 | connect(portId); 72 | } 73 | 74 | public void connect(CommPortIdentifier portId) throws Exception { 75 | serialPort = (SerialPort) portId.open(getClass().getName(), TIME_OUT); 76 | 77 | serialPort.setSerialPortParams(DATA_RATE, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); 78 | serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE); 79 | 80 | output = serialPort.getOutputStream(); 81 | input = serialPort.getInputStream(); 82 | 83 | serialPort.notifyOnDataAvailable(false); 84 | } 85 | 86 | public static List enumeratePorts() { 87 | List ports = new LinkedList(); 88 | 89 | Enumeration portEnum = CommPortIdentifier.getPortIdentifiers(); 90 | while (portEnum.hasMoreElements()) { 91 | CommPortIdentifier portIdentifier = (CommPortIdentifier) portEnum.nextElement(); 92 | for (Pattern acceptablePortName : ACCEPTABLE_PORT_NAMES) { 93 | String portName = portIdentifier.getName(); 94 | if (acceptablePortName.matcher(portName).matches()) { 95 | if (portName.startsWith("/dev/ttyACM")) { 96 | /* 97 | * the next line is for Raspberry Pi and gets us into 98 | * the while loop and was suggested here: 99 | * http://www.raspberrypi 100 | * .org/phpBB3/viewtopic.php?f=81&t=32186 101 | */ 102 | System.setProperty("gnu.io.rxtx.SerialPorts", portName); 103 | } 104 | ports.add(portIdentifier); 105 | } 106 | } 107 | } 108 | 109 | return ports; 110 | } 111 | 112 | public String readLine() throws IOException { 113 | StringBuilder line = new StringBuilder(); 114 | int length = 0; 115 | try { 116 | while (true) { 117 | int c; 118 | if ((input.available() > 0 || line.length() > 0) && (c = input.read()) >= 0) { 119 | line.append((char) c); 120 | ++length; 121 | boolean eol = length >= 2 && line.charAt(length - 2) == '\r' && line.charAt(length - 1) == '\n'; 122 | if (eol) { 123 | line.setLength(length - 2); 124 | break; 125 | } 126 | } else { 127 | /* 128 | * Sleeping here allows us to be interrupted (the serial 129 | * input is not interruptible itself). 130 | */ 131 | Thread.sleep(READ_DELAY); 132 | } 133 | } 134 | } catch (InterruptedException e) { 135 | logger.log(Level.FINE, "Read aborted"); 136 | return null; 137 | } 138 | logger.log(Level.FINE, "< ({0})", line); 139 | return line.toString(); 140 | } 141 | 142 | public int readBytes(byte[] buffer) throws IOException { 143 | int offset = 0; 144 | try { 145 | while (offset < buffer.length) { 146 | if (input.available() > 0 || offset > 0) { 147 | int size = input.read(buffer, offset, buffer.length - offset); 148 | if (size < 0) { 149 | break; 150 | } 151 | offset += size; 152 | } else { 153 | /* 154 | * Sleeping here allows us to be interrupted (the serial 155 | * input is not interruptible itself). 156 | */ 157 | Thread.sleep(READ_DELAY); 158 | } 159 | } 160 | } catch (InterruptedException e) { 161 | logger.log(Level.FINE, "Read aborted"); 162 | return -1; 163 | } 164 | logger.log(Level.FINE, "< {0} byte(s)", offset); 165 | return offset; 166 | } 167 | 168 | public void writeLine(String line) throws IOException { 169 | for (int i = 0; i < line.length(); ++i) { 170 | output.write(line.charAt(i)); 171 | } 172 | output.flush(); 173 | logger.log(Level.FINE, "> ({0})", line); 174 | } 175 | 176 | @Override 177 | public void close() { 178 | if (serialPort != null) { 179 | try { 180 | output.flush(); 181 | } catch (IOException e) { 182 | logger.log(Level.WARNING, "When flushing output before closing serial.", e); 183 | } 184 | serialPort.close(); 185 | serialPort = null; 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/ui/AboutDialog.java: -------------------------------------------------------------------------------- 1 | package org.hihan.girinoscope.ui; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.Color; 5 | import java.awt.Desktop; 6 | import java.io.BufferedReader; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.InputStreamReader; 10 | import java.net.URI; 11 | import java.net.URISyntaxException; 12 | import java.util.Enumeration; 13 | import java.util.logging.Level; 14 | import java.util.logging.Logger; 15 | 16 | import javax.swing.BorderFactory; 17 | import javax.swing.JDialog; 18 | import javax.swing.JEditorPane; 19 | import javax.swing.JFrame; 20 | import javax.swing.WindowConstants; 21 | import javax.swing.event.HyperlinkEvent; 22 | import javax.swing.event.HyperlinkListener; 23 | import javax.swing.text.AttributeSet; 24 | import javax.swing.text.html.HTMLEditorKit; 25 | import javax.swing.text.html.StyleSheet; 26 | 27 | @SuppressWarnings("serial") 28 | public class AboutDialog extends JDialog { 29 | 30 | private static final Logger logger = Logger.getLogger(AboutDialog.class.getName()); 31 | 32 | public AboutDialog(JFrame owner) { 33 | super(owner, true); 34 | setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 35 | 36 | setLayout(new BorderLayout()); 37 | setBackground(Color.WHITE); 38 | add(createEditorPane(), BorderLayout.CENTER); 39 | 40 | pack(); 41 | setLocationRelativeTo(owner); 42 | setResizable(false); 43 | } 44 | 45 | private JEditorPane createEditorPane() { 46 | try { 47 | InputStream input = getClass().getResource("about.html").openStream(); 48 | try { 49 | BufferedReader reader = new BufferedReader(new InputStreamReader(input)); 50 | StringBuilder html = new StringBuilder(); 51 | String line; 52 | while ((line = reader.readLine()) != null) { 53 | html.append(line); 54 | } 55 | return createEditorPane(html.toString()); 56 | } finally { 57 | input.close(); 58 | } 59 | } catch (IOException e) { 60 | throw new RuntimeException(e); 61 | } 62 | } 63 | 64 | private JEditorPane createEditorPane(String text) { 65 | HTMLEditorKit kit = new HTMLEditorKit(); 66 | StyleSheet styleSheet = kit.getStyleSheet(); 67 | styleSheet.addRule("body {bgcolor: white;}"); 68 | 69 | JEditorPane editorPane = new JEditorPane(); 70 | editorPane.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); 71 | editorPane.setOpaque(true); 72 | editorPane.setEditorKit(kit); 73 | editorPane.setContentType("text/html"); 74 | editorPane.setText(text); 75 | editorPane.setEditable(false); 76 | 77 | editorPane.addHyperlinkListener(new HyperlinkListener() { 78 | @Override 79 | public void hyperlinkUpdate(final HyperlinkEvent event) { 80 | if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { 81 | final String href = getHref(event); 82 | try { 83 | Desktop.getDesktop().browse(new URI(href)); 84 | } catch (IOException e) { 85 | logger.log(Level.WARNING, "Can’t open link " + href, e); 86 | } catch (URISyntaxException e) { 87 | logger.log(Level.WARNING, "Can’t open link " + href, e); 88 | } 89 | } 90 | } 91 | }); 92 | 93 | return editorPane; 94 | } 95 | 96 | private String getHref(HyperlinkEvent event) { 97 | AttributeSet attributes = event.getSourceElement().getAttributes(); 98 | return getAttribute((AttributeSet) getAttribute(attributes, "a"), "href").toString(); 99 | } 100 | 101 | private Object getAttribute(AttributeSet attributes, String name) { 102 | for (Enumeration enumeration = attributes.getAttributeNames(); enumeration.hasMoreElements();) { 103 | Object nameKey = enumeration.nextElement(); 104 | if (name.equals(nameKey.toString())) { 105 | return attributes.getAttribute(nameKey); 106 | } 107 | } 108 | return null; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/ui/Axis.java: -------------------------------------------------------------------------------- 1 | package org.hihan.girinoscope.ui; 2 | 3 | import java.awt.Font; 4 | import java.awt.Graphics2D; 5 | import java.awt.Rectangle; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class Axis { 10 | 11 | public static class GraphLabel { 12 | 13 | private String label; 14 | 15 | private Rectangle bounds; 16 | 17 | private GraphLabel(String label) { 18 | this.label = label; 19 | } 20 | 21 | public String getLabel() { 22 | return label; 23 | } 24 | 25 | public Rectangle getBounds() { 26 | return bounds; 27 | } 28 | } 29 | 30 | private double fraction; 31 | 32 | private List graphLabels; 33 | 34 | private Rectangle maxBounds; 35 | 36 | public Axis(double startValue, double endValue, String format) { 37 | this(startValue, endValue, chooseIncrement(startValue, endValue), format); 38 | } 39 | 40 | private static double chooseIncrement(double startValue, double endValue) { 41 | double length = endValue - startValue; 42 | double increment = Math.pow(10, Math.round(Math.log10(length / 10))); 43 | double fraction = length / increment; 44 | if (fraction < 5) { 45 | increment /= 2; 46 | } 47 | if (fraction > 10) { 48 | increment *= 2; 49 | } 50 | return increment; 51 | } 52 | 53 | public Axis(double startValue, double endValue, double increment, String format) { 54 | fraction = (endValue - startValue) / increment; 55 | graphLabels = new ArrayList(); 56 | for (double value = startValue; value <= endValue; value += increment) { 57 | graphLabels.add(new GraphLabel(String.format(format, value))); 58 | } 59 | } 60 | 61 | public void complete(Graphics2D g, Font font) { 62 | if (maxBounds == null) { 63 | maxBounds = new Rectangle(0, 0, 0, 0); 64 | for (GraphLabel graphLabel : graphLabels) { 65 | if (graphLabel.bounds == null) { 66 | graphLabel.bounds = g.getFontMetrics(font).getStringBounds(graphLabel.label, g).getBounds(); 67 | } 68 | maxBounds = maxBounds.union(graphLabel.bounds); 69 | } 70 | } 71 | } 72 | 73 | public double getFraction() { 74 | return fraction; 75 | } 76 | 77 | public GraphLabel[] graphLabels() { 78 | return graphLabels.toArray(new GraphLabel[0]); 79 | } 80 | 81 | public Rectangle getMaxBounds() { 82 | return maxBounds; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/ui/GraphPane.java: -------------------------------------------------------------------------------- 1 | package org.hihan.girinoscope.ui; 2 | 3 | import java.awt.BasicStroke; 4 | import java.awt.Color; 5 | import java.awt.Cursor; 6 | import java.awt.Font; 7 | import java.awt.Graphics; 8 | import java.awt.Graphics2D; 9 | import java.awt.Insets; 10 | import java.awt.Point; 11 | import java.awt.Rectangle; 12 | import java.awt.RenderingHints; 13 | import java.awt.Stroke; 14 | import java.awt.event.MouseEvent; 15 | import java.awt.event.MouseMotionListener; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | import javax.swing.JPanel; 20 | import javax.swing.SwingUtilities; 21 | 22 | import org.hihan.girinoscope.ui.Axis.GraphLabel; 23 | 24 | @SuppressWarnings("serial") 25 | public class GraphPane extends JPanel { 26 | 27 | private static final Color DIVISION_COLOR = new Color(0xbcbcbc); 28 | 29 | private static final Color SUB_DIVISION_COLOR = new Color(0xcdcdcd); 30 | 31 | private static final Color TEXT_COLOR = new Color(0x9a9a9a); 32 | 33 | private static final Color DATA_COLOR = Color.CYAN.darker(); 34 | 35 | private static final Color THRESHOLD_COLOR = Color.ORANGE.darker(); 36 | 37 | private static final Color WAIT_DURATION_COLOR = Color.GREEN.darker(); 38 | 39 | private static final Font FONT = Font.decode(Font.MONOSPACED); 40 | 41 | private static final Stroke DASHED = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, 42 | new float[] { 5 }, 0); 43 | 44 | private static final Stroke DOTTED = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, 45 | new float[] { 3 }, 0); 46 | 47 | private static final int V_MAX = 255; 48 | 49 | private static final int U_MAX = 1279; 50 | 51 | private Stroke dataStroke = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL); 52 | 53 | private Axis xAxis; 54 | 55 | private Axis yAxis; 56 | 57 | private byte[] data; 58 | 59 | private Rectangle graphArea; 60 | 61 | private int threshold; 62 | 63 | private int waitDuration; 64 | 65 | private enum Rule { 66 | THRESHOLD_RULE, WAIT_DURATION_RULE 67 | } 68 | 69 | private Rule grabbedRule; 70 | 71 | public GraphPane(int initialThreshold, int initialWaitDuration) { 72 | threshold = initialThreshold; 73 | waitDuration = initialWaitDuration; 74 | addMouseMotionListener(new MouseMotionListener() { 75 | 76 | @Override 77 | public void mouseMoved(MouseEvent event) { 78 | Map anchors = new HashMap(); 79 | 80 | Point thresholdRuleAnchorLocation = toGraphArea(U_MAX, threshold); 81 | SwingUtilities.convertPointToScreen(thresholdRuleAnchorLocation, GraphPane.this); 82 | anchors.put(Rule.THRESHOLD_RULE, thresholdRuleAnchorLocation); 83 | 84 | Point waitDurationRuleAnchorLocation = toGraphArea(waitDuration, V_MAX); 85 | SwingUtilities.convertPointToScreen(waitDurationRuleAnchorLocation, GraphPane.this); 86 | anchors.put(Rule.WAIT_DURATION_RULE, waitDurationRuleAnchorLocation); 87 | 88 | if (grabbedRule != null) { 89 | boolean stillLocked = anchors.get(grabbedRule).distance(event.getLocationOnScreen()) < 16; 90 | if (!stillLocked) { 91 | setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); 92 | grabbedRule = null; 93 | repaint(); 94 | } 95 | } 96 | 97 | if (grabbedRule == null) { 98 | for (Map.Entry entry : anchors.entrySet()) { 99 | boolean nowLocked = entry.getValue().distance(event.getLocationOnScreen()) < 16; 100 | if (nowLocked) { 101 | setCursor(new Cursor(Cursor.HAND_CURSOR)); 102 | grabbedRule = entry.getKey(); 103 | repaint(); 104 | return; 105 | } 106 | } 107 | } 108 | } 109 | 110 | @Override 111 | public void mouseDragged(MouseEvent event) { 112 | if (grabbedRule != null) { 113 | Point graphAreaPosition = event.getLocationOnScreen(); 114 | SwingUtilities.convertPointFromScreen(graphAreaPosition, GraphPane.this); 115 | Point uv = toData(graphAreaPosition.x, graphAreaPosition.y); 116 | switch (grabbedRule) { 117 | 118 | case THRESHOLD_RULE: 119 | int newThreshold = uv.y; 120 | GraphPane.this.threshold = Math.max(0, Math.min(newThreshold, V_MAX)); 121 | break; 122 | 123 | case WAIT_DURATION_RULE: 124 | int newWaitDuration = uv.x; 125 | GraphPane.this.waitDuration = Math.max(0, Math.min(newWaitDuration, U_MAX)); 126 | break; 127 | 128 | default: 129 | throw new IllegalArgumentException(grabbedRule.name()); 130 | } 131 | repaint(); 132 | } 133 | } 134 | }); 135 | } 136 | 137 | public void setDataStrokeWidth(float width) { 138 | dataStroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL); 139 | } 140 | 141 | public void setCoordinateSystem(Axis xAxis, Axis yAxis) { 142 | this.xAxis = xAxis; 143 | this.yAxis = yAxis; 144 | repaint(); 145 | } 146 | 147 | public void setData(byte[] data) { 148 | this.data = data; 149 | repaint(); 150 | } 151 | 152 | public int getThreshold() { 153 | return threshold; 154 | } 155 | 156 | public int getWaitDuration() { 157 | return waitDuration; 158 | } 159 | 160 | @Override 161 | protected void paintComponent(Graphics g) { 162 | Graphics2D g2d = (Graphics2D) g; 163 | 164 | g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 165 | g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); 166 | 167 | int w = getWidth(); 168 | int h = getHeight(); 169 | 170 | g2d.setColor(Color.WHITE); 171 | g2d.fillRect(0, 0, w, h); 172 | 173 | if (xAxis != null && yAxis != null) { 174 | xAxis.complete(g2d, FONT); 175 | yAxis.complete(g2d, FONT); 176 | 177 | graphArea = new Rectangle(16, 16, w - 32, h - 32); 178 | Insets labelInsets = new Insets(2, 12, 0, 0); 179 | graphArea.width -= yAxis.getMaxBounds().width + labelInsets.left + labelInsets.right; 180 | graphArea.height -= xAxis.getMaxBounds().height + labelInsets.top + labelInsets.bottom; 181 | 182 | if (w > 0 && h > 0) { 183 | paintXAxis(g2d, labelInsets); 184 | paintYAxis(g2d, labelInsets); 185 | if (data != null) { 186 | paintData(g2d); 187 | } 188 | paintWaitDurationRule(g2d); 189 | paintThresholdRule(g2d); 190 | } 191 | } 192 | } 193 | 194 | private void paintXAxis(Graphics2D g, Insets labelInsets) { 195 | g.translate(graphArea.x, graphArea.y); 196 | GraphLabel[] xLabels = xAxis.graphLabels(); 197 | for (int i = 0; i < xLabels.length; ++i) { 198 | GraphLabel xLabel = xLabels[i]; 199 | int xOffset = (int) (i * graphArea.width / xAxis.getFraction()); 200 | 201 | Stroke defaultStroke = g.getStroke(); 202 | 203 | g.setStroke(i % (xLabels.length / 2) != 0 ? DASHED : defaultStroke); 204 | g.setColor(i % (xLabels.length - 1) == 0 ? DIVISION_COLOR : SUB_DIVISION_COLOR); 205 | g.drawLine(xOffset, 0, xOffset, graphArea.height); 206 | 207 | g.setStroke(defaultStroke); 208 | g.setColor(TEXT_COLOR); 209 | Rectangle bounds = xLabel.getBounds(); 210 | int dx; 211 | if (i == 0) { 212 | dx = 0; 213 | } else { 214 | dx = -bounds.width / 2; 215 | } 216 | int dy = labelInsets.top; 217 | g.drawString(xLabel.getLabel(), xOffset + dx, graphArea.height + bounds.height + dy); 218 | } 219 | g.drawLine(graphArea.width, 0, graphArea.width, graphArea.height); 220 | 221 | g.translate(-graphArea.x, -graphArea.y); 222 | } 223 | 224 | private void paintYAxis(Graphics2D g, Insets labelInsets) { 225 | g.translate(graphArea.x, graphArea.y); 226 | GraphLabel[] yLabels = yAxis.graphLabels(); 227 | for (int i = 0; i < yLabels.length; ++i) { 228 | GraphLabel yLabel = yLabels[yLabels.length - i - 1]; 229 | int yOffset = (int) (i * graphArea.height / yAxis.getFraction()); 230 | 231 | Stroke defaultStroke = g.getStroke(); 232 | 233 | g.setStroke(i % (yLabels.length / 2) != 0 ? DASHED : defaultStroke); 234 | g.setColor(i % (yLabels.length - 1) == 0 ? DIVISION_COLOR : SUB_DIVISION_COLOR); 235 | g.drawLine(0, yOffset, graphArea.width, yOffset); 236 | 237 | g.setStroke(defaultStroke); 238 | g.setColor(TEXT_COLOR); 239 | Rectangle bounds = yLabel.getBounds(); 240 | int dy = bounds.height / 2; 241 | int dx = labelInsets.left; 242 | g.drawString(yLabel.getLabel(), graphArea.width + dx, yOffset + dy); 243 | } 244 | g.drawLine(0, graphArea.height, graphArea.width, graphArea.height); 245 | g.translate(-graphArea.x, -graphArea.y); 246 | } 247 | 248 | private void paintData(Graphics2D g) { 249 | g.setColor(DATA_COLOR); 250 | Stroke defaultStroke = g.getStroke(); 251 | g.setStroke(dataStroke); 252 | int u = U_MAX; 253 | Point previousPoint = null; 254 | for (byte b : data) { 255 | Point point = toGraphArea(u--, b & 0xFF); 256 | if (previousPoint != null) { 257 | g.drawLine(previousPoint.x, previousPoint.y, point.x, point.y); 258 | } 259 | previousPoint = point; 260 | } 261 | g.setStroke(defaultStroke); 262 | } 263 | 264 | private void paintThresholdRule(Graphics2D g) { 265 | g.setColor(THRESHOLD_COLOR); 266 | Point point = toGraphArea(U_MAX, threshold); 267 | Stroke defaultStroke = g.getStroke(); 268 | g.setStroke(DOTTED); 269 | g.drawLine(point.x, point.y, point.x + graphArea.width, point.y); 270 | g.setStroke(defaultStroke); 271 | 272 | Graphics2D gg = (Graphics2D) g.create(); 273 | gg.translate(point.x, point.y); 274 | gg.rotate(Math.PI / 4); 275 | if (grabbedRule == Rule.THRESHOLD_RULE) { 276 | gg.fill3DRect(-4, -4, 9, 9, true); 277 | } else { 278 | gg.fill3DRect(-3, -3, 7, 7, true); 279 | } 280 | } 281 | 282 | private void paintWaitDurationRule(Graphics2D g) { 283 | g.setColor(WAIT_DURATION_COLOR); 284 | Point point = toGraphArea(waitDuration, V_MAX); 285 | Stroke defaultStroke = g.getStroke(); 286 | g.setStroke(DOTTED); 287 | g.drawLine(point.x, point.y, point.x, point.y + graphArea.height); 288 | g.setStroke(defaultStroke); 289 | 290 | Graphics2D gg = (Graphics2D) g.create(); 291 | gg.translate(point.x, point.y); 292 | gg.rotate(Math.PI / 4); 293 | if (grabbedRule == Rule.WAIT_DURATION_RULE) { 294 | gg.fill3DRect(-4, -4, 9, 9, true); 295 | } else { 296 | gg.fill3DRect(-3, -3, 7, 7, true); 297 | } 298 | } 299 | 300 | private Point toGraphArea(int u, int v) { 301 | int x = (int) Math.round((U_MAX - u) * graphArea.width / U_MAX + graphArea.x); 302 | int y = (int) Math.round((V_MAX - v) * graphArea.height / V_MAX + graphArea.y); 303 | return new Point(x, y); 304 | } 305 | 306 | private Point toData(int x, int y) { 307 | int u = (int) Math.round(U_MAX - (x - graphArea.x) * U_MAX / graphArea.width); 308 | int v = (int) Math.round(V_MAX - (y - graphArea.y) * V_MAX / graphArea.height); 309 | return new Point(u, v); 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/ui/StatusBar.java: -------------------------------------------------------------------------------- 1 | package org.hihan.girinoscope.ui; 2 | 3 | import java.awt.Graphics; 4 | import java.awt.Graphics2D; 5 | import java.awt.geom.AffineTransform; 6 | 7 | import javax.swing.Box; 8 | import javax.swing.JLabel; 9 | import javax.swing.JToolBar; 10 | import javax.swing.UIManager; 11 | 12 | @SuppressWarnings("serial") 13 | public class StatusBar extends JToolBar { 14 | 15 | private JLabel label = new JLabel(); 16 | 17 | private boolean mirrored; 18 | 19 | public StatusBar() { 20 | setFloatable(false); 21 | add(Box.createVerticalStrut(16)); 22 | add(label); 23 | } 24 | 25 | public void setText(String text) { 26 | label.setText(text); 27 | } 28 | 29 | @Override 30 | protected void paintComponent(Graphics g) { 31 | String laf = UIManager.getLookAndFeel().getClass().getName(); 32 | /* 33 | * On other LaF, notably Nimbus, toolbar painting take the component 34 | * location into account (North or South in our case). It is not the 35 | * case with the GTK+ LaF which need our help here. 36 | */ 37 | mirrored = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel".equals(laf); 38 | super.paintComponent(mirrored ? createVerticalMirrorGraphics(g) : g); 39 | } 40 | 41 | private Graphics createVerticalMirrorGraphics(Graphics g) { 42 | Graphics2D g2d = (Graphics2D) g.create(); 43 | AffineTransform transform = AffineTransform.getScaleInstance(1, -1); 44 | transform.translate(0, -getHeight()); 45 | g2d.transform(transform); 46 | return g2d; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/ui/UI.java: -------------------------------------------------------------------------------- 1 | package org.hihan.girinoscope.ui; 2 | 3 | import gnu.io.CommPortIdentifier; 4 | 5 | import java.awt.BorderLayout; 6 | import java.awt.Color; 7 | import java.awt.Component; 8 | import java.awt.Dimension; 9 | import java.awt.event.ActionEvent; 10 | import java.beans.PropertyChangeEvent; 11 | import java.beans.PropertyChangeListener; 12 | import java.io.IOException; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.concurrent.Callable; 17 | import java.util.concurrent.ExecutionException; 18 | import java.util.concurrent.ExecutorService; 19 | import java.util.concurrent.Executors; 20 | import java.util.concurrent.Future; 21 | import java.util.concurrent.TimeUnit; 22 | import java.util.concurrent.TimeoutException; 23 | import java.util.logging.ConsoleHandler; 24 | import java.util.logging.Level; 25 | import java.util.logging.Logger; 26 | import java.util.logging.SimpleFormatter; 27 | 28 | import javax.swing.AbstractAction; 29 | import javax.swing.AbstractButton; 30 | import javax.swing.Action; 31 | import javax.swing.ButtonGroup; 32 | import javax.swing.JCheckBoxMenuItem; 33 | import javax.swing.JComponent; 34 | import javax.swing.JFrame; 35 | import javax.swing.JMenu; 36 | import javax.swing.JMenuBar; 37 | import javax.swing.JToolBar; 38 | import javax.swing.SwingUtilities; 39 | import javax.swing.SwingWorker; 40 | import javax.swing.UIManager; 41 | import javax.swing.UIManager.LookAndFeelInfo; 42 | import javax.swing.WindowConstants; 43 | 44 | import org.hihan.girinoscope.Native; 45 | import org.hihan.girinoscope.comm.Girino; 46 | import org.hihan.girinoscope.comm.Girino.Parameter; 47 | import org.hihan.girinoscope.comm.Girino.PrescalerInfo; 48 | import org.hihan.girinoscope.comm.Girino.TriggerEventMode; 49 | import org.hihan.girinoscope.comm.Girino.VoltageReference; 50 | import org.hihan.girinoscope.comm.Serial; 51 | import org.hihan.girinoscope.ui.images.Icon; 52 | 53 | @SuppressWarnings("serial") 54 | public class UI extends JFrame { 55 | 56 | private static final Logger logger = Logger.getLogger(UI.class.getName()); 57 | 58 | public static void main(String[] args) throws Exception { 59 | 60 | Logger rootLogger = Logger.getLogger("org.hihan.girinoscope"); 61 | rootLogger.setLevel(Level.WARNING); 62 | ConsoleHandler handler = new ConsoleHandler(); 63 | handler.setFormatter(new SimpleFormatter()); 64 | handler.setLevel(Level.ALL); 65 | rootLogger.addHandler(handler); 66 | 67 | SwingUtilities.invokeAndWait(new Runnable() { 68 | public void run() { 69 | Native.setBestLookAndFeel(); 70 | JFrame frame = new UI(); 71 | frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 72 | frame.pack(); 73 | frame.setLocationRelativeTo(null); 74 | frame.setVisible(true); 75 | } 76 | }); 77 | } 78 | 79 | private Girino girino = new Girino(); 80 | 81 | private CommPortIdentifier portId; 82 | 83 | private Map parameters = Girino.getDefaultParameters(new HashMap()); 84 | 85 | private GraphPane graphPane; 86 | 87 | private StatusBar statusBar; 88 | 89 | private DataAcquisitionTask currentDataAcquisitionTask; 90 | 91 | private ExecutorService executor = Executors.newSingleThreadExecutor(); 92 | 93 | private class DataAcquisitionTask extends SwingWorker { 94 | 95 | private CommPortIdentifier frozenPortId; 96 | 97 | private Map frozenParameters = new HashMap(); 98 | 99 | public DataAcquisitionTask() { 100 | startAcquiringAction.setEnabled(false); 101 | stopAcquiringAction.setEnabled(true); 102 | } 103 | 104 | @Override 105 | protected Void doInBackground() throws Exception { 106 | while (!isCancelled()) { 107 | updateConnection(); 108 | acquireData(); 109 | } 110 | return null; 111 | } 112 | 113 | private void updateConnection() throws Exception { 114 | synchronized (UI.this) { 115 | frozenPortId = portId; 116 | frozenParameters.putAll(parameters); 117 | } 118 | 119 | setStatus("blue", "Contacting Girino on %s...", frozenPortId.getName()); 120 | 121 | Future connection = executor.submit(new Callable() { 122 | 123 | @Override 124 | public Void call() throws Exception { 125 | girino.setConnection(frozenPortId, frozenParameters); 126 | return null; 127 | } 128 | }); 129 | try { 130 | connection.get(5, TimeUnit.SECONDS); 131 | } catch (TimeoutException e) { 132 | throw new TimeoutException("No Girino detected on " + frozenPortId.getName()); 133 | } catch (InterruptedException e) { 134 | connection.cancel(true); 135 | throw e; 136 | } 137 | } 138 | 139 | private void acquireData() throws Exception { 140 | setStatus("blue", "Acquiring data from %s...", frozenPortId.getName()); 141 | Future acquisition = null; 142 | boolean terminated; 143 | do { 144 | boolean updateConnection; 145 | synchronized (UI.this) { 146 | parameters.put(Parameter.THRESHOLD, graphPane.getThreshold()); 147 | parameters.put(Parameter.WAIT_DURATION, graphPane.getWaitDuration()); 148 | updateConnection = !getChanges(frozenParameters).isEmpty() || frozenPortId != portId; 149 | } 150 | if (updateConnection) { 151 | if (acquisition != null) { 152 | acquisition.cancel(true); 153 | } 154 | terminated = true; 155 | } else { 156 | try { 157 | if (acquisition == null) { 158 | acquisition = executor.submit(new Callable() { 159 | 160 | @Override 161 | public byte[] call() throws Exception { 162 | return girino.acquireData(); 163 | } 164 | }); 165 | } 166 | byte[] buffer = acquisition.get(1, TimeUnit.SECONDS); 167 | if (buffer != null) { 168 | publish(buffer); 169 | acquisition = null; 170 | terminated = false; 171 | } else { 172 | terminated = true; 173 | } 174 | } catch (TimeoutException e) { 175 | // Just to wake up regularly. 176 | terminated = false; 177 | } catch (InterruptedException e) { 178 | acquisition.cancel(true); 179 | throw e; 180 | } 181 | } 182 | } while (!terminated); 183 | } 184 | 185 | @Override 186 | protected void process(List buffer) { 187 | logger.log(Level.FINE, "{0} data buffer(s) to display.", buffer.size()); 188 | graphPane.setData(buffer.get(buffer.size() - 1)); 189 | } 190 | 191 | @Override 192 | protected void done() { 193 | startAcquiringAction.setEnabled(true); 194 | stopAcquiringAction.setEnabled(false); 195 | try { 196 | if (!isCancelled()) { 197 | get(); 198 | } 199 | setStatus("blue", "Done acquiring data from %s.", frozenPortId.getName()); 200 | } catch (ExecutionException e) { 201 | setStatus("red", e.getCause().getMessage()); 202 | } catch (Exception e) { 203 | setStatus("red", e.getMessage()); 204 | } 205 | } 206 | } 207 | 208 | private final Action startAcquiringAction = new AbstractAction("Start acquiring", Icon.get("media-record.png")) { 209 | { 210 | putValue(Action.SHORT_DESCRIPTION, "Start acquiring data from Girino."); 211 | } 212 | 213 | @Override 214 | public void actionPerformed(ActionEvent event) { 215 | synchronized (UI.this) { 216 | parameters.put(Parameter.THRESHOLD, graphPane.getThreshold()); 217 | parameters.put(Parameter.WAIT_DURATION, graphPane.getWaitDuration()); 218 | } 219 | currentDataAcquisitionTask = new DataAcquisitionTask(); 220 | currentDataAcquisitionTask.execute(); 221 | } 222 | }; 223 | 224 | private final Action stopAcquiringAction = new AbstractAction("Stop acquiring", Icon.get("media-playback-stop.png")) { 225 | { 226 | putValue(Action.SHORT_DESCRIPTION, "Stop acquiring data from Girino."); 227 | } 228 | 229 | @Override 230 | public void actionPerformed(ActionEvent event) { 231 | currentDataAcquisitionTask.cancel(true); 232 | } 233 | }; 234 | 235 | private final Action aboutAction = new AbstractAction("About Girinoscope", Icon.get("help-about.png")) { 236 | 237 | @Override 238 | public void actionPerformed(ActionEvent event) { 239 | new AboutDialog(UI.this).setVisible(true); 240 | } 241 | }; 242 | 243 | private final Action exitAction = new AbstractAction("Quit", Icon.get("application-exit.png")) { 244 | 245 | @Override 246 | public void actionPerformed(ActionEvent event) { 247 | dispose(); 248 | } 249 | }; 250 | 251 | public UI() { 252 | setTitle("Girinoscope"); 253 | setIconImage(Icon.getImage("icon.png")); 254 | 255 | setLayout(new BorderLayout()); 256 | 257 | graphPane = new GraphPane(parameters.get(Parameter.THRESHOLD), parameters.get(Parameter.WAIT_DURATION)); 258 | graphPane.setPreferredSize(new Dimension(800, 600)); 259 | add(graphPane, BorderLayout.CENTER); 260 | 261 | setJMenuBar(createMenuBar()); 262 | 263 | add(createToolBar(), BorderLayout.NORTH); 264 | 265 | statusBar = new StatusBar(); 266 | add(statusBar, BorderLayout.SOUTH); 267 | 268 | stopAcquiringAction.setEnabled(false); 269 | 270 | if (portId != null) { 271 | startAcquiringAction.setEnabled(true); 272 | } else { 273 | startAcquiringAction.setEnabled(false); 274 | setStatus("red", "No USB to serial adaptation port detected."); 275 | } 276 | } 277 | 278 | @Override 279 | public void dispose() { 280 | try { 281 | if (currentDataAcquisitionTask != null) { 282 | currentDataAcquisitionTask.cancel(true); 283 | } 284 | executor.shutdown(); 285 | girino.disconnect(); 286 | } catch (IOException e) { 287 | logger.log(Level.WARNING, "When disconnecting from Girino.", e); 288 | } 289 | super.dispose(); 290 | } 291 | 292 | private JMenuBar createMenuBar() { 293 | JMenuBar menuBar = new JMenuBar(); 294 | 295 | JMenu fileMenu = new JMenu("File"); 296 | fileMenu.add(exitAction); 297 | menuBar.add(fileMenu); 298 | 299 | JMenu toolMenu = new JMenu("Tools"); 300 | toolMenu.add(createSerialMenu()); 301 | toolMenu.add(createPrescalerMenu()); 302 | toolMenu.add(createTriggerEventMenu()); 303 | toolMenu.add(createVoltageReferenceMenu()); 304 | toolMenu.addSeparator(); 305 | toolMenu.add(createDataStrokeWidthMenu()); 306 | toolMenu.add(createThemeMenu()); 307 | menuBar.add(toolMenu); 308 | 309 | JMenu helpMenu = new JMenu("Help"); 310 | helpMenu.add(aboutAction); 311 | menuBar.add(helpMenu); 312 | 313 | return menuBar; 314 | } 315 | 316 | private JMenu createSerialMenu() { 317 | JMenu menu = new JMenu("Serial port"); 318 | ButtonGroup group = new ButtonGroup(); 319 | for (final CommPortIdentifier portId : Serial.enumeratePorts()) { 320 | Action setSerialPort = new AbstractAction(portId.getName()) { 321 | 322 | @Override 323 | public void actionPerformed(ActionEvent event) { 324 | UI.this.portId = portId; 325 | } 326 | }; 327 | AbstractButton button = new JCheckBoxMenuItem(setSerialPort); 328 | if (UI.this.portId == null) { 329 | button.doClick(); 330 | } 331 | group.add(button); 332 | menu.add(button); 333 | } 334 | return menu; 335 | } 336 | 337 | private JMenu createPrescalerMenu() { 338 | JMenu menu = new JMenu("Acquisition rate / Time frame"); 339 | ButtonGroup group = new ButtonGroup(); 340 | for (final PrescalerInfo info : PrescalerInfo.values()) { 341 | Action setPrescaler = new AbstractAction(info.description) { 342 | 343 | @Override 344 | public void actionPerformed(ActionEvent event) { 345 | synchronized (UI.this) { 346 | parameters.put(Parameter.PRESCALER, info.value); 347 | } 348 | String xFormat = info.timeframe > 0.005 ? "%.0f ms" : "%.1f ms"; 349 | Axis xAxis = new Axis(0, info.timeframe * 1000, xFormat); 350 | Axis yAxis = new Axis(-2.5, 2.5, 0.5, "%.2f V"); 351 | graphPane.setCoordinateSystem(xAxis, yAxis); 352 | } 353 | }; 354 | AbstractButton button = new JCheckBoxMenuItem(setPrescaler); 355 | if (info.reallyTooFast) { 356 | button.setForeground(Color.RED.darker()); 357 | } else if (info.tooFast) { 358 | button.setForeground(Color.ORANGE.darker()); 359 | } 360 | if (info.value == parameters.get(Parameter.PRESCALER)) { 361 | button.doClick(); 362 | } 363 | group.add(button); 364 | menu.add(button); 365 | } 366 | return menu; 367 | } 368 | 369 | private JMenu createTriggerEventMenu() { 370 | JMenu menu = new JMenu("Trigger event mode"); 371 | ButtonGroup group = new ButtonGroup(); 372 | for (final TriggerEventMode mode : TriggerEventMode.values()) { 373 | Action setPrescaler = new AbstractAction(mode.description) { 374 | 375 | @Override 376 | public void actionPerformed(ActionEvent event) { 377 | synchronized (UI.this) { 378 | parameters.put(Parameter.TRIGGER_EVENT, mode.value); 379 | } 380 | } 381 | }; 382 | AbstractButton button = new JCheckBoxMenuItem(setPrescaler); 383 | if (mode.value == parameters.get(Parameter.TRIGGER_EVENT)) { 384 | button.doClick(); 385 | } 386 | group.add(button); 387 | menu.add(button); 388 | } 389 | return menu; 390 | } 391 | 392 | private JMenu createVoltageReferenceMenu() { 393 | JMenu menu = new JMenu("Voltage reference"); 394 | ButtonGroup group = new ButtonGroup(); 395 | for (final VoltageReference reference : VoltageReference.values()) { 396 | Action setPrescaler = new AbstractAction(reference.description) { 397 | 398 | @Override 399 | public void actionPerformed(ActionEvent event) { 400 | synchronized (UI.this) { 401 | parameters.put(Parameter.VOLTAGE_REFERENCE, reference.value); 402 | } 403 | } 404 | }; 405 | AbstractButton button = new JCheckBoxMenuItem(setPrescaler); 406 | if (reference.value == parameters.get(Parameter.VOLTAGE_REFERENCE)) { 407 | button.doClick(); 408 | } 409 | group.add(button); 410 | menu.add(button); 411 | } 412 | return menu; 413 | } 414 | 415 | private JMenu createThemeMenu() { 416 | JMenu menu = new JMenu("Theme"); 417 | ButtonGroup group = new ButtonGroup(); 418 | for (final LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { 419 | Action setLnF = new AbstractAction(info.getName()) { 420 | 421 | @Override 422 | public void actionPerformed(ActionEvent event) { 423 | try { 424 | UIManager.setLookAndFeel(info.getClassName()); 425 | SwingUtilities.updateComponentTreeUI(getRootPane()); 426 | } catch (Exception e) { 427 | setStatus("red", "Failed to load {} LaF.", info.getName()); 428 | } 429 | } 430 | }; 431 | AbstractButton button = new JCheckBoxMenuItem(setLnF); 432 | group.add(button); 433 | menu.add(button); 434 | } 435 | return menu; 436 | } 437 | 438 | private JMenu createDataStrokeWidthMenu() { 439 | JMenu menu = new JMenu("Data stroke width"); 440 | ButtonGroup group = new ButtonGroup(); 441 | for (final int width : new int[] { 1, 2, 3 }) { 442 | Action setStrokeWidth = new AbstractAction(width + " px") { 443 | 444 | @Override 445 | public void actionPerformed(ActionEvent event) { 446 | graphPane.setDataStrokeWidth(width); 447 | } 448 | }; 449 | AbstractButton button = new JCheckBoxMenuItem(setStrokeWidth); 450 | if (width == 1) { 451 | button.doClick(); 452 | } 453 | group.add(button); 454 | menu.add(button); 455 | } 456 | return menu; 457 | } 458 | 459 | private JComponent createToolBar() { 460 | JToolBar toolBar = new JToolBar(); 461 | toolBar.setFloatable(false); 462 | final Component start = toolBar.add(startAcquiringAction); 463 | final Component stop = toolBar.add(stopAcquiringAction); 464 | start.addPropertyChangeListener("enabled", new PropertyChangeListener() { 465 | 466 | @Override 467 | public void propertyChange(PropertyChangeEvent evt) { 468 | if (!start.isEnabled()) { 469 | stop.requestFocusInWindow(); 470 | } 471 | } 472 | }); 473 | stop.addPropertyChangeListener("enabled", new PropertyChangeListener() { 474 | 475 | @Override 476 | public void propertyChange(PropertyChangeEvent evt) { 477 | if (!stop.isEnabled()) { 478 | start.requestFocusInWindow(); 479 | } 480 | } 481 | }); 482 | return toolBar; 483 | } 484 | 485 | private void setStatus(String color, String message, Object... arguments) { 486 | String formattedMessage = String.format(message != null ? message : "", arguments); 487 | final String htmlMessage = String.format("%s", color, formattedMessage); 488 | if (SwingUtilities.isEventDispatchThread()) { 489 | statusBar.setText(htmlMessage); 490 | } else { 491 | SwingUtilities.invokeLater(new Runnable() { 492 | 493 | @Override 494 | public void run() { 495 | statusBar.setText(htmlMessage); 496 | } 497 | }); 498 | } 499 | } 500 | 501 | private Map getChanges(Map oldParameters) { 502 | Map changes = new HashMap(); 503 | for (Map.Entry entry : parameters.entrySet()) { 504 | Parameter parameter = entry.getKey(); 505 | Integer newValue = entry.getValue(); 506 | if (!same(newValue, oldParameters.get(parameter))) { 507 | changes.put(parameter, newValue); 508 | } 509 | } 510 | for (Map.Entry entry : oldParameters.entrySet()) { 511 | Parameter parameter = entry.getKey(); 512 | if (!parameters.containsKey(parameter)) { 513 | changes.put(parameter, null); 514 | } 515 | } 516 | return changes; 517 | } 518 | 519 | private static boolean same(Object o1, Object o2) { 520 | if (o1 == o2) { 521 | return true; 522 | } else if (o1 == null || o2 == null) { 523 | return false; 524 | } else { 525 | return o1.equals(o2); 526 | } 527 | } 528 | } 529 | -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/ui/about.html: -------------------------------------------------------------------------------- 1 |

Girinoscope

2 |

A simple graphical user interface for 3 |
4 | Girino, a Fast Arduino Oscilloscope. 5 |

6 |
7 | Get the source code from GitHub. -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/ui/images/Icon.java: -------------------------------------------------------------------------------- 1 | package org.hihan.girinoscope.ui.images; 2 | 3 | import java.awt.Image; 4 | import java.io.IOException; 5 | import java.net.URL; 6 | 7 | import javax.imageio.ImageIO; 8 | import javax.swing.ImageIcon; 9 | 10 | /** 11 | * For the records, all the icons in this package have been found in my 12 | * '/usr/icons/Mint-X/actions/16' folders. 13 | */ 14 | public class Icon { 15 | 16 | public static ImageIcon get(String name) { 17 | URL url = Icon.class.getResource(name); 18 | if (url != null) { 19 | return new ImageIcon(url); 20 | } else { 21 | throw new IllegalArgumentException("Icon '" + name + "' does not exist."); 22 | } 23 | } 24 | 25 | public static Image getImage(String name) { 26 | URL url = Icon.class.getResource(name); 27 | if (url != null) { 28 | try { 29 | return ImageIO.read(url); 30 | } catch (IOException e) { 31 | throw new RuntimeException(e); 32 | } 33 | } else { 34 | throw new IllegalArgumentException("Icon '" + name + "' does not exist."); 35 | } 36 | 37 | } 38 | 39 | private Icon() { 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/ui/images/application-exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/src/org/hihan/girinoscope/ui/images/application-exit.png -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/ui/images/help-about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/src/org/hihan/girinoscope/ui/images/help-about.png -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/ui/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/src/org/hihan/girinoscope/ui/images/icon.png -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/ui/images/media-playback-stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/src/org/hihan/girinoscope/ui/images/media-playback-stop.png -------------------------------------------------------------------------------- /Girinoscope/src/org/hihan/girinoscope/ui/images/media-record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/Girinoscope/src/org/hihan/girinoscope/ui/images/media-record.png -------------------------------------------------------------------------------- /LTSpice/LM324.txt: -------------------------------------------------------------------------------- 1 | * LM324 OPERATIONAL AMPLIFIER "MACROMODEL" SUBCIRCUIT 2 | * CREATED USING PARTS RELEASE 4.01 ON 09/08/89 AT 10:54 3 | * (REV N/A) SUPPLY VOLTAGE: 5V 4 | * CONNECTIONS: NON-INVERTING INPUT 5 | * | INVERTING INPUT 6 | * | | POSITIVE POWER SUPPLY 7 | * | | | NEGATIVE POWER SUPPLY 8 | * | | | | OUTPUT 9 | * | | | | | 10 | .SUBCKT LM324 1 2 3 4 5 11 | * 12 | C1 11 12 5.544E-12 13 | C2 6 7 20.00E-12 14 | DC 5 53 DX 15 | DE 54 5 DX 16 | DLP 90 91 DX 17 | DLN 92 90 DX 18 | DP 4 3 DX 19 | EGND 99 0 POLY(2) (3,0) (4,0) 0 .5 .5 20 | FB 7 99 POLY(5) VB VC VE VLP VLN 0 15.91E6 -20E6 20E6 20E6 -20E6 21 | GA 6 0 11 12 125.7E-6 22 | GCM 0 6 10 99 7.067E-9 23 | IEE 3 10 DC 10.04E-6 24 | HLIM 90 0 VLIM 1K 25 | Q1 11 2 13 QX 26 | Q2 12 1 14 QX 27 | R2 6 9 100.0E3 28 | RC1 4 11 7.957E3 29 | RC2 4 12 7.957E3 30 | RE1 13 10 2.773E3 31 | RE2 14 10 2.773E3 32 | REE 10 99 19.92E6 33 | RO1 8 5 50 34 | RO2 7 99 50 35 | RP 3 4 30.31E3 36 | VB 9 0 DC 0 37 | VC 3 53 DC 2.100 38 | VE 54 4 DC .6 39 | VLIM 7 8 DC 0 40 | VLP 91 0 DC 40 41 | VLN 0 92 DC 40 42 | .MODEL DX D(IS=800.0E-18) 43 | .MODEL QX PNP(IS=800.0E-18 BF=250) 44 | .ENDS 45 |  -------------------------------------------------------------------------------- /LTSpice/girino.asc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/LTSpice/girino.asc -------------------------------------------------------------------------------- /LTSpice/pwm-threshold.asc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/LTSpice/pwm-threshold.asc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # arduino-oscilloscope 2 | 3 | This repository contains a few materials for creating a simple oscilloscope 4 | with arduino. Arduino oscilloscope based on Girino. 5 | The arduino and oscilloscope applications were open source, and I only 6 | patched them slightly for my needs. 7 | 8 | For a detailed explanation check my blog post: 9 | http://sangorrin.blogspot.jp/2015/06/arduino-oscilloscope.html 10 | 11 | -- Daniel Sangorrin 12 | -------------------------------------------------------------------------------- /arduino-oscilloscope.txt: -------------------------------------------------------------------------------- 1 | Arduino oscilloscope (based on Girino/Girinoscope) 2 | 2015 (c) Daniel Sangorrin 3 | ------------------------------------------------------------------------------- 4 | 5 | Ref: http://www.instructables.com/id/Girino-Fast-Arduino-Oscilloscope/?ALLSTEPS (main guide) 6 | Ref: http://www.instructables.com/files/orig/FQ1/8HPC/GZV1CF98/FQ18HPCGZV1CF98.7z (arduino code and circuit) 7 | Ref: https://hackaday.io/project/5881-small-scope (replica with pcb and gui) 8 | 9 | Overview 10 | ======== 11 | 12 | Waveform Digitizers: 13 | - incoming signal should be decoupled from the arduino to preserve it 14 | - with an offset of the signal it is possible to see negative signals 15 | - the sampling data should be buffered instead of being sent one by one 16 | - a hardware trigger is required to catch the signals 17 | - a circular buffer can be used to store a few samples of the signal just before the trigger 18 | - using lower lever functions that the standard ones makes the program run faster. 19 | 20 | Specs: 21 | - Input range: -2,5..2,5V (0..5V without level shifter) 22 | - Resolution: 8bit/sample 23 | - Sampling freq: 153.8 Ksamples/s (307.7 Ksamples/s for ATmega328) 24 | -> Calculation: Clock/Preescaler/CyclesPerSample 25 | - Clock: 16MHz or 20Mhz 26 | - Preescaler: 2..128 27 | - CyclesPerSample: 13 28 | Ref: http://www.openmusiclabs.com/learning/digital/atmega-adc/ 29 | Ref: http://www.openmusiclabs.com/learning/digital/atmega-adc/in-depth/ 30 | - Samples/trigger: 512 samples (1280 samples for ATmega328) 31 | - Threshold PWM freq: 62.5 KHz (with a low pass filter at 560Hz) 32 | 33 | Arduino hardware 34 | ================ 35 | 36 | ATMega328P 37 | Ref: Ref: http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf (ATMMega328P datasheet) 38 | 39 | Pinout 40 | - [Opt] errorPin: pin13 (connected to led, commented out in code by default) 41 | - pin 3 (PWM) 42 | + it is used to generate a PWM wave that gets filtered and 43 | serves as the threshold for the trigger to work 44 | [Note] instead, you can use a potentiometer 45 | - pin 7 (V- of analog comparator) 46 | + connected to the threshold signal (either the PWM signal filtered, or 47 | the one coming from a potentiometer) 48 | - pin 6 (V+ of analog comparator) 49 | + connected to the input signal after ofset level and buffering. 50 | + when V+ > V- it generates an interrupt 51 | Ref: http://www.instructables.com/id/Girino-Fast-Arduino-Oscilloscope/step11/How-the-Analog-Comparator-works/ 52 | - pin A0 (analog input 0) 53 | + also connected to the input signal. 54 | 55 | ADC registers (see Inits.cpp): 56 | - ADMUX: 57 | + set reference voltage for ADC (AVCC with external capacitor at AREF pin) 58 | + enable A0 pin 59 | + left adjust the sample so that it is stored in ADCL 60 | - ACSR: analogue comparator settings 61 | + trigger event (rising) 62 | + threshold option (don't use the internal bandgap) 63 | - ADCSRA: 64 | + select preescaler 65 | -> division factor: 128 (16MHz/128=125KHz) 66 | + enable ADC sample available interrupt 67 | - ADCSRB: 68 | + select Free Running mode. 69 | + enable AnalogComparator for triggering 70 | - ADCH: high part of the sample (not used in girino) 71 | - ADCL: low part of the sample 72 | - DIDR0: disable the digital input buffer of A0-A5 (use them as analog pins) 73 | - DIDR1: disable the digital input buffer of pins 6-7 (use them as analog comparator) 74 | - TCCR2A, TCCR2B: set to fast PWM 0xFF, no preescale (for the threshold), timer 2 75 | - Output Compare Registers A/B (OCRnx): are used to set the signal duty cycle. 76 | Ref: f = clock_freq/prescaler/TCNTn_maximum = 16MHz/1/256 = 62.5 KHz 77 | [Note] TCNTn_maximum for Timer 0 and 2 (8-bit) is 256 78 | [Note] TCNTn_maximum for Timer 0 and 2 (8-bit) is 65536 79 | Ref: http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM 80 | 81 | Girino hardware 82 | =============== 83 | 84 | Power supply (akiduki 650yen, http://akizukidenshi.com/catalog/g/gM-01805/) 85 | - 15V power supply: 2 86 | Voltage regulators 87 | - 7812: 1 (+12V) (akiduki 50yen, http://akizukidenshi.com/catalog/g/gI-00163/) 88 | - 7912: 1 (-12V) (akiduki 50yen, http://akizukidenshi.com/catalog/g/gI-03973/ 89 | OpAmps 90 | - LM324: 4 (akiduki 150yen, http://akizukidenshi.com/catalog/g/gI-00959/) 91 | [Alt] TL084 (akiduki 300yen, http://akizukidenshi.com/catalog/g/gI-04083/) 92 | - IC socket 14pin: 1 (akiduki 100yen, http://akizukidenshi.com/catalog/g/gP-00006/) 93 | Resistors 94 | - 1K: 2 95 | - 1M: 1 96 | - 10K: 4 97 | - 1K8: 1 98 | Potentiometer 99 | - 1K: 1 (akiduki 80yen, http://akizukidenshi.com/catalog/g/gP-00973/) 100 | Jumper 101 | - pin header: 1 (akiduki 100yen, http://akizukidenshi.com/catalog/g/gC-00167/) 102 | - jumper: 4 (akiduki 100yen, http://akizukidenshi.com/catalog/g/gP-03688/) 103 | Capacitors 104 | Ref: http://www.electronics2000.co.uk/calc/capacitor-code-calculator.php 105 | - 10uF: 3 (electrolitic, have a +) <-- filters low-freq noise 106 | - 1uF: 2 (ceramic) <-- filters high-freq noise 107 | - 2.2uF: 1 (electrolitic) 108 | - 0.33uF: 1 (electrolitic) 109 | - 100nF=0.1uF: 3 (ceramic) 110 | Universal board 111 | - for arduino (akiduki 200yen, http://akizukidenshi.com/catalog/g/gP-06877/) 112 | 113 | [Opt] Probe 60MHz (aitendo 900yen, http://www.aitendo.com/product/6705) 114 | [Opt] BNC connector (aitendo) 115 | [Note] Bypass Capacitors should be put as close as possible to the 116 | alimentation pins of the IC. They are used usually in couple, one 117 | ceramic and one electrolytic because they can filter out different 118 | frequencies. 119 | 120 | My hardware modifications 121 | ========================= 122 | 123 | Ref: http://www.lcardaba.com/articles/opamps.html 124 | Ref: https://github.com/marvin-sinister/small-scope-electronics (replica's Kicad project) 125 | 126 | [Opt] Input voltage protection circuit (add clamp diodes) 127 | Ref: http://electronics.stackexchange.com/questions/35807/how-would-i-design-a-protection-clipper-circuit-for-adc-input 128 | + To protect the input stage against overvoltage I'd add clamping diodes to 129 | VCC and VSS, respectively, right at the place where the 1 MOhm resistor is. 130 | Good, cheap, fast, low-capacitance diodes would be e.g. 1N914 131 | + Other diodes: 1SS380, 1S2076A, JFET transistor with S and D connected.. 132 | 133 | [Opt] Shift voltage: 134 | + use an OpAmp in buffer configuration before the 10kohm resistor 135 | 136 | [Opt] Threshold: 137 | - Use a better filter 138 | Ref: http://www.analog.com/designtools/en/filterwizard/#/type 139 | - Use the 3.3V provided by arduino as threshold value 140 | - Use a trimmer (potentiometer) to set the voltage level 141 | - using the internal bangap reference we can use a fixed level. 142 | Ref: http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/ 143 | Ref: http://electronics.stackexchange.com/questions/997/monitoring-voltage-without-a-known-reference 144 | [Opt] For arduino, I could use a 20MHz clock. 145 | [Opt] Low-pass filter: using a 1.8k resistor and a 1uF capacitor gets you a 146 | cut-off frequency of 88.5Hz [ 1/(2*pi*R*C) ], not 560Hz [ 1 / (R*C) ] 147 | which is rad/s. 148 | [Opt] One thing to be careful about: If you supply the op-amp with +/-12V it 149 | can drive almost as much into your Arduino - which will most likely kill 150 | the latter! Would be a good idea to add a series resistor after the last 151 | op-amp stage, and behind that two clamping diodes (Schottky type) going 152 | to 0V and 5V, respectively. 153 | [Opt] The third op-amp stage isn't really needed. Did you try to run without it? 154 | (make sure the unused op-amps inputs are tied to VCC and VSS, respectively, 155 | to avoid oscillations). 156 | 157 | Girino code 158 | =========== 159 | 160 | Ref: https://github.com/marvin-sinister/small-scope (replica's code) 161 | 162 | Overview of the program: 163 | - flow 164 | + an interrupt samples the signal every xx us and stores it in a circular buffer. 165 | + when the signal surpasses a threshold: there is a trigger interrupt! 166 | [Note] we specify the threshold with analogwrite (PWM + filter) 167 | + after the trigger, we take 'waitDuration' samples (sweep) and then disable/freeze sampling (holdoff) 168 | + then, we send the samples (the ones before the trigger plus the waitDuration samples) to the host. 169 | + finally, we enable sampling again. 170 | - data structures 171 | + Inter-communication flags 172 | -> boolean freeze (send_samples_flag): if True send the buffer to the serial port (set by ADC_vect) 173 | -> boolean wait (trigger): indicates that the threshold was surpassed, and we must freeze after waitDuration more samples. 174 | -> uint16_t waitDuration (samples_per_trigger): samples to take after the trigger (by default: 1280 - 32) 175 | + Circular buffer 176 | -> uint8_t ADCBuffer[1280]: circular buffer with the 8bit samples. 177 | -> uint16_t ADCCounter: cursor to the next empty slot in ADCBuffer. 178 | -> uint16_t stopIndex: cursor to the last slot to sample before freezing. 179 | + Settings 180 | -> uint8_t prescaler: system_clock_freq / ADC_input_clock (default 128) 181 | -> uint8_t triggerEvent: type of trigger (0:toggle, 2: falling edge, 3: rising edge. Default: 3) 182 | -> uint8_t threshold: the threshold voltage for triggering (analogwrite PWM, default 127) 183 | -> char commandBuffer[4+1]: used to change settings from the host 184 | - setup 185 | + Baudrate: 115200 186 | + Init data structures 187 | + Enable interrupts: sei() 188 | + initPins(); 189 | + initADC(); 190 | + initAnalogComparator(); 191 | - loop 192 | + if freeze is true 193 | -> Send "ADCBuffer" through serial port 194 | -> cbi(PORTB,PORTB5); 195 | -> wait = false; 196 | -> freeze = false; 197 | + if serial input available 198 | -> parse command 199 | - interrupts 200 | Ref: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html 201 | + ADC_vect: ADC Conversion Complete Interrupt 202 | -> gets 8bit sample into the ADCBuffer 203 | -> ADCCounter++ 204 | -> if wait 205 | if (stopIndex == ADCCounter) <-- buffer is filled 206 | disable ADC and stop Free Running Conversion Mode: cbi( ADCSRA, ADEN ); 207 | send to the host: freeze = true; 208 | + ANALOG_COMP_vect: Analog Comparator interrupt 209 | [Note] compares a signal with a reference voltage. If the signal 210 | surpasses it it raises an interrupt. 211 | -> disable Analog Comparator interrupt: cbi( ACSR,ACIE ); 212 | -> sbi( PORTB, PORTB5 ); 213 | -> wait = true; 214 | -> stopIndex = ( ADCCounter + waitDuration ) % ADCBUFFERSIZE; 215 | 216 | Util functions 217 | DEBUG: enable debugging messages 218 | dprint(x): writes to the serial port something like: # x: 123 219 | dshow("Some string"): writes the string 220 | cbi(sfr, bit): clears a bit in register sfr 221 | sbi(sfr, bit): sets a bit in register sfr 222 | 223 | Patch (from girinoscope) 224 | - Girino.h, line 41: 225 | // Replaced 3 by 4 since the wait duration range is [0, 1280]. 226 | #define COMBUFFERSIZE 4 // Size of buffer for incoming numbers 227 | - Girino.ino, line 224: 228 | // Added a necessary x2 factor since we read 16 bits now. 229 | delay(COMMANDDELAY * 2); 230 | - Girino.ino, line 229: 231 | // Replaced 'uint8' by 'uint16' for the same reason. 232 | uint16_t newT = atoi( commandBuffer ); 233 | 234 | Patch (from Woami http://www.instructables.com/member/womai/) for efficiency (ISR.cpp) 235 | 1) Integer division is time consuming: 236 | -ADCCounter = ( ADCCounter + 1 ) % ADCBUFFERSIZE; 237 | +if (++ADCCounter >= ADCBUFFERSIZE) ADCCounter = 0; 238 | 2) Avoid the variable wait by setting stopIndex to a value that the counter never reaches 239 | when you aren't yet in the post-trigger phase (when starting a new sweep) 240 | -if(wait) 241 | +stopIndex = ADCBUFFERSIZE + 1; 242 | 243 | ISR(ANALOG_COMP_vect) { 244 | // Disable Analog Comparator interrupt 245 | cbi( ACSR,ACIE ); 246 | // Turn on errorPin 247 | //digitalWrite( errorPin, HIGH ); 248 | sbi( PORTB, PORTB5 ); 249 | stopIndex = ( ADCCounter + waitDuration ) % ADCBUFFERSIZE; 250 | } 251 | 252 | ISR(ADC_vect) { 253 | ADCBuffer[ADCCounter] = ADCH; 254 | if (++ADCCounter >= ADCBUFFERSIZE) ADCCounter = 0; 255 | if ( stopIndex == ADCCounter ) { 256 | cbi( ADCSRA, ADEN ); 257 | freeze = true; 258 | } 259 | } 260 | 261 | If error "HardwareSerial::HardwareSerial' is not a type" 262 | -HardwareSerial::HardwareSerial 263 | +HardwareSerial 264 | 265 | [Opt] Patch to increase the speed of the serial port to 1Mbps 266 | Ref: https://mekonik.wordpress.com/2009/03/02/modified-arduino-library-serial/ 267 | Ref: https://github.com/marvin-sinister/small-scope-qt (replica's GUI) 268 | 269 | Oscilloscope frontend 270 | ===================== 271 | 272 | Ref: https://github.com/Chatanga/Girinoscope/releases (oscilloscope frontend code) 273 | 274 | Linux 275 | $ sudo apt-get install ant 276 | $ git clone https://github.com/Chatanga/Girinoscope.git 277 | $ cd Girinoscope 278 | $ vi src/xxx/comm/Girino.java 279 | -> change buffer size 1280 to 512 280 | $ ant build 281 | $ ant run 282 | --> it works 283 | Windows 284 | - Download release and just double-click girinoscope.bat 285 | 286 | Ref: https://github.com/marvin-sinister/small-scope-qt (replica's GUI) 287 | 288 | TODO 289 | 290 | Signal gnerator 291 | =============== 292 | 293 | You can build a simple analog signal generator with an Arduino driving a 294 | R-2R resistor network (google the term and you'll get plenty of hits) 295 | from an 8-bit port. Use 1% resistors and you'll get almost 8 bits of 296 | resolution. You can the scale an buffer the signal with an op-amp stage. 297 | Just a few cents worth of parts apart from the arduino. 298 | Here is such a project that uses an AVR, ready to be copied: 299 | http://www.myplace.nu/avr/minidds/index.htm 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | -------------------------------------------------------------------------------- /pass/AITENDO-ARDU.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/pass/AITENDO-ARDU.bmp -------------------------------------------------------------------------------- /pass/AITENDO-ARDU_.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/pass/AITENDO-ARDU_.bmp -------------------------------------------------------------------------------- /pass/POWER-JACK.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/pass/POWER-JACK.bmp -------------------------------------------------------------------------------- /pass/backside-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/pass/backside-blue.png -------------------------------------------------------------------------------- /pass/backside-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/pass/backside-green.png -------------------------------------------------------------------------------- /pass/frontside-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/pass/frontside-blue.png -------------------------------------------------------------------------------- /pass/frontside-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sangorrin/arduino-oscilloscope/a9ac22a6279a096e597d586bbdbc9de32744ea0e/pass/frontside-green.png -------------------------------------------------------------------------------- /pass/universal-pcb-board-memo.txt: -------------------------------------------------------------------------------- 1 | Universal PCB board 2 | 2015 (c) Daniel Sangorrin 3 | ------------------------------------------------------------------------------ 4 | 5 | Structure of an Universal PCB board 6 | =================================== 7 | 8 | - matrix of pads/holes where the leads of the components are inserted 9 | + typically holes are 1mm of diameter and the pitch is 2.54mm 10 | - sometimes include bus lines (straigth line connecting several pads) 11 | - normally leads are connected on the underside (solder side) 12 | 13 | Main methods to join pads 14 | ========================= 15 | 16 | Ref: http://electronics.stackexchange.com/questions/55236/how-to-make-traces-on-an-universal-pcb 17 | 18 | - solder bridges (use solder to join pads) 19 | + Procedure for connecting pads: 20 | -> place components in such a way that leads that need to be connected 21 | are placed in adjacent holes. 22 | -> set your soldering iron to a lower temperature 23 | -> put some solder on the pads. 24 | -> put some solder on your iron and tip in between the pads. Luckily, you’ll connect them. 25 | + Disadvantage: take a lot of solder, especially long ones. 26 | - jumper/solder wire (typical wire with plastic insulation) 27 | + typical wire 28 | Ref: http://www.radioshack.com/50-ft-blue-insulated-wrapping-wire-30awg/2780503.html 29 | [Note] wire means one single conductor or strand (as opposed to cable) 30 | Ref: http://www.differencebetween.info/difference-between-cable-and-wire 31 | + best for when you can't go around an existing solder joint. 32 | + without solder: http://en.wikipedia.org/wiki/Wire_wrap 33 | - bare/naked wire (a wire without the plastic wrapper) 34 | + allows connecting non-adjacent holes easily 35 | + useful for straight lines and buses, using less solder than solder bridges. 36 | + disadvantage: could easily make contact with an adjacent pad that should not be connected 37 | - using the leads (legs) of the components 38 | + procedure: bend the leads (legs) of the components and connect to adjacent pads 39 | + disadvantage: leads are usually thicker than wire. 40 | 41 | Universal board layout software 42 | =============================== 43 | 44 | PasS 45 | ---- 46 | 47 | Ref: http://www.geocities.jp/uaubn/pass/ (official site) 48 | Ref: http://airvariable.asablo.jp/blog/2012/05/04/6434269 (blog of a user) 49 | Ref: http://okgnz.web.fc2.com/passcad/index.htm (blog of a user, many circuits!) 50 | Ref: http://blog.livedoor.jp/cielo_cielo/archives/65820452.html (blog of a user, he used to use paper too) 51 | 52 | License: 53 | - Free to use only in private. 54 | 55 | Installation: 56 | - Install Microsoft Visual Basic 5 runtime (Msvbvm50.exe) 57 | Ref: https://support.microsoft.com/en-us/kb/180071 58 | - Un compress "pass-program.lzh" and "pass-parts.lzh" in a user folder (C:\Users\dsl\pass) 59 | - Fix locale settings: 60 | Ref: http://users.wfu.edu/yipcw/atg/microsoft/applocale/ 61 | + Download apploc.mxi > Right-click > Properties > Compatibility with WinXP SP3 > Install it 62 | Ref: http://www.microsoft.com/en-us/download/details.aspx?id=13209 63 | + Open C:\Windows\AppPatch\AppLoc.exe with Admin permissions 64 | - Open AppLoc.exe and follow the wizard to open Pass.exe using Japanese locale 65 | [Note] check create a link, so you can open directly with launchy! :D 66 | --> It works! 67 | 68 | Overview 69 | - Upper bar 70 | + change to 1/2 pitch 71 | -> this is not related with the board's pitch which is 2.54mm (10 pixels) 72 | but with a mode that allows you route lines between two pads. 73 | -> It consumes double memory, so don't use it unless needed. 74 | -> You can also change to 1/2 pitch mode after finishing, for retouching 75 | some line. BUT then you cannot go back to normal pitch mode! 76 | + rotate 90 degrees 77 | + select 1-side or 2-sides board 78 | - Left (parts) 79 | + boards (akiduki), capacitors, connectors, IL connectors, 80 | diodes, drill holes, ICs, jacks/terminals, LEDs, 81 | others (buzzer, transformer, crystal, LCS..), pin headers, 82 | pin sockets, transistors, resistors, IC sockets, sensors, switches, 83 | labels, tools (fill with color for GND, thru holes), user parts. 84 | - Right (board) 85 | + components side (front side) 86 | -> move mode (for placing parts) 87 | -> lines mode (for connecting parts) 88 | + front (red) 89 | + back (blue) <-- typically use this 90 | + front using jumper wire (orange) 91 | + back using jumper wire (green) 92 | + external line (gray): defines the shape of the board after cutting 93 | -> zoom 2x (only for connecting parts with lines) 94 | -> draw/delete a draft 95 | -> display/hide lines, pin numbers, borders, or labels 96 | -> save temporarily or periodically, defaults to 10min (alternative to Ctrl-Z) 97 | -> copy to clipboard (to save it in word or paint) 98 | + soldering side (back side) 99 | -> information about amount of wire used 100 | -> show/hide lines, parts border 101 | -> refresh 102 | -> copy to clipboard (to save it in word or paint) 103 | 104 | Typical procedure 105 | - Create new file 106 | + Choose 'no' if they ask you for 1/2 pitch mode (you can set it later anyway) 107 | - Move mode (click button with a cursor) 108 | + Drag a board to the right part, like Akizuki type C (pitch 2.54mm, diagonal 3.58mm) 109 | Ref: http://akizukidenshi.com/catalog/g/gP-03229/ 110 | + Drag parts into the board (maximum: 500) 111 | + Move parts: left-click + drag 112 | + Select parts: left-click + drag a rectangle 113 | + Right-click on a part: delete, copy, rotate, move to other side 114 | -> Ctrl-C won't work! 115 | + Double-click on a part: input reference number and name 116 | - Line connection mode (click button with the type of line you want to use, or 2-click board) 117 | + zoom 2x. and click lower-right rectangle to zoom the window 118 | + paint by dragging 119 | + right-click menu works here too. 120 | + try to avoid 90 degree corners, use 45 degree instead 121 | + if you need to route wires between pads, change to 1/2 pitch mode 122 | + if you need to cross a line, use thru holes 123 | - Export the result 124 | + gerber: use Gonpass addon (based on Gconpass), open in PCBE 125 | Ref: http://okgnz.web.fc2.com/passcad/index.htm (Gonpass) 126 | Ref: http://www.geocities.jp/uaubn/gconpass/ (Gconpass) 127 | + Click on clipboard button, and paste in word or paint 128 | 129 | Creating your own parts 130 | - All parts are BMP files copied to C:\Users\dsl\pass\parts\USR\xxx.bmp (or to a section). 131 | + Edit with Paint! 132 | - Boards 133 | Ref: pass-doc-create-your-board.pdf 134 | + Max size: 900x550 pixels (970x830 dots) 135 | + Colors: see the pdf for exact RGB values (or pick them from existing boards) 136 | + Holes (in white) must be located at (X,Y) that are multiple of 10. 137 | + Back side: 138 | -> change the name xxx.bmp -> xxx_.bmp 139 | -> the horizontal axis is inverted 140 | -> the upper-left corner pixel must be the same as the front side 141 | - Components 142 | + Pins are 1 red pixel. They must be separated 10 pixels. 143 | + Pin numbers defined by the red color level (0..255) 144 | 145 | Adding lettering 146 | - use the smallfonts.png as a reference and draw letters/numbers with 147 | paint or FireAlpaca pixel-by-pixel. 148 | 149 | Fritzing 150 | -------- 151 | 152 | Ref: http://fritzing.org/home/ (official site) 153 | Ref: http://fab.fritzing.org/fritzing-fab (converts design into a PCB) 154 | 155 | MBE: Minimal Editor Board 156 | ------------------------- 157 | 158 | Ref: http://www.suigyodo.com/online/mbe/mbe.htm (official site) 159 | Ref: http://www.ne.jp/asahi/air/variable/picmel/applications/melody/index.html (blog of a user) 160 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /pass/universal-pcb-oscilloscope.pas: -------------------------------------------------------------------------------- 1 | *** Version 2 | "Version 1.5.2 (20100621)" 3 | *** Pitch 4 | 1 5 | *** Board 6 | "\Board\AITENDO-ARDU.bmp","\Board\AITENDO-ARDU_.bmp" 7 | *** Type 8 | 1 9 | *** Parts 10 | "\IC\ICT-3.bmp",220,238,40,17,0 11 | "7912",220,255 12 | "",220,267 13 | "\C\CE-1.bmp",226,271,19,19,0 14 | "2.2u",229,291 15 | "",226,302 16 | "\C\CC-1.bmp",266,276,19,9,0 17 | "0.1u",263,274 18 | "",266,297 19 | "\C\CE-1.bmp",236,211,19,19,0 20 | "1u",229,222 21 | "",236,242 22 | "\C\CC-1.bmp",346,146,19,9,180 23 | "0.1u",350,134 24 | "",346,167 25 | "\C\CC-1.bmp",266,176,9,19,90 26 | "0.1u",255,164 27 | "",266,197 28 | "\C\CE-1a.bmp",325,250,32,32,90 29 | "10u",332,282 30 | "",325,294 31 | "\R\R-4.bmp",336,198,9,45,90 32 | "10k",327,216 33 | "",332,259 34 | "\R\R-4.bmp",346,198,9,45,90 35 | "10k",347,217 36 | "",342,259 37 | "\R\R-4.bmp",356,218,9,45,270 38 | "10k",359,238 39 | "",352,279 40 | "\C\CS-2.bmp",236,136,29,9,0 41 | "1u",242,143 42 | "",236,157 43 | "\PH\PH1-1.bmp",255,305,11,11,0 44 | "Vcc",245,316 45 | "",255,328 46 | "\PH\PH1-1.bmp",305,305,11,11,0 47 | "Ain",311,316 48 | "",305,328 49 | "\PH\PH1-1.bmp",285,305,11,11,0 50 | "15V",287,317 51 | "",285,328 52 | "\PH\PH1-2.bmp",265,305,21,11,0 53 | "gnd",266,316 54 | "",265,328 55 | "\PH\PH1-1.bmp",285,115,11,11,0 56 | "TH",281,104 57 | "",285,138 58 | "\PH\PH1-1.bmp",295,115,11,11,0 59 | "An",298,103 60 | "",295,138 61 | "\PH\PH1-1.bmp",325,115,11,11,0 62 | "PWM",323,104 63 | "",325,138 64 | "\C\CE-1a.bmp",340,164,32,32,0 65 | "10u",351,175 66 | "",340,208 67 | "\C\CE-1a.bmp",224,169,32,32,270 68 | "10u",213,166 69 | "",224,213 70 | "\R\R-5.bmp",278,136,55,9,0 71 | "1k8",302,136 72 | "",278,157 73 | "\PH\PH1-1.bmp",265,195,11,11,0 74 | "Sig",246,195 75 | "",265,218 76 | "\R\R-4.bmp",266,208,9,45,270 77 | "1M",252,212 78 | "",262,269 79 | "\R\R-4.bmp",278,236,45,9,180 80 | "1k",294,231 81 | "",274,297 82 | "\R\R-4.bmp",278,246,45,9,180 83 | "1k",292,249 84 | "",274,307 85 | "\C\CE-1.bmp",281,256,19,19,270 86 | "0.33u",253,260 87 | "",281,287 88 | "\SC\ICS-14.bmp",285,153,41,74,90 89 | "",285,194 90 | "",285,206 91 | "\CN\POWER-JACK.bmp",157,256,57,84,0 92 | "",157,340 93 | "",157,352 94 | "\IC\ICT-3.bmp",261,286,40,17,180 95 | "",261,303 96 | "",261,315 97 | "\R\R-4.bmp",326,178,9,45,270 98 | "",326,187 99 | "",326,199 100 | "\PH\PH1-1.bmp",205,115,11,11,0 101 | "GND",204,102 102 | "",205,138 103 | *** BottomLine 104 | 330,130,330,140 105 | 290,130,290,140 106 | 290,140,290,150 107 | 290,150,290,160 108 | 290,160,290,170 109 | 320,160,320,170 110 | 320,150,320,160 111 | 300,150,310,150 112 | 310,150,320,150 113 | 300,130,300,140 114 | 300,140,300,150 115 | 320,200,330,200 116 | 330,200,340,200 117 | 340,200,350,200 118 | 290,210,290,220 119 | 290,220,290,230 120 | 290,230,300,230 121 | 300,230,310,230 122 | 310,230,320,230 123 | 320,230,330,230 124 | 330,230,340,230 125 | 340,230,340,240 126 | 290,270,290,280 127 | 290,280,290,290 128 | 290,290,290,300 129 | 270,280,270,290 130 | 250,220,250,230 131 | 250,230,250,240 132 | 250,240,250,250 133 | 240,250,240,260 134 | 240,260,240,270 135 | 240,270,240,280 136 | 280,180,290,180 137 | 280,140,280,150 138 | 280,150,280,160 139 | 280,160,280,170 140 | 280,170,280,180 141 | 260,140,270,140 142 | 270,140,280,140 143 | 240,190,250,190 144 | 250,190,260,190 145 | 260,190,270,190 146 | 270,190,280,190 147 | 280,190,290,190 148 | 210,290,220,290 149 | 220,290,230,290 150 | 230,290,240,290 151 | 240,280,240,290 152 | 260,240,260,250 153 | 260,250,260,260 154 | 260,260,260,270 155 | 260,270,260,280 156 | 260,280,260,290 157 | 260,290,260,300 158 | 260,240,270,240 159 | 270,240,280,240 160 | 320,210,330,210 161 | 330,210,340,210 162 | 340,210,350,210 163 | 350,210,360,210 164 | 320,240,320,250 165 | 280,250,280,260 166 | 280,260,280,270 167 | 280,270,280,280 168 | 280,280,280,290 169 | 280,290,280,300 170 | 320,250,330,250 171 | 330,250,340,250 172 | 340,250,350,250 173 | 350,240,350,250 174 | 360,210,360,220 175 | 330,210,330,220 176 | 310,220,320,220 177 | 310,180,310,190 178 | 310,190,310,200 179 | 310,200,310,210 180 | 310,210,310,220 181 | 310,180,320,180 182 | 320,180,330,180 183 | 340,250,340,260 184 | 280,260,290,260 185 | 290,260,300,260 186 | 300,260,310,260 187 | 310,260,320,260 188 | 320,260,320,270 189 | 320,270,330,270 190 | 330,270,340,270 191 | 340,270,350,270 192 | 350,270,360,270 193 | 360,260,360,270 194 | 360,270,370,270 195 | 370,190,370,200 196 | 370,200,370,210 197 | 370,210,370,220 198 | 370,220,370,230 199 | 370,230,370,240 200 | 370,240,370,250 201 | 370,250,370,260 202 | 370,260,370,270 203 | 320,190,330,190 204 | 330,190,340,190 205 | 340,190,350,190 206 | 350,180,350,190 207 | 350,150,350,160 208 | 350,160,350,170 209 | 350,170,350,180 210 | 360,150,360,160 211 | 360,160,360,170 212 | 360,170,360,180 213 | 360,180,360,190 214 | 360,190,370,190 215 | 210,280,220,280 216 | 220,280,230,280 217 | 230,140,230,150 218 | 230,150,230,160 219 | 230,160,230,170 220 | 230,170,230,180 221 | 230,180,230,190 222 | 230,190,230,200 223 | 230,200,230,210 224 | 230,210,230,220 225 | 230,220,230,230 226 | 230,230,230,240 227 | 230,240,230,250 228 | 230,250,230,260 229 | 230,260,230,270 230 | 230,270,230,280 231 | 210,130,210,140 232 | 210,140,220,140 233 | 220,140,230,140 234 | 230,140,240,140 235 | 230,180,240,180 236 | 240,180,250,180 237 | 250,180,260,180 238 | 260,180,270,180 239 | 230,220,240,220 240 | 270,200,280,200 241 | 280,200,290,200 242 | 270,200,270,210 243 | 270,250,280,250 244 | *** TopLine 245 | *** BottomJump 246 | 270,190,270,200 247 | 270,200,270,210 248 | 270,210,270,220 249 | 270,220,270,230 250 | 270,230,270,240 251 | 270,240,270,250 252 | 270,250,270,260 253 | 270,260,270,270 254 | 270,270,270,280 255 | 270,190,280,190 256 | 280,190,290,190 257 | 250,180,250,190 258 | 250,190,250,200 259 | 250,200,250,210 260 | 250,210,250,220 261 | 250,180,260,180 262 | 260,180,270,180 263 | 270,180,280,180 264 | 280,180,290,180 265 | 290,180,300,180 266 | 300,180,310,180 267 | 310,180,320,180 268 | 320,180,320,190 269 | 310,300,320,300 270 | 320,300,330,300 271 | 330,130,330,140 272 | 330,140,330,150 273 | 330,150,330,160 274 | 330,160,330,170 275 | 330,170,330,180 276 | 330,180,330,190 277 | 330,190,330,200 278 | 330,200,330,210 279 | 330,210,330,220 280 | 330,220,330,230 281 | 330,230,330,240 282 | 330,240,330,250 283 | 330,250,330,260 284 | 330,260,330,270 285 | 330,270,330,280 286 | 330,280,330,290 287 | 330,290,330,300 288 | 300,130,310,130 289 | 310,130,320,130 290 | 320,130,330,130 291 | *** TopJump 292 | *** Area 293 | --------------------------------------------------------------------------------