arduino-0.4.0/0000755000000000000000000000000013470770202011344 5ustar0000000000000000arduino-0.4.0/COPYING0000644000000000000000000010451313470770202012403 0ustar0000000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . arduino-0.4.0/DESCRIPTION0000644000000000000000000000100313470770202013044 0ustar0000000000000000Name: arduino Version: 0.4.0 Date: 2019-05-21 Author: John Donoghue Maintainer: John Donoghue Title: Octave Arduino Toolkit Description: Basic Octave implementation of the matlab arduino extension, allowing communication to a programmed arduino board to control its hardware. Categories: Arduino Toolkit Depends: octave (>= 4.0.0), instrument-control (>= 0.3.0) SystemRequirements: arduino-ide (>= 1.5) License: GPLv3+ Url: https://octave.sourceforge.io/arduino/ arduino-0.4.0/INDEX0000644000000000000000000000447713470770202012152 0ustar0000000000000000arduino >> Arduino Toolkit General Functions arduinosetup isarduino listArduinoLibraries scanForArduinos Arduino Functions @arduino/checkI2CAddress @arduino/configurePin @arduino/configurePinResource @arduino/decrementResourceCount @arduino/display @arduino/getI2CTerminals @arduino/getLEDTerminals @arduino/getMCU @arduino/getPWMTerminals @arduino/getPinInfo @arduino/getPinsFromTerminals @arduino/getResourceCount @arduino/getResourceOwner @arduino/getSPITerminals @arduino/getServoTerminals @arduino/getSharedResourceProperty @arduino/getTerminalMode @arduino/getTerminalsFromPins @arduino/incrementResourceCount @arduino/isTerminalAnalog @arduino/isTerminalDigital @arduino/playTone @arduino/readAnalogPin @arduino/readDigitalPin @arduino/readVoltage @arduino/reset @arduino/sendCommand @arduino/setSharedResourceProperty @arduino/uptime @arduino/validatePin @arduino/version @arduino/writeDigitalPin @arduino/writePWMDutyCycle @arduino/writePWMVoltage @arduino/arduino Arduino I2C Functions scanI2Cbus @i2cdev/display @i2cdev/i2cdev @i2cdev/read @i2cdev/readRegister @i2cdev/subsref @i2cdev/write @i2cdev/writeRegister Arduino Rotary Encoder Functions @rotaryEncoder/display @rotaryEncoder/readCount @rotaryEncoder/readSpeed @rotaryEncoder/resetCount @rotaryEncoder/rotaryEncoder @rotaryEncoder/subsref Arduino Servo Functions @servo/display @servo/readPosition @servo/servo @servo/subsref @servo/writePosition Arduino Shiftregister Functions @shiftRegister/display @shiftRegister/read @shiftRegister/reset @shiftRegister/shiftRegister @shiftRegister/write @shiftRegister/subsref Arduino SPI Functions @spidev/display @spidev/spidev @spidev/subsref @spidev/writeRead Arduino Addons addon arduinoioaddons.ExampleAddon.Echo arduinoioaddons.ExampleLCD.LCD arduinoioaddons.EEPRomAddon.EEPRom arduinoioaddons.RTCAddon.DS1307 arduinoioaddons.adafruit.motorshieldv2 arduinoioaddons.adafruit.dcmotorv2 arduinoioaddons.adafruit.stepper Arduino Sensors arduinosensor.DS1307 arduinosensor.MPC3002 arduinosensor.SI7021 arduinosensor.GUVAS12SD Arduino I/O package arduinoio.AddonBase arduinoio.FilePath arduinoio.LibFiles arduinoio.LibraryBase arduinoio.getBoardConfig Test Functions: arduino_bistsetup arduino-0.4.0/NEWS0000644000000000000000000000431313470770202012044 0ustar0000000000000000Summary of important user-visible changes for arduino 0.4.0: ------------------------------------------------------------------- ** New addons - adafruit.motorshieldv2 ** New functions: - @arduino/checkI2CAddress - arduino_bistsetup ** Modified functions: - added optional libtype specifier to listArduinoLibraries - bugfix to core subsref functions - updated property compare on core - attempt to use user arduino preferences as back up for arduino binary find - get full windows port for scanForArduinos, no case compare for board type ** minor function documentation updates ** Added sensors package: - arduinosensor.DS1307 - arduinosensor.MPC3002 - arduinosensor.SI7021 - arduinosensor.GUVAS12SD Summary of important user-visible changes for arduino 0.3.0: ------------------------------------------------------------------- ** added getLibName, setup and loop functions to LibraryBase ** Modified functions: - implemented playTone - added forcebuild property to arduino - @spidev/writeRead uses transaction based transfers - @spidev/spidev allow any CS pin to be used - @i2cdev/readRegister return data only ** New functions: - @rotationalEncoder - @arduino/getPinInfo - @arduino/uptime - @arduino/version - @arduino/getSharedResourceProperty - @arduino/setSharedResourceProperty - arduinoio.AddonBase - isarduino ** New addons - ExampleLCD.LCD - EEPRomAddon.EEPRom - RTCAddon.DS1307 ** minor function documentation updates ** New board configurations: - Arduino Pro/Pro Mini - Arduino Nano - Lilypad ** updated to arduinoaddons to query using metadata Summary of important user-visible changes for arduino 0.2.0: ------------------------------------------------------------------- ** update arduinosetup for windows arduino ide changes ** bug fixes for use with older versions of octave ** bug fix mode config in flash ** added initial support for additional board types: - ARM sparkfun SAMD21 dev board ** added manual Summary of important user-visible changes for arduino 0.1.0: ------------------------------------------------------------------- ** Initial release arduino-0.4.0/README.md0000644000000000000000000000465513470770202012635 0ustar0000000000000000Introduction ============ This is a basic implementation of the Matlab toolkit extension. It attempts to provide the same function calls as the Matlab toolkit, as well as additional functionality. Requirements ============ The arduino toolkit requires the arduino ide for programming the arduino board, and the instrument-control toolkit to communicate to the board. Installing ========== To install, run the octave package manager: 1. to install from source forge: pkg install -forge arduino 2. to install from a local tarball. pkg install arduino-XXXXXXX.tar.gz Where XXXXXXX is the version of the the downloaded tarball. Usage: ====== 1. Load the arduino package. pkg load arduino 2. If the arduino board is not programmed, program it with the arduino communication software. arduinosetup Additional libraries can be programmed with it. Use the listArduinoLibraries to retrieve a list of known libraries. 3. Open a connection to the arduino a = arduino () 4. Use the arduino function calls to control arduino hardware. See the function list and examples directories. Expanding the known board types =============================== Currently the toolkit recognizes 7 boards: * uno * nano * promini * mega2560 * lilypad * uno wifi rev2 * sparkfunsamd21 Additional boards can be added with minimal code changes. To add an additional board: 1. The arduino core library (code programmed to the arduino) must provide a board id that is unique and matches the config id. 2. the arduinoio.boardTypeString function must return the board name when provided the id. 3. A config_.m file must be present as arduinoio.config.config_, which describes the pin functionality for the board. A Matlab script in available in arduino toolkit sources that to create 90% of the config file based on the arduino_pins header file from the arduino ide. Adding additional addon libraries ================================= Addon libraries can be created using a similar interface as the Matlab toolkit, or use existing Matlab code with minor changes. Known limitations and bugs ========================== 1. Octave does not document classdef files, so documentation for the arduino class and arduinoio.LibraryBase is not created in the function reference, however is in the reference manual. 2. Octave has issues with displaying function help after the classdef constructor is called, and may not show the help for a given function. arduino-0.4.0/doc/0000755000000000000000000000000013470770202012111 5ustar0000000000000000arduino-0.4.0/doc/arduino.pdf0000644000000000000000000122011513470770202014247 0ustar0000000000000000%PDF-1.5 % 1 0 obj << /Length 587 /Filter /FlateDecode >> stream xmTM@+z&?tBL$d4*.<_fW_wիrc;`GUOV&ʮ[v6W7TvbuYt/N.5=S> stream xmTM@+z&?tBL0d4*.<̿~UfW_uvc;Z̫MfG} I]/ޭmޯo⣩0^'^x]fkn{EK{*ʇupg6;ލ$4;gZ8, M[TPRJGeWxmE7 "/7j;{Yʋ"1tm|oirI ɑc׺>[TқEnn#bBSEV嶭mzsg)gR133w xAb;aGL6K&0+}&"?(Ҧa/ c,!-f3*Ix {asIC%hS7}H=ŤIY(jŧ Z4{SO5Z ekxvKǬ@2a> stream xmSn0+$z"aKU^CvF^p=!94gB˥0pދ s#P~k@hZ+vQڦ(A,Rf5Ħq8>K_X NH3$Ǟ{<0*5c~Pʯ5W42^!0^#rqxƘE3x z)cgl1BҰ?Xq!NAWA*d1)iȧΰО 9璆NVfkVaUJ?%͚5ػbTW=ј52f&p2pjV^cHMcVYxLS7E=1j g endstream endobj 6 0 obj << /Length 333 /Filter /FlateDecode >> stream xڅN0E /EP!PX!M!cZ@Hؾ3F2AdN1<:6b8,B~A0SVtDW! uqrSՋgsvG|ŲBgx]S-y<> ʇzZя`?pp -a 2q(!AjÌ 0 !׸mWMF/G׼~M~ܴYiU>t]`o% <O0E׳)i[z(]Uҁt 17Njc<\5M@ȒP罊 endstream endobj 13 0 obj << /Length 618 /Filter /FlateDecode >> stream xڍSn0+tHE|#r* HAQ.]r~F p;;;fQ?yT7n&kT??Ge5LyNyVӌC뫼_+1-+\L}Vfpg=T_*=*ӺiU) |i&,Jy1o:CjLī;;X^VK'XaՄHJ.TtPK(;{beѮIugۖNpSV2"WeVuARc%oTxH4r.qivER6|à!}8$Bt \S2Hָ+ s'fGz{sm4, k}^(jڀ!am[;0P KXG E0@Wq#@ՆLLmº6ALD SxOcV0Lr41.]).j,8!7pJbWj$`AҾG1=1vA"^$x8yInk[{7_%͘ endstream endobj 19 0 obj << /Length 1055 /Filter /FlateDecode >> stream xڍVKo6WVX3K}$hQt=-HMԖJJ3ʑ^Ï7$O F2#>eAw =SZ2$ [kn+&U.69˴J6M% wOvu XY%|'T\l<5K:a>c&}?Z Uo&v0i_ոJYR!.PLCv[{r!gmGtlVHVFh Dt :EAX$w[+>5 ?>tG * ONqeHZuףo+#ӨjKQ1S ֪!{- dFؕRc8ڪCHJK7|tm(~ EYZ݄CPAT;o_?? +ג!HdK $6-,/e1YX;F_jK +$32w+v- B?=\M2 RG:K:.QmC&}o}4\͂X:4] م${Ö< o [;]im;L  hݟ] j(7eOfoQʂH sP,zc~ċyd뽭q]$Odp)99'z|)kw_C)xۄW js0 8o|a2e0se'phAun^xԄ 52iAs|d )?He#n`!ŸJǺ4 fNEΗ_ DZC =[U\%nv~gYk@b7h_&m"z_ͅWl endstream endobj 67 0 obj << /Length 2477 /Filter /FlateDecode >> stream xK{6ZJ ].nq&f#[YCI.O//ⓅdcȐ,L1X6[ݼO}-u7 1#8'˫ x8  * ꣏ Q"6 *6_EŇMXL+.K3?#%5CْS9#Œ*ݾlخM]ͧVݱS<=}?3&L*_}e'2C"cN0󋭦MՔyvA;47Z$뎫DDfwP8[*~m?o*9-qȧ0a˖z@9S ' 4'TNȌPDR׉u1?tˊ~HePX8҆l4[>[MC],)aUY4Ϧ/Wx91/-OF]1hކ >& U [ M}77P/-_6k]Uzl%j?ٕ"~N O8iB=̊ Kſ׬R5(kp~Uk_/~)wtKrJ'P!Fz(mxOQҞQM Ue&x]ojzuܫzF8GR!eҁz'<f2>wB&vªރ, Nc=.1+6]=`1 u2.BQzKzr)k'u ań:X];PvCt.DQvaݔg+Iﻲ-Li!]m~^Kx)r>p ;,){TEiJ{GU(wUbWly/ËOU6xU/t)ի"'DJ/+ңD;na.\F>m}=Gh}yYTY_ZړssI _nM}@?\""ńVh݆!(HD`n]ԇ+*2_~(v[֍{t}ehw ]Ԫߟت@z 1EBVW͂f;sԇd^z;~ Jcyn3K ,Y%PڛeRT8 J_}y̧ZzJwыAvЧ=DT&tTCXu9RN(mx vQ^2DsjoaW^W}ٌvhsN 'mx*!zXF(")B_H2$p gU}w[G`T6[^'mx*8h"}" %L_m\!!vМs?InK'ͱ6KhNx~=0@; {FJ;wi!sbe kwzh}֕y ix ܆R(NJ9S ƺ9m}Soc$O"O6}WCC*q#x!6z cu0/>zc> stream x[s۸| =Fp!OMd'4MmjjKJN}A 8%*_0;;zo~AĄȉYe&WOd__w Oʿ{eNg݇I+:X{7{XߟxGjeFcCA0h9fF۱NTN_tzyY'ʴӷ~{=})M#tä1.{{ho7~sMMrKӤ<604㖜oҶE7('Ęp>|K٥gU*=p+ݵX%s UTr<_}g;՛-*-:U4[p8S{?׋jo?wB<l->c9>Eex4 Ä5kO>r&:tK(^ )2DNZ6h6a\%by; ~]fâsܙ֨Ξ/AN1)&2- #C^ϖj=8ɏ[&=}:Y }Ø%f\7yɷ-3ՠ+ luZ-_)2PR0ވ:4 %^t,HҴl f֍M>i/{%ϞC0-L}rG-8c93""NZ6DLZqh.b54̴vO(Le1)ɋli\m}ۯWCk6?/cR?Z6C2k5}w?9|ڷ Z,Ǩ-E-فZYflt9sy^DI92kbv`gk2mfEqBg\p冞b:,5Luw,(h,LjL,eQ4w]OƘ6#ϝf'ȳc #=#He ՘D &` vL.2&_3t%Q8 -Oe1)'2-$@Lʄo~}{j%J}Qr a AHh6 Tqc"p|rj8]]{OTH tl+"F2Owr@U*u΍[]GsaJh'*<Ѳ fƤT鑧+bk B o;*XaLA iـN1-uA0e?!v߰r>b݈r )A$fx6@5&]f qr#j(K3n,xdq.b6EnY'RzTBOl˛(O1)*4-@Qt󹃩?ŦnTG mI1)'-pـSqE(@5Yo~zwt2?_!uCzENTx6*-Gxh6m? %x=7u~Z'蛎j1cSEZ6XD&7V&u7qԽʪ@Jx}A&j|Nh-Z&iޮ6@4cے2V#,Se ݰrXęa1ut>tߌ--D+r&N--8Eǭ1?&㓷 5>Lj[w9'V욓iԴ(L ?W endstream endobj 9 0 obj << /Type /ObjStm /N 100 /First 831 /Length 2266 /Filter /FlateDecode >> stream xڵZMϯѹpX*l $!+@AE(Ba W^u;W<1k}LEj9 p(90U1-%c\!$Zà`H>J1V@URJ DH`LR)C!W(SO_P& @5 =@*C) ѵ@E,]X0dX05!4+VXC1J&üI, ,LOؤPR]]l%mBc:m[]vH^cA6r';d؋o,)ˁU@䴐n0|Rg9`ȿr@dzmē#;&,60q9ro8w9fX<9_߿~w:;ܝn>sp|~xtşOo߿SxF=^r!e__4=߾=vEz4VQ#9kQ(cҌY\tC8OWߝ?\%hEfqbAR֨p%]Ư7yWN+wxs;}sGr$x?N^NǓdz^b_ n>_wb?#c/裬b]~Hx<"r?w{厒;J("E:t(QHG"E:v(QhGюE;v(zTj1s D*` viUJ5_GɩS9Y~RD eh628"2){ZHT>%{ǬRcaݸZy*e+6(Ρ\ػE JW)Uf&Rh)S)b %CѦS)q0VJB9^tWV* "\wx2fzuNBvS*]l bIl|jJJx-k'w o#Rm%rY'#<$GY)aRJE|\CtVd ׏ec[4a:cƔf"H3)6G j.SWisD?S)p%8`MCXuc5X%Yz*YP*맒h'3D^B45207ϔ YB9XvTp4qu*K_vY'!5239Ry[JU0!c։h-" H Zr(]!1%G3s9E?Џ46)o>=~7Q-һ:wuJ>j˨xZFKk}xcZGb:u(Q"?iySMeyٖG -xт4{!I񂷴ii/o[\F->ZZ}hiG{R,ׄuN clva"o+m89^\ř$D6^v2QRlmgYkyӣk^ 7M/u.gkB;FDpf?4Sό0s>qzJNTASFܯ*2RM%#|a%yѻR"6LJm{=Ra;AePH9LU\N$xN`ē9M< m]. +ֹRp"L䊢~s`ZzPɃ 2Ƴͽ E\Np3iku*'K~<08|ṜHA6i;B-Ϝ_&sJeN?3 򃫠'S"+u*Xsv endstream endobj 204 0 obj << /Length 2571 /Filter /FlateDecode >> stream x]s6{ ]JF W;Nv7{b1gm+i&ϸز9%D/k<@TĈɑyFg}uy>>@tu0|uzؘ~a6NgML8HÌVX}GyGT]x4SC9mXOߏgɡY|_ls/yg똵2Mnn?}^͉P[/cvK*e04;S`Mgجr^,P˅ڟ7ņ!Ji;/4<9ߞ4G:[}iYA[8ݳZ% @1QyUlf(k(OZסj|% j%g\JF19]RNhvVdf%IUJժn~j%T b6GaV ZvUK9)jk?tS9F7Хe]4ͦҌO'B)}tnYH19S\X$fL4` < % "xl\TiŘ*%1Q*fJZu֓wKQ/as\# N#w2(1; Ƴ38~;{W'Ǝ{@?U T)ϩ,10N]21y,X{tUn5-UlbT fi`3Ef־v\l nR7 {-wMO1˹'2-,`Y;Mn^$ܿR9wf8;bS9rsN Lh6pVUf݇y9]~/O'qQlۖJ5cP)%"@Trt*v^_-׋a2|#~flLT̅b6DwTJēwaԫu7cRt>S rn@ˆnfAZTih9ao,_Gjg[y9R,gGGvSZU_wӆJ~c+NV:C̎}fa̔r3ƛ^^] 1[xeۉ?~۾ɇO欞)>Rb¦pU;~]aV+YfM w[zgтqeY<{%]S-rrʖ-cC endstream endobj 156 0 obj << /Type /ObjStm /N 100 /First 890 /Length 1913 /Filter /FlateDecode >> stream xڵYr7}WQyXh\rJֻ͖I?Ha<ŗCXT>}Cc KYe>6b𱎔S>$Y&QE уMfV=Dl+!/r %|rwE#ED+q"̊|p3E8+ l%YcI m;a{H9(aua[™,fg咗岘ۼM@Np3N^yO"$'QDgrJʧ$p1Dve9!zv*xxbq!` 6OHVYLih$D9#$1`*1 XxĵJ#xpiFidq^B &<ԓh%%f#$V@ `5I #wX!?XHOlc0(9%,Y-݌$@K#7C">B QB9]p:G,`!܈$d,f dM2K!pĔ pBM$2eZɓ_uovffUm4ogWr뵬Ԛj7PA.AR=y7juWwg{9kՁD8OơLN'$ev:I hx LF'e Qg=aqxzcQFR~EIǬ޵HCP.]-),>C{~i7Wuy~m⮚͟w[4^m,mSVs爐JLbͰzn]Yv ݪeF[F*+cяEF7r ^-ҍ <.x\q゗ ^*xू ^*xू ^*x傗 ^.x傗 ^.xOF7vxoG(^}#Oi?RzC^O 2S2LiY4y0֖ڡ81'ej=W䤥I5PrƠG{&i99ьt6M5钖gabN3rG~vR΀Shg&LΐY0-%;mh sR %heGL4ҘӴ.jm唷Է,6}k98M@i949Q"}D3Ź,7#q6|7!fjOˉcGh)MIv{5yH6>|n:#;L;#{;NfJisCm`_9L;#\tZ.C_#.k'ir#C}}Eh ^Rӡ4&t/T8JEsDOCa${i0RuΙܞSn)MۗgK>󴜞y0OqZNĜ8EwxQ9Gm 'Fⴙ`WUȐ64b$:PF8рi$No뾼;}+{Qowu}fQdo+̴ks\PzӺֹǃַdbش jɟNhv,޿/~ku.7nS7#Ay|ڀT$ǶϚkνB[fLWC\߮q_m<~+3yv/Qˏq6_B_mnCwk`9Hzqq5˦}Vjѣ$OfuqsBz\M=(=^_m}zUu͙`wMU[l?e:+zZ5YgOtHnӬn^n endstream endobj 300 0 obj << /Type /ObjStm /N 100 /First 861 /Length 1107 /Filter /FlateDecode >> stream xڕVn8+l6>E(NRh I;(p"K%'ӿs-[NE<"e=LqɤĠv 1i1!5FτL AFͤ% tc\'aLsZ>l |i4:fS3cDc,xJ1 F2,44c,sN+fɎ̒?:cN8g8󰩌`1y1/,&`+X cKعVNT1 e.!$QHʫAf,XA܂, M!@WZZWut<*-R0Wy %~2lSZhƀAYsZT]sZC+[81,pk DH!<ݣ!9.yM˘B5Q|Uاô! s)e-۰~n|m!\{xy |k=X74}x _{yI-A_Bz75+N_X:>|Bs~[U=SZ\R]'hU 澷w~~s{}5`옼Iz,\Tpz>Ďl_bU]yC uz= CR^jؤwpg?͹tg0*aHnڃć8Xaף[ċ&mSAOwS(J{RhlKh8_p#ᷡmViRPu̚Uݍ!vYw;y}Hw+uՔ8:Xl=b(AY.Fph7u}(~x·OinlC]d? endstream endobj 456 0 obj << /Type /ObjStm /N 100 /First 855 /Length 992 /Filter /FlateDecode >> stream xڕKo8\(v:(0I1FDc9v8dᐔGǡ☕V"!)7*bIm0:eade\ "Ĥdh&%+k:jeq>7zy6s1(ֲN%ۈ#Dba#jĕNt3r1X `TUprFTQ "cOh"bfC*eĞ?VeT nkDd0aڇkt`LP;yLH2A ClA (XPiV*.!) P@9 c؈Cp+b'"yak;c%BF=@Ɔ&G̠W/Gg|<dž 1G`GD?xd0!b*iJțQ#&=Cg6! _1|BZQH뤃L'=0 Qʋ LMDĜ@F!r<P E/|zl>7Uܷn]<C. cnjfu}߮kj]nx?z ׃v;e۬ЪΏuoU֜ y]ת|CΫݯ˷bQ6q=UAEɮ\C=jjM|4/7= a|Whs2wc~8nqc`UWݮ.C;#Xݓn^E>aVd⏙ endstream endobj 664 0 obj << /Length 1181 /Filter /FlateDecode >> stream xڭWK6Q"V|[A=9h%V`;!,y~ 1 AK,wǀ>>\ɟw?$Y<D,΋I߾_D$,QVӹxO(Db\(Iean˶m.Y]M)k{ׁA$rNኔO}}i: >EIx2tn 9kZ;G~{tVPEF*(5CC2$JԔ ])H1b++z~ d8S?K Júu5OdЛ3ɍ E<\^?wXκ(H1 +b.#(,)g*W )])(Au2=X]%] X, Pr*(h պhtN HPQ؛ < Cj 3q5SIKkZSe8\Jp@D3d)t)³o糩r~M̡j ͣx } qtҘ</]C9nCu>;ysw&;-ݣ=-&}eb2^Hd^sbXnfؔPKp~Gt!m= UBg=5 f^EBR4Д^GTVl;?+|=_qĒXV?Wڬ Mեoge ay"}a3Mx&Ä endstream endobj 668 0 obj << /Length 1124 /Filter /FlateDecode >> stream xڵWKs6WHu"_bnNiS+CLBk w$%zz|\ŷp|N"dx q·Rwh֠>|x>{ gs"{&ms7Wtq E20xQ+ē" 5f!cy]GqL ^$r;-tS6^wk uDCi4}/CQ)7%E`((JS+ű[³Cǻ;K\>՚foTUpZ{:+Ta:"D$(}ky # X lR(zqj-\|%ܪ*=i%# H=!7ds.dmVZ `БWX*N eO1`T_452C}f\0mcN¬*Uo88|2=f#AJG.8i25F' x'cQ&3Z:,z8Fk;J Ԍ ̖j xwE mڱ[d[E9|\P 6ϰ&[b#)c򉶻ư6tJ 5΂ڲQMHsqb[RܮL@`.8w5a}!Sx+7}*wGYfb4sbonwh2_J;?$`=OInrrJ=8?5J>}NWDXqk#E&!]du7ط(uO$|  `;ghnȏ)l.8R\J,Fs3Eu#jf8<zatz %k>rIy(Z#E13fUmnI|,ʧV/U *lԯDF?HZ}wy{WN$Pc*yK# 6xs2ݯU{ֱ O&뻥äO;^NN:&z@。A\we>Rx)-^y)|jL_;pA> %GB:҄)n3N1m[G endstream endobj 671 0 obj << /Length 877 /Filter /FlateDecode >> stream xڥVn0+(RDRR4h衅Uh1$9P5P6fhEýTxi&L^^Evwx8^`ͽR<ʹZ{JDa峽U`|a5RB*zuگ\gi(5d!0z T"]un2èX8T!ėD^ 0$R|i؈ќ8svQ駺oH%Ӂ ~ RqF ֳ9tP]PzॣxqƬRb]8D\r!b} <8[kR1[.|X 8G F]r"iksf":8X%+x-ds0(98pao5aDAC㮢K e MJxxo d.\ . 9Q|(|9 hҀ;i3`!)%oN%LJ`$yoP1#%fiq;ˁAX.6ݔ3ggau@ E¼+Z*~ZQôVc\S1w3Mۻ/?-ʜ喒yrY'GP!ya8U*]$+ ݁%odE/x{ˈ55tX`2#0 \/&4-sBS ƺi`չ|֖ʓoR3hh~osn皃}Gb{Ot"؏aӌXddmҵ{= ^@KZIdaPJY =`<}K/}(N;=o_cB[ ݟXt{ endstream endobj 675 0 obj << /Length 1505 /Filter /FlateDecode >> stream xڽXY6~_a,PT öHH_6(ܼ4-h Y2$ʛEYZk A!9{!g *qWJn1WZp\x3LezHj6 M/(0M/T^NT^DPኵ.evWi:vISLv߼=cTj֡Dk%AQAɁ ask*޼+PyF#UeΊL]Q|VS)l][T{fϼ5e{n_:uٯHM,j늺jeY7˜xlJ'lU}cQ1Al a޲e%$-*p=e`ܕ>KW* ɶ<6ָ>h|dՐ4 Q95~c9$lkʋX֋6HVh'hra ۝Jahk Q]aۗRaCɯGi0qh'?T_Äo1'E TH`iS) IK=՛V`Cehϼe0DeUy9~LLEa ,LU C3%7|z?OBzܚ`e^ gJ^`5:ERjJGT=rTT&DAvxTgXS ZRQH q1 ]K :]E(fH("ƙw(R(yF W-xH(xuv\]x̝G @{Vpl'H)n'c(q80NyFHpyǑ`i vM\ ҏ{44>F2< sF҈_|@;:sp<) D1Ob2Fi\NuLgΝt+ 7J [0J^/\\ZRu*?YW|uL<7sz\Lᴒ|rxj787l'5VXt$>=In0/Ka}Z&ʨo贍1&s>Ϳ^`aFrZ'> stream xXKo6W Zznöh(dS큑X[Kr%:I}g8Ce7Eb-Mn""+mԸL Wo h+E*0lbG.[o(i&+WuϖȅXR .^,G,4U,9ww5/^Qa@~N+ uJoqTָ@f)hM* G#iմl!oA?Q㻦% ?p=s)A,K0nZ n.UBrqޝP`$\cΪ%T2%2 ܐ%.XJ# 'jԡ05Z 6{)2*5;"sÚuAfy\'DTmiVsws?/7fgae4;Km}O;(T i y\`W-[z O5BXqjM]Cd0VꐋmRh%?D"i;7ޟ*MCLF)phPh &qIITá(snC,kBr#qfG eN(z3,fd&XDeG2 .]\`RR4~6![9&ao;*UN'6)^0q&Z 8ʨq%h11t$򈞿h21lP+nTXM(v"bZ$qe>yG+'߳*Vw,ٓgKU«`;ҳ0]ݠ^<]SJ=^u몓j9[@|=)PAI(nxg3e)bӍt$P`Xq sf%3:k/U}(%5>P;Z(7 Hb!qahz ag2BiMM90ަbwDWGC:ݧ.phfқ + a.t=s1)*Wy,_G!۞zKȀ:4{2g7pIӇQ;ROmˤD~u%I "[fcynQA#F$Uݲ9TD#e3{ery{0c^Es|PAoH9MV/W+TЉ7I3>o0 s^aTq;+wG/ 6 ߲rg膵u/5ZhucqN'dXseeàIks*ߧ!`h|7d,y!=2U:Oe"y zr.qbL< =gUm8iȱ%cbBe4XfAڄ 9(P*CcLBW&KGi_]w_+r endstream endobj 681 0 obj << /Length 401 /Filter /FlateDecode >> stream xڍN0E -agX*6 V$* JC$@Y\{E$<oRNdwZ\^LT #i698w()rH> stream xڝXKo6W,z"YF޹9E[h-Ɂ^Zi]΋wA Kq7o6!6E8Tǫf *(>n(cmЧKN*,SpsqaVFĩﶺ%%<>$X:n;f*\M[48禮5M=3۸Ynbax=1x<qR B8KQjAVE(7-;h';8Gt\Pp`yE;;؝e+4)dft,#r q'91rUa`puoy!%y_|ުy<.Mz1QO=vҺi){L?l9nIO˼9! &:2ڠKI+}BY^ THR`mˣi C@r!Ox`8`譐P2ZM=׌_mo/%{^$@uSPN<opj0s֭@J!Cu4 {۷hЅѺTaCåx1;JmHwi~a.|\){;k3to׶LRU$s-VNq\\d{ĉfr~T[]h(7J:L\o3nd8Jq5b7,}T?s(D+nO(|mTreK%WʥϽX;En?[ $$r">>,:ߘ2KGAǣMxXE*}>< u=HWYxX% pK@*bNh gM8`-AΰǠ͡ .(4l< n[7| j .YYr#MGe$v5Ψ/։&}II?,$-JlE#9mYܜH+*T8V)rV=Ơk|GruL2 ?'r r^rߊgd n^P4?y8SdxݮHb.35tBއ듫Zrn_դ>Q/;X]mWaU7k-r?B& endstream endobj 689 0 obj << /Length 1414 /Filter /FlateDecode >> stream xڭWo6_a`Za!ö>0%yx,2C<~3[iHϢt/CU Z|x, W#7ۋwI` 6l-Ǣv[-rE^8n;>.Q*ˆy׋$L$^q@:BxēN(y "𺠅_{ݵiaC,V,בUݡp *npMɍ0>,ON=x&,'Gj6ڒ\{ \2NIoVu s"%dиq}t(Q :u٨=ײAOl"^֒/`D$s 1+rڐ]Z> stream xڝWmo6 _`jع0z谦Ö}; $;K"ȩnC(Hb$ 4L&׻fBį.Zˋq<7b\ۢsN5S7 CgaFQ\y]pCnpӯ˟.~\AQ/QPg6T^yqDxU*늺B 'bA`s"2`i;m}'+ejLo`>D/ȥ Kb@m02f![* '@SQDm//Ի4H*2ٱ_#V6y_T+Rg|jhֺnVvD툧Mr @T8hPלb{i_-Q TotSW8z>ԜҪUV`ktNp" 4"Jj;I`X%*1E껱TkrSUw䛭-=x$8UB GᘭXhfAosU#k F yޫ+Tŏ,Sh%~Mq ytMxq[qpaps rw|saIpGj? ʳc?,c1 ^=@!lT= !СP<~2>@xмEŁ^ @;^`mƊ@朏3\Ԝ4CgO#v<|S S֮Ʀ _4,􃱸Óyi )ĉ'VenxPQz+^ooVoз}p.j<9?@X H99*HniLƞ6_UiQ~5Z$:DZ}#3⻲lc._G);/*ot0bvƸ ;3/B41ptͱ$eS,‘(Jz6;+sThQQo#ͭv[eN4O~#'|p]֌ d0iNXST @?kAXKG (6ެ"W> stream xڝVmo6_!d@!B=!u-CaX舋^ 8M#r!ǻ{# G5sb/2΀ߎ(F{* J3rFjhj[^[yf8l̋4n7`nyԤgѯ f9:$Xv͸G#38ڪ+VT% ,ia ˦fZԼVKXXAh g &Y/C \e ЀB KIHnxXVzoꪀu sRi K A5{7kX旿k4<'C њ3ϬyiWޗHgYO$FԦɒkMVuyVܨ~r^{n  (!v뜟K̶B9X|#4)C9|@LٍX D2%yV,kV?a wcAG\THJ_7BV0 I>+jwfNaM)IΚ 3e.O@ /((S F=Ǫ f@C(MZu*Ws+Csa f 5󉰙S;;QL4 7"}BD4N9fQgb,x^oj@<6Boh` aqޛ{eOBrB3N~`*mݍQ>#<]4ԼRs )V-bnZ+ > stream xVQ4~_AA9H9ˇJ----2;!:Nav,ZB'A?~hDžE|Yvvfr{ؗmXUa?n+rDL k\kx{E> stream xڍVo6_!`/0"%Yr=Zd@v阨,y,x'Yvvb>(DPȠ(ӸL:\%jZ|p%o ՛y$^%+lvA.xf6+2{QS.8iv~a(b) mcr'CEȗiM]H<1JEO4[JT,ˌ/bz$"d]:GTU,dI7M yvgU[׺rm^}$:nPi۾ٲז8ml::ֵ^|i,rAq+|4[N!6Z*$f"1ǣj4GX+OCtN5# ޮEDPjxI$ "whg!u&kձV\GdWhy_ ţ yLCj=o$shnÓ+gz{ypVa1U-rZ$`!Wdr7(*ICغjN/Cy_HA;VY鎵zhƙfƎ/WB8Dw@_\m}p},&аwX2#lC4iv8Bj}FfU >VogXOofEi3bOtPB^!t-*"jp )l6b4eGӬ>A X5oj2Mzf9dĵ25{7LUV+7VVcWVn\ozkoC_GXE g>oi{9w?&80 ƒE`7eOf]zǦ2JBhf|c٬0%k1x8ϧfG0ⴢN ?0 ͱ+|~.Ꝇ{Ҕh1ޫ#(A&VK̃ d>Genn!'3eAӏn$G({}{s^i]L%>}3Pi`0Ni|p%Bk!׷#/y^0yC ze1Y4) endstream endobj 706 0 obj << /Length 1158 /Filter /FlateDecode >> stream xڵWYoF~ .QjчNz[CSr(;3H[e#as9ofv-~W$^1OyZxIVڣoߞ A0I^|瞈EElз?}-8y4IYz^y"JDm #E1<Yj٢t*l YT"K׵PJ0-2ߜiH,"Ir ̊/?;4i7M+޻@+솥FNՖЦ4+SuJ7.\S* y[zlDL9#+$U`'-xI蘆|βv _uݑ)cizL#d~]cJ~R+y/ 䯝4D;Dcni4 BSi/G9yι ƠejC$UZ%}z<}|JώM垍Q@Y"n4D]G`A ¦Yr *k4FTRE5U;f--pftY+c_l0Lj>c-ƂժjܵfKR5n GXs>2;pc9zRw?2%nj2.8S==wyܾ A]ⷧȫPUbMĿ#Q"󉪢b\t@"VVN8 7xW N{Sv:@r+nΕ#k ]9Skes̳b ,~*?{T߽hNQ5cQӃq#Rv3ݕxXrR=]KF΂d+pkN,Svd`Zkslo [&O'G`8Q`G?c endstream endobj 710 0 obj << /Length 1271 /Filter /FlateDecode >> stream xڭWmo6_`^a4:`閹[6(5ؒGIMw#eqD#y|#&!I'I*T$|s fp6XQ4aa0lXM-g|m[KOwqmkՀqxL׋_O.IH#aՏ|d d6a$ [pؔ-I"=?A[77_0Fȴ [Dn+Jc^u="CAg^yޙ[T/> ɡjueXRJ+ ^Sc pruBGZKeJڛfv#͛5f|]e"OLԶ:u"|,( G3"oW/-5=nн\>Il u.jK}l|JJcSEL#ppB9,szcG\|a='*(ȵqăKz] ĮyGB js!?w /FmZgoh왂J'U{b4u@Ne…T$E' o4˖B܊sܩk!ā?Ѥ^űNKTZpA%b@o!mgP%Ө42UӫqYhQS|)*}KT Ik:ۈ]B6&k.j6Œv83/.GU$e𸉈qx> stream xڍSR0+kpJWq0nE H|nQa͹羀!j"XXD(=h筶9oy̖k)dEW %H" bz!$Di{m<$T6xoT7)\C_s( ` OTUS/B[L|s!1B *oUٮ5~ߨ~Ns.̾.d>9Q?!/ؖo;O; 'qeU-\v#d'{7j낺ӐMxur4#R0_> stream xڽXQo8 ~0jIeon ;0ܖmN4;G#>+vCQĒ)H~Lh$Y$sNr."u]P'e MH4Z"AStԷFc*_W]YDz{{,0*R9HbFfb.4fRNu(c h9IJV{8wNEoi:P`y;(Br]U5nAP5-52JLٹ[oj Xmq΍lw`H O3@ATF ,F^KY{#dD))XN'B)' o^.' N8K/HٱCP񛬙$4:vQu)>PX i/I“\kPs6攈" EG6aIaݴ͗8B 0+q6ss|b'&QD #k;|5嵛_x3FCJHQs"ݘAQ$R,9LAMJp)Gp a%83óAoluI}pU=j1b3 La쁌1mC[vg% ]v9?aWS% L22qS c9OYr TK82,y?>zc/Gژu E˪qc8|T8eᷛk%M@!mծjݣnU|i2Ec;<_l,Uvuf J7>F~G;r.2+Ʋ"sų0$Y!~ߎkl'!rS%Oؒu|uBYhݭ_OVPbxdyLӴ'taKT"31!u϶ AW^pҌ1_ɽ$h(9VavD 9zCl8˝Mej^z>:\d[jìzJQFE=CMU-> e t@dNS`йtκL5!";l= |C搒 ,YR`̵t/u>?$O o7J#EXn_h /!zk%'LN>]j=ApɹUi1 x r)l[:感IarSstOwwsՓW$-cp͜&f2jz6V~ôI]FîH *UQE EzmM9V{*i9P}f=Z}w'(}30MQAKNԞ"iq ;bs_߷]I_5P endstream endobj 725 0 obj << /Length 1507 /Filter /FlateDecode >> stream xXKHϯYᦟn{Eb8x*#ہUp b#$Ҷz ] R X}YŻA0$zZ[lbU7>_B^Rٱ]M3ӛve9״2V.?}f2"J" - B/- 4J:oq<8WE4)5㒗P {HF$`ݒ@tt9ܯ3j>Q&]d|~~ɲo}3vNb #A<#YIp0Z{sm%=Ήf ;'9?̩_uPkXQUPcVVNDkww pwnD,8VEIWOчiDM!cSb|}:ϼRҰ0YZJ!-6VA[o 7ץ*\ N* C~4⛾m)G!ƾi5V^+:Tͮ׶jqq/}O2.!BScv>zJńS _M(]v"Udly@+-sU@VuzYA/.ЌT 7)E,( `_sF3@c'=6~ᐄIh_;>E g,RAwB*$cO;쫓`ݳ9]]`pNR($diޯj?a4iƬJuv2un aEcey*JS0eٷX aA3aGϮA"F}J8ވҬӇj 05P'>u8qc؎~̀a\J:͏N%̐(˄X77;&K+ O <$DXѬHJxJv~m\ۍ t|A-H*hg!TE%{6Չ[l  %"i1'=MLC0/)㛫3.8uLn kc\PW{ Rd6{%.UP}vw{ٛz4vvtp(( IW'<U $ᯡ?m endstream endobj 728 0 obj << /Length 1570 /Filter /FlateDecode >> stream xXKo6W,CWMH"E⃁J =w3EvO^#V_%iAmW˅` n&?^\}v7eu[pnثv ɮכ04t:˦ƓvUu?OoGQRSC}nDz/ƮH^w(˦yH8`#(:M3?t}LPUhSm)+{欏U>n͈ٴDkYnUDWz{$xzww4;;e]4x_m؈ xLDϿݹ缃npK6ȶXrO 2uO`D''BO/ CinXw:XZX9LCz3v#sЗkpF+,媥h6G-#weҊEQl5 /b /UGڵE{Ep^f VI P Cs3hcO( ,I;'[WM 9Zp\c7VBo Z?z8 DmR &1\27@)Bp{- TYm5X3qlhB"9YL2GWv~&ekU@;^rY&ݐ=Y !#b|,aQkeAÙ9 ഄ^v30Ya[9zjfQ@),LrztZv_̡%Cہ9\HA?m9viAչ]>W',b?ڛ78ek ~%J j1uc#NY{b-Y1Ume˥Ӷ%D[,xsTCwg`+{貹X6y^)sn^6.YƼj;,ۖz oil/EQr:{_>%D+M]kBA'O`0p tɟ)SlْalCž27H& VWGv ⛌/aQ1g^)O/UIygUԌApF֥8=J8մk<6CrKJӎO|ܱ&{5S4nmUꆁ(/9Ky-Lܱ^fww[[)敬`2qjcj/wjp.wAmKL||+Z (wauyP#4[*,?ZW,ĕF..}4|] \+̻EEdkj8?\" endstream endobj 732 0 obj << /Length 1624 /Filter /FlateDecode >> stream xY[oF~X/iDTŊ^fT,l$f%vTE,y9w"?"(hXm/iY.D4ۋ˷/p ƋXm{sY-}J\q2b^[,>ȵdK=,~sN8⌞އ+p1f(A((Lcn{eF_gkT~VuYї}b'iZɺ6o4^daIa&rF Vz8E Dw#&:Y䨇qM͊^T⊼kkFd X'0PS-!FQ.v*fYE Q9QN ߫e* `1bQd̕OSD > Xǎ( )G_1Q |2ǜ}@.s]F6dZ"̶ThygO"E?|Qavsl}WxbDO;$6|^ߖt"6hmN4`N:l6 .ΚAb$/7]|6}Tօylw޺*ffCCp?fIyt*Zttx_){x{Whs³> stream xX]o7|_͋\~,Yֈ|u:C')'A89QNjP\E(](!k"L1ʎlpĆqM {;&WGs <9! "zk)zK=yIUĜ{ڟ(K!cu! -*FGqa2Eӑ5G@Z. #Q h"ŚPQ<1"E1$'  `$!k#‚Y%JF%b P 1C9@y2:cbM'!恡 '- '3"eU0 9tȣu(jXsh8P%Dx3WqE2AOȉ׉$$k SB z$4<5(@PϚ $[x6ّ36ni^nMAp7|wގo>طKw=4cu:lq{._3Λn2ռ]toV~wYݖУaO~K4f9| ⪹4ۆ3Aq,V6N?Uڻֻ]s5tar1(VZb h.tG?n3f㎰1$7ƿBr&6C^gde;4+1>TCK?zv -@-ļ(I0DVq KqCY^2"{?..Of[ym+O o+Oer=abR *Fڃ*gWv #y>'9|9,Pa(gcJ6i(g™zR=>d%<+F )>+m@bvkKڡlvl=Q@;UFd>mQv.L nfEFxA.F?--Y*%% ^-p\h@-O=cO>W}? 3h( endstream endobj 735 0 obj << /Length 1493 /Filter /FlateDecode >> stream xXo6~_ GJzT.J - [IwǀsINwfxt$&ICɦm#rz N>0>nKUw6?\^NvzQĜn9CSU_"oM]/H8sqяדq0¢H#i!Ƅ&3"9 }'̓s9ф! Ј(QS\9r:޸cΟqak:E4|UyF\mA괰FlxΣ1ɲTA<)ItG׋) MG+ѨR ';.Nn9yB@g zg_>hR#zZ3.o!a ^Yl4=^4|2jܶ0H,Dn5ύ-$(\#h{ 6ov2pi~RV}UKjG?̈́D$OC”.!H(#Q |7._聾Vl<أ_rʕ:As@tJhE>MY4aοkݍQYwCQv mEC_}pFW*oOqo/t>r$"1ypf0G>r%w٨8scq P'mmo b`b EEI9aQf?Tzkl u}p΅?sK*<ӆ:[ȯsU`WP&EL^Ⱦ2M %ס p\uQ˿Xue:FX7|<墯 `XPo/j":zY=ө_vh6Wvq\R][h'zyS* uXLȟ݃"MAH(S`Wa\ j1z (=HDuRTw`$;i.vUcobhM!̧{haB@v$c, tF zR,ʱx)Bo&s\hs)m7`.>mh"篦l)dl9iIHO@h6T' PԶw^`LcKu,k6 NsKslr$QF)NuW6Y  Wb]+|=o1?jՀˠ1.'؜gͭ[%܊pǭyTGEG Le1?q@]\h&SZk/\hKY (c`,jzEaׅu.؃:~< fa}UZU4Ygk %(ʗ9WwJ2Fdn)Ipq3Hn43'3ݭX.'25.C?Hw.zQy.T=F9n|kbb»՗4%MG^W5оs}R{^ǚZ w endstream endobj 739 0 obj << /Length 797 /Filter /FlateDecode >> stream x]k0+|)_Xշ`_t4v:JIX;XJ 8R{!ˆˆ^nz۸@O9F0F1fR <&FV~@)01i\J"BϓpSi#7")\" ȍ!pAǤYQ=撜Y-"k\0襐"aVZeEՍb$X+?Z,OzcRj'~G a0%JrN a28 U&B6X<7]U0T'<\$˓\Jm-fhQڮQe10Шu472/U2x !rs b Ѫ4cP22mFv9GᗶSKNJU[v,% >@JƣH{]v Qfty4Uo[{X.Èś@S{u*F8cN2‡ 8-Bqc\$MJϖ" U[;ɯL*PkN.S{2mUG.iC!>ҿ:ИWF6;&ى.ߕ/pM:i{Y&:F6Me]TcAwa;䪒le.2ֱMS)C -B*6b- QWJtSW>6_McEj}${?=Zѭ8̆)U endstream endobj 742 0 obj << /Length 1391 /Filter /FlateDecode >> stream xXn6}WQ"FIbEflmTvTRdQ7(]Hr4sx8sfdIor oUW| [ /۫{78E"x]m7_y]PJ#q'>.X46Pa'l*'$O38"ugp %J93p"8~.DZnڛ~f'8j,`DI7 !xyYK-yV(OMtNipGHyaQbn :됗4sp\"n=bʮ+)00oD_+33e"l?T$Mq{+XѮk yx7ƜGa=R@Tb0!g kٱrFPL ey^#P#{sν霔Mi,Da )sAeSL[_DHiTv7qRĠkdmLk\^XTsQFk`0II\M#A>!R (>]KBGQ.Q܍GBoL-ˣ\d-1~ H$kuAۛbMAZmT>jX,#PEbs?vPfpe~m ۟t9@H~覼qzjo*.U;Ba o(#\c<+6u?Kry`IsT0qjZ֮n'ٷcWI V>LBARߥhIpcA#!ꬿllp㏖"Nw`gZ2qp r3ݙ rLφZ>EaŶBW`'_4kz:t6C)\W; ש=5w^}>Eelΐ !4> stream xXnF}Wy"sͽ@Ѡ\CZZ,(RŅ7^,+h҇€MÝ3s {`/!^R["uz6q!_W7{8BYao.\{}' dAZuE]0^lD#BDq吜8g"GpSa"kEi" 1Λu_TVt moVone^䅄"F^x< y *@U(A4/)̃_#`0DƠ"Ȧ! ·k* @⮨G`2MhLj M>NG(,I}U_o}QyY0&;x*-Ƴ~pUW_#̶})pQTkSiќ¤(wվڱc}V>kf0_mUJL17sg_W,Bo#]\0TJ6і`ڪ.ގr614ywgrᨈ$-$ʲ>a16NPȠw$s$LLaVu7O20J@!H=>Y;mI,G)lqB75q"Bf(>yq 2ꛖgx 4,7 ,LPc 9tf.sᘡ,M^p(K}C6uk"ϋ2( ڌ)@?fQ4 4c<:{5]$OjώOm6ґJ:i:߷L5ȾIFmgHO;*]C>Y.ڹ\$NȦ(ô/(vJ ŗߗA:JmoġǼk2_4rX )i--㔐)ޑ8|dƠs57ڟcGqN9G^]'ɭn8\7n-x cUͩ}^4m2\||gOyK'&'t9Q3k3*W ICn\\Q((p-1%&Cl&G|OV]kMRwyKȋ endstream endobj 748 0 obj << /Length 1383 /Filter /FlateDecode >> stream xXmo6_!D _D-Xbӎ:[(A}") 8ˆ(R҉&$h , և3<ܕ@_\>#.xf`T|&^ޖN(fū(N^EyZ=IkRk4iR}Z=}5:#Z{ps0pi0O4QD() )妯b'UTPCU?LP/, S b zCcx:7c1@ϑ*?qy<Ǚ}#؇"A4JisXO Vé 2*%dNj3f`ACTag4"p‰Vt^ 1Hǰ WT+͉ ƄgnMfCM(ύr6QXNEۄw*)BP b^EEO]!S~|iQ9rbD{ Oo"s}YF\˛JM׬~5GGwSU)=\o{qI endstream endobj 752 0 obj << /Length 1289 /Filter /FlateDecode >> stream xX[o6~ϯ$˛DÀu[ u-;l%iw((3=+زxt*$GA11gxn}q1v13o$ I,IougMq6c|Ŝ'(P Mٖb*p*CF.i&(H ܌! x,EDO"p SCtrb"Pʌe[P5Z'h} WuU XBշU}^lRCpA@(C@$(NR~W롪UGŏն1!H& 5/&2tnY'8' >]&`g돾MH2*ѹAk2%Y[y(_Ic 'Lfۡ4Ls*X5jmR>Rtbog6iz{#… ;61pU_M;f?kBGX1J1_] CS,ಣh{ Jj6OCw||?P pqVd?џ-#=P>-L JtF&/9|bԞ/EI@4k>7O+fӖp{HpȓCG \kƗP-h{#ga[*4m{oک;hFpK|H+zLȗ"GGIqΐȲ3"fì Nk?\gm怡ڌ,,f?wpHdnݍP6M37>s* ܙ np4>h=v oGHԺ̱v-æu%YPs2 λy_fltRG,tN<^zk>:L puFpQXT=8cGdͰîon5zk-%+_S :9zu<ʘ { )R-AU0?~1I,x@TrD䋉ؖxA ޱ@lvWݙRsx JHL+rӾpIͮ/.Qg s9< }5 }"s]'`2TC>73i{Y6w59%[D6} ;ff8v0_|*݌aXS EFEo|2[Y~k1<>3XiƨA[iRƫ> stream xWK8ϯpqk ElILĞuɒ@xm-Cw믻?+(23! Ddﶫ]\u_iˑK2A+͖PE:Fv-JBH^=(JJY~YHynjk^Vs]X@^Xog= fQr"}W  sup+fE8v_Ezumq]\r!*ư 4(fc?"gҸn 3OcRd@ {LSs#>HUp:O@I!F#zY Y}UToN):AJ((z$bRH)|$E&ܼKTUFM5 VD R_#~#G^ڞ=rwV`'JjcZN 3Dnj7꽵jP:~kݽ'3w![ŠkIDZO > stream xX[o6~ϯ$+"Eu0hح[ƢmmR"YTtE*s|8$8Adzn?޽\/41כ9"x܉*"U4|i8ljKz-WQ,xū9M()9S=qy`bw7a(7G eI芡Y/^ԅkDш(IP-f ы˕Aܣl~ <}fܾH[Zv۲̏6@̢(m%dw?YS~T|RhLqاijI)fb?i;W8I'h1bt#G$E<*֨ՙ_4S'p Ynu"zc8>(x{f(2՛&pS>|u|WO(bPl~jSHx#tiV/,* VGjR㆙V:'L\X(CÓ28Q=%ZTݖIwKvds67geXp,FS՝.0ЌSCla7xz:::4/rsv,Fq1'\`XddN[ߺA_ܿ! D y!Y ӂԞŠOIS3JŃCL=5m#Lp@YTlQn}@@\]>'G $bf1#P(2Zq=6*0ęm2 IAѨJ "YoUKdž؛t1aY˜H8poݵ ru\j1>~TSbX2 /ѩawO> stream xXn6}W`E@Ѵ "MҦ.VwH,E"ù̑%)')O(2͕g^Q A0H~syt*=,ʨw\{/] Yg/Urꯂ]kF5JOƤbe}w9Z;H,|HG9 C* M@'$]Ǒ҄HyBNX T$ kd ݵ{}ݭ{bUgWuUj>Fm,k#6 qiM|w:ܪբ)(AaP`Pտ8]!zպy_H|*UUTW$uEy7S{ce&鑄ZoB)&zcD{kjbwI#]яhfz0y/+bl,&z92"cXaS/qMoyYsD{(%Y31ԪKȁAF~ V* d_l{HAdIKB [nUevj/RNb"?iè ٔ 5P [cqm65`hU|P0E$fÎj&8Ҷ 0 x3:imX["VژHp&zl^bsKtvvo z jICi0Q&E@vP-Zjw׷`/p♽bm4Hۜs~0ŨDPQuhbbEJ2N̈G%!9usΧ~٭ͫuqUtyyCFAx5^nOF9i^k@VS1oYjm2Gf$loOW>WiFdқj~MgY|nV.p6r0,Mk,m?xT6n`A54,]ڎV,cϜ@>m.mSt[=r5lԖSS8 t{Mmu{džϡ([MZ4 aNߎ4 qȟNOGY$u裡> stream xW[o6~ϯP ^%CmI:5҇u$lɓ%;Ir6CssDr!h9n{ψKA0 $Z"")H M-vMRX^')"~HڜӭW:Ii33|wv< *DO3w%C5 l a_v >DQd2r鄋@h˾OX` 'D"xlN_UUWoWWՂt7qS 9JZ3I-ֻS $xumaZ]ȪOSfa  e.Z(bbhx>t1IIU%OO0)!{ɸh@ǫd8`$} &aN,-Cn8u*! bJμĶg@1:̾X1A`d)t(ba}Н-qrMm{wX؟}j+P 7_~*[E8^U0ẴbeBbMɊLgO:m >lQQ&9 ~ha7uWKgRs3|̏=Ŗ0YևNˮAs,c S+v\KnoCuKle/\jFbr&wN^bd:`Eyvi*Zp+z]#^52p &;_cX:Mm1!P__38aP7u9,jmۘ/զΏA=qU]ByoP)tL 6rzcNzx̍P(7qGu-@<Nj2;Y&/{Wπ wetJexzd4dxלoY P>j!Kp+*?/v] nVi@S^'" 0%Al4bint6gS+؟LWq endstream endobj 767 0 obj << /Length 1362 /Filter /FlateDecode >> stream xXKoFWHz|(Phխ遒V[$ξ]u,r9;3;o>l0MF7YPβrjyc.~!V.ēi{s^ laGt*Avqwq¹9z?TMAe'뽌ᴈzv2.@Wz꤯0_n"N",qCݎC px 䣕 B@ ,a-Wta]%ݟ !JFQywkf@9/YcII! n4Q=Y$X~ϱH})%SK(@i*',i(d ݜYP$$s%Cl<:k>q YӖgpJ*ʗU]EQBߦff] Oz`Yw_}„^h0Ec\/Rձ Z]+whu/ LF}÷t@hYӹ8߲,pzX`HWn!:&q_ 3,LTUk& e]"M=xʣ%fpk'ZsY4EzU´$gbm0ɸҒU\<XT՘6V6F9I_Qѯj NÚa⨜&[ԩ%_BH|!_% ? endstream endobj 771 0 obj << /Length 1407 /Filter /FlateDecode >> stream xYKo6W(#>E-P)K4@N&!Iw}&e%Nh9HFoޟ. (4'IV\xB\Y ٹ 2/jZ-~KVti9Owi&LS-m궱oDri֦3Ҥ+rU&_|ns$(}W$#\H.- '"ͤbɷ5[M:S.M[Sٹ*RJf䋌q(E-jPLPSaI-dFwz31~!AXVo_2TQtNMAxFܼf{q0q2'8:K &DʯN>XW6Yֽ͹)">X2)TCv QzElD׭u00 do Ao]G9v"wݫ i Fg0 QxmӀif ,uQ۶k[fiaq*By9M$- $F=R%֣kl\.t2@xG~ ZJ@N@ZјjEfm"7MnKRP" va9]n 2 ]tq2y`[Æ(gZO> stream xXKF%[Z7m"$f <ܷj2Uu"kxv價,Z+zC!` G%(hƵ-cj Cv<Ό_k_Z96A=V*+M[[T 3,F5oOFJ<;GRdi["-=v0~z$eTǰs{;B1J8N%rt-6v9B6pʠihO|bʹ.,8 rS.G޽{t! ణ˻Z1*fPl4Iy., ޸ֵ3oRU%exSLԓ+0˕zWnI=ز=FP}m0ck 5ύ(jMV~wRE֖UҴ f]&ЌқޙPVLp++Ux_ /LR4e2A@0c4z18hUTBF.PW)g'/bnSZ$P1C؄{>:r˅'u32+mW]q~jLe1-lԯ?G3{x,('+ 6ajNzvzZ7ʫzV?ZުR^]d  CFN+:o\v<4X*W^( [0sx> D_.}bM}W'-v~>52l|=u뙂 ,QUI@Y sĨmZ^O޵f]9/8s~-OI}Jr.8{ۄImIumx+IL萦)گD98PV|1,sjɌ;>% % HUٶ'vK/|Ar%|e%!g9 z~7T8ν}ѮlJ7, endstream endobj 777 0 obj << /Length 1224 /Filter /FlateDecode >> stream xXKoFWi/EڲiwKvYca <6O5 43~j. _U]U1xoوMvwo 6v3ˋ5$LfCmw۴dR/9Ƹwˬ˫R=a',3DQQ~r7#3Z#ta$B!g~LwtU[+{ >ҼiU7'4mr8A,4id+;0!8[˪^6L0u:&LQ*?api]w<"@5h['z4D`X~]ߔrg"3wG׫}S/\co'-08B_d$ZUZkee逿 Qk҂muƄqRi*zjcpi֎1B&$~#U (VKi=3ΉMDbG;(g_'QX*ag@n dע`!H8̱-;x*D¤A4gpmNi$$=XjϬFwPE=Jw'3$&eFҢXACF{)-(fְϔ^KE*eUPǕ껪˄>J+H, Z &-`ǴBS2zt@ LRdRP|]?[{yKA5 #'=aulu*E/Cj#[m Zﶲ1nnldIBbV@dvլ[klv{bNwH-϶Է`hh &l0E/i3eǬ RCu*ei=_0$b]X{~\.4r 3=a^Ǫ *M:wva<2|3BkNX7΃*&MʕB$/uUR0 %%S4o3 :aMW+V.:7}k㶯l44rquۊy).1L:eLibLj6jԈPEky Zyj9hG?r*x},8|1̯MBNz=;(ДEi6=VU43S鈾z3=>ȇqI_?Ai endstream endobj 780 0 obj << /Length 1318 /Filter /FlateDecode >> stream xXKs6WHΘ0&=әiiխ遒䐔].][NzZ~awa]h ' ׋*_/ \rE\DG)4&ir;U, ﲺ˛0m !a"c4>M^0b:ViedH_>$nՠ)KT4ț[xQMw'l.k> HMx #Eǻ]p*sEj_₟׭f$E$uQ4*ЦccgXA8ݮhq hNEiDD%H|1kbRƾ:x0 Vgwz,֞ɆfPdQC.LپnR.$ID 0I(QA (nfipmjcMQ虭6J;_=KfA8@(qvE(H190<'Cwaga:9?hkD]~}egehXbO\߃-G3K()pQ F濷yZmE3?GsLh*Jao9[AwzsMvY#9=5N9s`\*=;hS`Fz;NQpB5:S<6:^5 ,4Ziq- 'z v/Xl$8Za`m{ע& endstream endobj 783 0 obj << /Length 1161 /Filter /FlateDecode >> stream xڥWn6}W/1$%bŦh>l t–]ݿ(EI-899u?n w科חۮJOz]nȄǙ߮>TLEHpӘ|ʘq}P|z\-!}!\ %K(]F%,^"dB9;9{_xG.j vȔS}AEY,{>-}ސՇʿ/~,y1ޡloAÀ~$Z55a#.at|~p7v;;Nuf̴VRK ·AZpoOM-02nd48S`Bp}?(B(",2<냶gɚLȪx] =Q~s, 5j?BrgQlG+hۂv/=MrwqʤHRI # ؓF\x&a@-;Y @UBd6͑om/U,od9«g'uĤ(0QT Eꆂ+ΉKfL'>)M\5RJ^RWF3R̀Mu2$]bl ]`Bpbn639#Q^bq1vQܱd|h*`~Z'8A Z+c=f >K,>8gC2uD\i=tiv5˜3oH~ f{ endstream endobj 786 0 obj << /Length 1408 /Filter /FlateDecode >> stream xYIoFWf Ɯ(MaL,)Y M- A>{ !AR$vW9{qvt+ \(~yy#$"͘:+}ŊRŊ1_,Lt\#$a4Yۍ_8ƾ=I/b.fQ+@FX\Vuuު &֨vb+(luM !J֓@̔O{0N5oÙc aId:(]wL%G?9|0zjv,9ʬ[ת?rYeE{g!4O$bzv\ H}:a z֝`e*y뫶*O!$!$oqYn~#wl6Rޟ#ctj:/"z!|~loO:J;ў5cx:8N1}3C^- endstream endobj 790 0 obj << /Length 1467 /Filter /FlateDecode >> stream xXo6_H@̊ XC mEɐwQ(V`(gww?M7 mR͉f|8iWlOWJ ɒnsUC~Mo9QvoXT7"7{Ӛzg-KE\?va4.$RD:>jEh :"yW5BGsWO!]%xdKΩ3=ZOi9~h?\trߛcT;f>RFy[揕P^[a S[KfqZFc{{t0%&#i*u*;5cLD+WGw>AJdJK5/Eܜ,Nas0-N0cw'yz?&/.*Mb,Sisw3zEPH7e"2q4or&4W+.y.Ř$t:dI5I0 Xb,_rJLr0zsJf{#.L*5X_3bh @OHWSo-CԼ!ψʖ`}zP>] ͫ@pݵ (N#,/@>sNpȻE7icU<[2պyJ=e&R6Ac5$o |(+\(,Nı{DK>uGWQEBEST0Q .ƦjJbJG&vHE6 լS[%$a G$5C _uǮ5{TRI(+4i>pS&cCRPm2Hi¨X :**ɟ紇j55)8(TX(h^qѽwz*a=Rol21D 1>eo>+}vPKN2>A tKO>QX|bػz-j+Y n)Jo>}2Ꮽٕ}ک˴l`T?b Qu>W':]KM^yej_k~|́pg^Ug !<1^1POΏ6C:GF!]̢F ns9NrV0IQYu*>Ϭ5q@i2_}8U}yu-@u%HPuÙM`+᳂ul4ZoOwGO1J$ ED6 MkoM`iƪ)>ǡfjY8;tMwon~^n犅m &06bzmIE]_a2> ]*':ci' Pp}X1ڟyRm7M&&*CRA,ŬJӬ endstream endobj 793 0 obj << /Length 1354 /Filter /FlateDecode >> stream xX]o6}ϯ[db/}0$X V$AZ-$/%fVg0uuxx?Bg Ͳg*1g+q1Ɠ;)g4!ERb3ZgDwЫvsΣ<BF湈Z?уڨV+5YEċ_~Z K&B.nfjyJh,%}}8^6WL7bcZ=aF 9n;T:lYc)Oj9{î<;Fp#+ǣRvr5oC$(%˅@?qAu a@9eяn4逵3@)a#OOSNH4Il.U4nCJ҅HdZZǠ 9PFbބP2Gf+TqJ8dpdDCX1)aP T[N| ?':͡.*%(}S;`R"XĐ) Ue Eking:>L(=vy7UY >h5eŠ% $DӲ] u 7t!*ىLX4FL%켽|y:Zv_B-r5vkyFUOJ MeI닮Ӂ!Slڻr=lZ) 3r o+szhn7Ff(lhYa6 CDwit&ADsrwrM}oN =d+ՙ#˴^NDeշfJ~0BB<<>5Z;e"w m_ta.w'}c]kj-G;|@&آKc/XErB7+c[uږztkt3=WGrgTorTHP΄DFV'TVôn~[!U;ZLj"s~\.':¹Xit݈>0]|.1T900uwV`{o " pkZ 3+<3 ͆g6hU9ӜL!Nⱄ3gT.UpQutp0߃vZ)lR`=`WQ|[; "üh( oRooeOnXB__"Ϻ.+P?8LjP3ADomCm܇`\e>r"a,Q/*{ﰦo-oMev[mjgG#;! {ӎ6ko!$)#, X|GNkb:Pqj63k+IIG~BX cU k8&V_ȑ endstream endobj 796 0 obj << /Length 1396 /Filter /FlateDecode >> stream xXKo6W,|%R=H &YjBu_!D, E3-G7q$aWm78xj9o7oOR?\ծg^޺cܹw uޗM-W D+\^Q0j'ZjM Jst9C? q;y>xν7Ij"3֒V3ؠ=(k7H>Av\ȫO\.#ePD-gw.p7w5іsKXOe$dQN|8$HH攀< ;ףjE1Éhn5]D%N٨PT=%g)I9̖ OYb4ƹ_].R EJd gkG3@g#-s%&ZEuvkV$YEA?#c+#srpnF҈G>׊7p|SS#;ǵ>#Uah!:4B)𮾐[n~)dCfCDوۅO+zZGVǣWfYS3:>FG.QyZ,zpQnEpRgzQѯɺۨB}A-T)e*dǡzP!O}8(t/CghR֎JSFNTeY>BbÕF0dL?.iBJ)mf1,\Li2ovŸaB_d`s :Ti@Us5A 0 o<DKqbD\t};X.WAUz蔅˛ j(h YQUo:Op+drz։~8ꩵ^fb+@7lvdvC@A2y\ơ(),o3jZ+"#g*/: Sr-Mfv3$#? a^Ѓ<$mfcJD0D!3΂Gψp֡vTE¶t?&E8;e4 7_j WjtO0O^P/M[Jj,SG=*sk84UPJeY+Q?ϯjH~*`htL ԯg^F\t?hQ3kh&W{܄$K-7Te$5tjĩ%DqyE,2M’~-B$FmJhn#,ԏ 5 ĭҫJSö}B^b'Y}CQ(7X'X endstream endobj 799 0 obj << /Length 1347 /Filter /FlateDecode >> stream xXn6}WQ,ZM.Z CD{J ]_!9Zp0p4g(ԋz)Ҍ^j۟.(څ`N,]\]DZG#G9*wæ Bι B!b:Ȅ?6PlJ,41I,+#֧&$cfe ba}A7_]'OȘZSw0QQU{c'9咫(c U1KaN"F.!eqdאu}+КVon>b@46 X?Օ '&y"QD^ 8L2thJ.r 9CB ~(<ڣ ~?#hxDz1xFhP)ݙ@?nL/D`!$[T12(95mtG긩S4=q)b]W(__Mulߐ r!~ȵC aJfJL@8-)١~T,fۤ7CC#N]oaQ+ IUU[#wά鶮Gf\FPO|1 5To#JXS(/cX> rf\ATQ.>]Qa=ܲ`}(z0ϦY:E`f"STYͬ0&c*y_[jFub}W LMCKD)Kݢh16#@T޶nmӓ՗b_dXvIL#&C/*>āpД;m\bVsԍ`wսV.z+%VBB'"dmtN!9v1q<+Stӵ{NZ7* FΚ8"SuEkEQâv[+ǀ?.y$ΆNaZ%I Dd~æ٬kru]?.1Hī]Q[P}Z?*sm2tc9Xi|Wlp@/F"aB~x3̲4iobzQSr"R6 ڤ/iNœ D( 'X'Ddل%ء'܀Mewc`9Y6sgwڼv,eD- BC:__mWuWLɓx1 }E}==t6&qAhQ@*͹t*v_g/NjGOU9UNq\쬳~5T$dm! endstream endobj 802 0 obj << /Length 1113 /Filter /FlateDecode >> stream xڵWn6}W^tuчč{A}h K\ $Zc]0d\̙3Cyp/IIE zm=;u, F+߬/^F(hƼfj]z7|e ~v 0oWiM+՘_BV6\wDxVݷn'KkۉEZ1zdS dezɾ43=!ưh,+;q)-'KN]/5f4 퀃(,zSB9dž>j/[]gO4Ǫ`׌F0{cy(8`_VݾΟ޻Ro!aɒ%[˙$aΪlRjyQ-p7Ng$fGbpΈ`{uGnB;(Z OHKU3dfspEf :Ɗ"pxDZ $έ82Wœ;ݸc#gG{[< `7,pcն PH}l.)poZIY{w! ܟA!{YX왰YT%^X5Sk5֑>SHfJY V^LKR XM+%)ݝܳ[sdn W[䢈yQ0?$,@"7cS {D=S<q ƗZz8F A;g|W {붳}[P%UÇ$Gɥe̷ endstream endobj 805 0 obj << /Length 1068 /Filter /FlateDecode >> stream x͗Ms6<3&OLti[#6]PTl.)XQN E._ǃ]&iX4ǚdxA]/n~.oL()h=ZV_hq_n:ӦoLަZ]j۸'ݘ[ӚfeҌ)H_I,?]1:T&1»캭[~I2p΃៶1MU So~}Jq!%svX[oں~_\}$ru̱;Ť!O h,WX@!H*C\Wv.Sы/bRV8/iW`͝ ݽ] ,Ln 3?fq" .1AY!hTl >Y/H= !•]DŽƚeL.uZa N7-7=탙"^"؅Ҵֱt`.5 LxQ̠!뺩̳f[v͔hL8Uh- 8PSW׸dGX*jW7eUfo҂' _}NJTaZ֤_z>KRxQw;dd>rob+ Iu &M2uZ v9kAwgUt.ٿ z0.yО@~]7Q ̂WpoĮmOIt"Aߧ3>6 g\N|ԝe<'G!hǕ98jSRMJz1o63pҔ;2RwfOԁX/:8fZ|uhBaF:BѵU7 *;ax^i eB C:$znWm 5߽6_{v-$.a)s= endstream endobj 809 0 obj << /Length 977 /Filter /FlateDecode >> stream xWMo6WE,K KD+m(*n}"rSZ29$CdH4(gxX{>#.xfJ`9Ԧ /Q:ca&9U$y7F+BE1MqG6LHpv$]ILI& (+jeCv<;* bQ*qPO#e_5{,0 tbHqKl됟W`1,^a8}5"]\%i@ʄL)ʀ|20_f|ob:vV>vQ'{ ^`D =ǿ 2d)Jא1e{SIh@': sVS yTnr(L |rɃCQkM dsv~2KklE2rrBB%aaւ0&1|)G2xC[a-*LNո.zVosvέY7RǞآzsl v?5 ټCYu:Vq07`:akWش44@8H Ļ*߿7k<ːo)Z#L6.^]mct[$ EiOs{Ryyrr/铤mq~]?0 0&{ܖ,MsWRDŽк O#)y/};/s|ϗ刦nOM.^(E0mo}$K㯞xCVUgGh8>Ӡq`HI~Omnw&HCຳxy:wFonDƛZQjU ) ,ivUי\U$, /ף==*1cn"عt~z=LDu,s1bh 1 endstream endobj 813 0 obj << /Length 1200 /Filter /FlateDecode >> stream xXKoFWH#@/u"b.E-b)KYR$rU= >f! _,H3N2UlW/>tEݹF߯}21TԺ ~ oV*✇U$ ?2FWMmvDxUF"I }ՏQdH/D:>r^7KMA&KH,BםS )I;˭;4sDhztZ^rI9G׬opwe/Nc:9(v]TH|x́+I@)ɥdVS&ƈLb X/ J'SNaԇ8d ?RIFkn> stream xW[8~_Jk #X3J<,<ĥAmMN&ˠBGU;\DH( IEݗqA\B(9֛%ԺAn0*\/WCSm_xNmTR4y~}b=+T -+iD`hL nMa˗(!JdHdF"˪ܷ>m?_W$I\j盘XʥoSN}TO%Q0ʤ ?EW u~Û- ¾oTUیcQQnqjW{xNwˆ$Zwʅ{NQJX8.xH  rJ@U^fJ'z/HzBU6%l߮u~:n^9ReUwʖE ؑ@Z3^5?)cZE'䄰_.Y>a:(JT۶QD_)WT}I>DVɖbd dkgrK$ฬAL7Od]Ns$FjtCKᧀ<7mIgD9]80j3vplV$րt`ZvVX,ք,ww_6B$;!Q}S7ArSG~֎5Ӣ,<1omI]GWϪS}"٢N` rL*~ֽ [tFwaژ86$1/f%ąf|Ym^7{586<>@tmQ^韛Oc5M"R4(K8EP>@q{ѱ ꎉ fI/{m!*<AOsסn(.[˾SP&=Ry̎3}1Pv endstream endobj 819 0 obj << /Length 1337 /Filter /FlateDecode >> stream xXn6+tCCR(覙b L tvrԒ\Iv&?=ȉ3-D^^>3f2q* fٗ?^P'`0ayqA%XEgPr= n}V Cn}UsIXI)O ,xx&Vܘh pS :Ybhj}=ƑY@%B'Ty zpž'BYGh`lSkoRY15VԊ#) UPa}U{1JFkz*['.(/L!˦^.NYs"_"a1'T_'## | >NqYRmzكx/-)pHMS@TVQ.nm^Sˇ׸r..'?&yb6/O4W,\-?L@8UeŽN9aclG}f"`]0/[̄3=*]Ifs!G(q%m+iW7JwY'\D0a8qf"פ{.\Ġ񳨜稜:zi5P)NW0Rb4>y>k%1WɵN</f_vP endstream endobj 823 0 obj << /Length 1444 /Filter /FlateDecode >> stream xYK60z÷4hHl}k{Pl9 I ×L#AlQ|7-aGf!Ŋr{naf'`H{Z%-֡jgu7cYrs.sųn94N³z]wnYsZ`Yf\^vb4.@zCjJ"RN*Bu? 6+YN $ܾ}?υ>: Q2xňcmϻm9lʮ[^)SR:sNCzn`dUkVo&G 6k tvS PHtvڥmo7x( әKOTx_u}t}khVە1cb?'+ Ta1UN2$#p#bjե PZ}zBP)5 )EBeSReJ#$)풢BcJ3)!+eȨi.qqbϑC^"Et3DZQ.>uRUDb9`GH_!#ŗ{ h)TP B+Q)3TKwuvu5$s;[ {e6e0U02<_ջk *t)BDoB"\!1.vKF JBxC`_W:[h{PL)IsX:WoӬVf6mZUjBŨDf$d^e=謄6x^,mW@Y^װ; lmV…XlWۗI抐g|6 cZ~aJ wFt7(q%<{lV!=̅PZqP=wE&EFrv%\$Q j"Smk gA+~i\:>g~,uOh.\(&I~"`:<?5=阏G62A+P7l,K6s KoѴ#٪Of0PΌD1# |g݁_+)> stream xWMs6Wh|fB43;nM4[t$RJ M*T,_KHpa.IB҅T )&U\ha:mu ƚ,Vczof[c)c,W˔s[*tUіuk,S*qx *L3tUL!,xY*iU2T۽@S%ƶibn͕c SJ:s ˤݘ`}i;>`986sfr2!e4y+9\ |/aZ62~9'8Mkk6eҫ9cn{`H)M R& J0DDٚy͇!S *che<weak90E+ `q&)¾}6R!XEfBLk~ZdH <''b$U86~rʪv8>$FXemWwu[fS@/‹p(wM$U8AZ@]8E0$Y]\+aC&= 8;)\JF c"T ġL"~]Ke>kheᾬBWQ~4ap%aBW+^ endstream endobj 830 0 obj << /Length 1105 /Filter /FlateDecode >> stream xWs6` ZI ;Kݝ%3o0 /d=$0xxzh;>XHO}'9~̉ɞ.h?9fpY9op% MLUr{unjs^K"%"4VNhKQgL >XY$Nx[zQ@+o]Qy̭6=֨X*K@|gDFz[^F*}R."hON-!g!'If#b|hiMg3˜1Ң[ P x5S#:#V٢!LP ٞ`<Ƅh,xyZ9w+aӴ1y oY@#3 MڕH2Ifb>/D0+u*B tD&$`֨T@=9Bj#}ږCɩq (öt5j7*3-miU 1qH"1c@oN6`$`YYYghbIMzW1'fS{]w QC>FDYaT/2?e4gZXoZmiߌvZB10{3/a?cvQጋ'563C137ZӸxƐ@֍Y)*3䊣M6d%%6XbyR7$^Wc*9dx>Ma&߅,&g4$;AͩP.3N鮱m_BӢ~Vʺ푅[L`3F'հ _ubx\wɞ9tF->x_zI{}A)>"<_֥ڋcQǺm%fCo {޴ҎnpH/9,x! endstream endobj 834 0 obj << /Length 849 /Filter /FlateDecode >> stream xWQo0~c"-ۉ3m $6&!!Q\b'kBw}g_' H2"YL/&`|4,OB8@ILcpP=KJsc\&KNR*K cWivzm.Ag"m #B- $Tpe-*ܶIdcWGwWeY%Ek[Q(>ߏg@ Z3 ֪ǫpF@Pa۝ őz3OHtS|1sxٯwk7fbڰe!\DA[ :>R i0MU3g@CH##HeޏDaKo@ٓqF#3(*i5ҷ ؄TY6EfMj98ôn31t`4V3eH֥>Sp##RV:'cCJhP$I|s*C>GSQ=`/uƴCER5*|^zBx^$\ PwrB7)UK 7{2`jL&&WHCwϱ8Y6'+۟|+<{}d% D*Kھ7sT`Iyo; Pcu?"쇀eoy%A%z4 $Gb-VK!+Vg:+M./xPS; ;?`݂ϓ/_ @|܇V^Hʝ8:ݲ&]M%L,{ԢKǨ [9Ѱ73bXcj6s+ endstream endobj 736 0 obj << /Type /ObjStm /N 100 /First 886 /Length 1179 /Filter /FlateDecode >> stream x՚n7|rFm[͡C E.lH߾ߨv{˝+JZ[ʩJ]i,9U~MЏs 3ss|dE4y1T5 z$"N%ʄSyz"W4pG&eR-fCKL 9QQAPd v42&j5N\SLU' a8 ;&h@jN5$d( @՚*)fadIQT REB&[\8JP+!*e\zehVo%fC“"MŒSkƸy Y 4+,95 co Nd"\qԣꜸ )474<@-#yFd v䱌larE K08Lbq qB24b Uޗ-aͬzI%= egwc)͐ØkՎAfFϨ' Gz  U?3/l-g6l +!dhf 2sZ|r>rφʊiMQfGnda۹ Xį^ڻ3^gq΍eX['Ų= eacqgy(vnN"=6ʂ=3G=RF=R8zAGh#Dꞩ40*"C;5{f6̗m_Xz?wW endstream endobj 837 0 obj << /Length 985 /Filter /FlateDecode >> stream xWKo8W݋ D, MvZ8W T$9tY,kðDgfF"/TPT;jL'τFkoK<[gڔ17sMR71fP9Ѹ Ξ~7a^ 7(I%‚;XzGSF H^8XS[f_#VI I.J]W&kl6KwW6F!C c(n}ZvD^eUT!H A HCd ;H1|cK`5RLtէnCzA zc%!p8~Oh:[Sܸz=!Qli?wM]y4zƦE!XCƷ! 4J9!M!Km,kbqrGA;%tckWLܴf횿XN.ܱĠ<ϳm-g.̮]'( Dgߑp9pvglBm*GjTKБ(VśP@)]0# 6ԷC;,M<_CC ĈzAZco694PB WPvS|X9ݎ#:A+M`d5C$4})iTL!|u??:J J*]ԘC`7K4҈0ҽ6yq9ca\„u񱱳}Be+ޢJ)pa굝81"\>9T`"%y?fU`!MpD*0U^c!B\s^CS?Ԧ]ٕΔ<3M[dl؅8>,粔mL xEYWu,ꮸUʮua#c{ endstream endobj 841 0 obj << /Length 1174 /Filter /FlateDecode >> stream xWKo6W{C=nADNm#e klA8fX@@H$Aq%?+kx$ g$XoƪekN5Q (N~dUʬ$GQ T4 9~_r~}2)Gʰ(NWUts@bPg`U{-΀IRD"{RtE1qp'> pب(Ctƣn[×u z5$I^ s6]c녕eϐ i1[3^@W}'e~ZIu7(rp1S$5} \3H2D8*naSi|^ i/; *ō~}KaJ ~9RĘp}we981Cn ~F*aL?iy@ǽcQ:N%f0ҍLTcmb"38gr䊫jM.7 zxZFE~ Jߝ#qNt(LJ,,#JEW~=)n[>~~b9EUbۆb/:>t("TL /'}W M}eg)d$4J爂}\MɬS&tZ& .r=ί9:Ȃ%J zlg!Zƞ0\$%"g~ShoIO1tk5uN%-|wG2\g=v!݉MЉ{)k6PesmI`ԼdXi:9ET*];̵#{&\fHyd%21cm|!=# _zrӤ>yCIrjH͝Z:T&_=h&M@,I^U5}ѹNى62\C:K&`M w1g ot́{ Rv_ 5HHdUm~Y]؉Wn\EVV0uE[m;Ze٨VIJ{jg!Mɕ`L&6IN'` ܳ endstream endobj 844 0 obj << /Length 862 /Filter /FlateDecode >> stream xVMo@W R7l^%mz@`mZ m}gņ7u8fg߼yY` A2$'kpB|\ R`"l>L5+26D1c,TgQ̹/m7妲Oxx*QL,U(xub\PgG"Mi@€M%" aٶMm԰:$A] D!d`;rF۫St޸dcSy=[oWo.A0JRႳRs2Se?bSt1D||zc'COlOqz)jNvc&rأ`=U~FdMkd*T~]Q_Ogt׉=qbuxY:,kfUoˆrmxܰH]R+Q([>Q^]ھ*ixOʞ"wgqHk[V. wq] ׯsqkzj` KKFjQ [VkG^7gS|痩bФ%FڗC |9v]exR! Ț!iy[k4>ɱfk=hR"3S cS ɱvO3V\W6~~Ax SQ ,"9C%IW/())ҞʯnLGHr*Z*`fyǬYgٽKi_ :K^>_#f`9/;RJ$~mn|_Y!a )3R3O(۲}ir_󡷜̖.=1nګ2+wyn endstream endobj 848 0 obj << /Length 1167 /Filter /FlateDecode >> stream xڽWK6Б"FHI Cv-=2mJg%v-ՊH eˬԼw}8G#b sSM+zQqe1㒡ƺk CVT"<}sN9,3R/}nI#prå9N9 L89Eㄠ~3m! A?ptUg RrtlS(6F X-8Yڕfaa71ArpxzC3exZ4$n5iB6ƥ~iPzك/^_Ԡڡ罘{Pf^eLY?Y:r*r8T }w~+pyeH뚗wowV\hvhbZظ jA^*몑à'$f2-&6kQh[V];I^24nI[kТ?T56m=Ż3ۭK\MvL7iLe1+hQ_@Ãfby11,Yw {zC9fey#g^#WA ԇx 3c@m\TlW͙ztS; =@ [w-f]BbF1J5_M|R%.V)XXMzšvu}YXn]~@ endstream endobj 852 0 obj << /Length 1847 /Filter /FlateDecode >> stream xڽXK60z)@٤ۦ#,˶ZYrX3R(|4g~C/\E(a UzpHn}ez76.>9oɩ<']e$Lۼ*t>f4[D/o[g^~n$c.ks}I~xĝnAYwINuNjX%Lj5K\Q}ޘImZZy\)Πf%}˧AId [b.3")*6)qޚ i1k ,m0E̛#sp&#N>oꤾ3[*(Qr|J[SoEYrmۼXar0}ی0"߮IX= G^U'I^PˁNC!ZGo}K^EZ˽JqoyCnJ/,B kBy1a""- TqT;R:HЃ  نP%~ 犾@qRoRXP^eTP&Aq! |&0e>T]fW1Ÿ\T<< =W* C! TRf0C|5O!1DԛgzZ!J ÞC ?Đ E޻FaBo\ġ1LӉ(6%ٮ'Za- /y-^ Fts6Q,l[B£ T6D5镕:mhG2h6Asܥa9֗AiՠLJE/Y{TKjtp9}P#:kZ%LRtDN&PZ@hC׶N bHY4做t%C~ȌŢnmJEÎG/W& IɫQRW\4, nT$[Q˘yQ(x0-wʲ qݘmgbr-VThϊcf|%bNؖg]'c -Ǥ*Aglakm( bcmAT ldAaE ɱcFJ5L] d8 Y%g,grZ4뤂LOfٻdNbDiRo^Jg00F<0!!j j%;X^ ?] -iܜO}x"of!!g)Zw刡cC1-lyn'1M GY2vXݐ {  E:(VJכ8t3 u ř[?ʭd "fzjDe Nx]5R Xdb|±6kE 3xSͧ/b ay0f8+#X.75 |l s{lܹ⮫Lv4%s~9wJiON]0Qn/UT{lps{mnQo4`p {ДSbAvkOu7tnlܽXk5ԇm/O<-=!iIϓ`4g<@;w@'v|OʪYR h@u^t~վNGuUz-i7 endstream endobj 855 0 obj << /Length 684 /Filter /FlateDecode >> stream xڍTMs0Wp [&ҙķa }WqCv۷+Q/z)Ҍ^qD{x/pu}£ɣzj -_}-tr.XASW%U ,igc=%LO2]?͘G9%)?udFE^HSp8~ wA QL@vs :! @$l9ɖ/ e, O~zG{N#. bpoQM$7/3 P YJNq2U8 @n˃<4dCÜM{DS;oޚޛnry&ءw9,ÌRS8;WE_ icOmi g,ݩhu;H mgOw<.vmk\̂(qB-޸pƪc'.Յ5mukE ѕ)86fTmBJR& KQxQ/V /"JjUYx=)~QrVO8ɝH?'WA+ZrJ DTqMQxԎ} Ml[T_]t(tB{QK] ss!܎i ܘj endstream endobj 860 0 obj << /Length 3138 /Filter /FlateDecode >> stream xڍk۸{~X;zP\{ \fCVm"R& w^h {I61K6e)lWe=i6 ݫD𶀸 0zxmoxWuyoDLͿï~~'iU:wW&)wi+Gxn%;2m"wӽ͉Ǔi~oZݏ}bRԻR-PDUH =ϲ(oZWEν8.6Q.b)rVѳ5#j]֌2i If}| 8Z{ h"CZ? rQcu3}L$7ҷ[Ag*ݕq)*D h YɊC i~{x}KJ]I~I5xWm9?\Efd΁>LxnۢGM/˝'kIH>~r #\ve$gN|@ԴYi"FKcL3]9(۱ʡyTrO+[`z>XݜDOzZ1HOg8p_ mǷtESq?X*6:0`~6}'ס0KyyϏ*Kw3n.+81B 2bv2-1aNkُH3 /7^pByUK/UT!vEἔU3T 򔾳,2OT\N]ip5 2ӋQЙlT>fD G$~ x@dy:$TOfgt?N{ 4RHb$$}U~Hv'E37O18FOKG! <8X/3k\"<>8vqa %Q)c;N!&En̞g+pŌG8(AHy`V' o-T'Cw1*= r:!PFK"X_@+mU_XLn;Ri)\t=oOCK t}#KBE繥Gs>ǹv)&m6 65t] !`s2{ M..`5G4/1!G[ 0!vQP+zxi:ݻ,"Jx-}mT W՘7_euh=`_[8j;5ȁ~ќy:,Wi(:ՇO+rk9YuлR9 NHY\g1KG )#%KM-,P&W Hi 5|9]fMETO)|Ǚ_5.d2wmS.'\QuUEϘˠ :X3K^ r*y8BPI5r LPZ00Nu *#7؁qhRͯAOW"%N w? 8iEi"J+PLXJa^NTtJFDh+ɯ+s,7^JZzP" Oy; - =j'paђ,x<*It-#`fcBhrt⸠^.GyLy~I;Jjqw((Cy$!R!"s'3 ]fa%@CL<|b:Hu$_ϻ1D!s'6$ 1%dJƄFR)Y=N|GwNTS` ' =k74S Es`6&1B)-Zy 3%&P` |? F $U WKzco*VU?ѷ ~ Զr3(=O)649&bt;\QJ+H^dʊUcn,p ,ގ$G9FM`G#т0nj TI 5ꗩ9,rm_O)K=FgʷBBϤ#$ =CC ḱr]]=-ɷ`⨱@x dX_Tcr,7jP E'GO18bgw%L3K1s x`o?O.|2Q̙ {A IKݓ!Ghwugr9R ,t Q1`+pNѷ,s!^_W`0'exSgqW&_֢rfI{6Y&^薼ܹ[^<,%-OƷOHO{2[)G@ ܒʦ1NLfd7kתn(*lbS4Z`:򩓯 gR ꊣt(5@K< N,FJȖߐ @XM( :ٔ=5Tҭ" ,\E 1{awfRFndۍ"QIKRd! זVHOoQ)so|E h*_~{$^'s f ds+L![' endstream endobj 863 0 obj << /Length 3225 /Filter /FlateDecode >> stream xڍrܸ_K*̈́7nZ[k)`cò/vm@7h47>7Yx>y?ෟ_n w|x&_7%nn+nEp{?Vfӡ6%1n "󽤸ÿ_{p %aO/roWB>^!L~30%oyǷYB/f ̙ۥ_ nhv ٧9.Oۗ fX3vzf@*"tG3JR1 .Jy̞/3gosoNgYGVCxvyā5ɓjK,@Uz>-xO>!a09 ( хݘkeӨqX~.( ~S[g ~͓ZP %6jų8Y#|!k 6kGN /(յU.UU8x{%`35"8!new[{Mm.-h6ʊ9Ig j*31̾DןTkP szCo쐌$ENgʼgQNU(z+ Y=;x;ጦLdzӞЍ/d @" Z;b4c=b}^fL90Y:c +5o O_şk.HuVu|vdå7_ԃﱝgB`a-b\ Ho col|10bqt4 PJ\n#LҎ%җ/PPB)(\!KClOM½6& B(HWAEW=h V2Jp _eb\ GE! {1X(9vd*jkL? |!0,SH<ѥ w6ƾNEBqꑬIvMʥLGPy;i9 FP ʺ2Ȟ<8g4)/U)H0 {gDN|I._ S|!ul gd%= Mm"̦W=AQ 3|{yHk%(hcZAEW3btjzG@j-9(a wjc?'acC># C# FmKH3dPY^$ T9=wmƒq~Bv8Gqg>Qށ =t%N_a&b R~4˂vؼfR #ߺ"{E!Z j]1Ʋype@2lkQHeǰX8"TBŏ8*h3,;I5SMJQ7#O+6.}ao _ۭ"R<=*LGo60 Du8'd֐}@AnS' 蔘0ʟ$W.qq+`F^3.OP'.G^] smX NZ=XҔ8<*v{T[^eY!zW^k?<I!n@Viiauxŭ1]yƃ\6AAՅmʮUdT6) LP$%XS|kR+|ZI-L5P5.H6gBJ@MSMg)Vr]ѝm\hϲl',8??ۼ}K= [^RYKSu)_%JUDt%`ЂYXLZߋ"HI_@N>o e]nsVwէK%8VUg̖KpD,$,hwvHv] ASoԮ,OO<M fNp8&V_<|gwF|ǾkK9D\F#`ђ+LI f"#um2׵QPH&# (u-pBKqjH'pѰ^-Y#$DFYábNq)!OKQ=9EBBNeݚ= j<6` |!3 4_n(_*.Z9RVn6Ot Z!8 uS .еh(KG,#/V6'JÂ*r>1(5Skr 1s'e$˓;[vćnD vN reF)Ns~'`MV8ѤvxxW@\JSVj:*ݚІ$[%j~i藸cB&SdY+C i r X)ƭL Pf`9!u|+Vm΋-Y2P29xi,1  PJ\ խ]TcՂBoص0y U[$5eEQ)HjW;(BV_^HH2-K0O-6C0 p9% 8X?\gRGxC^Jxb}ov s !T l٫*#Z(q^jXd%6*J2#W.%N"VY_R Boa g%?4PJ[՘Uy <4m 2jwkSb߫ *0ډ뼌G$I^0?#wXj̵`LC >VjTö uBZÕ10"ĥ6! Ѯq†AlT? Uю'/z endstream endobj 867 0 obj << /Length 3152 /Filter /FlateDecode >> stream xڍْ}b*/˩QxMrv<`(HB-gJIJ@Jb%wUzWٮΪ{tg=2ypQDMtC]30v!&}6-veRl7O wl?e}&+ؙi2C?Z+-JsG9q+dnG/.eK; 2=( ^[Zp|)3Ati ;yqݻ-Q=nrh߉tzje䂗0 uYӬf oPfdNt0/f&ƕI9v|:A05`WRKyVj}sLx'2_۬|'EONlfmj%i!y7\5D2m3D8oe90SCD;bΚf,[j"+L9s0#+{D9x1;.1EQ0/q5Kwx.E${VC8С,̨}5ta \EJβPA2 S򕷳=q43P2r9hwg0b-},c7r]g.&G/q$ƌA7_9f&̵/7Yl| 7x&rN@A9"譈Y0he Y÷"VtĖlR IL!L73poG}S%e߱Y0ΧaQlUpyGMg2ocJwvf eGUW;$b'ӨQtZM(DHnU k`%dqi-!Sr>a6XTI"k߱Vf B{.ݱِ4)E, ǃq%sq9A*'BɆa2y4hK NhQ[(>3Tnjڴ)9:+;0\P¸B?k4$tCeæhpۓ-+%̡PUܣ*IU}%>RX(mC$kAc sc=6f1 S BFԮ-_x-vErdK57nB mfR>LML=w1R3 5؜2 {1Xפ)k~]fpIfXM UF+ WG CŶ)_̼Z{μ$rO>0t1W 2y˽ֺ|ct1`4'X 02Le+TG6kEQ4l3ty/%.eFl%*.Yai@Hgz1Gߌ§[p Ć'io(_տ%Y>Yҡ  i\WU{SC?& kZ)Yne♊?2 >,^ NGޚ۲0MZ^fHv"1ȁjtf8 ߌx5L #yIʼnw"|xhWH%J_Tb} endstream endobj 871 0 obj << /Length 3187 /Filter /FlateDecode >> stream xZK50#6aAGbwӫ:%GM"cU4S *}TgS{{^w`_߿7Eħ&n_W֑:p̲,KGA[37-3ISQ~9P"!B'"-OqN$*Q]gO$gh7i4*Yy7N~ /vvn:@QS 1NI+(,"e56rENcqY"jx Y%bfe/VݘRf)aV6ϋp 0a#\(\۹L" ó^nfc+o彭%49osJSxow+qJ@ŐGb*kQ!nYxd6J3tD~\3pZ)"}5 V(_!AM3(hO8q%D| P*^V:HB|U~6 q#aaE:\9[hoR+{!uCG䚈:8lc?ߴ 7n-- d 8GtgeGb  ;N$Ag_p|2l J`>-j7.~ŝ`JwWB|QFfdp9j[r+ŽezW8e_}V4BO2 ݩ4_8PpH x l 2nFo$/Wap̫&3)%]l^x;p,da,khd$iA&R;TFYF r@"SYYJzVp r+ncrҔ}SKFNQE5Pf2| H ߉o`kkIɦ HxZP<t#P,%qGnVQ4r 5v$Oh!LKG h -쾤MSiu y:%.bUq*@sƉ<$NBrZ!xv<هqlNgr{c8?iV͖ۭF|\6k xSN;6xt,_HF.z/Cp߁#LwV) 208HDlŤL1mg93ϜHV0۰Z3L`(]RM"0&| F=fO0َV< @y1 ɗx\ e/A.W6{' 7h'4h/XR$l.9}Е7=~/G&RC믩:XmA&M`j5X{&E`PkT&x-A >毵-S<?5ʶ 8uQn~Y#w !!!Zd4ͩ!M6_S\$4E& F =H˹O&σaGVh`m9u୲_۷|wpiVrlp\yRb L0-RfKH+nD5'LwUe+'WF/%iu}mB rY!=YVpY؁y!ʿGer~:A;Rb' yv{u:$wY&g7\}2Ie#qfbћG 0=L.."@Y7oMXڨoJ(aq}i4qk!!pul&v-/|s4໋(HӞ? Hg(GdvCY'2]Ռ&EdPm/̸$HjTY8-_L/iX<`2څGvr~]Dwn{yI;y\^H:/Ce НkO8qKGY5:T-᷹gtUF:uCoH̋ !LaPTcyD.ܓ0F^~wqu ֺ9,0_?<xQ|KMI?P| @]Q[5]ԏH Cto}'s4 D3u?IwGÁ $.]&oB;bs('n/ ;\(mwcďE㴇CwW2!{?Xs;}$~\TL ~C +7?njR♟%JujMֿΤa'Xdmq~߇ 6Jo RRTWEEQSA> stream xڍn>_!Dwv;'9ؓXF9Ȣ"6)#)_r zjyRnBn'}Rܔw!A |.;@[`?fM!y[=T7 ۻxضrwIOG|aq%J6E/Ӆ8ei;oCˁ|f)Q=[qykR3(\[v . k~ <:^hƵOۻ,;' ^v8Z9X֟}Gr '.JvQ1e8Kglз<1I29 :3ނ^$=vg_őC!L(O%Y_ϬO100IK~gcriӏ ['E08b#Y_:Ӑ:@@[AQ]{7_!Y܏*fE/o,;8ѵ(4J0JK:OBkpJk%BEvŞѨ?Qgk4t|D\xƾ~~e cɚl'܆7+땶UѻM_@׌$x&g` a'n rXM\]0[h58PlrZ៕_UpMJХOvh^3SH8,7UM'__k3B(&Ws:7RE6%y9;) mϨt_ /fa U"2@ԣR?oFn64q t[NA uLk3OJLwR]Ie+DSFEOYm#\H;.2/ƄŜwϹE\|6k*~5!T2M5X-:-@(mw_췋yܧ9 , 8*0,A강=ⵛL@kZ@/I^BhRi.صb5*;~'Pw:+kZ5ɯkDk(/ 0A&%ZD.Np[y6]vdcdxJC&9b׉l"Tn! 7@ck(eOI* S"uu|h8E 1r,UXE5%85|[9a5\2 `5污쬐tmZ!Wb i# )_g0i2TU &"<ʑsN <-uzeNZoɦZilφ\3({No[LEU vĸ#*kJ[`5rS?`$[KCZ^WM( c!歽|rاejt9L}dM'Nٳ 灛4C%GNSRKJ4qڈZ`PxEG[MԣX+8 $r ٓ7'Ԯ{- &\z fڶp/ҍd."TXlwۢǾsSh_V;A`ɐ6 RqM|#PC =}?`0!8l*ĔЦ*Q4ZF(IIGx*҉Sv &Ki=2'HDf= mHZ^~[5s22bkuV G(J#M'<@`8'RP&=7mSI8x|'Ζ };7i_7eϱ# GwȪ:ϕ#A,ky JkB#|<vda6=Aӫh̠g2ǖh>|f<Ǐ;|OK!*$v}wVsfͰBAÄ8McU(鱋7x ȃ2Rcy>$kLZ˳\qŦ?N;'.>Dk< o{s/)-B.؃_  O7^~' `Od띯AC>M_cyJ3ܯ7ĹOzCW?7b7%Bɟ? o'BJ' endstream endobj 880 0 obj << /Length 2970 /Filter /FlateDecode >> stream xڍَ}b' X)lRir8aLlzN)7ߧ>(qcaWuUwV=dO=4Cs(yh/2º<%t; %|VՃVOo.?lLnwEQl?c;{ۚ~4:6٦.y< Uy7S',۫Rﳪw͏nxvWc6;:suf49=O gN/F~wzdG f3օ8{_2UAU9>TW⫿⽌^#l*>)7 cT?>̾X~((̣ j\ID( 7t$7O@45G z|"چMyqdqM2- ž%†䤮pjOvҊ}b89pS,ĤQubNM^pajPo2vw[U'3*$F ЗʘaMt % _l0c'XxfH7nq\'G~7b 3Q#^ԋQ4 <{7%,FƴSzcD,hW&ހoK<&)FP1vdK0)#cCh ~w1+iY¼;xLH9T*Ǐko=԰-x|ex7W{IhW+N蓢m ߇*>TKY$~B:hOw q+a8 fXQ%-k4(s0m!f=+F3@RI|_FU6$E |_X Rq|Mj',P$>V'<b\#ii =xy Ju9()T9Zh0C ڭ/M$Am79*t\!.XKrҨwrWA+ T)SgRX,= \;P^(Ȃ;s{e3F38_ЅA>(QYP&b(&Mpȶ;- J^KELQ!lU:vU\ij)a:#<>.ATHdVG`~"C5|fq10]ͬ0S%GUT푧Ej˲{Tg~+R{\\ AG3?a4{p׳(+,}d -7 U%FpT@oq">ŞcGC "OML?rx渠D+Nū~, EK]ƭ+μnU*kFRps"7$CKiYrMH|vo}ԧ;diqmP5D)xZϨM&) \/ޒ7ǀihcwM>X2KgDLpwy(qt/{OǢ( OCF͝CӅAF)2L QML Gv8^E7VgaDCQ* $,ZY@1P#BiP8Qp+0ѭZyWK9QRMJ1fЗQjPec #qGY"B0̡$^Jk|ۼu`&'Yb_fqd(:=+ܼ U;s]Sqԗw"pm 8|f8Jb:{_9@ρܫe[wL}q'RPmUSu !D}ikLW(fHUAE ~ǿ$xS421"Q0~M4} v( d0jNH㫣, %]~ӂ?-B:t#b8f}ŗ8 :nnvk B?Ra (qupJZ/yPg&7; ٢%:t]rROk`  I~D~8 9iBV.hX'AN\ԉ1vΌ[c qOJr`Ga #Sy;+ȃX<] ^ F;y[o^|CR~mlz[6-b˺tե ocSs/9S endstream endobj 884 0 obj << /Length 3365 /Filter /FlateDecode >> stream xڍr#_%*QCIlW(TD$󠁙_~4@kvӮj݇|ǍP7 ?ۺ+}/O)ݿæe?/w6T-C^Z{`zo@ol< eT7>`#<->Sfͳ8tz\ng>pb8kGgtc?Z$weTM<-> &h;í7wtG92&O"D]'!ۖ(׈Ef $d'KYn a'7ttU=5,žm]K:8;ˋlM@hOo;}*aD3: cgd:>xς|! |A(}!.p-a^";L[&$88~ ahxb0p ٌ)Fj8 bA~΋jp`7e:-b]{]`a,A;Mp\gqGr3:~/bMjx,26.tD[B3NuWZkodhpWd4 A`(; ` 4:'(?ݎxd4b`Fbvgs]rǖ BY@s$21 >Ff,"a-QvB'9sj{YKAM xYj9v '0C 6;d-mOvu k[sO{\1<~\cGuh`]֌QH0P3,=1SPpљ$5k犌j| rVը]FqM\B<* \0қQY*ct*nBZ>ڸp}RwJw(It܋IM ce kS23UZDx%9 Y[1rގv`3`\ `Apb _ [)bSbFZ4,DŧWjI$5C0:t儏e(tkMW5,o(54b". OjN2 { 7a`"2 :aYN.}t2>e@sV\lv^(ZDm`o@GOy5J ZGA! ;SQ\e> PRʕTJMXx_4RmÖX51U.?%m :HFgU4PO!A np&8;"3K|o8^Ic.x)hÇL›3EZkRͶwBG*d~sa KWwF>K+_v7/)51SiԞ"viV4d;YAN҂* @XSj~#\P42sEpVTձp΋uBjr4^dWZSVqJLJ0Tb,=ߔ DH o@ZV$ sj4 RbVn~mryq\&N}UZ ZnZ`+ZTBx_aoA$ endstream endobj 888 0 obj << /Length 3229 /Filter /FlateDecode >> stream xڍZs6_K7{sZ%xl( 8HH_Ai2],~ $8_pgY]QvVOgxx&Kt$߮.Ij/Uڜۻ>/Sͦz9Ȼ^5J5su]ܾJt ?Y섒0JgoEt:+?e08EsXLfzYu9MՕWMѷ<^M˶Om{iz؈ߝ#~'lѺ'tkp/Jgt.І` xZWhEj2fF%-8FmD1h5msyψѻo+=jӎM+wZ0HIg?ˢ_YIN 3f47TH ^_QuG^;p׾@!!f_W :$dg S'+ @3Q?)Ħe"[fYJZ/2)XLUz3̊-tr't*h=tU:F!vCWRvKC=XDX{AF;&Y_ȔHe0mNAcNds։P_~sƢ쫯5dьAM 2#i6µ SEh^|'j)LGSDstVJPӪ=9 Ö̃-`5j=  0,bG 1I̛dh g? ̭r+ ~iTY Tx+ћp ǃL)ȮqCxʏG@h[ J M}ιILd "`BW-ܲX±Nl D;9$2n`PCg_b¾ID9d+8l'$4@HVh t4q*G.F$&"gOf5M `N3% }?#Wpfw-L5py`N9ܺA͵@!fzA"WҦ+%͂ӅX AI"g8g⪺xE+iU,qi?DF(Z:"EF3wJ\9[ɞ٭9_0*`r[0Ą] T% . iSV. /;p:lWY620Q( D$#Gu 9FHu-V/{;Uj u_4u2-TK^=I?x}'.pecS\)K fֵ*̘[^ 7Ù5ҁ.ro {̏ p%\`7id.٤*_˷Z8h)?{ڦa>1%ƩzL ($鷄[2$4ǡ 1t|N%ŏZm5c`JVZʌo<,vdcC;Ai#t72w p-@kӓeaaw0`QB&lq8BVaJdQLc1=r\Nz]kF龜eĀu &8:֐i;xIb(0+nAIċO'}b vf ۷"UO80\a`ibMCvN)k͈MX" u/# ^]?TK6*nrvZGN}5^SNMÁ€$*r,0cȶ1]vBx@*JNGQz`YvxҤTҘx}@y|R!Q,EO4f+ Cvo2b,AAz/G5o6Ādwa 6k%f=uWf(hY fʨv/QpFʠaB;Wl.L xTG_,}d1}|AD$KdN O(4tzҽn+oCEj ,7\)FTusU[ LM/[VBd8'@.(`Ǔܯ `.^ \8BTq$.mq! Epm:ީ(\8Z'.ҹ)k2PXÅ~bY"q"9>1 dSoQp֬^^GpܟC-</pwňfF{M-nrxfO(Ƥ8 l \7>)ڰ/=}\abDl|(_Z}2L=8265bFIs ҉&缲aY 5|f/'n%a" qFnvdC0MMԊ1L3L=ȏu˘4+*.FS8Ω fzff{b rO ?Rȫ/HS 7!m~8snqaJ<Dh; 3iS1t|;+ *ær^r[:@ Uʐ?^n$h9+xu?uz'YmImuIz(IyIMTL9Ai|hJ9c&AҒ킀a-"F &pnf[kx8`5Ef!U BczъV/; f}#][o5_JwaHr%S2ϹKt;a90]0&b9&8LfKDoUW L=. on~_>,#ӟ΃ V1j|?y?]}n%ˇ78X-81T7^]2&銻ȿ.W|ąͣ||N|)?g5 endstream endobj 893 0 obj << /Length 2801 /Filter /FlateDecode >> stream xڵY[oH~?"5R 3O3N6`mɿߺ1gVHquuuuUuec]ϺWcjM튉%r7 xS[|t9hŦj1[7vP:޺q~tk3{ z^Xiu,6!>T6w@g8[.ܲ, f,7 w:fH}xay~m='G;=hCd|GV1 1ib&r5*`u<@-1 y(\G(6 b ɀ>s-'C/,LHx`W5 \ٺ T?C6$L$^ = #C ¹3pR/BvLV:=Ef{ͻ1;hA f5p2jz#8 B8OT+d̵:5O}vc[lO{]c$w*l#yĖ]P4]F ^F F_F43TZPK4Ja-f1/ɨE_A ݃-ƣhu;3!*΅T+o=Vj*;etDqV&ü P$@5{J{TEJIrsAIU gW *bQҔӌǸ2v{cD1k9 "[/Dyz.lQM vOk`Zv"z:U ?R} 9AљN9}K!o"7oH!:fk:]o}cMO\s8M$ +*+,b.IZJE6 6+wrX^Fh\kH u䠗|%;Ymʉh>D\"1Ur(?|V*ki쐈bXQ6=pN7y%s~a$NՙMÂc׳,}(@*Wg@D 8쐮9v].oɉnO)@hVɯ}#:nl~ۖr&ܪB&RSG<@PG0s bylo %OCN/VI|=,,7Yod~Y>U4B1=ffI{ro8?@:XXUtɓ4uL70B"N*q پB8Ɖǫ% .ڦWQxjՐGK>G>y}>֏J|$$ӆAŕW N^TC6s9ՒN5&Ix/R@Gi(J. \k#%^aek$[ .K{ޕr-}SR΀R'پ-h3nv4ʵ,[?iF]$̦~ń(mä^KkY>1@"[;u8҅MƂ{_VG"Veaɿڅ}$I,n:ĕ4wT!wIsxU)4\qޕL+Ny?jr:0I2ߋTQԮAXؿ5\?|nun?" k endstream endobj 900 0 obj << /Length 1312 /Filter /FlateDecode >> stream xڍkk8{E/uv,[~dS eЖ^Q:J"ֶͿ8nK FQ?6ʢQAg -UF<_1'烠?_M%Ɉ4|9T5_nvG'58n?yE#tQi^ɒ,E PY_W_AI ?h^̅`=`aG ''kٍjEMHj[i8{H?Ϸ/.&`!L!+ZAЏn̼:nkSR SK-!hQ܊ =q(:Xh1#͑ dYH)4xC6R5ݗszΞVTgiJιC2O0rBxVb)NO,3^2# _^]|q,>_~P?;jѣ0Ca+Z(V8B[hӑZ 1~ 4X Dx]3"1˽Ga|7"RVXW;?0ke!! XhѐxƨNP~3{_ 9uˢDp8F N*"d9othCA^FÜ!ZT"h% p!&궲w走T潅I(GlQ ΝtB F4JEd0{a)|q,?rs YZ{Y枋Bf 6}BzD E0gMj#JuFT9km!t ؟f kQo'+|sUHTf,\?;'i<8]^,Fik/i͚S1df(T*NaIZ>h*VQAt2Rq:cHtVO^PerFFO]KCٔJX XQ,gy"3?՜M;hCǑXm5bW].ؚ83uAk V!jp##okA[l~R떀-n}*BFJ@D.0VJv]T"9e8 IS7ёcf0YlhPe ;T(Jɦ3XG-t(424;%!YDA5*> stream x]Ms7WHU|{%Qb{Hrɱ4); 3 NkTʉg{hQGDr4{BmnFyyܩFgO{ԈQba#$)ۻ~\\-)I;ܚXI8Sq B9Ŭ1w@I,R" ۮ((:Gh Mf7-'SVllقkJշ(%Ey[iomd̆%:lX({=Brfyb:e,vjZ;*HRJm 4'l e ʏ$g̎&So'On7ɝULΫ]3F Z<.3@aH /9M5]/ϻ3^zHl%;<,68!vb ?‰}[MfUjBxxC:auq 38!v:sFgUB>YqZb|Z) av!">U>ڥɅ]\*z4)"QlZ(cHY nlfbD$!̱!Ӑc29fc"L!gȎT `2&h5_傄ʂP] a 0aZd9 `.X߽V ˊQIy/V OA S]v/RNuL70U>:ć+e#.d2g̲ J ,דsbfz4rMj}!QɳspF}m!ZHEpmrٻ-ܦ=ᕴ n>XW p@ jf犒C}c[zwjϚdD|>bI}d>b<=f$P4ɪv3ŇugbuBf?];i  yHűiaVÙ 2_z6ՋN?<)qvwX}[.K~{mI\򳧳YSVIeq~EIC/N"8藀V/9f6*{D躹o:qW1"qqĶ*=F$H CF3T}3MvECQd0;O-j3>^eeV ʕ50 A@"88܈+8cb%DG5]{XTI͖}NJ8a""b'"Ą(b섍ӚQ!=Hフy2!eF3Nf*7Ϳ?7m{*QDkv|}fB7vp+,sMچ_5d >O1^;9U6$ eNy#A:c9f2y :I):zCD M=8`8YR[Q}9sfӻz|=ʶYGR ;Ep8xLWO`2.p;shjTw;aE_? ' >XQ8,j_H jى8JCza>i耿FF>n5 aLc=:ϼdbNd'j:GlMc f{7>)'j:+% /3o5 |deq)'j:{7>rbہ BJIEˣ[M78~o5h9 >f7P7yL2Q.#7*7 h7*Ior[M 87䈷szsr V+,"Vn=Q匔Z_G˔],1.`:ׁ ,w]t'7˻dؘmc2aIJ׳+f}ra^%HCx6MbCdX`-@f a9WWn$o 86JG :CGz_eh v:jmgWMH+*M{4C>Ac HZ/f.+BRQ5)_"L\U3n>C+p }4dI(Uc$sx9,&̴PCϖfv& 똃˂c˲{C9Aq"ÕyK~vAՋzX_1za^%B9xKJ{/8;5p/+aM0aZdLcMa&pSߚO"È45vM,^585N k}*9_a||^Wbɸca^)v,hc8c肄n9aXg$p^^ep WfvzHՇ NR|x@2sAuG̓'L[-"U"ܫa%QE$7BpXX.Aq̽ }Q5;3^˭!}ذѰ"2h{aڠRD7,-f=qR1 @J`ఖqT3b{53AN7_]"%?Vp>~X/ p $/{/d$B ^'KTࣇu s spH`~]Ua.ػ`e`X!1 g͋y˜?}䛆8v}O'8X"@_{gl1'OR({ɂ'S{JS1 <߸Q#uZ>j-Bi qM^"T2e 1J2A1T!50Sh{~ Ԧ2wLww./eJ8XYh8hb-9 8X C= tR!!Ȏ_xrd昃_uj=Wؿ;_Nf\ˁ~b2Kݓ>+ 35Qk_]Q H6+w L̢ %z+7Ɋ+V!rX pܛ \ a̦  I6`6f$so-=(?K#bZ4}kg7®,'F(d́M 9Dpp0Mԟ}ye~|yv&38AW?||0_o8of?pw3zYs6AHŽэlq8lX?W̽q28 EY4*h{1ce#1eyZyIg:d TQ aqE,<0-PY$,ׇ;7Va{^V"5m]g7m&?cSKhѕ&ci=ocBՙ41'ax :eNSR;e9b!~ et^/IdCDy|A;7Z;(48VyH~BzeX}vzb'l4"Eq>G z$ Hpl endstream endobj 838 0 obj << /Type /ObjStm /N 100 /First 886 /Length 2046 /Filter /FlateDecode >> stream xڽZo~Cx!F-.C\,ΐd8Hw)J{깆)Pг*zqCn 5^$qP[õbΡkw)h^AK N)ԢK _p$]2`r551,w 2VS*N&; )+z `9$^ox\&+ 9;rú{res7:LhǁW]B;23p=^10s b Yr r] ꊧ:GSm.,FPR9QJ6YdwjԂaNJ@;(*QI\B %DUx'PLjKP#L|phAX&˭&,5+z) $[)KTaW0"Zw!)lw v\UmΠZYi6f1hH-"QtMD+^={Za?nZy{qB5jj7u lT(v}% x> pʹX@x,[?G6e+ dNr3 nG`cux ?=W߯íi- ЙZ4_Ct90'kQFZE~-oH=_$ɡ|TɄGI)н$j6'G֗tf gXMi&Dq/Dt )CvO>wj *[0;OD8Aiݦ`]mȃS4hvb*IUygsʑarr6|>u9ޟo>?} ݇xv$,( {qC`ظhwU-ޑXZzݯ; MJ~ef:99999;'DNnwu;%Sܧy.N;麗* ĔOPBRb.VP*I͎H[Hۂ,$^fS)\"?KRI:@Z%vkD{~M ,8XliZZ^܂SL6ܦdsB9?yo?w켐I.=ʣD~A($qL3}9gZVYҲb+Y{}-#涧ɨ|+Y2"V .隷^+rƙtbU/bi#}lH[v&`}h۴^Ӣ.ssSp~&Nu scG>N mrLywLQ=ԱN,TiomмB AYPڞ'%+od endstream endobj 1049 0 obj << /Length 2978 /Filter /FlateDecode >> stream x]Ko9W(klܲNf؞`qؒђͿ_MXT1I!T槮cX| J1+dV}u/sgxY󟵞UEg7nV?7gL)TSw[B3$bʈpe徖aVG~YVYq_ւunܯ7gRn۾]K6js^?q?FX#g֘ydޒzd'u \1%{mI^ \߮@7WWz?^=dǎ&`Ǒ Vpt9zJˤ?/qW0/xwyda-!`"䐽j04fqA04f,ӕt1Dh08p@i%`O1'i]Zw?ﻷW3G҉|=X ߟڽs{.偈 KxbI` "FAZ ڂvޯSX͙?Kp,U 9.+ۨ ?U\o׻}$š8JGp*U9.'̨ G!48JM]'jJRI{'S2byR ĒAvbQ`6$Y3]akiJGd*<"}䐽>ZoSE8UTS 8V񉬱s *>YQ!9Q'*>Td!dCJJT߰SW!OT Jbq * {8_mSvjVVVz,/.9r@Z"$2^.2i%vr;~q"8's:ey~nuaVKjWRz"#MQ2Fv.K0f^Be*YY§4 3-*KG$+h0lɆADC4BN*_w |o =>u2,oGjݠIS9*2A "2,I5aepju3Mn.Դ3ΛTaָ."zQeAUÂ(bJ#UNjNb6o~ILW{-1χLu`>WiȽ3~)YizԊ qe]{cCEFPbn8> 6|*%97(k1!lN+0[N }(PJ.YF樢Kй CI**Г4wxж_.ኵم'_ҋ=bﳙc6x`3;=d`V 0vCn\C'o**qdf W9='$ʈGEӸ To/PNHdtpU8OD6" 6]9{eCH,l"جur?=e-PKΑ9Zr>`x-Dd(9gGMKTCMbUy"22׏E5Տ\H`!fȽ2 ҥU0O\OTy g? +!-WKњH T Vb] D^+dJ|'h=EXeyVsP42Mb*F endstream endobj 999 0 obj << /Type /ObjStm /N 100 /First 955 /Length 2220 /Filter /FlateDecode >> stream xZ[~_EGuQfa7yIa21l}s:ӓ&`4=TխSI]["2=ZbsWIVƚ::KT Tc%(ҞHւՂFA8 $j覉⚸XlnQxx|;ק?_~>[ f KO^ӻttz~Cww2̦Kv盈;y .O62JY@D+W04 zVے0+Wlb֖&&NsS=wibrψ;S<3I-kY1ٲme xObRv(f#E3ߡEܦ>kWO>Oj }N!~,f\lgc1U >S8n&\g )zO~,&1r*RJ/WL! Թ!}DWEv|2Z-lݐ>\JYu23c?6{6DgWs؄~hYzb=64!kͲJL!X7GL֐ը3N|;#>JY1yMLj/ɱU_I혓2L 3n)H@0idFz;FWlJqR*#^ʜYC${AD1Wż)gC)tӟm)obT@BFL^V[PT bAm&ĘK]KBP_+Mr)6 'Be6x;9>AiAb A`eR=bp B%Oh"n^;1pv#\ V #{N Ɉq+&|OA#Z ijg%6ؑQ^i3M{]8bF5v~Fq1bLb9&["^.=Bu* h+>{Ty̗cςRkr,E"Jm>p /)= zar' s^mc).Y;]]4@60-%W|Zd}rCȲ]4hXL*zP }> stream xڍT]6,!"CIǀ ݍt7 1HH74HRJ H Jt|>}k֚k9{ku!tC$Jڊ@!0!Er@=H7pPQhNBi#PI$BB;"=%`@[tzr(!=N(2? p+('+zE0DBPvB%}}}^HOGYn>/0zA=}_t? r^xC$ y#C -;폳>_+W"`0tu08 U@`7_``{ 0xQ^^pįAwYA uCyڟ2 A_ɺ!}0Wnpo_.h_ qFWtE@0(0 ң /dd{"L u8pRl߁_1&a8w1$;WU5<$nG6iaҥ\3ܢmc2/5sO;u,s2f:Y (z78PY[[lVa]{C)z9c n&B?Z#vgd"oa|Ku{ływF\S}L[#),x?jh+/!:L&QH#{t%#cP5nnO³vX1@k`Fԙ~Kn݂?E''Vq[a<|2z+**ˎJ{Qgg1/j[di2c'a*kiFov7A%lgS>lQwOqIK6$3? p*%j=ʷ8dxr,q:i)tz;:!.Ӷ`u1wρ/1Ԡf(ehoP|i,sֱ؏墯ܓ-(ܟv)2H Pb lMY0#|!׻s7@U>3=5jQhzŅLnU`k|&wzx^5$ 4aA/r/nsU xH9Qo?'QNW]mzۄ|Vw1~(EOR(%P]^S;q1 ه9B_Z1ļ澾UQ2LI_`,do|( wN4(|9/ 3e8YM} 46ly-.i~!zd9z;eMFمށJwͷ?(jÕ៞k*r=M窬/t!:=R`Z!Lwrl>so/g-|s/1BK@ithVJoSMH7Ay(~ uGNwF',iD4o$aFxcݱi 9U9|U͏g1Gpi%xi9ۙ,>KסVQlr txx2o)o퓂weh0ovۥ]3DhN,u6jHkn/-QCؘ[73'LXRK/4;$ĈIJaQl9Z_:fB8:`EkY[qXswB2$O$^>J~)ǟ,o7ט3ϟ g8Iۛ>- Mʅ=@O\deC#",[3vaa][G䟦/\;•eMYf-Vzff_Du"ZF g_+,̊wK%;nTy,⛽GFDu;O B`'/tS^ zT}]:zMFݲ'q8 07FcO=m;\<.|Yp!q̒;KS̔AI{8O$F+Nj UoNG EQ8~=Nqe0uFȄFgh,@6wq=!D'ן2.MU[ʩ!ڨ2wФ'Bjy-7UE&#sg[Ijs5lΜ%Ez=E}~6@%'7S֦[fȩsuo; ;< }g Fuis.C0gQmM$X*hΈ4e}3²fՒ mA/nw߬ʝKb6/sq={{#YVD^F㆏a3҄e*@MnO,j^xM 2=0Vͯ=^t>?j=ªX[Ȱ=a,\φN]&?s LGaCE[ M̌7aB7`:e͸hzܷu9l$&z9DZ@d35tx(d!Ηdv,4&N/S$?幯p"XfȦxe M<`a嗏 atjiH(>(lFkq?~"PBz"|| .?h(%i{HA#\`^dӺoﶄJcg-H&쌠 'K8B \yx^;OŽw|N=r^4{$| f✑݉A|uA1ݑ*^VˆXgn-xa%PK&M.b54sg\#,6 GN>[m f)r CcgTcɵWzR"M296QvIx%m}Gl|<{ɏx>rMX IɘeCvVOr`&"{"NQUW Q>-Yf-*ioc3&#y~4TJQfQZˉH-G;,B'$S2ᬚ'mQJAB+3RѶvNߎw^ߢyj9є["h.r?1ڡ$&{(hUvvWʁs~{e|vj"^fxYJk&7Ƥ͟;t2ꓖ4\P Zztzl@1Ufku̪}b r.rQ:98weME2D.rJwڷ >$ \:؆;v,NԴlFʻ בJёuꄁu9vLY<&;⩅*F tsZNyRof_qRg r0UeQstIhR1by {ZF -s^m HSx([DMɆҖG;K)7#>)K 2'ľ:/q.U%MZ?H"Oˉ ײybLx]CR|94+jd*/NƅzEO|0E1} ]iR4d5S/=EA|AxZ r)̇R2) n@gZã]\a4KB\;~X!Zx1s[-NnI})XL-l=|V<6uWOHښhCjXmӾ&(.r;~1w, p\Ȭy!\]z}~P@Y YpCEݗޘq ݫ0g>Xa\Gj?:IcJk7 &9= D[$z-SFâh0 0.8\LO bn&WVGX8q@%NV&O !}5MD/Ɨ(ťdw{?6-~U. W9h\Wzb9]is4Bq++t{khgFO޲N5YIM<=)\bAO?_\ZǙPj]4r1(ɣa pagG\n=,+Z{=l΀_Cvc&xמpRNK'=N{@noz* /\yIk٪[:XY>%e1.LU# ybAlֻR\CT^*٣q+Q~eTe/OHLTvf28_;bk-|R3IuDVK<>h*zqgSq21ب&jϕÉXuQCo#K9R*YbI7UW0H*jTw '߇3Fe`!Je0P1p2~Jno+0}w\\84|\Ω>-'>\+לu@a61&iRBa&]N4zӺC3Ͻ5B*Ean -b#69w4*)Jœ9={TQ$Uשm`@ͩC}h+eR&E .:*BF%X.eRbeZ :!ip첊ܢm5& 7UdLk%e:j7;mǐ?SSVE<\;) why2džIF%jiϒQdKaqhOo:̭f\*%>o8j o7|0$!fEW 뎽I/OTQdj&,ZDm=Ǘ->jf8`s/ 5ZX". T}>`X]zMUk}vX[[&Uwt]wS-<\"`_y KjnPNJN~,HA"*[<^jsД+ږVm-7i*_5[bCre4rOW$_1[' 2Wګ5X5]@u^ÖĆ5-9ҳo%wM/,!mK۬5ĬUzvd}M Hz1&j"I)-@^Dűbkq}A!\dG͕poV7l5WSgF̂ߝ H~,>}ut/]i2-$u6ozdYσoԤQ L?ckeỀ@*8OGxy<+z(%FS[(Luc`oZ=3z3*C;Qv;|#@{w5']oMfEM2n(HQ3 զ3a^g5vQ C ,,Gfu)(E%}w`^ !=uSN n Kr}ZV%2ktW{!PWh8]%ԧ9W h:i%Afi‹Ecm; 8ޤ.rB̹#]n/ՐUw}p G z6Z]ݶ%1YS66̎Zr~(f&f8~˻DսǮB k'g2Wr<._m/-Չz#ş_64H{a7=umvm;x.ٺwacf+ݽ{r$of endstream endobj 1068 0 obj << /Length1 2352 /Length2 17899 /Length3 0 /Length 19269 /Filter /FlateDecode >> stream xڌP[ Cݽqww`=Xp sg&wW^uUw嬵MFL'dbgd*ngLD `b02322ÑMGf3hM(kg r0ع8̌\qsM);[S'82;{G3h|PS8h1ud -Lm@;Z팁͍ٞƉќt(:: 314z82o)` 46uؚ:@Mmvہ%+hk0Zeݝi&9Z;ف ] ֆF Q7 ) A hDK#_i@e51uv(Tw/&. @/-Y37u122rsL mao/#_ >^v3 S)bO"8&& `djlj7#j?&_~u1,Ϳ%(,lcc11Xlͣ`7?_l\?]*撳u)O01ޘ?Bu_Y_2wo uqMhlߣ+lgmm_ A dkn2ā& @gcuտhk`j112h@ׇ'e2 n)fklgה1  =Ab@ok :Qv6_K#vj? q8 Ab0HA,/+Aq@\d ?Eq/qQ@\ ?EqQ@\T ?E_(# 4/bٌA}🕿ځ$?ߝe g #_v;XcaoaO5? ? 2V b;HlP[8g ( 1 "=A! !SHe;."dmdM cpp4GA ? H?J (s[8:AWЦpKvOPHgڙya5gH+ "/m*N88Zs^)RX^qRQfzK-]Ȇu=3;'"{sqƊdc'9ب %oLpNGoQUAV ai քa)+8C\ ~_W ϻ?p<]Hfkߩĥ}6g 68VF}+ m9Y%> }f${,a{A%xŤ\t.6ݒ[rB%3r~vPd,x]p=GMaaJD>nk]ɣt\|8IIܗًI=pYϢLY,=RՋ*8c?I)q*G0Sv>ghY=X5Ѥvyރ{m$Q)T׹;vAaw4VqJŢ,{j^{b^vK+To">]鴧*B#߇="7 E`:v01 \RjFIXLo_|$ѕNYɽ\>f)XE{A{[.bS& V1]pX]|XP9P_۴Ӄs\F73 Gȕ%w_ص،^dp`qCo}fuA E߂DSGpJ9) S OC_%ϒr5D+8n|2uiYk(W2>dbum݁q$d e~ ;}WF:c= 4XJ|ye7ds.o(]=8uYcv>ixaC?a*Zrs*,kb'UX)sgO8z5P7} R$rifà1?uۤ~ kU\Ln Nq*hC1UK/ goUg!֫A9* CɅ[re¶ěZFw!]+F([݂ݞBXjMݺ8ǭDǏo?*8="0b}|_aT8 `NL>׵8MsŢNV^:njE#!@sXq8/՘'tђqZf k~/-E;NI"Wd-UA-¨O(ؤ\d1Y ㉔`B[, -dSAcG@æDrSV#mX%F|G]?h>ёа6nϷ}6V)Q ?F'Օ4oD0]VpewUf_7.w^iQ&!*_d`sp[ &s%Ec7M/Ž=odE-0[y !mVdL"+mSGz; -i&=LsWDPSl\89Ou.AvYj 90j#nu{P+?#|"aA!RИ4B* 5y8"ÒY6gFިP-65w9D߸ (UyDXYcSlK/ lr%Q=Р[76z8%b>HAksCUN㾆F G=EbP#A//dnJ &P' swOu=u2*7Y ώ0e`~Xw4eսkU"]^n.vU7 CI1T"SsDgyTC|E.]F+SJ|T"^{㯾 //]*-wj8_圶c_nɄ,o~/ڝH[#̚AZDV0O NqPHQ6_vdT3)|وyU\')Uhc4bSߔn n1%Yg`-yyHg⛰;R"<ܶMn=gb8uSM 3>rfء rT粕a 7)}5q`b2?,9tHJK Mb ܐԾN7hWv/4{|~3I?qB4囡aK{}pc^(0{' +X=g]kx[}^-ҬNSgzYp^X:{]3Lh eRBCo;f+K o`⧩̄m>_7Ef=:Yr&35ϫ]=Iۉ3y4cЛJ:^MkKg*ղb!ռʬהּ/F@h)L_J~_]M׾]w n0 #<> @C92&%WhusW#VɇgĿo,wY JW6 bo^+0fn>sbYccߔ! o_ޱbřjg C~Ը\Vhkף㽂^(k9_tϐG\n9Lu 4uǸYh~5ZpRJg|^2tY>џ~29N^YែD t,yZHmPLs(R( E>a3- !!jU@qs[10i*q0NF} _c+RNyXFAd}_ Xk.U{AĎ}s\Vm`j-Yyq\dmN39,(T8{|Ei:5xp$OWP.w~ìK_dW]mL8uD" >MC.<$TC8Z hW ˲{cW sSZm{#(j+\*;ߊqw/\ZŻ(.ZFtʽwg _`ksnT@Wײ!Yw攲UrPYNO+Âj0a-Qn#`\{+si]rVґB{l2snz^{܆+ &]e ɬCПCC;% UCJE^W q'qRV^E!W;jqżM(h e5׶t`8ge#c՗Ɂ t%޾fKnz3'X&I`2xr\ |4]y C;(z -ZgF v l}y'Sw]< >_+cq>hWv P59:?SNi3ƽy\X'뮞lNjI۽ ~ ;q=W=[>LB_uQoqu z& t V(iσsG,1QP"N HݮA'aljJX *)p3r< "~ WgI&|. %Fqe"{Q˶Jk1V/f@: X4p]jWGvϸx̦63Jyfһ; ]'Ĕ(THpd*#tY=mkV}nH"AX0cn{ $>PIʮ·7CzjB6džd՗5mttr!K\62o`Esz9Y"a~,L; WJH$<}sD%.D0ZUBr%8gdwZjtףH5rRdBuұbB]0`[Dk_d25SI/+#ˢۜͥ:Cvb_=>{]t EMԉVkrounxVebb2=rF+=vC_p8'pWF3ob4x)M]uKpIf+%pL<6 -x])Ұ)ìH_$L-s2 p& ?H;+,d~DI@ӥϒaw]ɹ(.f}qD#_.!H[}׵9rku$ٜ)@)nxc#4,dPY+s0=n/q(^MMq\ v,h~wV4fo*JOJ:ުp#yQQQ voɓtv]_4=\W-"ʝ '6&mM+i((yL2H-֚cщr?%#Ǿ!QOj~ZT1]y´kyX{[+ ^p~ =rjZ/t #WJ~uAM:٣~q_̦x}WSUYpo%&B'Oo T`+aROef0՞~,Ȋ5kr$[~Tw=,Aҍ`bۻi.O};}@:-WFM0Dq=̼"7'C9ra_aU،r[0~sBd\hMo!`BvYʪ%zTmf( Ḧtf&tGT =z ];-t+fZ(׵5bSBd[m!rJ !厨+`1}y{4`F!I~&zK.9aՊ%(ea*6ۿ`Z 0r_v؉vɃ\䉍XjLkЀ~ކe 4`]s)w{Զ#И|U .$a0G*Mm8 3Uĵ&0xc Cw4;!9rLt<eNŷB(/vO(%`Y æB7fpY':|1^P. qUp"@q-Oa+f+'(g`1 Q-I &|BP0Y6b*<"P+ޜL4:˵ ,7.:|F߃Ywa4IRͶ!V)%ȵ&!0Yx  -c iMk0c~دcN ̧2r!ҲhGf{IX`x!=-[FRΠ)9ǤIT_̮zwy|Rۯ L iCAGs6(^Y|Nj/h"Tkݘ~c|-8P@צ9jCxsݡDZ1d,oA]m.(#ZD=m 6Lz'n<+àASpRvvfw\?T%qt|? D\&r) 6Ӛ BƈZSU֩:E'_AJu}-We=Q-.X4`~œ8?1TeO\U~wD_XR,@ne[^ΣyAbfb2hnidӁgUSe]]xd7iuٽ@;"qP\ HpE^ѩ*/B9e.yJ}+5vߧvI%>$&]))W',̮JNHJYٵ9MNWQ.xy)QWV?_5 q, `O2q*lōȁYE.fajɂyN}߿hK sW,d€/9<>U:2H_]j_ki@Fŷ8co !Іb4,DzcS1<@HU Akpuz a6 hKM#fBK/B,Ƴ3oAdl*}ot_Z.+?rSSOsK.QhQ6}oOn?4F| ,ڂ>܊z4ܦF iշ̀H 5:͎H7{[IcN-zo3sP@դT>@$._SctF8/JS1>\sz^v:@c#TKГ~zĴqUyqˆ/A!`vLJVSdLU^P_o%F\fN0^j@u̪w#%ƶX;~w,+HA']YRl83c?i=֯lM3` |WBׅa '>MtW&CKM?5%{:DG{~V53~ecT>W xKjAd% `Yɩkiů1kw'콪Ki{y4T5݅QEKZ֋1^y}t|5X5I'4Br3 h~ Ι{Eco<x5!@a|dPm}oC]?B^KNClUm:#O }I$ZVj0%)!>!¤b:3tAܟ~3IcMps qW(oRMw3J'̤JahHŋ1MB Ӡrib<]^ٳ ނ$fD93*w8/ qnK 2ث~ސml6iCdz8웧)faj_=116w3C-@Kk7yc_ǘmLv, {UkޯC>d}2T 宽T-ML Y9,{aX4!,V2 d< ,EߚMe|R?]v]VhM3.zv4V6d/A0B~g>lHףN=e ˷w}}]@&8qX/n^Kad ?$ w%s w.ey,p`Ϸ)Q~Z3K1DtͷunLt'q݉v671 u|@fF;:!V)n.,=>5/1%k']u+mmP0%\ĎXj":D DshezSȎ|&Xz|+o\۝&P|uh%8KaAZ|x9Vԣr-^wr$0jC&RƢ#WKw% *W+ Vd[O'궸 By"~G2,B.qtڪ Q[0f+иJ1R\)TQz+]M~P2g6bJ*ɯlJ_G[-?q;9nNg;jf눙X8Mvϻ+*d~{CPD*jU*@Ѱ-?c iTn>ʁ}h'j#;aJkv=+?.2aN9n7mKk'v~8R @7lj,c'Be',lҪV`BM4S"M/:F )f%~Sޜ#\@-y]קY|-#4 $x==|964c1y e"Ⴭ*bw\bіd IqE7C;)X!hfW]Hi3%.Hc$RwFBҙ9<-ڸIghŊA#."?C}+'0aiסpN^ͤ$P7_'VVkf,*axdQ3<ާ4nx]uDR.4Qr!*iX;kP,pttYg*csh;2TZ> i:V_%Z { KGp?OgJz0u\ʝ/dld7X$f hoRv&BJri$3$ <Gx|z 鷎jt,*Ne)W_b{Ƨ/3ف(^^Er>Sj2~U0\@t<\]ep\*!cc1 !1hJazw. ")O+z~ `/a(M7<ޣV@9–qg $ L7`My""滫o{:Ǘ09>(D)|;5ۅ4\yԭ##0}5hk 5_]1)+-iez? h 5:7Db$%b)SMy/ID3@ubT+da:^ëSb!U,%$;RG*r"u}2rK`{+`!v{sIR3tS\>(WɜQ7_xB5)?P:h 1sW7&B5/']qRg1:ʮ q-3o%`'"\W{HGX\v&ގ٤D3&B>ڽ6ڧ ,!t# j[>$DJ F=gOm@+fSU#U/#zv3f[=4h ,(PKOjS Qմzul6VLq4. 9п\ 7b`W%' v +k8bi>r8ڨV$jӺk _@Ťo*rj-J9_WgƱK[Ljc>}&])h5h:fܜ^ۺ1wl)ߢlTV,|cQMC3Kk< = @}{<$\t"F48Â$hseiRpXΰJSX}mAs8Fķ* m!njx>n5I|UKЬ UJj}9ˣƷCX)=mAf~KDF\k̪QXK;]nB )Tm1iyܟ4SIRLlNEI^ߡaR/V"ɸO's:0 Mn%\MP%) 玪I粨H{ G4*<ěnN]s2403 'zG zv=_ec= :tI^>eСs9}ak 4uYoZʲ $oKv 0TpH_a[T؊54W6 k(ec bO<@-z8`6ih +\(,c,:/g86|(hkѥĭ#/xe5Xed#{+.~+a<g|]D};lN㺹6}U}R',A6!Orv/〇@< ^/=]ɬKts0ZYQdkLcMaj{>ʁM2U35j?A>Lp&:v~cjjjoz2yl(BWAa6q7SMʀ~)16-~D^W= .zzMR3*Л`1$eW]p?簈٘f3GoM6hoPZqk3Y;$˓ofD ?_4v ,V&L-kWF9ZlX${3/=CCtW?;QQ>.;vջqٴ@3fKkw^ŵaJF3obs͈R98{=lF6ʞےRLko;ʧFw$)4,l*Y4H+t摷9N\M3?a%9>Xcg˱SCQjVZڮ< mLۤbDQ !X<|S1m!%ge0ʣt"Ј: ' ]zM:yy(l6n~|a F< ӾF*l/,էyO\h_' k |Q<qTWnwO$RUQ;z>1p^"ÊL딘r]R`%IGB1q2"L}y^q×87?̻N0PWdޅN d, 6qEd98? -q4 k&}p 1㚩;4 |C)S- X%!DzAn³+EMʠmKUvހ7-޸,Wq73Bf ]G0b9T @ jq,&AKOeےōE#,lBWa^yqګˤ*$} v. q 4<ר;C : nϸ1؂;67 ")#7OAa 4.Aю]Δw:[Kׄoxq(ctkfzKNcOWke X"N׬2~{"ϊq!Na=|(3J4l5kt1% )ADRmmg(W%A8HRuF炇6ѬW<[zNG4/*Jt)J!p. 0s«#M;|p!;"#zcu}E8r:< a})^ЕӱhxJrP~Jj'Bvs4%YTn[2-Sy)C Y #lmD~cϏjqs~ E3?%WaN aN@K JYi(CЅ$OʃaK)j_O!azoV *k~k6x"=M~{TGJunϺi5oi f”"\BN޵S>()L#B8E|d79#eH,l1 V6VKUwJQSB庮 3g!ZL]bf lCF<̖Дn>O>U'Lot›Y v*Z%^$<ovXT߼O@u$vg )T6|'bppaW?|Q]/MmjN39 b{$5˙DRР&׽xs9{<6O~wq#"7|nX# yK$Xvn M[Ayw!JܠtA$w]ja/K[i+m GIe0VY1MaW$L1f'Sr0(`47qeəЉvY*j1qI>\?Wo`ZWo۞|YJIuv@ gwd:s.dJͯW^l Yt3ssP (pˋ6|K7-뛥gpD{i?j9n܎/"_btrËwfV/VF.CdtAkl[gFi ph#gژƌI'@R!*09"$Rb*Er!gX;hp5@K[S5c)ͺ:OR 5x>k̂#]NR½W*Pg7QL5IRt"X;V]V򅱦;b́-xR'sI:(5'wL uNu.'ф K&кK1KQf\ tr{ x'lD5qh>D#=]AhCG0Vv$HAvP<_ 2 5>O8(wxcYbF %.[T \l CIدaȓӒJ5-Jmf,%q\<u[ STIhԒ?ʩ06ԥJYTS$* e",k+sY\GAn`rE$߹VQ]|! j&Y2 ofq/Xчi:D9r$ R}=Ӫ' 3J@xD!;Fܵ&E)~yJ6.ͧ endstream endobj 1070 0 obj << /Length1 1398 /Length2 5888 /Length3 0 /Length 6843 /Filter /FlateDecode >> stream xڍwT6 RDJD`Ih"^U@IP )7*(U@t"EEEus]Y+yg3}DH 8!0HA 1aHm, tB]`1 XR|K@0@Ujp,[ q<P> [܁Jp  A 8G+!#4AAp?B:phiOOOa+Vqz"p@c8À-!? o    Gb .H$dh poo } BQht#\@u]aNA΁, \ v!@u%# P  c.=!\ru#qXy} Jwo?uF<>K$ ;Z pskT8Hꖘ{AEzῌs5?4 'C ?,a~>i0; G'e1/%@?0tɚ0 oik i_FeeGHL($*AR[?B_-= x^E]>?ԅyt+JG(+"uw_v߀qExA# ZpwoBX%B`qao= 8o֛/  7Da_6–A ,M,apy. K:ԐP|D%$  I}5~("D.@B~@{p>h )0\Gl;CH˿C(LSupA,fQ.axIg`Nmnٳ}j8j8W8b.&q4=HV.]"2dmT9tpU1DvH~k{eI.#m/qMv;L|r}mΩ#z띦dp;W(NMMU|:Ϝbtz;+s|[K[7xo9&G ʩHTvIC|>ּ# zvXhOw-wzrK__x؇7UL&ɷg52j!j)b*_4};9"H»{>xӼVeI(d }4~f7&XM-4*Z麰[`*+÷J|@(% ~$Y6{8FTh'm7H Q}? NеxgWė${򺨈'~7h*NǛz}Zo- ܗ%.(8 ]}D7h-qtNSNHK-%r·~s`eΔajqfw]ͼ`a?y'Wf5=uA_pb&Lt3ZEوwI[V9\&k۵6ej?ڶ:={y7hjrJ^}J#ICH?z} x"7_^EoϷ+jqI|z2CMa=~+x?.>;B"nL~~{)04I7rE]hzcgrŞ,2 v@ߝۋ}EGL.՚~E}3LY]π7mD(#W^11zm[y+` 8k1WH`8"p!gPdaO|Ln-&텇T}W:UV;Fx^c~VxZe$2Z_,SQ? 7JS"Œ-gSowe?iލA_Wg :NSAcg3Ւ>xa\pѳjJޢ2Ff*hշ2*Dk<ꖼQ!E L1ȯ-6;!tKrJA3q1"< ֍} ӽk~;ٖ 'FyQwuc[ęTe,\L5zçpә1A_k`u +)pF'%Qc X*,rXgH;u|"WQkGb^nހjO"5GSvI ?Vy;Kʯ6yJb]LJМmP!G/3$$ג?=`Z@^ҞYXQlrgmVBnD3_hab؍$2J8aڗ338(3&t<3F]Ck*+&z{c1It×/-tӢ#Ku]j5kkw+Fz\@d)ڤn(Y[9n/G&FWc+ږL$K|f>Rxf"H~DA=45pQB;܋\MXo_V)ۙ*3ǚ2܎Rk".0pLMS^a $Ia/8yM+2Z@*a+s^mF mwܹ=zj7g([f Z˻L1dUOǛ,HСdyAJzKh(ic $U̼{-ǶSr/Ȍ:}: w6D?~ر ynK69i@CqgUjP0|9mR֢(+Ei1 /Wf2BjC,! vf$*~MlEMp ,c-pP܊ZbEsyLMt/|)|up`fTbcχ'~kB?X[_lvIQ&"BLcy˷YG+ [ {R \[ĮT׎n.nr>?hju:#QH9WbiX.JZhVpi2/܀SO >Ɇ&%L8,̑ %2s?~MPJ.=fAH5$`UƳfPRIŐK#7d.=xU{ȞsRA{^\m5Kg5TEx NAu?&u2U:[C393֌ |(%hqX+ƧfOJ݂Hms1JTe fR=]X~4!Zឋs"H`{@8.!.1xU:A7K,Dg'դ[=ՠT 9rZk=$3ڜ_%t,IѬɼ3%jb.ڸX(v[gT]FY[(G옊`N8*6:[zk\J];t?sU֊$39;>|g;VY=Te7 2N %_ivM}ݫRtSU-(t)Fq=vʆ9r,ݤĤq8+R}ydvI9M9Le3.jL=xeAVsE8.U\+JNp{cWz%nP(/zu9˴I8d|9.ҨIE6+]rg ')CXQ-xߧ~܌'aNʓR ! UI_űY>VMh#w(o9KӲ)@@ nK!a,S4X"ϊ˯F'DXwooj90a{` L/L9I`5U-зݼe{/xQez_n7<4mtonzC A9*6's&lxE+T եSkz.޿8U%ha誹ȶuF ~@[ϥLnsIz-qeqCѫ\<^3e~F9_\4 t8Driج}5o$*'?x"T1UsH-~^+%U{p#Ywq&aP⤉%ŲvTh4avgja`6]\+3ݏGwsKt4ljnvEA=d-[StjZ~^fZP3#mq7%-N&FCAx,6fD_ZI>_׊(fF'Q ԋ=|O{xJ_uN+3s0j?oՠjO޳* 2]Z d+_?xD9\WT"ܱeuWKXaC>OSzx'H0%/ ~Ƞ7W gUxkWB=p:6hn?9G$9%jJ tn[(k:b\a1=RZ߭մ)y xe+,t;c"[d4im35DcF5AH%DQtD!|  =Nݔ#0z#qЦ-//hrC~6~;G5ֺFMzIBg#WOU˙i.&?pg6сJV-Lt8<\]p_Ĭos&,yxVF Gͼ/ 9Xh%k?R+3y5;)y0\A=)d-*D/RdL}T16SI"wV$Av3/QQ | 嚟\8ҊA+}hPnչ[|2}u^c(h>H\I-uff[`9£xUCαw6z5tz0#Kiֲx̯0H38MxmL}Gv endstream endobj 1072 0 obj << /Length1 1398 /Length2 5888 /Length3 0 /Length 6843 /Filter /FlateDecode >> stream xڍuT6("LABa0$[mlAD@;%$DAB:D3~{}?};NV=C~E(FAB a0mp>aH4J!c``ަ hPĥABB@a!!h4P삄h ༏vt ߏ@.7$%%+ !`PC!`{!K9J h \!0,  ;&!C-{$CQP4T:PZ|? ODHԯ`0vpܑ(8ij p|@0 Ǣ`0lj TU qX,猂?YvppXvEy}E?ǀ:; N0u? ń$%D$Ł0' Y ivǀy#ma'00o Hh#Q0g1H7~ , QXPMOQȔq*)݀" $$,?x;bQh|~w.HG!'A rt !1! _!7dwloH{?x," -*;j\?3Hs4~egZk4v/DiўvI f&YwT<kGjDY icx G_ + Ʀm1gj 0DxQt_Tո8(/AZ(iF5,]= 'u%/ &5 d Uy6FOl2:T -_ܛ 7"BPpgt<xGBeRIGЕnlx%l_lq Շ_Yoz.Z\f@n"1b+;4Ij!#] .te& <2?ċB\ITj#$>嗚 7 4U[\ݦROi͌%ZzZT9u+^Br4)O=_?LfԢ]c#UF f}d?f|/s/sU{@Rcs+aU:h;\,iX RRl%ux1d"%qMꒆ|KYff$e7Qk.a+;z TL;߮QVz<D,2N|Ns=:l4`Pxo-Wb.;hi+> ?ɅŶSp.wnCe`aPJ^!M$S|{1K gwY2\ =̀|0Be= ~BFǤY 0GFBџŖLUT}N^4\aAT|~40l3ЗNe n]/a& ,^/+z`[,;_`Dy鲅]sp'JUfԂ)Ʊ'oP^&!`#qNOMUyI+PNqahN23Agc߭]'>)ҧ:Msͣc`D%Lu%K:Z$nD N=^$cUE ^q6Ǝ]9k-! >iV@ے U9](WR(o|@"Δ9K̼k7׾L8>׏ayi0Bڍ OEgKׁTS$< .~us%Ucݝ1Uѵ_t J,j ]⃒p7j]@bpTEFN_t$` gaI 7r׍0oܸeaA5YyPA})~iw6s|_+3<||/Z. !3td#d=?pKTXX-G5L7vp*rP٩NY ┪ůjvONF)_p!*&|Ua\[QV oτE\xAGrUvB=t+bŭHvDfhc_,!B=e>dj?nWɻ\ZKk"g%w f[0^ň|Su_? (51zkEWa|f m-8R JڴR3áDb[.ʖE?hkoAXc\fV^,Ztm^qMY{籨|# $ *߭SR3a20Oh{n7}ѨD$q$)Ԃ;G/9 Rڻ^ *}<9[fsL^`-iwmf,'<@{ +VvF,(*Cdg),VcW 8>S) Gp`VO*>&%Omot g_ra:#2"Ɨ 97cKTܣqa^={rÛ iPJ6F[Zիb&WU=B}k--_= .HF,`ZzWMWK'bV[IK_ica9 ,Jh~$3^Õh֧}RY(3q]Laբ0:wR]@g Dŭ37AZhx*l?T "Q\]|!hΖkAҍM$C$Q>A%~bvs#>bR_7T̿xEǾ6 tk@Ԉ1:cm$i9MU}-@3?nx{W8M H4, CY<V('^u}gw2MlT>8=z]0lFڒZR)-gB(V6ne-1NL{c#lc^ ogeծ~Й;d<ܩfp/#°y=܇Krɝe#cMZ_)GbNrZxYr@zNM_L*o\/iPa T+L,iNUuz6~ ,כX_*YU-\&,X9u{ՋYta)L|@!v3~4Y];-=TLڿ ȭ~)&{%m}܄4dTs*˶A[B=ǯ$ AONwew\rm_v?=yyU?3o$jHI6#d4d]+$?R}Oе`; ԓNp)},츅UG߃NiN3TW$]5Yjcij|ahZ蟅9 lH&n&H } MxHzRk^i>p?qu y*~=/Uѻ2_R˘aG쬶MF6/OnK?}" Q|NeiG4OپASUxtI^¶5fh"s7*=|fJ AȸJ(/BOrgh 55ɌjބI>e,<60)_aU.K/v=PX1,42z3>o$@*~K7}2SxP8ý5ɝmh1>mǫܖ_gy$Y_o(hJ/ȼ=ʢ S ^Y(N6oY~qZZ+"׊ ;"]Pn)lP֒I6djgǼ`̜Yߒ9e!17 xA?PU+ٍDv/G?߰?_j_율u++<3 ϕ-'2ᡟE/ʌTD3mc* &|T-Hyt(u1 6~LnY!O$q׹Z}ngydjDLK~dK$ߘݙP +sXIL|9*_ttV5> stream xڍtT. C "0twH0  13C HKJ*tt#t ){׺wZ|{gww?+g (a(^>@AKKM $P#䯛@B0P@@@(O0#@@ PB@TEP H'jkW ..w:@ A0eqœ9`(\v(?; GJs?CQv$ r``EmP q8B jgX]oBPd wr<0[ QCy@0_@# + w xH0B!FUsJ0kBO1g0;aYՙuq)`\$BP0x7t rc&r;l0C@|6E" Q+-F7揍Y>0b'C/k8?S4P3cp8WPD1/>, m\5 ]=e n?i1r3ysw⿪X )::sa/ZWFZp` }Z-5鿣j(F r0[ yP2b Ep0. qd 1!1jC^/?Pֿ'(B @$c,F(L 3 f13f7p_~"Ss @< ` 8Q}EPI;ڐ$^҉ P3"T҈r~zڌFt3my^J*O#^f [f#xcF :' L]Xw#nXvsPx߫蘊wSUnnn-KӤe7Yy5XAw/s):p5,,Q;UC$νRO_eݶu}(JG„Fs/2?mPyYܒݶ*\N8>Cnw̨$T{';[=l(@!0"QJ?`u2/X^HC բ#f".o ywU\ @4eڟvASe|[)\'F3wbqdNF}֠5,(#NUl`vk,mьH0Zݻ_0+>ʬN@Pف'ooRWHͲhE'B yߘk붲jrճ8Lo6e7:=)hrhԧ'0, 7͔aqݶQ.:2*H%A yoEVd+xEG Ive lyEis蒥ƍ8D'nLv>9QPFF}BI =`b[U|(?LJP=TtM )0y y7{KjnyzCPfEg NC )vFϕQ;݅[ =M ԛN9vy"V`̖#,Z&8E}冷QO -VE\ȮX{8ͪ7MSgtǡd (5&twmx X'+JɣC dY;ƹm@F!7 wy)Fy~ d!$gdNZXPW܏؞BLƷSy:Dvjqc/I/}D`wֱc$;=X7\]8%At| >;5m Q??-z+}R*^pzmx̳!xEVm2ӊR5hZ`]0C8BXKwSP=ͣ6BROLVYEnkD z>rLIsTKX i|OXIz&lCڷgXOʂg'[CCs& w?aIܧ  WEM:&49R#;~WI8aF J*סsncij?UKCJn;.ѭ wga˕Yw.${enj+ɣgnMȖ 76\*=*Aky_cKӟG|#p*GpiK/pIB6˾&g7q1 ̗~z\| ;$.ĵ2TXl+Tk6K ʉظI#P7m\~ycOLmAߢ=>*˝'![0@OS@yLgJ^uBt|P_=BM6ơ:FO{%sQ1݋1U3׃C]%yTR~S˩|بjEwߜxA"FNXJU,)1s9 K( cdBMo[U &6,?PqkhpnuWo62m0z0Et(8MfK75sY |{P+ڴƂNu &՗v Ui27qd{s/^W 侲O,jgaLX~)2e$`yL;oX/*ŦnZT,_"F[|8W&4DIa3Sz.4nr2cx'oٝ¿r<:q+.h$8*T7؜|+R<_ 00oĮ?*-zvSmȃ1^tStw"V?H_ϔs_ &?YSL 9ڇ;RP)39 JH&l7_y_=tK -Ȓ,u~kpShRWk5!)Fm_pʩmTHX]oQ(`ŝl?I~ H/LY 0͓OC}d D4M/jֲv씮bblsy`/hWT~W_~0o"K㳮qx3Ch5_k_+sjWЂ|~^FkdnB˝x\|m goWLHf(Q!X2rqjZAߧrM~91"XZ)"'즶(Ir.P9 .6M?%G"[!VɕҒHNow oR_@7|xj(AٔyZbE ._:tϯc/r+/m6ﬕ)[rShwXWKr*wraƛ(USYʟRg0Pe~꿀JGtb7 ˞X1y&pMO6txɄtͶ\ȥ$i48Nja7gURՇލ7qO<ˎ,f(rc`\6|i86`>r%XU0$r| ]Jeq;M6%ړe$ 5'R~%gxiT4b޴?aG\DGpVȉ@ݧxͥ^O"H$g@K3aO}DL=|OA/5*wv?JToD~2Y" N{Ps7>̹JPַ7Ӊt-B`3/NAv⁧9=?{KPe|sL3rwz(\ >'˖O+JÜ 6 .'v䰐*Ԫ͓Koݸ=revy>.$|N2r!"b~JGJtcD]0@z <7+SOX-۴өbuz[M]I&$O.NGQem㸻b>L7JV%kqT.p|׹J4tfI-i|Л J?'`U+5ܥ2(#Oqeͥ9i7ȑ&CN}Q;cj.g"Vj-eUNok@] o<țY㼏-xɾzBh0[XA7ND_Bv5> |{1H$)QKkZ2u60ҽ#?Sh-`KYTQ@݃z>/Te J6JuUR_])Үb;ùC׻[Gb܊3]nGo9 Tw4hUAF깞;džKYjYf5o"AVΟ%/FU%W$\7Fs/W{sܨ/i$p˖&N~ee/և5_(6t%Ӝ WUzMq:w4qFf_p"9ұRVh5/霃I9UMu1}JOT^#LOi KiPex Ċ'3:Ӟfj˭^L!ŏ'kwؽ6d-e&߭DjiUR$R}.C*V&#»'ϻj?NbZ2&(3炟z+G)QDf󺈓PM?=pYvGW~Dbloe(Qg"CVVɖK0]k+M|*_i)f4ljPF6Z Od9bB]b[fx23JtI3&ckIq.=ot3z\7~0-sޘiBfp.LMa+i}4> stream xڌP\ - AK݃6nAww;!8 %I_^Qں$J*¦@ {;zf&{f&+  1:ގQ' H&fȸY<̜ OQh{/8u> | Zs4܃%NSh&-Q N;xp}?[zU]gG@kV/2\HJw}Ka;ʻ5O?cԢuK)fpH] ai=L匿ǰykxT8wjBDO.-Zh+"A|L°ϒQc>ʮmty; };T ݥHe&q*`G+`Q(cmXJpW_~AswfZq % ro5(>q=Ay]<1o21isA\V5+tOٸs(I9?/ĵ`7 !o5J8\x^ VI,>1H^&-ٻ3W=iu]p^@d8~cHphME>恽y{p*gHއ9ΊiQoofz6!k?l}.~rW.-FAU /{7/Vԋ9@N;j0LX%2f<|ջ|2u޹߷HMn{T閰x٣ l)Iү#_"[V܅ j3kC"d0LcR2U":lM,jgݺU|Zkbjo'v8>SOݶM&cîNG*!6 5G⛡Kx*GBSJ2!$\W'*3&RF ,P}whfVj?*lIbܝT=)B%ܧ5^olo,~Я/6핯~>su|57d a\C+#,x\(O]W\J|l3W.wR`Ȉi-Nj`PX R.UuS78D/~&Dkgmmlln$:mk0vM+.es*Gܼ9pfuzorIYqo!Th2,|}-9"m!-" GDD)Kˢ4R!DNnxPBӍs4 >u7+;:GBad\~+3Ok5!-7|6bX`_l η s*JG;h#\S]і±Eśq" }.G9[G~C"B'$L _O'n(Lconٗ -!؞J@c42#'– yru/%KCpU.)菦>dKzݕrQ%lS>wH?Y(<4zo+R!Lfl1,)Hm5fªp l)Rh ӏ`~ftR( Ө1cf fV{놧&kׄN K ~?oOz@<T A|'+G@En~筑K61"QcqR'Yږ ܄dmkx?[4 j 伺H:Ge%Kwyg%gѰZ:%b!;; '< q t4#PskU^G%8,;[$>$b]| 6ƃ*~42`œZS2rUi9;ƀv3m` ZM<ݠC@J*eV}uuSHhՊ :*f{BsuׅH%d%TScmm̫f-Y!i/I|oĦ̌yP^R2ZHpַ>w6ͰC SUW3K 텫z^Y_ %/M.-gB(%Z*w}< i#o8V?zz9sw17_daAzprDRg$j?yNIV֎[%9cgpp*í*"cE{!穟IBf+,lhe6^,gu+NJƯ;9#5zi%V =ˣkF '*-_TźWܘP+rҽO=q*xُ~'@( WzW?z> AkVC^Xw(~M)zʵB=Т^2iRt^Kc3!#K,Wm"Q[Vqm\:xP@vɨP-)mLnmm7-9VFեmZ;s c!xYxXQQ(olX 3]&l;ucPsgTSrIݛ J9>/h-6>~ \ }Mtfc^nu"^#9a,no:~΅jp%/㘻/qHTyVuoc/2{P89ˍ~9R")aeL|H'"NɃ-@*4F㩁wIhE U}inCJtB9y,Ą]ᎻAS]љ4ɜSN&DI@z4nV=7Qr}E ߋ|97ȝc/\=]8AmBn/}d* ]_#]5L:= *ߞUl%Z+Cu.x?4ðEp!4oYᔌbp}lإ"E/h"eod藍5cHyTV$|u&N i拲C|^EMwXS}c%c / .~OmHZ+C `qj&ޱ6%e7eI֪T(|]]lD5R nGMx1u(1ߨ|gI_ dC}1HKVauP`xF.ͯEJ%WkNհƨ~.PL|Kt|vO2 . ;S:+KoR$^rL/0*| jC@Q(ע Sqz4b+iILqCAMbkaE $MRe g7IYl9c:ay,'2,N[T/R&א-~1ܖ0llߒ6RL{H8فqfInז_U xzvl\LadxC%˿~`4e]K8V7O͖&V~jͣu[ ;,)֐[B˭9)叁f-2~>Q 2Q}Wk]|"LG9+Z_o{ШT#n s׸\= 3y.QLn׬ܜۂ\OLp^G /{tQ;䶴p)pКke@ve4-'B7}M}V(U06 [Z ɶ'}PkvG4^tϕʉ7oo^5Yz>JϘL:(LU;C-JH8(JJ[,=#˳|Nq5uYAY$#BqI2ID/)̒ 'RQ ,>ԙ"!}݈/hh?v9TTP?-T˥ fSK`K;rƬ|)\gl)slG& +sB`g XiXnwDmOdf|R4}'KD"Tpߤ$$)BENuLū6#I>=O'BA9| BrxUHRf2 k%f"V)2F=YhqaS|=$tR_ !@yQ/&ݾ Eg/oBe)eYnWK݂<'Bg{ 0*_Wj*i-5f;Z%Ě-U@Mڹ>Vhǜׂyl꙾9g 4rn-g5&B-'J3q0<AK&t7oOڗETعփǔge֛tliB/Qђݡ+i0#B1Hz(RxME #}^l.G#3ehέh(E}. [~1*~2?!Dk[cNbM\>~N/}Hf9 r.gAAobB0Cb{Xnjv^|9T N?4:UD*>k(r3lT ͥ UcW/6R,Ά3Bеh|EiA !XIO1IËƖ A*6mbU܁ ~7d%J?2 x>:b&b|V$4S=1Pt09@,qftyj:?JuKȪF9ZK ![tszbϧ{Z@nC,kFJwT@%0$柞]BvdR.{MdGroocʾo8;s!|@:e4S5uvch_EM3{Hd bzmܡ [͠˒D-tő;߼f:' ReAS.ټvpYkj {ٺ˩:?H2~\ fz+֛-7]nNG/۳=5f`gtg_C#ͻm>Okr*v$Ӳv6\ rdհx5eT5@ܦ_= 粬b; #b٦]k.P$cDjxf6pL;0*;n"0]12L⁲#a-!tKY1dmч$)C>D|u<ٸ{e٬{RKji,9̯ 9^s٥܃ ՝E].ñݾ$2_*gÙH< ?(6~StcԘ@_x IX`mģv'ꂙH@]a~J^ФSxR l oq]ȵSǷ<0~Rëg^)b XS);I2,{3?R/Qre8 tOݶzmiE#:RnǍ gڒ"ҕy:҇ƱMp(DD˃n붬v.A$2q)pҲװ_svxUɮ8jy2R$"߼ w N&5Xx%8 !C\=aHcP9:'[RWY(VpQR)%.;w"xEv1Ith |\kRc1[uSB9HI<]`E Z7/adHaD>P{䅵o1s%^;Iy!xeP18"-eaG z؉WZB9)f,`rSwq^(ٲi!3_,Wav=,?BJWEL`ho5/=")'YjA >vwM]+A{?h2aoas;~{ wo.ca贲\=EDwCGVP{Gz(r7&i~g|3[o0Oj_ b"FJnlst1X}jS?+7.С9! 0dvZao(t!Yp0}g] 褿f\oK;Y>t,8 ڦ:,zU'M1ahg h K] GnWe;|ׅ.M_RrPzKϵKPb(kek7aS"7@aL 1wք"xķOނC5uƺ+"G>_ٗ|>{Q$gW˩ p&Gqٛ+SԺ>eA Lp/՗?(Cc96c/ ^oFe`'0s]&'hz8Py!gf̣5W 7QxI*6~iLɮ{>&zaS 8WF6h̭kWBhT Jӗ\?a)T0n tN^=QCxɩổ699& ڐ2òHM;N\ ni*sGJ\œ5ƀHًl;X$={.il"mOO<0(u$O1x1r$LP:v0'm$FCB|zDs!/wZI>&#ItxUW>k->lN~l51h^XNg!¼5'DD7Ϊ ^oSg.DޠwpŪ݌j V#NJ׬F` > ,}*B5ސ2-ގ-\" 4<^POal7Ume埱bAtMbj78ʺ-[(iy*zDߟ`O=~1wY܍4tL3KRgm鐆üRV^S< 7 K ۂC8ޕw%<{`+զoe#_،UgD_[2qT`y hsB^dxIۖݻg,_ѓ +pe6c亂O 9o#iF^?"9 E#ȝcۮ=uc%E)Sȋxbx\rc:Rm#%ȧ4X_a-O/7yIIUq33>~0 xc[9bX\dz)Zsaq413^,Q [`ۭa,uE Ǭk3 NȞM&7\x"͗NvǺCubՕ!Ruޫh(4e%(>0mSN(GG Džb t[^3]e: iTKt$킁M c]Musdv/gǗ'A" &Iel74cVj @%Ɨe w'GCl@ N]Y[;z6|G3I=G+j1>hRD{yشSXYbda) FIC٪`$*TӰcs!)Nj c>̅Ynf 7ZaBTv"1 \MF l>ud 8*Z篫Gb 1Yv4 WS"9voA$DH̜[RlBh`:ltKS3 A%s7mdT$^ɉ؎Diؕ9e=A O"E$#)j#o.kha'K?][PT_[+,?O.cF|]34"{ꘀfVqę{4` Swti+ j0 ˡ628L!p ,Z7h]AV @gU%jmv #Pm^,z;哐P/ֱkWG/I\˘;nq`ѷi|ded^(m{֍7!8vmv'HFGYL lF>_OUEA;KK*r:=~MUqD͏RN>BRAkbz}{vi/|)QϼHGTL u6xZ*a8e 1Gc#.M 4%g5fOU#Y w^&16d\<Uxŋ-`1\~fiv կSĵEm}s*{N"TlāId>P WxbI!+gHT!HT$[q鄖VHn<K biE556!vMB .́Jgw`ҾR˺rOrR)u [g$~oLS6u(CuFX5,;ސKɉ N! sU>ʘBʧ&KC tIy>ƥ{[sq$9)20<Բ+Hmݖ;++۩VX4Et3:LX\'pwDR$^Z|I"dci yhbtpRJXo=T!ÜEpܧ.Q&::xIO$)BK[hnp8s'qA*̍K_!5q\ZL ޴fbv~|Ǚ"?6uILFCzn''h&7A>:㳦pPJ@veص&[GoJa7RYd8E\u1%+fZ"D[ ke*흆lbl15{ utۊff`8@*'L,hP7YXR??lu:c ֒ XYXdU) tV1R=Rɷӈ^ٓ4빃8GA:1E+Ń+Y:O]'wq^1WI;/mM7JZ %ingEW^jar!G2jtۧn)mH_A(Y^bMh?T N`Q&Y jY  [MduS2#7cX~#S1lc^adoCċ x)j:י 2ZV? g|XFgݧN_t'Wʿ~3@TFXA59Of(҄KX_Ҽ.xTej,p <l}"<M|)f.42.K,Hi;kn\Zک"ўvyWqQ(_ƨdG#xzaO벼fW,Ls@&I>"n, I6遳<*N 7Ʒ 'g*5z+SUi؛%gה6ɇw+dTCt)o{S! l!hx*r";Wb: |ogMDi,aHo:h?0% s?vk|gï q _dɦ@_8NA2=_uڽ M%ȸ-mlf1R#.-<F\=$ZtJ5ߓL̕J|Mī$z5^gj9"wtL>[Rtw׸?8ؓ&CO!,9RHf/)nd㏜y%lVǬKٞ=y`nzpl]t{Ɲk痥b_gVz%yv >I.ӑd.t FV,BYdh1Y M*ض]?7YUL'_-jl~cW],"#EM!&ƫmtrJ]و=:TOۃASjPƋ;K2"?/*_(+5rEv" 4;BcLiC;Hfמq*XcAe녀;+GDo>2ALqͧ5YHMe@.]CMXpP1W|.;f7VZVfrUfX:_?۲; DYԑ` :/j?@3A=g*=y[])YFgѤAE6K^l1r[!1sI$= 7w뇍vd]H.J48U\7C a{ՅmӋ,L! wip?~HhV|Q[~R&qwpD(`{>|IUuD'ْf.`"ivjK!C֏:tm.*1BRZ0zsrO0!BΏ:RHJ:|Gʩ(])ȧ{pl5ɑ8fX9Qv" )D'2MhܻL_ SE(U6fJo>c]#+ C Db@ dzߋDӗi,:-!-t4BRIfz=aEr1+DKRbPphQyb<`Sy5/Y>VVOئ$Bʭ`=8RY:Ƽ ~\Yum{yt=үZ]CT5I52u~*fҪ-LpT{vKjjeq2G59k}uǃIlI? _0 ^kK0kt= m5d*0]p S9)a->zֺۂ#,-,~o6~ԂTbxbIDygI9ґw.gTonm)O #K)rOKX1:YS]CϓkM,Z#HP +Lfq_,ղ^^Cs1Y]'z`u{W8&N~G3;ÑN4n@R(/?Ǻ7b)x~2VrҥaHTb*a|+dD'ΜOryJUʸkb B}.NUfM.sam,[=9մn:kIi7 O lV5aFM-%wͺ"Ч'g0V4мzf|5eipr8F@əuT] KQO{] vu8 KFEiv?&V4`_K)QItuu90 Jyԁ(a? S?> 7yȠ~DOnf~$|'yJΉSt2՞p'!BA)1+B?x|)(:ȢA)MA`A=6x)pIwȟE(íA@13>MKORؑۇ5Ӫdkl9ЎUrzJĹG2׻'Y] tv=Q~d(Ս:2YL0ʑcXl`[| FZ"~9l8?J85]XPJOd0|>p{f˽NG/`jXWYTZI3F~fsJ6b_I{-ٲ8fdgNj E03[C³ޟ)U'epOI5c5{o(3. ̛<i[VUZ[E6Q4 /:OQ >%T[?d#c#4 $MM~@h'<';9XA`pVRXsKv[1K(B)1t|%Wbl b7 .Cjl__ wuF Qn,9#6U:vFL7c%n>a$o+Hc"mɔ,T9pkӿg?v*xG5Իz ߷D/TDB++XkB Y|䀠x:c?٭3:nx|tc Vmr $R^4#."vm=ߑuրusl\δ\nӉ$w̫}ˤF  B.E;baU+iv Ukh@t@B;S]**,0 xFQ6D2E'͑WfU]Ԩ\7İlws2$)u$f'%Ä##B ԙEf,!{HYoZ@Wz91ؙ1]\{ܒ@ 9p#bzP880C C̔dq:&gb*5'~ s8[x]MlU~Y aًh*CUQuUc--ڍzSxƹ ' :)ʏ8"O ! C7VNtIˉ00y\4*}p0nG1 /S6OWqH*JW,/;?=f'-DNT8_}rNa-4}40ENvFH>0r@ RzCtE Crx&T&xTw /23a-jƷh#޾L^FA_V;0p'SMTRcf8hƩ/Fcx ,mU](FZ?myHXp6H=]^Q4ru|cTF5]N!(X^I m4+hx>rc49HaEl|&DM.|c[y2QK8M1gC$5r7-`wQ'Q:x1hưhb^"$^9$ePwTFq~,aMTk?@gj]1Ⱥ0t>gU'Յ5[28aRm+|@KcD*Æ6>~Kw|eQf燧@_5)d_.ͧ14U} U',:;D5VĎƥK?uv)9*W_|PqM eq{G}C˘b%qM?r (ymz>S["թ"MWZ#bvHlªsӅ6NUL 8QgyP[Ͱ h)&SuPsA^ Gu"4G,$MUW& >|fmwiˎbbI~55[\eG!;0bțE*gd 0Z HV桚A#Q 9^=5Yr{BI.T #V)'(-fWibz2x2'HjtN)8(+]EV 8~oƽQ@9hU:Rwa,AWC,p9`qyC\Xa.[=n.'>7\>,Xc';vAɐZ?PcRXI0Bdx]1]WגSjCkQ'[B٫pDc'PJwʾ5\`)gT13&P/p-TC`;QL s 9w _ʂ*W("ԝV!rD0<[Iݴ )75P3vg/IY"_[TyπE)jY۱/ވ dlVY-=^=?RA^kA]t0XCeZ2as~Q5Y0LJZ"dYYvPv\[1ޅ[a`㬝/|j yb\pn:ug"݂#̊f7dͬ@w5Qvy/߷G*vDB'܏!ڭ7`ЫaR8!9e<#\[e ;эSK\^ ̷ĝ=X/8MZBw$)F}ش]òE7?$fk:utj7\KjLsf?Tq:<\6j r܇\O6;7ōl.8T,B%AU5 6F^Dqt3 nlPW-G?fOP pug7pيD"9(pa}¹tlf{q)Ø=|B4,Uy,[7&,(W~/nSJw$%zď(4(Gd}7 'Zğux]<脛Pv| O 3M;T)%2Փy0V}sV6*x>t~u>%jLc1EiO@1)"٫ozv# Nx{$Pa =3.%{DZd.|95GS:v0Si0`( Qb< C|qaݑה+;;&~z(}* 8/~ȍߛA@HH6Q,RKUp6ԥר<1[)R {p.A2O|aYv3t[50>6j¦]1Yoqp8&豝57 _Br $F |=ׅp㇍=W/@#Ч 3 >ϱ^YSM J?vqm-+ʁ]p%ᡘ"JRSO@ZBhЀU:m޴9hjT74X)lsO.j0yoy#b.^EzE@t2K!44 Tx>oh7fXhfHc}@~~"_CwGhoxf*!X 68Ŀ7`dkW#ojMK>94+ wkb>v8M!YaR|bI{gUO!,=@⣻Ѩ&8/ zf7 Nqbge8Us-E v uj]Uusiayv}!x2D2/EfbYqxGlXv,u4@ oܤa._!syG~v1 N$[a=^$i4)"gw 4G+2(R@z2f*8~W-4 ;4\DyT'XEP ;,O ]T3$(5)mb|*O]01S@H᠗Oa'I_ȻN} GWO|٣"X4+]jm_v)eMC𥙲ֵ&MIז#P[z<oN`TʅuvbԂנgW9R՘cɂবAŻD~QT dvU?vR3_b䌸wƛ  ^dϝAEiooē, x;l864N#]wjݯX* sMGQ-'=ׯ `"c :m"g҅~)*^֢ux{jEk.{F=Mz|XFeڣ{dߜS2'&-%SC<͘DXf ۨQ6/{.+՛u1گoV.xd= P_o7N{jEoh H@ ){͓ cYƽwv*XX{*?꿼]tPTTDtZ+mUjDtaˊ],׍oAt,'!"BXN~,יa$y)Z ѫT wu>Kn]3?rz)pby m-6#5]hJJP͹¯kDY^WoZNxN_3FԦ >Tnqe_^s@ŏƦPj ԫ7H.-J%%zﮗiX\7!xiX}nyٰDCKcܵ6}6".'Ktd'EoTT*L5:fbW8ށz]0wOŮΰtEI $77LCx-Лssn<2Nf@Xbѿ5 =QAMg5f:u D2r+Fi0j%%>ґǮ Ȧ Y`pCyYY^=h*˴&|}q1q_+y믤^ɡZy1 E N$V fgH/e:dZ'0oQg tc_f =Ӵ +fnK89]3j屫_{4 ;ܒ.Sy2mml B ?e*ߟjaYSFe b&.\* 3KDgW[/OC8Gt8)h! 8Bw֢Wȋn{~΀Ni5 qΫnq~s+:ߴ !@^^SU18'3[K!j/A; ̋LUUI_^/V$~fN໹!w0 =pÃIڪN~lMcicŐTu ftK}u^a4,PZ?rx}T-(֛҅[[.VpT ϹWjbٱ :Seo;#>\lw KB;mp};(񒦸:\˺IAgwwQ^|5@Ks:,6N(uLC ZI@#zv1$Te@ }Q[ttlU%k0Ch/7Zj{{r?_HEQGdb#]fþb>Bq&ܦ,J.6HB}AB{ρQ1%b9xwi=P ]do؜ߊ<|B?ˡE.l: Iƍ$rQz> stream xڌPٶn $Kpw  @KwWuoQ7|9愒TEQ (WT3!PRjH(. G]n2 Sw3EG`caCG>st"P;:y޳'Ɯ;@27u(Y3A@7F͉ӓޕJ r].@ _L7Ƅ@ а#Vwt4uv s뻃.Pv:c?27 r`R Ln^n S M\M=LAvfn U\]@NnL :d+%,n'rOݛcupt`aW N̚ gw,EdV@7' 7/ z[3\ /{~NN~ K_WS o&VV `9 .Z'購/+察~YF[NR^s28Y,\E*X:X:x)}JSN?c)9o,@g X8Y^]m_Q_#ng/dᄁ p"nnw@CJ* 7sV_TqtYYXV۾? ~iwJIsGn'߉~ -^o0ޞ0%b,x,_f0K!Vb{_?`C{v?]S/SCT{>?Oq5{v?]g/zz3w{?pp%93[ ^?K%?nn/K z+_zGw{7hX{;Ye. +_>xU{"s:9)ߛq~/q0Y߻W糧=绹3ߐڙZ+{?1Y5<_>{O:wo{x?ռ]G@aeќ?ئ.FqRpr_ -Koꬠ-_)}h뻒4w"$/ amIOfNE 5D>8 lsvAQ)x,_]W=G|.eь6,7^%qc$CB5;F"@w^쫷QڃGKy>>C+v*x}h٫U$!m-_1ź&K-k4v!Sƪn7peuYmt굴I#\坭,p&"DxNl y^N'|Ƕy~y?c6଍)ZֻKiݐTkx9bLn8ZXjbQ.9LZ̨pZ+,a/Pv6sցi.od6}n~XiN ƨƈ"Ǻ+HG[\?LZ_bQ&,zR5},~Zn}6<.>ډA#9xuߟ2XY 鞬vѾ1x)ט}KRa; ۬1IM`=2[oZ+ lZ&ܧ7(;sPyoq+I) _E 2`h0#~fPB-+=' T-js Ũq)GgErw'/(!_ 0zɮe)3 6#SQ"b VڟjJԍTMäk`i>e6B!Gi) \._%{;Gw[Ş*(_\)@Ю!0ujpaq9/( =4JAkqH4<=[)@2krًllnϿoj {NA I#ޝ %I cL]w0^֎!FҚPs0qrSUpr\!k=oR'=|XYc#uKGH,%BLa3BPa*Vf"guEE,cƼ1 jB6.::n~vpE' {=As 71(id{w?zW[kǿr`)5 g*9(~ $nÿj~kYoۯ@3 1m/W|Y1ZupQ)KW]eP_p:i+=#~tGS~JW>ͧK-b~x&Nb~Ӷ 9&ˇo: M/rLv11~}dU=䫥^fNJtjޮi|f"t0|-l}]5Gr#E[F >:cE*-6D+k5dc"8]x R?_Y܆0D!rH tjy0PRr-ɒ i!͖8d]-/<]r?;_A12 Ɍ ڔE6nў_w>[.;esBoveWU21άcdtiY5>BKҨ(&` ̦JKI.--hu˃浄z܅u]ߐ''Cҿ&e}\$"b raaH^E$7؃TpDŽr޾fe?#D|Hs &M@JH@IyM1_$ F7+l( }PK =dDj] f/XScn˟ mXTsS I50 qM|iHJV=IH Knit@}՟Kuo%[Mpa"ZǞW"͗8F5?.hitq>FEsq6 029R=8<H/u,3L+ p#S~f %Jws㦕OK?P!JnTEv ބ=TX d7;?_~>nD+xVTX;VtfOqN\N^BXF=kb+ؙ ze C0(~D q Zcaat O=ty-dΥ,CVOF,l{سr%{QTьV؃: قE;2`;9W؅& ܋{it8qi97Gzz( _3\zW aFS~uPm>҆@+}d  /'>gSAJTZeo/gL%_ 3N*;2Ϛ6J=gK?`raf!PZE=Ge҂GJBRt炬WJj!l"0A-ߴTXEd|Mnj e".H2kc9(sY{5@>gPΡ+OHQ;PrqB@%+GAf.lRv6#SF.vmV:%x܌ts ٠;dA#L }J>Qy=!`@ڲS9t#W$<)*d1CYh/l;Z\m /ԉ؀EZV{5jT+a s#fn3B?>FVJtˈU713mA[/>B H=*I:p ninFj&Xl,uHN{|/n ]7N.(R3=%\zr띤[|Qx6|}WvB4q=n B월vmp˖:٦Fd|҄s4DBu ,"W(ds_%fo ewcg K c5u|PǥAs49 9թ≫ղ6>'$:4<@e@*y+I,m b\Y=V=zh]d֔>j,[n2w#Q?oh8h5lo;$Bf\G|Xn:dN=i)Jxޮ e∵ڹue>؏M];PuE: ': 1VXSr-LpE"Q)9HA-ΐ`FJX"c :"eF,Ý#CTg(yh˯,crN2 ͎DE*~؋ \* d+[=`wP$c O?ʲ]F+i*vk`n&zFP+_Zd D:O'C&Cl`<[lᚨBR4Cjuѡ*l'z)VbVUz~^3y$B&Zh$XtZ7ٵBuJϭ?Nnc,Q"(./(3ؑ8/8]Y3o\o9D=7q|EUՇ_o(ʡ;(9~7Ki|[u9< sRsCB {+/2ok<5}RvXCde6E#1e2,E/%Rs֠1 zG +mKy Rˮs5=S,u-Gz ɝq HNLLH*2]jHDT2@@.E=hD&!˖M4ShQό凈T+э$j031 bX9R|}eD9҄Z:Zf:>Aq^?"55ߢlJ-N~xIqK%_2O))IXbE~$A?✍b⤑5'D{A+&tv….IKG|%蔈RƏewjZ.\lb+if iKe\]܆CD R쑸 u ч3U4(=#ڍ< ͪnUz[l2>Br `/pKxW^n>N0r}_(TQ,ihұ5Tj|!JQ"feUـ[836Mtz0iݯ9e 1N2v wodBA4O\i~i!=Hpz%>ұuuDЁ)bod}k5_=nqKt9*y(|SKaTu̡jN2$)=ӎ?~ V! ,gӲelk#xYOd{G5 Ĺ$̷N S~|#60+BmCE[0AZ7,qͶɕɬ(Xa\id%8^d ++9{{4֎~|Ln36( 9 *E ;}h[ծXPq3"#&3PJvM;l&׆0{! \_|7x1ۚήw:Xo;W<$p4ƀM@KKGT>l^Wk;ቋb-=xkKӋԟxXw1f)2"6 k]_b93Q /ʡ[aקД囘-G玷A=:qR˽6D ʕ>H5)+%foF<YG4YKKѰSAːi6' 6XYI=^2G5? 笚uWOөŤK%N6x^HDtܮlkg.2 ? "pryǵ `Y'NY1;V^fle9g`yΰMӟ>^)rR3Y#ۡb)a7,] W#opv ?cHe1AL7C*/(]'ָj =aӮwCҚ.FS9Zѯ3(pŮ[_X{o8Jg>L_>ə# mPҾ┆\M?@c$䚂`?R(;IH|bm_[az2un}7jJSfNN"kjoʔ/)$_Pp^Q6_KTyr:E"ADGSb7' h fXvP&h iϨY=~cYv3c9sTECػ6~  mUwk%bԇ>f$߮d{C(> YeRy$4m/43կ;WZfmƑ$e!jg.%kZ.<|*NN#YWr0bjO%BVk2sn^:IB~[/lsS"Q+Ћq0Ә7Q~>Zz-/ˇYh#uGR#-6T{dDu .gߦpsprFt>HLmtL4I4~ZKC ,Fu'ɰsꨄ!.82S)4dMzj{o?>KNaqʹ{f(2&(:1F`BHvp}g0/K<\kn{(r MIHÆ5'#8@.ȵZgmۤr? U3)m‘F cd%-4췹q4MI좴K [3ZbgZu_/Zؾ$Vwぎ9d u~=W2G_VT~22QR1ۯ@ !EyBR>3zSի#Fuπ, 2 D)ϠY*(γ6 EtR" P ILUK1 x2R+Lihj7EL轿i%PgONq|B2)ZYj6pZ8M؁fEkTy@6kj|n+f5w/`sGR?Sg }pyYKk'nSU K:O0pQ&! 5 1s1CB94.%Vڧ̱E܏tVqF5 q^,a-NjMp3Lr~4鷛R:!OVɻD>$#>`WC'[0rgQ{2f"ڇJ#>el&m݁}+F0},zY]! Mxz%1i$.E"CIU'o߯yxZNxC94!Ms!B=1.TgV\t { !zpW`=R)%AJ?^_4K'ekx:dS8.pL bwvZ4)<ĸ8e֏uhϓH{ ɰnGY ٔzoVafoV]ۄƁ#uX4o\'4D,0{.$\79`d_PGyI5l[9 i M(A.gX˸A8.I2(=]d137h1Hc}E39jLC)bxkW6Ζ)+Þ 5 O3"sbUY/1?Kϯ4JpTӵKlx+{w-;S9ȬfRD2e#k(+m 'wFb _^k\fO/ dߜ|#40)}C03xn]Abpܶƞ@~4=WX F-RL>&*·5zh!U!+RHXr7OM|?8e/} Dcr^. *VdC-=}F^SkRks,%?! }lN&!KZӐlYyu!YAyUExw(T/ }"yRhjO)ՄĹ5i}fRwÖNqĆ6`A[)kM{jJ}M nys!to+I/2ibmLtaVnu8vԮdG ui Yl@G k$X BGb~>#2-@' GnS"m#R./DaI{E 3$AS"b¶hsoFQDž+ bUyoFU`h%~[h(dg5ު9AL˔)d Z&Ny :M{hהvJh/ ˗H+Yki/tu$m40# Q{l0ilsbZCP=Q 5[۲N{2aɦV.Zqi~, 攤H;ya>S9 (9?9 z#&'U0aw /ya>HxC+ȍ2zr3`\rZ**"zVjAwᢝyv 88ObH`b[ئUŅd 7<: Nk]E0FC~93_U^-8@4ZK_Ihzn9Ň$HȐNQ_Qv·F[ K|հah!4l^^+6eK?ژ `ԋބyRAUUԴŜ ٝޕKM#ƀ3qGhhz cZ {ge2sbAy {t=^\[hDŽK?6fm}Ŕ&C-SoIcZµ5t, 6G&C"BZT˴8ъOʼn/nn#WV{ Qk+%:Y̰UC!e/vs*..wƤ?oZ⤯u`$*ƃlu:mY^/ [1𜑾BŊsk4lܷ^fDmrNFy*Ӎ~"/: 9a`@֙gU>ɖVdw"0vfe Z9q/f‡A mΒ4nMEO 0Mcbf&bu:L%~r:υMUO!=J|.|OsưzpwR"V-4'}aqD:fb`eڍ*r2g|^@d0雟ঌw)8 ~'98d N?XD.v-7IM Âlt,~JNF ش~:峲,y;+Ҷ)?@n]է ٜ7#BQU 1c_Ծp'~yvTu*'#|< zQ7.o gDv!XUԹgyP H=6!xNf~ TRkDqc0TSX %RR8YHʈ-ӃI:Rdj12kթԎbq\gAR˶jܣ#0*G:O׍ 5i1~0!^`H y7P|4 W } V`ugmOlCfY"#A4mH1K?wVa>*u`M_A>nNx' |/Pb˝}T|=L0]8DC+N<:yӣ֟<z~NC_a$#6B Jqi29,IcrkJ̟Dqa(a·J@/FWȩtx[JfYU(/O y}̦|h+'1:3Pr%yJyň4e1I!SVJ^Ц$SrO` ssoIrdS\h~D_,Z&[lduaR'3(3Gy7?<- y-eۿXQM?Y6Z#EI 0f/nT( MF*>:741Jn[G9  7Ŭ@y3va}MQZAoo㉾>WNVz?ۖ\?/MFܒ,3^W(׭}ɓu7!<|>5qˁ腷* 1 %PJKZІGP]Ʉ#K4$w4RBY)i!i2ݸ\#?M,ZD4uJ&-H GY](齥 ;`re3g[U#:m=i.ATR?ɲ|Qʧh5A˙ ݲQ >4.9 ˏ̍|J!zRKHSq ƩRDlDm,9^O\rZZi辯 =)LRT _?(<ȷJ;>f c<\2SYeWFc7_#vK.QURC ^dMf3&*-)?&,L NL9nbI[|2.\_7'8?ia=}_z|Xg g, нN!=I~sPZޮѨ $?*X dW aZɃny%H%\eMb8u銹6_ }{g\fheJFKNor^ -qo(ocHV jZK|6zF52Xn]м|BG"T܇2Aao$+2='V&&))rGU9 2D`8%@ʄBd~B-x=A4o88M>_lhUe?\ݨ/"4\&G6n'iH#CB !y 2q[Arաeb janD8{k(ύEG8N{G:m⚠p!`ϟ6\wX9nR;OY&2M\ZoOxGsc},U 2.WR+j֢M55m-$ {qcM곈` Np6gc}V`bqxiX7'j?9;pPӘmji#8f!jjyd[7ql8$j5bVDSA{lUAR߂T}4CD$4 /nlLBs1سN跊Xii^]\lw_ޘ ġ"hOu@kU2FDQHV<6:mтnO#V i`3|e~>;K]tU3u{jQ>8c/8U˞OXbG rrswc"P悾uWϊyņQr60$bpﬦ 'ß&|-2hNϺKV=_>fʎL|t32BTŭa/z- W@;&Tc6U8rӗqCnfySVC!CNŰGqMifx>+p#ˮ_dq=ؗv vȇh-_.eD Z?1a4S)|QʷǰעNˑd9q*yE U3c' ҄$KdRGñ_сnI4+,GO>zYD! ":7:s X諐M[g`D ͔1i=#tDocWB .7`DU-.#MO8^er!?VJٜAR2PuQPӹdw--Z{]d*p)Ҳ i2E\mt9ckqA3{*+^`|x6,~JTn?-g֢GV²VJlpb*^{.MV6nb/ٛr~ ;J% DcdcԾ0`'/#{ G/v"6:nJַPB4GdWCRdx~T!rv\ ٠JCE5]7;|tICvFHpEј7O'onZ?QT. "܄BQFHĩB=ѶZԪ{kH|Xۀٞ2atv^pg0!xhޒ͸$ QQSwt=( 攷Wvy'l(Z5 Z3="p0 }+ڔqA7 s~!prZ@G,#9Ś;']2sS 'eƣ! ]U‹p]6 {ӳPt},kQ|ʟ뺪:B~*W] }hBi.aOo-1g s. vQE !STXkce P`RýzTo[4ۡ h&䉨kL&8IM ]e:N&N{v5SlcʣҚ0)UF0{9!#*?1j]z؍ BɋnŅRdm 'DK,(E{Sx /Pьq)]\A|hX WM|%9sj1;5Whv>uC2?-Xm2gEY9 oı^/9=顉d¤"ˊ9Xk{11O^P@Lˣ)}Gw74h"Aܕ֎¼.HOklveis0fHvf~hTh E_ +\N~a/'|PFl /:9H3S,_7q%-fA%Ww[@5kd!Ɍ2h{c~ЉǛ@gq/Tf:$XbnƴjԢ$Rg{BfT7*ՅA|t\2awhDJokAk .< ZHQioW@oYϬV\.Y&J* -{9]$ѧA5@eG6+C p[V,~J}C y#J5!u41]&G5H%/sy;G4/Ykj*ƭ'p_m1 uA=v_8;ݭܭHb B8{mo4ꁒNzzKQ6 nkjybP~.DFп#=`Ri Q\6ڔP o00wIw nH!)8 ~R ˁRDYkkm$̹-Ceu jnDe2k:퀩yiM4d谍358OW918 h] AWR )E %1*EPUE>?Eun+Ynem wgWaEzPׅu4^ Y1\#eyx`K*d8 q#:<Τv5̫1jxtJ^w&?R mQԥ]piŠ 5EIɷda%e 6ˑc^#@w6 +3k#K ;T c0;AQ!zNuuB-F]^y{Jx櫩|OaXEVEi=:?暨0)p.Rr~ MXWʫF"&@LiӜ8ʾ..Ğap2XxkLg{%O_-vo @5k!^>E(L[y{:wyEcI#t4@3b@xT}z‘.8rwN<RN/PY ]lݹnҰζKs`vcֻO7OxN`w%p:-j{@ IE1[8r/;SxB7d#dt;}88m1(GI endstream endobj 1080 0 obj << /Length1 2231 /Length2 17884 /Length3 0 /Length 19207 /Filter /FlateDecode >> stream xڌPҀ NppwwwX !@p]-\>}LEI(mvfbcfH(`cr0#QQimYG::Аp8I8)*ځ.667??++?vI s"3@ tBwwYZ9'֌9@23MoLlvf rvgaquue6ubscj@'g9௔J&ƌDа9Kngj-؀̀`79.lKÿ.m#oc33;[{;l ݜ&`MlM>lLL޺ @ZL`s2s;;1;lʑ/7oeKNHO4{;˿l Yab rpI[m Ϛ% :nfV,p-dk-oO{;{[@og Od 0ZH--or豾~uG̢,/%#+sx2qعXllb>a+kouϖ?h= tdֹ@Fgb5{6ym#iR؂lֹ.oSh6 *A.W*l6 b`˷fc2I4W9Yiq*vN.+͘%֙o#afv;7߈ 6@{ s~3 sD\,b-,"x,"_aH!v[?AEP/EPCo[?AECo>uK|o2O9YQyےz37cFoW ? E~o*V?-/[baҰFڿux{-Yo\_G-dӟjE?zSwz*EaqroY9&.|mf`oo5S7O@q5sqt|{Vf?; ͐?W2펳s\_#hH|S|(X>+ak6.WZ?R};OFIL#.t9斸gjCע3txs2͕wVg4(PQ(Pb5b3rN' i\e4CT{CnBI NS,u{u ,K,zש|46me;qgw8-js0ʷuZ#E?^94A{q #~ bo^2>=.X2BT¶#X1\utPvۄ)c  QJQ18("-dȺG5s u](L9)VR8P7T̾6)D;>Piu+d'ï?Z :.>=jMn.t%?G4g-Obyh=ywe{xTZm8"TM}9E[Qx9խm}_ŦFcʠE+k`փɚ;Voe#L,d5nw9BFVWQ4/ٜ?gxV_GxTyVHG>;ddܮжtqz2b3XfR_Ԭ:KaAnѮ!ڦƽC1{[篫­kD|O1_]iiAJαH6p;~ٻj>YخȢ KF b˿K #B؄؟9 ;tܹMD4B _syspc4"'#ʘ&cyϜpoD" b\^> 85I̽!? %,*a,$hgFFB+x0Dtf@ isYsIiY*ЅG_WNQ&?Pֹ~J4u h0,.,Qu˅C-("RA^^$b!̯鯐N,,Clj킠%go{vz;Kkv)˦c4ZIC(뜜LMf2Ŷ< d=ηR )ތ:%$?4GQ<B^dsզ߈\dZP߷|pׯ3T_6|6Q ?b؟=@,d硹؎|%*72] 9>p0 حlIY!;âB[6tx2_GHQ4UZUm҇C ǠS#₶3uXfX<j_jP7[D?-=yUKޠNk 3OO:b>*o~ 'n׺''HI''sEH17Z;3xT}/X} ]0NMtUS拋[hhc]+:nܞ%f ͔omߤ5gӔNI92$<ֻg=;DGpvC+<shݓ5)ciSNץLJ&SJ=lIUWh\(ROEQ~E[-31{H\8up>e[(J~م2@H :Q>^ZVdM3!H~NlYQ3tG֯%U=K(oB)rB%Ge߁XLO?IpA0LH-hutQtnl(qR!['b?FΥ,y8pZ/$wn1N2ֶ'q q̳_@!*A5p<2mw.:;ƫtZ%Xm?3^!GEC-oBs.}JO\g]KdTB6QQn0۲~;=7EyRzguQD}Mh;R*ix JDQMxi\[U&" i.Cvq,5Sq%pB 26Y?4³MKZʽCV3H<,ԍ6.&4mzkSTH_>>nx֣ڸmF_h8xm K,H ZGr?T$!McW#Ot5PMT-Y̵P\3 {r|}vlAt%y§Vlj}΀nJL=RtM/^ `jf8 '{ގ`cސ9Dv_UjR97͊Gt3+x% U'UA6LG̞ KV؉ ˌ4T|G>_nzt{7U\GUJ`pė-pq]~Ed 1*<0)%=,O4'D/E\xɻ(`8Gx[.!ݤ? Y[:Y eQ[>>J'ca KXkc._wW<-"r@Z/w@H!![LhZp!M|Ϝմ:gFHJcЏ, &03/"}lAw;~eqNN؃UQfwV3&YnP]"DӬ e$I56T6kWf".;  H?ը~ag φ3 Uh$J[wrZOVo|ʵNVYq`F3\feщu>, b)Ef_^%%1 ̵}q6:\õ,|~vqvk\-)0GQdM*o9h~2q ٠Gy-hnl='ln%Ta#sC.դ*/Y8=R_e?8/ݗBLR Tb8JI)UYS~?3RQ6P1%z`(CZc1wS\w,/9D>Y6Sht 4]qJH/EK9g' MfjH+*4WA]fvf'MɣLɂ x1|wx;M"< #"C+aH0j+m;{tEYt&k""'ӽYl`l8U ͈|:ZOAX. 87>ć& Lڊ l8)ខvVA缢Or<X?^Cw+ˋ6d -+a \^' bkb5CS$}n2>2#()SPc/ֹ Oi$lEs=f+j姇S6Օ.fve^Jr͍\HS⡳:zL1ұb)[*9m?[s2pDj'[W3Hsf&yPI˪;'糔[1EAj4$v2`R#a4= ݸv:ݧQF9e*e9=_Ub>|+݇yW`aPԸ{ v,<~k;qvH dW0j^y۾Y-)= ĨV\:cPaՎOE7\d!Ay愓XcݹD? L֝l7e%gL 6T D'LGkx!~s9L½IN;vͣ`oQ4+R Z 1'? ֶ0d|>PcAП {ݿ\I_kSjV3,z5jK1CfxJL w).@tf~A󔗮䢯0S4z{e-?+-1ZX|lӵӠIM)8o.剙nbM?A]lWsexD2'PLw_Bd8;?"wýn88V\,RoIƧz9 }0y֪%,W G"ЏO-AB[ tǐXVfc(13 w G hURW5g\yꚚLԝ+I)81_j-'6-~/qDlK>? +c)\<4hS:lYY!Coj' UJaTŘȮ*4*}Yz)(†m~k*SY1;gbȇLw~|=ҷP)㤪T@9*\@& 5;#|$ TU3 K9m.RB@z2ezØ%Ɋ.Mb8Ċ,i>?V~gblcv,O =j[$#No*ERĮI-aDeV^2E^"6u(Hb'2뺂#-#dn_Z+-h=h$WHO8Cc0Z1+'5GAwB""䌖m6p#J=/5~EgdKeRhSiI]| d^r_q TB|JCy'Մ>wv;U9Qaѥ6ti Y|71[VJ1+} PԵx &gX5"˘+ph:^d>\҄qaƧσ6kۅ7n30/gH7ivl9c5śKdX6;5S`H|IKB|){ؐfQWQIH%-< T!F*, ,Uq1MZE2)kVeJCM.-'cVxKgRYߴ:_mV$!pXDQp(* ?Scg)E'$H#6nPdOD"T3npu?ڄb sm- ;ajzV%_/|!` amD3SCw{^ skD8InQ,15г烚7EU:9졐bΓhvTje,nEV߾avHy[%Ut|Q ߆W9HC>B/~ gbjS\yO6 ډ z%`9sN)vw%?ڙ7;D2^FֺETOI;xaUM=Jcz~} _@a癇IX;nKqa$ w܌4vMd1dhhKekIѫn&D̪hduGK{dXUZ J|91fy `J;4fxVX:(ƪ ;>,YLo4=lA~VTs-oPPxPjgA//MWG_?|'_\^ml=8suؓ'mJ=q+웢-WGh 8IϹ䏽p0~zCSAė/M)}ؘ'3~VW[wHJ2{fK'rSKV=g OPR0\jpPFZx9zW Q+y:|'o.wYpE?L/@4G5#X DB2rhl6eiwwc"٣V9ھ' #OYMsp)&4Ai,JSC?cz)M>r܋='1{wc5^XȔϕx?1I{B+'txL ujس%A5XƘ36ςHw̔}O=*5rpCtIET,Y`U{xXÊ"vazy<͐Gack%r>ѝ1L/p[-w tOq&z 6͏wb'içJO6bs,)LX7_Q슢.MHbc,b&S ~ȾhE.AYOSLqI {w?603(CgXc5'&}DLS$y0W=b__nClMD g*"c\O [ZeH%A(çQ=xŏCWFUG$jMI? ⫛O>e;?#;7$+ߢ2=Cp&"|Q+0mSmelW YgFK vC yaN^M˔ k?+M+m]QBcTYԮ約F-^^9 hL0jԲ` dɰUW SY3Ĩ|wR&Aq➔s8x 8+ {, B| m:&؇vLnӪx$d_ĦFP)ܴU}zvbd)R 2b"6`s*w8Zt^ r%Z9Ub2[eH` ˷`sc(8,2Wy^ԳNfe^Btu:%8p@P'cF30 $O9@_ҌI V%]ɛV2uW{+?WVLXL[" x5uS 6Bd|N3OxYkaH'-ϲ\6GzY{`Z%YbD)WNqBcX}=lb%T!:UUǯ02IBN  PU-y^gHSR[/>}јXĠ8jA)jEf-D򲬞SWuG ٿe-[} @S[{!D5X]EU/ %nэO W/?N6˓$⛐3~gbƟhH--hRrp?Tڧr0H?dhAAP[ *b$Fn\ؑ>hOi $Bgpx C#ONx<#6!F~wn' |v)DëS*4|y,#KGoLz6fGdl@dFĿRޜ-UbnåGkaIgecV=뀓GjЇr 3Ӓ¼ ~E(W>OBpt{;w_RkM|v /p>eVcQ  I\H&,`.N2lTlJ >j %G}phD7!he9Uø'N8FH@S~Xdؙt-Z6٘v^g^ _B{AH*"kq;nY* RB"E[)5ߑg9u_ʌ݉}i2i{y+7\(]ތhwz!7K0[X6=+&ފS&aFyV0ZoOkm;8 rqMzpfcaܱ˥ H 6x5c^Qü"Hm5S4DAv|uFہqHh6wc>xs!J;Vv*32֪a/,|lM7m&FmݳH@1ӳJzFg&H!޷5xWzNN_LEK~jeۧ_>nji%d]j+&W̭j+Ї%V{QdTdш[VLj' a2Mm^ϜWC; au%4AYIXeBX%Gy^%z-Tx򵶣eϨ[$C-ѴG~9$pHvqKCX5h kaO֪7RF5Vx5b)] '?A(o(e 6ӕ9DR8oF%;4ͳG(,u#IdWx[͆M#, Q+b'f= {"=&c/F/޿_+~P–]ߚz9@{lp<MQU3!5wcFu`HdyvSalql_[4T>Tə j6l}풄[&Ulo]I\ẕh1kM$nDR1Eՙd, -G~w۹TQs2^H29HH&q]ӣr>)%1qD))ֺ;s_؊p˗!2՟b&n͍S6γ'͂V5#er}̈i>Onu+G{ƥd{ ɓR8uJ W{q|SCO6%?5>qc4_~l"7z`SxtSheU"ac8\|xL7Ywt"6NܠZK(?fߒZg̑Jhͯ{h)ZDPUXU;WC NSj2 kWò` 9h©vO (ql{_.pzNf* 1͜P~AvpŠx`Ec@XLQLl!rOTeq ';)NqltLR-jۧ{R-{#P13BIFCK41}uK/Jiy! ˜/t6;=g]?W'0x5gBNEjHh7H2'A,^ [Cۅ}WThFZFYó8x/ zED~OB`$_]B^I\SUb:W+<"\SQJۈtq$ʘ IJ m-ucTaWfz G v^KdWXSzK3*gxUm( iI7&1$:vx%!鈵?V7L2>yU}L 9^,lw@?н}zO nŜ =0V@] A &JHmt G]euhh. @-r|@d=Ѧ߭=ͮ2L/Xkrߖq'KcPc=uU1ҁdU mǁ0?hd׵+/5h&F5s;,N0nPInm4Lf{N]R1mچGEQߵA(݂ Q/NƐ*,J ]5 Bw!7ػ@QWj9u^yJ҃vV&p*2:b@ȼҕ"D95oSpO f yTܶ5(R|oFL;>?|Aoܣ(Wp,UN#}S5 n(j39H^ =LM]hK!=B);ZQΔz@ b}Nv(ox>W+W`܇;t ֎\ _ʰэ-tkPMu} )J*xCs:0Owr.Q !Pޫb  M,DL9.bEP4T_K}ZNOp(;`ݎ&k! 7ʂ ˠ,ΕeD.\*'+x_[cm&VAVa R%M]M~/ (2^jϦK%ΨB-@WN &冶.lB޴F֠z3!XB^U3Ϙfti])G(\sϓjΒHW:G1k{;!#Q6'^Yh7E-h2>DTVau;N|[sp5+x E ]_*؅4We C#N[_$ X{s!{.I)s|$lfȽmx&Uy [RJmD)/[˪2Li^GH?ۻY\FEUːj'?]5)3vr ;#%Y .?pXбSP dh,]}kYKS.6!ƫsw#r5ԀR-d|D>IQ* JNT{/8P!ۨZzn>`>!!3ٗ.B_& %.\QP ֣Nd'k}d"A^++\+d졲h?μBR2MTшI:dW[bJˠ+2+/Mk=:֣f㯶THHNF=3Et"k! p]^y,J{ 'Qک8JQX.rһ/1B˾/FNa-[H?17-i*>\J?vӦNIr@ﻊ@?Q!*2>zvt|>+/X{š)rѝ GLZxYӨ!y6nħtL 7|ŷ:tUP=xrb3V;c,u +7;4̈́+`i8[mliW󑵏EJq1h1Wjuܘl03qm~eC<;N`H1+o 松hn ~#׏8#I^ < ]L1B3ęV=8*igDğ4P/a* A,h v/!l#%}iNVu !=k. usHb.~0_Zb"EDNf-v^*0Ѡ-CBrj I0t>҈gyxSvEoSGRk3s3|k3!p#wH`*H9&պ*BnIͨ&AJX)E Y}"WQ֠6;?u.@bXlڜrT\%:jpT'$.[P%z@.Rh &k3wŸRܶNj4,b⒆٧14a#t؋bUu5h#]>e, `G *uFD_/⻉\hY?~kw3Ն?#dTjWYPqӫL,sIfUpG*|w&+j}.N|ѫHӊCT7 gE@?6r,\3He3jJJ.l;ҕ/9ԾNYkE_t~hyp +1RZFܤZ C(BN~yIwS~ڱ!ܳq]U׿%tI}KT\R??oUU&g>;nv4Pܫ.+pkrw̻T%9@$?)] w'׳R@QtOt8` >tN]*FX,Eq^AgdKGְ VMV_ PAa'Rjhi7G_lWb%cjH+䉢blEmGgs IPUٳvr=+/QJ# '++6my`yf;ZΘ.Ϋ!2" 2h lZȻEIo3c˵Bw~$[a`}5!A M썲Z.Vexî˾ +xZ?jyOI17ҿD:T_ C0UYBU{19/AN 媳qF-%!+6=S%w", endstream endobj 1082 0 obj << /Length1 1976 /Length2 11986 /Length3 0 /Length 13183 /Filter /FlateDecode >> stream xڍeTKq wi!w 4H  w`A>gfN2sX]{ꏎJ]M l;Aظ9*Z\NNvNNn4::m{N; vCc2TPtwp99ܜB]2 + ;@tC;{ll!Нh`{9@ 4wCl-Z`K_!_B n`W1&V'b ]=V;)m rהi @@@'7"w'++?@KA tX_VO+斖`Ggs'o )C s'n`zssTw9I 9Wf r0Ѓu;: nh'rZBOޛGlt '+JrwqdB| t,m9D$_:}kh)@5}oBX,! wt0_ u+ ` 5!@}fvr-As+hS?RR`//7'%w usпc5 |=m cݘWoNr+# kv@A m *@+*@̡m!d6;/Anr /:biM5W9`7_W 栽fiNܠ{ mUlWq]]ͽ8rA N`t Z?ףpH5/pH&op&op&:H&n1-~TiB z7VuV Bp @ 4e?MBЬ(?ʀp<.`]vo4?nw 7C-]]ߗ Ծ"@/%R$̮!Nԓmg_ٝ-vOȾÕ`ZX yG#A38ݠf4;o_D|P׋9lo=&~vHڑOzcDj0:YDVԭ>#«Θ)L2Wژ 6j7JbX(01<ڭhPbI*9j 1 &~D+%i29G|F XMڏj::9}18#n \!ѻA2 E|njrϘj1K?4Cl|S|s:.ke툝!d XA f3;"4.U]q&P6bf(,!^Lua4Ɂh1h,?O)EirOQK i$9b q5 5ӭ] 3RBom96v-O"QǼQ09aY\q|f'#b6LTr)$ ggםﴃچY$Y'Ե?2p'`! 7{_bgЇ QƏHm$L*&ofּjpnL}S4r+ z㎚T̂> J<}%Cgˬa:=ȉ#Ҧǖj@Mۈ}E~V13Հ .C-kQZ+,j:Qc+P|bwRZ|A#TˇRF*غ[LWN/F^646isƅ 2S*;f,"Y]k]L]Ö[C74I}zN ~n74jL®zܷRzkio.n.%cyU=Bs+'Wf@+#-0S2O7H\4/űc]Ϋ]BOk62Ֆ?ezgв.2NH2} L|?ap?NmԳ{Z^pXnC)Xb({Ф(C ;WUU8//)_;>H7B*R.op^ H?n\z 1U^Bt{q,*[5d)=vZ Ө%3hr܃Qq˛DF.:1SCij wæ%˙ _8f»ȚU;ik*,a:-cC")}+ $L5t~*4ֿvx U~~Y%rx~RZc߲HVh*_3#&iE eX'8 vMN1;pfA?gI:c,9==DO D?a)Irvؗj|a J/)кϗHBNCh9矂kNTgf>-rL5?i7}7-ߏ̾24zx=j`Բ! `n;IsF>;ɾhr^Uf+0Y=`.r6YW_QQ0v4]VKk}J;]m- K~D!'1 +Ɠ,GI"a^`1ö˼sŴhfXlz?^w1h=WBUќE&>S>9`&2)ƺrr/ŨSeDk-tXe6z*4ߐ -'v2 ^P}|ψs%#M>zPv,}철QFZ#3#;>/!nlw&(Sq$[ccCLdySޱNVy"Q/YsFoL],*R&nL&b+"Xt-߮Tϲ( 9ʭmeA[3bAdwSp~z^CR^<Ɇ[GM' .f^1EՌieot8 ƕ&mRerktb[7|)C>3鰭Lvqvc2+:h^"?=Q_8`t6 \5_e޵8_idA`=samDxn!LX fݸ qă)S)H_<-72x"Р4'Ru>4y PBU{s+v}D3H<UR@gCZc Xwo%TG ͬI:oxf8Y?L7B y0TAOL* JB" Bp߮?^aky[a1 ˒A.`/.:q .X 4V(lkӣ@>SXơY6ܖHx1hME~+bWj-c'6bk1D ?wc_ G^rB>S `7*!k;w^%4ηsŕ7jha ʱl'Y_*z'A o\OQ>5B;FMK~ZE9hx:/Sin=Zq^=۹C{>NK8uDz|T\/ iT<,/a G"{]`y빚th,/׽6<<{:2)ugoZVQG$q O8c+ɗʼnV<Y-;<<@2ādu[1|~nqs8˻XlV3LhHIlFO-^sy {F.mfGDfؒTL ;Ri,10=~zOi\|_: @Q=zpR(gLZi3s!^t|)~C}EqB5Z۵4AqNf|zl Xe\ܜ1y>xާ;).{_cfs!HuA|C9cs&zu9YH}diP`]?X̪&#zu%/|5v96*fX'yBr w(~)U\IQ¨3|F؄LGdfSW5(CKβG 2CءY1oe&"&3?6h 8B P[c«~3 FFLkAq@]pv+OITLB#!v/D$(l?@ٍ/obIK`fi}xL_qz\Gv>hƗ6R Jha*@Wubپ˘_ ޸|NrHB],6B?E6SE?n4kM~,5`zuMUqd"jiPOtG=eMHW$pHhҲJ^0yE" <;H^d/(Vg!"\AlTߚ3v]pl1I0svweU.lkfJ9k+ Z;Z "Fg$&pH1#ߜ_W,.A >7kĉgR)sZ,!`@JUݪгE4J$ <|nmp[!&kM{_ˉjEyC3ٝ[X#R9zLy[z[22Jy煪L0s A.<-t}B/RКP%Sջ}(i@ݖ= 5d2W|X Ek̗9֘1 x>e&5l 5 _WE& BVV@/0;- jjCIonMҩo@eրkB\dvta:iTD ;u>y\pOT efא)7Af\ αC`]d q &1֏sZ@Fj`YdDw녚kˣl~[Y:9~B0W$r[oUmNz)_,ԡ!WMՃ<\>gn˽ 0-txt3B9U^]U d+~HB+ vjJrjOuIVNZdSr65T];%iwr"&M(/b9]أX̕jTR?.T˲|EƘ-e@MOhi/g)>e*3gwd_ ;mO~ko9J6jiaVʕȒICq~ؐx{ec1VtږOAsqDlnPos@Tu["q#)[cdH|(߿F*u wSL(乮& fq͚mS^FaxšvP\=Җ QleLJͧ{6kx76НElzIq!Vxy;9fѝc|%eZ#<[-:/BBL/X7*ѐ/QPц$}F{P^ͮ`\jm &GÝ4j$X%Tj͝J}E}\jb^nIfWx\gFnLuБ&5{LGp[mGlv"wꢰm|;lv"dQH5{=M_ؤF<ҬݿS R]Php -H9vXx.[ %--P͖=E ݃zppqWJP/30urW)ZvGꇘD:ʷ/z1kׂ{p ic +n]ߐ7Mm.#d{D!~)*Nu2$= &~ _zSEDGiÝwv )V'ȓUO=gZ”ID˲l3{&cVmC|b \uLdێ[qfg \ V8mS)?q=BacYgM jgLB,9sOHgsLIզiS,/(E|nU΅i1EYg$gEHc{mfu,5o'p)ֈ!'XUJu3Yy'!Z/vrM9|z,!(lr?rݩ`?)Fu+j\AT9F#!J-YғϨLVeE^ãR?vsa)Stci~X׼]QŽ`D/vjzmMڧ8s%nչAw6c"ߜV[2JCpIrKgp&C0-Ghģyt%qrEj|ɠ/ŵqhp,S,0-" %j*~Zo$Z'w #&c-t)z%5_P)`U3fC#"Iu#6,FV\j! 6_C #Z1U'ׁvT7O|[{B?6 cHam4ŴiEӛ*`MhO)G2)4ARppgZ/9Ӓz-+/8~G - Hqǖ4+z'{?h,O<2X%!ئRGM7(*!=[Jn_Pn*quaNUvROZ|g4Ʀ74Tqr~ǚ8Z{)Tu^7|>_nvzz\9]V{n\!bQ%2R{]7KJ{/. /QU/6Eu#MDd x`5jkV$8(zkffYګ&R f8Wv>ҘjG2NorpuDui_n+/ORm3įokE,O<2ǖYQ x?录f3[EՆчB!Zހ&t=\+n'}DŽWA4Wbs:Ba$4*~m~+?ArkV )YYCmIp=lC\D}.(dmO5Adtȿx{Ftl䭥6l+'|Ћ)3\M9&}@o΂^q\D`!)Th$T&`˿ /KVdY!q]ɡ^r{NǼnW+wX5Gȝ8 Ci7c;3 Cr a(!#.hsUE2q2QCq}A!~~S~77љ%q"ߦ yiȜZ*1QJE&ޚD뷾ɝ6#({1u0LwDGq徦~aXS4ΦQfS ,&5I;M&2+۠ͯPD>;d9f4rXeŤײF),~wY%g#ph3;$JE UOji#XѮ0 %''>)FO'2y/Bl÷6zzW؁ 5. dD(˾=)-5\^{R ʡk(4ޗ2:={sш@XZ #RϤ-:{~|j ^' #F-FbyH v,zga)zx邷e)6ݸ.vC 8$/];Yzߟƽ4yڿ?yX 0U(bp4fݷŠ Hz= (fo#$)bTTQmG5#;,>Tw, "6G g$a`сG:[{ W~ՎӜKo"ajL~5;cلTpQ=6=vu9 'B-I( 0=0+26T"%EDS:άn bZJqx'xM wʴiۦ/@8wYA4fս9x 2zzcfARnNgKagc4?~IbFh)B+EY)EฦepޝBOÛ@ 5XDJDU&9wcHܩ#AM9 m򛤓h8$Xg5]w ]%ʽWđp$mA>O1Ρ0-<^ [81j0iSnA>GHM;ޮ<>/dDJ̱5-p^(ټ?dI˞}1fmK&4axQujJAtTBRwWG᱐:4$7EO98ё  oL"q %2;"_ѻXx6k ]:)z'-H9owLS.+ނĘ7DSf6cF~%^ LRO}o_G"kǢ6(4E,F&>˳.=19dA&#(K&hp.ω*xʅx$=wr{w)\Ūk';Tafx8EU#Sixpm>ȁm7 xb)I|tܹɭ>q]%՞]>}9|\QPvqj*M<%KeZ7&moy9pP|1o[|oY 8Tyhmc.Q]&jo)N/<7&L _3Iيx ^1Km}=0DSPͶ0xe7V~j:0_f$jjǾ~0ԡLe7 p󦞥G`nBvzy,=:(&DYs$4=?ސoRD#"aq| ӹ]5x)ZX=zS%?k\\8v`xͦ1G8{;uLeRE;>v,FE˧:XH+=>=G^5-n΍BS%O/|E<ۥ s ~!2j5Cv5 ]tF䧛[7 *` ׁz,Oj>jՙkm2(#m{(BP%+5V LGr^uKm+|ax1?uF&-?ookg*7WiUMp>7w.W`4QژVJwk>pM‡LsH}:LHL YZ+n3g |L(M:IwsSn2ZK]IF'ymF׃70f,?I:Nzv}uj :1> stream xڍwT[6R"C7 tw03 ] ҩH(%] " %!)~csZ߷fg}]{_^aa㑵@0$?/H /$¢E@B<P8L?0eS#Q@ 8 Pt~ ~Q =$T0EupD rܿYW 4HG+-ЃB!H`rD"$y^47 E: bBƋ;Bzp{7 .P[ A<Tu@OEr~?ODPد`- { RRE 0'삀^` :P ̇!~Am"N !x?Sz@lQpapo_+{(vn|0'DEeA H $@#n_Nf np75$jA#^ OǿWx @0k{@}3~7 0࿎OIDX;>??# Qaq i?mG Mu;&E\A [ԃ_!?;Rtqg `WH4()j\ *H0J 07P@촡H[|m74( G@-?_>lQE_.J=.P\Qz1 #Q!j@L@@?]_Um==PN/fZkKojn+TrV)Kͳ{~5IO0s͌rveړ%#4;gC>Y!s)ʹH4Ş%=hjDZ"k3L3$NרּUSM(:e1wb5bscE|1Xx n 90cjkX/b9YXŚFi}xp2 ZHTE-͵8o1!G0g<-Nx}:lI Ec&sXsA$qV]66Ϊ3okb.YnCZSh9iMX{#+= O"pRMG4sAIz [&^-pz^&3c\сi'%m=oD+Ek{UZ\]K-b4'0Xz#ᬉS:Qqˋ Png "eS?)<%C2M@GH-]D)מjZF!&gNHݑkN4dRyd2M扅}Yk 1tmb#Mp Gգ9L Ӹ^䉁ØifԇGz%`l恼GL{?u~dٷZ* C}Ce0#O\鶲LGnKRMz~9ei#涡hϟ|sa>9ݡզFǖִ` r6el:&cВeS @%ӱiGHC b/VD~"J]VM$Q& XsWc ?J#OYj1ۯM:'u+Ew"&LBs 0ݰ>$+jDk֡))O*ɮZb19+CoDXF̽GsV߰  }Gjd"L^WW/.Zi!M9΅Md[֮@&sb}ApP9ۊM,IΕSsKJ;w!\#-)%tipFT'݃@f & %^n›W.rv>K]7$e%: :fSnTQ}i֎L˱kz]#7{A" l81`ڗޏ >&~ʄۡei*PZqՠ*Ey F(A>+ufj\i{[ ,ьk;GS'AG)] 'ҶW2Ԫ'(l- {wf4 ǁ$1_N a*`XwMa4!d8dGZ 'mu&G% 9Np6~jR\剏˜Jh^Sp&S*>_#%ӼタJM[@(L3Mhcă;?#&$O3yj!XPoᡘC[Fi7 ~bʩ>ogNwvqi'N/45)PpeXQ~Gbwؔ1g?ZGQ'K~.YNab>#|Xͤ᲎o79WbqנGVv$uW?sqY|uRȑOq!k܈x~?gd!U#y)QzU679/^(K88-sAYav¾^5`QnW-eAh?G%.]S _⁋9sn' ?=s(o@␡GeicK48H!eg3n.is5A2{ֱ]S_6S צ\E̫Xg#|_s-21g Qf^&O>O6B2׵ȺXp<Qj$]ښY$k'?tWtymшP4==v|8Zgq1~y.5m/pUxl: YEd 䪆1kr0F mUϢJٻ>ŕ80AC͝a,*}lU0SX&\Tss#-={,^cR22y;} 7toQ%ـ]ڶ0TŜ Ux1)vCF MǘN2H'ȻdșK2NNSMI-gq "8hwTge OZ 7!yBC&̸,lǗwW"mJ7uY*_2 V#H%#- u~1_rb*s roF@cU\? *07NҶC,f[ŕ !+E]Ŧ@mXFuvOG>b۫\[-a#ݶG.gx;Ǜ7SKU)q|\K:͏/c:Q$HI{w?dzjltoc~=pt>p)UD,~Qg4&H'xPnk1~D!t:j8tśΪJ;tAcP ƴ=}<6O ܌~w%d1w{oƮMf̤FyUX+Zyn|2ηı4δA%ޑ1!Q_DH^K$]ْ]> ZWW͎ ż^ ,!c(<` 5 GnEΌ:S7CS™R%<ܵK.{˲0 zx޻ "i"h{fޣ-hT I>oȝ9jSōdcX~Uk?of-v£1~90?Y.y$Q̟Btz~1ó?Ljڬ;Yݸ2 y@6g`6Bo `geblK շjvL[̤8rܼe OV3꺣bs5Jwdvc2B7*6ψ Hj{);zByt^_^NA9H~CȳQXe.KΕ!ogaAf+^*h(>; X2 i?9RϺc;`v0A|{{P ޣב}@,T_RZ Z[frr*RG {5; &_&;?.`O^j㠻Y3|0V]Md[S>]k$iQ4/.[Ե[rkbWe=%-YfP0`?ꏚ̜ީc~YDH]5 TYȑʪ3Bo#NQyH]^i[[\dٔ>q]P>>UtD0%FM4K' a`t|I3_w^x:|,=s^޵E]ӎɵ V3'hgG6LtvbigoUn *ޤ;ȾFzG=h"Ic2QؖȜ 56N[LŎ:Go karj.t"MޜcqTZ7u|b2KЗ;mC^I|>HUxҌ}Q%󈔗Ӿʨ-zc%\+KKa52&ɷN#̟E<UB}1T*/5 >6#pvw5Lso}Pp;W5T?ox|8 _#`#,C'GlGa]%зa^ͅ:L#&fRcR[ cGL\u+'aNzoEk#z-n;X HDm@Kc3(R"ҍγqKXW$E˯ˈq̂>vqrTX5zSFZ}ՙ endstream endobj 1086 0 obj << /Length1 1406 /Length2 6162 /Length3 0 /Length 7128 /Filter /FlateDecode >> stream xڍx4\ڶFAA c3:kD{DoQDI$z'B|}9oZ{sݞ,F v[*Jt, PD&`g7`w$;B۔A(4PhzB"!1)!q)  J DKAP;@ ؕ>PG߷.07@HRRw8@₮F0G ()pwxAQC  r5;0Bأ@!p$:nq4z +_ѿAῃA`0P-F@p_@ @ǃ$B _3 JfG! ~ u#:^pWP1<\MP7_6 @o>f ~W=z H"C#VnHiO7thB\&#(;_YWwG0o?@a>!@U@kP3@.@jP;/t_xTzC( #_Ot_>M.ZC#~MXT rw UiMfB3VH h#4?& AEhf׿xC tz/ϣ+ }Q(~xYjSnϗEL]y? ^NSCa+~?v0!ӣ I[b[r&^lRx݉|( pѣ)vnc>`a[E Y<"#w00| ;Wln9./]@Z*W%w8i*1G (zTJ[X|tA[ GR'#uYܞ#lDwj٫0Ά2E`yLܺ7:ӈs mX'"_&^<~($l*RQL:lox @AN1|Oeœ9~]POmj*8#kVb{2S1Tˆ;>7~:0/[SMkI1ٜ&Fm piRb 2Wb#/dBeR%O>LR6؉']c:@PZ+]NMhvWE<ş&6O?wyҰgP5nraCƛMo3 !5ְ"XEchR?Ue?H߽gľ;`W ?$"U:A~؄QDDY}#LNk`ےis YݥY/Ek-/(DU⇧Ozb|]{O7CtZp,G4Xόh_ ܩj)CxORnqv{!..t TRw3[1O~pgUoja: bR͵=,)]X>p1x Byl2e8vaeKco~dʎOlef)o\_E s*, ~%ofHӉq~uuYOfg #oIt3Lbq|7,Eܝ˦ӏm!slM$`Mn5k,o@Dǘ{ uF_S<1 D2e>x?dWe׎OQX EMM>eȂߺ.\?閅`;#;`̭Rl|4]eY|#=EÒ3Io<{lJp I&wY \ow'ПwK=Lտ9$LCGݠ*M<8Hvʙ:0 \ʶUSce,y|M{6\dKSM{8{_8+{?w4D.t!t~xE@Xb3q8r2&[[}Ǔ\S<\޹` ԾѶ[6:#׏䦸'9ge(B;Zs*l Pκf ovU|U K\opkqfZxpuֆ;F ~Svs+UUXs EOf}' yLoSTq_/`%o V1Roñ!Y JG)- E=iMˈ)A0KhX ^K<,DĥY)˲R2ъ1_GhhH"Oak5qlLZBm''n.\(a1"+v me6 to☆I>X S0b i8WT8-VÁ4jWݢAef}æjn7/+Aivg|1T$WjU }wi18N!d(O5i@{6=3^$P4/U06ĢBCoVVFN߅# ܷ{gwfSz3>hkn}V^[H!<,rHly韍viضI̖~pՔMlL~/Wda S\dF^W n aQ2¤y@o-4ajk +БX?dchO3Q/_S|cs0(Rf@K ہJA+u S+9@~^86$"E{]u+f~Q( _p{=~0L¼fy~^ SdaĞ+}oW剝0p/,L\|3@s5&JmL5iU$7I`Qx]3\R8ƁD+<+A+c}Lt57[ )`⪠O|8]v2MKtb/npfdcq'j-(^갅1>se]spԹGstCraUDA@mO%jWj&#*יٙv5ؾ9M ,MhtWfAd/ضTǷ_0'uNJ`Q KoSǻ)pъ~0ӕrn yyC}fd| ~z@?|$/W&B˝;b4j?Dy{%R#[k.s?*7y^zjrڦ5[>e VpC鳴$ɹ,4ba_I?0.UŪ:PrZ_W耡d-1 6i GtrGx>-2m!=g gjZuOt-5l}oo~0{|}Ь&g۸$!xJt @Mq灤[G[]'ZrtE⟕Y}2$dN'1_ SdN]bN/!-b\ӄ:3x$3iuh LuzVkT{m>8֣A`|dqCWZ3&&nouҗRz<;Nui &e7q1Ox?jLiY+&eߖwCVs,#^WbzKOsPÁdkeudEMUocL!Yf}6?M3΋URswX3}K*:_$uI|c^"7}(W  $t}@t8^?Ͷ317HB,2ඡe'DBӽ/?9C6߶ UQ`&9<%5; XxyI+!kaO& |lqe `tޯ@+S#刜hc׳%mt`@.^9A(y䶆ꦔ\*e>Do O$bYBO\6ҹsؼ3c1u Us$vNs"&QvT*v~}VG.-#iQy>H;p8ɒV['}ɵ*ndŘc} {q'Ҋze"߻xԅz۰ؚV4nlp!?'``{8$_@mg:HP|TM-& ,bۃڶ*lL^bzk,sjh5$j,#B7{Fz~~^KE]艮oyLDcXE'Y?O~wp) Wve9dvVC( o~|5)ïyTCF)MZ KЫ %^!l ~0M*i'6S{gxYڼA5lC%Yv4¿Q16I jc],~3U-݄JnO{F 㡏 kc;򗶼zVjOb^Gb毕Hh#佬M3{,l ~dM Yy{`M/sQ'!ga[پ>I3l3v ;dp|d6d/7}ݴ^~Ы.=K;xh+^co=/|occF(֌sN!*"?hz_ZϼJ=פR7{)LjXSO6>sADZu[n6\9,W6CgNV{a<| XP4[v] oY 7xd@D/x. KqSֶf|ڴ2xMwrPc#s;$yb.=a}Ky~NǷ1"ѡAPpSkL?JMљ,O6 EͽKf%20k}w}:xGG Raqq~~"~gKf[QƊjL`HL*)P+xC/>ӽt_W՗`J[P{b oq똱 =NΤa4/ed=ɼFK{ys*~ب]"?~yPS'ߝCO_I{i0b}C;DI 7nAk^nm4x){V3/9rEN(3ڏE?|sAcg3+UӈGKB!MS`9~_@gKKVX$D8X0HG1%RG )Y灀3/)bL#m(]KltV凐xWӇJ9fZ"/!8 kDKeC.U ̅iv qЋm ”Ҧc\^Y+4Ĥ>tRYx9i" '6)Kvk3gVӥ&+iIFi+^Ûe'z[ ـW7't(mHXXؑ?J^4Un8j:/ݥUçJ)L%g7ȧyHb8$:J)rO=g. ?yՎ gfJ-h endstream endobj 1088 0 obj << /Length1 1481 /Length2 8465 /Length3 0 /Length 9458 /Filter /FlateDecode >> stream xڍtT6 1tt 1)")"(t}߷Y7}γ3. "xyDrz*<~n>,ff= /; AEs6y⁨;xDyDyx|<<""D  @ñ`.n;{>Zج""B2`75 P!;Z0k)Q ӓ 熹Isyܽ_# @mlaԇB\*sLXفAa>a@Ѓ `b ~<;DX5`@ ?ܿ A~߿]=(u7e48n0// O'zXg-:D*U`{@K\0B7~OM忳?);9E? gߌ#@0 ]u *4@+#Wxm kT]9A`-y/ÐY;>"iqf?UZl~3 pH06`?b0CG- Ŋߦ?w@@^@@r^`k)XCehE '!>ܞG r132m?b.Wv x͗bDfm9F$vj|?T[[M,6vd:_=O9]Ofl+ԗdɍ2I!,̏,\*[!3>Ѣ?Dq2OpgFz#v`yC [ISK6+XȑF]r jw*2XŞ~Md-()Q"P|5Xqgh%BU?s=xrxZ>g:q48l@NÈ N|elfzk]`<g{J"lԁk`++Qpb* 6{ec5BսJ*,ȱ۬G5JR$fZF` G! 4fU(>7?!)NaO+l㣱K]cͭ9ä?%FV?_~ZYUqʔTub`:|v.#>Oϊ ,*r+h?禈~`T(Ĵ":ZN؈D;S[se*].5Շ4H%Tiցv$b]JT$D<&lLCۓFTO _cwfŨAtBFc(i>=حzɧȻ0ǚT\ZAO%gK`-*qn9@s43Ͼ\+q{sPxQMVa:$Or~AL&6IOi8*c/\\э:0q''q l3O2gc^,N(*. C)4479ovzUXt^4!C]r!\Y$QNRZUh;%0p^4Rrp#}G]o6T 4gl5b:r]):2G=@;a.E;@qYG/@}y}ꕓx^gnU^-1YIo0NrSjOnTLu#[gnUj|Kao#̈́s>}٬U8:>4Bl1S$ Un6 P/#9#L@[ԽWg Tn"l Cz_, 3Ť4kVW 4w|~g;ĉߐl u B|LD7vdOrlXY637EYg t5p)u/?՘~ '#7iTԮJLT"?Zณ\@!-4d Q9^Q9uɔ9- P4D/">:+'w,4Rbpao TdgW;S~vb#"o^=}S&)bEgn3ӗ;n Xy^ʨ4!UeFiHq՗mMO*2$mī]Y;-).>g岴",]dKTP  +"NF:?mu_4 'ڋ:<<ΐnM!H}ɏ0 XrN5OL*|bɴKf&hE47yU8<;tJ/_D&VKC|œ# RYSz.K-@p[sw+jvƼ͸y/#s^ln"7#Di^k[RpqK",zJ@R렪eOwN Gr&첏;mܵl%~RC-3*~/zSO+.49hN-R_"h X-=D]3_ÕU U} ?n^V7ɐZY!J,|߬)ō^㟎(zLaK QPwO2 qKp\ҷ97*ܐ}|q-\^w)'`6ϬEԮ| TENV]3L.^Я,K$iOc&>~PD uLXmG{caDU۞CdP4*B07o\s} Zr]"t_ulژo^c/(j[=f$r2[L=l"»2°|a7z]Gv`KKwQIh˕pj>n/1{^/SZ/$L̳h^yצ#Ek ރSƥ%yʙ@>p yv;SnTL >j2:̧%6#~W5rF|Adm2?ꩋKƖ6;j R4HJl|C R֬nJ.?eJ틞U+ء(C8- LHư(F'>].,@H7՗iC VXzj*4$胸CQwO5?08oudZTrLPV @-XUX\ HF%Z0"O Q#C NEx$qݥDJ@y+jdy^5X[[MhwxH2m60r:Pyg╀5aBjgZ񬡞]Velٍ 䒯cp2lCyZ':)7eFa а~@Svt}֯G( ܕ{rzmz 0p'ޑqKm Iɟ߇sx.>❂Ւ=EW)tH;&7L` 0:dBjic,%LgOj{ӇNZe/ k1]ށ4Sdo^5!F >+GqOڛ@PD7qe@dc\8V\L[Y?N;y.*jNxFyO|-w#g3B1Mb=Yر=1)o#^uWsHϢaϓ_zV ߞm¡BVՓ87٫sh R[=Yo@54UViUFdb[nDWƋ%֩_ZlzxzR[ c-wLTꄐP*V|=K+& vR6rrfD<˙JcYQpN=Rr(ʄ+Cz aV`Jq%QT__bʜMFYݯ_G͉  gE)K1:3a^[tvtNn#T?[Pl!`3Pt?a32,N&Id>&u}vIeKO-n`fkGa˅6?:fWT#XۧBQ!4ԓ^\vvŜ"J>Vi* &G?,o~f CȋjցW}Uޣإl#B%[$PSSewχToz3%#3;r'ѝ}9g4~O9Ήxl]s/)G6J)(Xwiȓ,M@ባ롵(e&D2ϒTMSΕ\OdgY5Rm?!",XZ*KM׃S2%3[(l=$,oh )7k&2}7|FȚ]^OR ¬ͩ\^5-ĜՐ:hZZcFyq8@ 6{%fVk6j5` ? tPt lO}τgB*\j~eMiCo%;2 SókU^&f%is1l ovb<ĝ wEa#hL,+]{Y*%̻_Y 4tW'ϺQ?@|MKo 銢Fk\qa#8L}kݬ B~.i.m\A&JWZ0dXB1Cuu*մ YocdpeI^ιv,ܥ%KA\='j+ [` /l>Vс k4g SF9,8;S =\Ňڹa}Ȋt0P;¥܇3 Ra(3G ѕ~:eMi<$8$!!1U~,:\ς({+o zTin{qjJ%vWjYJ>Tr)Md  ޙH/ԹmN;ր%^lP@1LH4qL4(sI#'v>cAjz=R$܌,6LCՏ'o˗E_+6liy٩%'rsALۈT(!{f's2R:oB~k&uz?rˉĹBިSC_'{1~wDpfߵ-G[cy x5bRRh|ʭmÆ[4g׃_ ΐG'TA7OޜhPV Xw 1(D`{(F>=Z dzX(wL>O )gJRݩRQ ceWϳFyOF;&3F׮f D{1kx7{q~(Ծ|CŤdhx/qyi'TtѸ_Y`W8 S~>bɉ]-_$l䴔Jʵ4}g鈤cO^~ X3ç`h:œFt{́M/_$X첊%}vshkiݨOvnF Oe245"ռQi$%46}94+v?3ڎIߏFEE|)ZnW/ixXy΁,rJ;)"x%fŮ #$gF6,AS Ҡ18~8V-V&ʬ{s'zIrhVu>m)+!%j= s/>M|vMZ^NAM1ܗ'[//*ں4W8|h;) f% IԒwߔ]HyF+Y8V_l7Qz#EeڤT%fœ8iah>#-7i+zE> stream xڌP w 6KpapwA$4;sO꽢 Xm{wCAE$f2JݘؘYJlVVfVVvD**M7{TZ@W#,$\n`P wqظxYY쬬|5$M=l,Jy#JbceZs:_1#@f47hmnV͉ӓb%Lq].@ ʦKcFhZ۸Gt4u{s+4*N@+ǀؘ @69Lm6@"#ⷡ+oajcoj6+uS\82w1K9ZHnqݛ9<},m-,a(' XGftpr5oMo'_Jbp N '% %psq[ `ac0Z8"-w賂Ǐ frcWY4ute.8 `bpqE,)h 'Y)7a'o,exn?cnjyr7㿣H/= 6[ J &8_SmW harn]s m\m6n~#Pjf0x+x$RR K 0uq1FdO; @r,A.[`-A<?"XA<? "Xd S|JOx|A3hAվZ]A`v4up0?rNrxٸ10+0s15-%[Ǚ?b;q#?bA\`ns=xIO_L |awvopݖ\Yx+o5_`?z/+&D >ko'k,2Ap> OOo=4 |Ųro쟱S;;+gI//66pN`' ?d[}_,12Kf=N:ٻ),}]B-- %fc/l;lwȸ~=,.pWOr\M]\Zkf/p ?㍫9gnǿ 8a8׿ _/?9#]./>^@sğs s0ֻۚobL;BT;itL?]PS課B\nRїhEI}#'<='O .LO#1i=;iA7CvS8ayx.FVq+ =`{ h*,>9z3/iWRD8_u>+쮝zטSԾ} ߯ acX# ;Wcw'3JRӃaD_t:`)-Tk;p`^ww'̵ѵḮϰ&&rs?.o_mf eoıӴ׮F[/wTDt4tj,N*3.:!EwK/'zi >Dr\f 'z8P1I T[ML2}SvȲ1Z^‹]%i;{v}rZF.pq6}#^Z!@7GWGlYQE5YJ{a/5w_wmtuH[r 8-ŋ˵nhpJrx8Y!egf9Qe|ު6chuY"W1MfY/?(- Lb(!9%tJMă/ÒwCH.*l d leEud#5AG951Am|3[Dȏƕ|.t 7"{|EfyޙR!Zigp.y=28V+D`!Wym;f,ܜ9~'r>GYadVLwS m˹ܒؤbKcGAsRZߒ5#e/L^)Z][ bt,#Ю_zpHG?_iR+"P!U|Ӣ{L72&VUfr}V&fFpi"fz Rman|oGb;ݍ#)@~:{;骴El"@R?Oy Ylcq#[ RiA6L 2ԎK谟:S7؆eĈ^1XUϖ4Lj܁t< YgًO@W)f:ޯbYn& ßo*+PB}Mv^+L+,!1Y;'̿DгB8 ^T%3t:Zo[>_ +eS/Zvb_[A dB0WƬ}Yv=ʰ Jq>롏F}#ȳ[贊sEGo7v pn{uNO4{nFr=oQxD>pF_%|H9cx:@\N#_u+a|TAS37 <z h#&gj|ZF.ISvc{]DA~Y[C)F!Dt'6߯~z}!4&I| ?5}Yh%^g3ݳ|9a7"ӸwPAI>{"APIxO$ گT:a0 xfC|N[uF$s괐L'dYqS޺&4JϴHoNT(-4-ޓÈoS_t{ #z!aExGqXM-Co>%}g?sCoT싅aic[i \cݱ{lB~(0zj탚W.Fi4GX:>!Y<ƆR\ a ՟7Cv<|fL&|e&=1>4뷼$3eu@,2c9{Z8v:Ft\7 u\OF6p "0fM y m&X%=?^,!ƫμe ڥsU#fca7(lW;M+zacpu`"ݩcNJUjyeZ}MxLˏصyZE~**ɹJ7\Njq(q%sTQ|;Z&,<1HQt 6佧nj) Yv6SCcQ1J,\p3% }Z2Cd3eD1[f>4;buœ P\kB$IQ8źMXOLhwoW}:Nv+MV'Z`36q_ylj"$/:hm0,OZ;q#]aW^T {Ѯbۑrmq^vvҵDiV+5.e:|H&oq'[3"Rݠy_YѨZ*i{ytK][}@ijn„PιhT~1<׬z2N!Q;-]ع_4);U*rk<,F0>L.c^(mf? JMxRB|wu̙˘nSkL\0esRJȧogw]IшTݯْG?Gs?H1ka6d`sh"ȁ#T? H_3YxROE݁짭G{v8)0$9cuw8Y;64Ⴀj + =(I-lZ?W AR" Nc# /`iE%[p6\@VDp ^?~x}+v:J jg#x ~d6ڟa?FӗހUijP|q'G9F59ՉE.Yeq^2TnG4ӥs>iVޢ4+yϣ {WR\HյlI'%cf!6(cI@J0K֯B#[ud#znhg[gK?Zu }`"L>f 2荸z "\?fixTHTv%NUva˙N1[2[.;ZybUzTy z={fXC%Pm}EDk=B,kjWWy4r0y-"CXζt2k4aLOmpSN&K9`^SG^Ȼ4ҖYuTy)lu>K$5%SbX6.fc4'l8h64Á~<^w|spIlwӴd7|nĉ|!-6滮cAz~ ]ذS$61P5o9|7t9o4d7bSew` d{F5HUp}!$0[)+*Y"f_՟=[C7x861943H;yÃ(̨p=@N̜Au%|9z/Iy-Ø:d/sX7,Bg z)gCW|=22d~=Q1LCdUOB H jc4EP'b0Ā@ھ. m'\TGNvPxbP/k@pl|?;q_KbaOWas{tֆ1ڒ}PM9 =FBST&>5ӷc@2W,Kk;ZD(O뺧B7Txd왋[)qzA+Dٵ?,s"NdgƢsӶ xEӲLLYL7mFhY{E$ M]fuQ´Z%bc TpoՎuMLūIfx/&;{;nN2: RM}@ rS@MV]q~ "ge4%hs 9-^%C9M8}5zcʯ/\U4ʼhJQT RcàKOK7L p&t?: V.NOK\m{9grvNT[/ qZB/U4Л涥!ʉ*䂁b"|B3J#-1 7  8G)ņ|3=opG}" ? N~]u[ů&2 qkHN>,:j1#ue u jxb6=PfʗC #ڃYӏxC:hUs2DԕI$'Qїm9B,&mMvE%V [4L-R֏y|6[\kfʷ5$4((;5)JfDԌS 2!'8I%^MurGmhFRs}Cs0Su{rުW?,O@a|0/Tu{9un<k C[s.]ݚu ʖ"O]EMPcpeXB9sTg% ]*~M?Qյ[4hRzBlf/^BA}2_9G+F߇R|{FyVķ)j]8уw 'Ş O,Ϩ^~}Itu3R˸С6N<rnSnچll  -缸}7MRYeENվ?h2PZdzyM]s@C}%qke_UL~XaȻQ>rܴ?#ϴ}Ϙ;` Z ]t)^ZEǿ}QDxͯM|{mw9i7Dܩ?T\bkV=7< [6d\,.F-Gܿ>O65Xȳ;(d\H[vbk ו4U-I @b`~R3Zc gP>l鶶^v}d`e`øjةŔw__3%i3.Yjx_ L#q ϵ+>RV!{5߱xQ)E[jzhFxEATn:.bf:`*{qEo4F͒uװ@ڲQD~9Mr|ޏL+L6$LVDRH! A:Oͼ٤tt_9qlUNyK =,~ (<(+O lgeHyƛI_ܡ3; wʹŮTRMG}YESj %6$H?ۏԸãѷ4pq@e׿y`rv9M ފ"p+"Y(jx27[}đkBogġkJ]p\yP4qv h€LŦYXAJ̕pPv.J3 [)bz.2LZ&]z6v ]WgH2A`3'@!Y:v5/a釶è3~b"\Ir;q`Nu]쪛W7p_8IEY0.dIQ[Wb)u;\ ֙aM˰<…'VK6?|Eʻ8:] |)Ҟp-ұisKYY"xs]yU XUVwY#,vZ{6EGkY߹W~%q1ܙ w؆ޞ Q4q㖌;|" Uwn0v S+BDhc&$z%4RW􀈚. "Sì K*Myo,x`]83{-~XL)C{C})1| uǛ1W]f9m]kGQ%^c7G~2fcPCQfɕ'gx5e,"g:^(Rs%4lU-.*u*'Nfcz3.\题26҈'"h'Lpy+o pw+"K٬+OtRdpT7ra:g;"q/峩ԟ%=#'JIdfo8E3]Ma?UA3ߺу#Ym5F-z5p+ʳQҼg!%,KV ?%e*;Sal}u>;Ok-Tau>*>,+ڞnH>%R[@m=$ K 1 LZ\hE"BgN.O^B_~.,xTd(YMVjA6X Ɓ?߹vq^}3DP Ҁtͬ uEuSűyEZ7!e:: 2!G%Χ[^8?@3x6D>>|gf_*H. CE =$u6{(W5_>GP!8 .XFm70;k {D&?XQnaQMx/|ek`J(}%A? Vݩ 2W9@GD@:s]= ,@ڴsxW˅P9i=ot,ȨEwMZҥar*̿K+H-,_<Mb姬G{&Bp߫܀BvCoZVӗ~+KBl$Af$IuΏ MOՌ:ӁdX_1> u_ALbwSIgg)0uR(.V@C? $ZM%g>T$bv2;jnJT$tNԸVUA ixnknڔqݞ—;3=$y= Upt E^3t*žAhNayz㓟U~?P;^ݺ+V`\N_rc༐9{$K2(mTmEN=7T%gѾ0Xl~6UV`ț>(b JvR̃eɥf1ѩoKe"CIֆ6YR:vz'</)Z)YT,L)bG?8=NPeYktutU4o6vx`~r(Q4 AfwjnQ(dYӲ]ww]#=/Eg|RŁ(h"%_{+7hi{?-W<"N-˓bSZ<~1 Be&]z8,9Im'yG>(1=?9dB'Mn}ڐˍЇ9--YQrTbO}/%6/H?'+K0@O4u<)7brs"x&h><{zKUGRh #.F|'(NGIja8Q{I~SёUZRFTm 0@$hJPݶ˷>E.PEc]Y+ܛ@Ai=$jBRSn=yyI.o2$% ,M7u%I˶WEMk4qBQ:Xt&rpq&ր C\}ӿb- ்F(5jѱ_|9TH $PBqU9-<{ՠ]AlƄ0d8.UrhP:^@0h+$B)$gobsfP iSz&U?c_Z35 8ؐt :(aB@YX~Or#^ꑒ g[ q -\S>ASh?&Y#/ @Bs jc+8)R3q?gNؐ 0A(t6L{|ϛgmb6]*ٞvAx? ǹ[aG7$I%i>upq?97Կ's>CʳVb= RX4?lMY+jH&Vǰn_s:#`(u+zQ*௓H媃0JYxSuӼz4>]m>\v;ED}mF>ƫxrPLBF#1Zeˏx/`\[(0ct xEgC P28괰A/YDoM`]<]̧ՁBw#C%WNHXv<>,^3 pLzZPsm#F9=1Z[0S7 '[*Eehl† VaϟR:> 33f}nǜ ĕze0oWY.rIoP$^Ps7fctiLЁ`wv"E/M!#9w(pϯM!5޷bŷ8f,(HSNs`*R$6yܶRq8%:/: :KtЕߠKwD;Qb% HZ37!bE]6xO-~e9l世)>]@}Lu-?|Q]Wlbwx 3 'T~ KeᇝxWaA^ioMPUB#/|>97֔p`O}^擦ʯhF1m8:3y̆u qGuV.͟A gN]{Z:H#(!> RGwT$Ο|p;}3pfzI{rŖٗ3Cr5p(U| MK1hf/쩐:u75qdž<^ۘFdhOPBzF"[ ^J+ѽ4k$ E UxbZ#0?K~-E]VN#y33I UNז-AL%DL伧ޢPl*!y)eOtI.]?:.hsuүhqhy1,\B۹0a+ d)kTҶOฬF!Tc|/ղ0DHy dHi8FDtM yPr;Um2yg+ȼONp0C;{.`4#i%: !ֺv[!cc N\v@cR i݀[W _g?]IVeW(st𔫃HGfF5Hr)̤{;Ccls%FyE_W>n{IU6aJr놃0ϲ(eA~Kx ]V1݆#n}u45 s糏)z #aȋm{D^8C_߅d)ALhp%ˌs U]EyVuHĪWTB֏uia]Ald&XM;IbqhMnUN%-%ZLiTz,%Tbر&5eF!1US`q:(yuXy5݋h]uQlG nha3J+oE_N2ں2IP ?nrb}").~vQQ5yNnI g;Wf%~xf{{݀^٩IS[wј)7w #ͺMLP«Wc xonGBプEca_X],񋐘` wݷNeES8b,z['DT*z3&*W~&Tӹ{}pƱwUH9%jDmkZyO01O'Zi;q0F\pwIG7+bc, 2sת=S?`\eflO $x=3uu'O7pq_n,j=Z 'k1̿p Qb46 FM;|EP8z$|u!T"Z(1q*MBCE]1iF7aM?G ?PEiSӉ?q8L[ ͍z,0|ᆞ0头#f a0{UFHCP\Te-b=ŦJmOm̀TCH0f|Dr"sST^rgqH4Fzs>FC^ٶ|wPh.uNl8 =XILjiwlK#IJ,<>H r4;;@Zdū>.^g6-k|m,]_6BL؛5.PNS!hG!?v&AsdG(AE;-n38u.Gs.پ賴[lK5xU*#[}p&-yxˆ*OGcMrC,)b:t9 O!${r۞S%+91h J?ތ :HGtX;AȚT{*b;X~@K7 6&@>Tۜ hNDدfV xWvG+4hqGL5f>QMO2Q]Z2DgO3l* #j3 Nm& <%oH;LJk#6>bD]%E'fU똁 mE|+&!yjk*N* o%^:;j=9k(\!&lLWKس+0JXʗ9W)XSMu|jÍ DPq/oh־+v"򗓸N~Z<ќhUnjff8nl8sJd1pb\e.)0m쬟r&D]9֑t}JH&|K@gɎ?`y^°k‹GTc ͧÀܲ8=Bo>]U1Y+@B-3fZUM:i^b$78INu|9n3eDdnD&EJ 56pmt*oܵ6?5,NIksK .L =EDFOM7M;po> hڐPXkYv#O/(m!@r>NC`/~N5DŽ̨X[ >肳+Cb{`q٧M›E\z 4U,۾̶ͯ^1+.Jj)pcn-kR \Tj*Ð[ٳJ.x: oiw7/DYMKmo0iZhV/b⟤޽#)[n @۔bɢX1jbZʔ)oxBt܃mNFehG؅oBJ㞐gV{C 84:Qۏ4&vSz͛ T'bWc~WL "nM<:᥎L=կ ;*.|],D̎{=N!ћfkVQ_$FXۄލ`ʢ@>o_>ʼnňv Oewu"l=_GR$P=%#Y Ɋ$亭SͬYVj魿e"H-lk|AwõV64˯ʹhD BrBX]]f'ئ3@>Nwuqfʐw"w;?K( s ?Ve4U (lͰjS=|j`P\]"H+hR 6eU@<2CgT̋,:Ay@O@;53>a >irA*/a퐭[%RȟTk͢dxh|d`xb?ӫKXIЎEn]+oćEK90)΁f{4&DҍBfuYY'} n])Bz)ZCk "PSVش@ÃZTWǦkHӏ3rfeIنnHN}T$ ܶZ^̆l4c& lk}I( p ^5ܷ1CAVH8#mcB I,:BgLƆVBUI#e=-s ] 'b@S"O \-?lzH"mǑz=eyTs@I{O =Q:G=k7Di${^'BnT_rvOz5lڻiőmF)}꒖V-[0Wd#I34J k([=DhDueAY3R}#3E_ Z@'|4<И=xQt %jrMW}e=\k[j YsKe} NgE$l}I ްK0OԅE +)cv(ړIeV"FbWQYqc"/֯Zp|YUPvW'Ĉ/-TF=Iw2-G^Uw3]B 3s*a;уy&%mQVǣZ] vjg^Fo?`;!_x=jz E.9`t[3-IQ2ctKűuU*$EusAI#SXKmUVPV6}U2&'bu?lBI"Ԫ>"NܨOWZɛKNjM\A@h+1ކ8Cu&4i}nJH7 1n#!`,Egɻ<'Pڣ6\xK|_S"]dtrL_@^SI,f$c{ }, 1"&D A['+IC/-b"s7m;[{PQi>7d^U|{ Iȇl,r:U (Wweljf TCQwr,^v\ 8džH-ܼ=2$3*n̾9]ٶkzHyh@>S@A͝7Iog8Mc[P1<{Z{~z'FSZ{x ֵ&֞3FN6VدU˲2@9J}"G R4z],>[kr 1쐩Y. 0gt\7..uд OƋj З͢3(W@F@dGtRLmqT|!Rb{,n] n^=;>+t$*,l"9K28?ᐅ(" SVǑKT{IQ0ٳ*4g帙 U l܆O>'؜&5 V|"L4sGYuZΌպ:BK+HbSiݞ@̛OH {D'&nR`:o?? akkr 6JN`rźNT!+7I7LѥT"hU|~"N/B1 w:u ]sz rOA B2(9l< qW#qy^<^G Fӷvd S[Q?i* *Dm gHyX,ʞP9 ( #UyoUEWU9RVbMm5'!33v| ekۈf^߰f 2Jl/=uwOxPaXuqG_rr_! TP Aŭ2lWiȆ<'7lnwHX{=dT[(PAkP1 </~ Q$4EHxZw;Ϣ.Ύ#Q(7]W| >v54' QLh" zC?7k:O㉄ιY(hZ 952,vEfX:2=VLDF6DQu/PZ"Hq I (8Pi5nNE1<ɾ  fdR]7}aEמ/t5>\ nFW^< uP2K>!,obV等7n{n?F] eďPWћ ,~C:_\N8rU#Aۤj`; G~iц[k p,]CّQBN%V-qkQDsa*(ϮA4r,8}2e/w5i&PCe =a TĻ N n٤y.vbx+Q˭);t ǃ-W&0 3p< U*ϫLe͍eeԘUG1$rF9& #4$dJPl]@3Uuƚ4Kfp[ss ȍAB,<f(PAW4&>s؈=\;r"Mv$ۗ(Wf㻜~&@`D*´~{cnٻ85=r˝9*$z?|p[]ڴX'FI&ATBq9E+yVw09NL- !1!ȶs7p C#JjFl?R MDBwv}"fY>A|e;hS8z~w._bt#?ڬ=9M c ыaGH Cԍtpz?|5ԟƚvfC`%HO= yJ֨y56< J@k;xm,UJt<:龴Nl?XWkMIڟ;bniV(Y endstream endobj 1092 0 obj << /Length1 2127 /Length2 13081 /Length3 0 /Length 14348 /Filter /FlateDecode >> stream xڍP,XqVXBq8)V{rv9?s0,}zPi2[9Yefv6?F q-F2tC^dR;e'0@ ```cpU e(@7I'goW-%,L Ks0@b t|hit!Nq`ed1wtcqrgx h`#XPhZ NOsW E^>&jLt,N|(!4HYKlW'GŝCW`h{EǪiXYB9"J3Ι N/rDFXR 5ZnDdW8S>i >e1 yl,Pྡྷ3 +kR fF2)(&-CȳU&wJ$Z%6S`6|xƞ뽆}VBj6.LJ tM?Vʡki.>i!tL3y+;]#%f©4f,2l/І*ftmf9`2ywbp18QN`@8. k05sPnĵ/֕Lwi!cmq`쎼lbQaDdHkQ\ۡôƾfM8Sqm6 ]T2Vx2,^+{ӖQݵv(!+?׵rm2fzG-,gH'm^dW4pr=t丁sɑ Ljw8rZ5!:`Rd5 < ž#=ogaDzSwl/=wc6a2M.΅6 { $qCZi[e}h_/W'aYoO/chbl'~%G)oDGYW]ˆ X6"{YDmfoEs5hu!FuMLX氞YEvj[Hldp#N,i1K-SYǪu(]Jm{'KWPb[@sy TCў_e݂z%<dٽ'vQ-? M쒠-DÊE[L(UGtlIж^AR-a1!!R$Xgw1W?a_YsY$||x!ӦW >5i#wS#R7$g/A 7(ޢ&W8wd 3f$HF˄J9v4O59^_4b\VW+؞ E-(Ȏך;/SM|Rs 0;i,]CRPCtv|yPv6L|g8X} ?OnBXvnF M+ N&SuO\r\8'1 YBEٓx j9A}~o}sol] H ݷ/ /7 BzW+f$3l񯣆mg`U˛7i$P)KWd,er_9!g>l#ű԰Jػg2.vu6w=.lO>mN4+ydyPnֵDf%sd/ W%%'|'y$ lAk&uJյJtKJh^ Gi=`D}pmIM.38 7 LʤzmQk]]12TN3:n .L .O5Yo;: f%s; !vVItQI:F8>_žog66@ñ:=5^W I2ik>lF|i7ťm .I` ty-~Z(lňDf4I2.4cg ߢW΍0DgV]«p_v~y ^|a~! *?& #Af;ρR'A1oYqoTk _i8,%v{H x DRΤl;|5-"EG@Y7(p&ڱvo4??5Oqi( ԠWస8|1" w] (VjېZ<2snsEoȠ_ET7ݲ}㬪{X|*Ci92he8 KnZ%# tm#oھ7dDligrOZvͣ^LgRoL'}pXK!alҐVXa@F}+'Ti9+uyڇ*n$C_\ <']팑?agA59U^DTl!.{rԚT{UK;Pk\a52qJ9ɱPX?"HDM=ļǣa"gLJ"0Zۦ9S s [ثv%u9{5}cg-_b*^ȼ6} 9[cD.`c(ACNȀL\7hV F8Jќs`~GNMmŝi3 p=`Ȣs9$>>ݞ"+n{1.DL=(co-b9竊M5ͦQ=gPGU\)L˸ni ڍs墭ˁ^>kj>Wb%Ebi *MxAj>-FߏXCVm,D ýTC|AE ׷H|QľdQMkU. WN5:gϻB3_ǸeTDC1 L󸲯$=_!FuV_ε-y}K|!?ge&=g;J>Hx ژSs26nr`A7-!HsЊ,3m{ %T>s,|!Y+h׏nMʕCCuaꐗi#kHZ)N0,:dѻSA 2i{S,i4rդSfT7۲ɅXw2z1O\֗o ˄ب~G~pQ{ZmJa(KH u-W s,/[jgA~l3QfҢ飳 Qׁa+-pƨ i N5+:MH\&:DvѯKRI~ y^$Ewha3 7OR34z؀ 0'ɁkۙHZQgDQbM9M-n| !]ȏB= |kF0ѲXxE1HZfyf3#Y9d;1ѭuz=T!9aCu=QL ? nf<~p*h}[ũ04.UU1E)M 9,)}{NԔJaUYt2GGLH۶tW~ )楊- Z(5yV2GN!0_8& {qPi|(Wz9kDC7_zHZI9p D׻!_[ *zOlK/sg 5?֪֙ +=f!ςpdfKAN͋)Ѻr58~oT:4% rORgg/Z=1Iufw2Q#TbeJWA.wپ:}2͊u˙m/`;Ngu̯&'AǜYG3c$͋!1+{v=W֗\^IS~ hh.ʇ4c޷6(ĚaEhf2J4b}uIZE7w YX< 05jHy=uZCreM_V46H[mCg0M&QVј&T%(Pry4rE37z/v0ޑn\A yd|tjD:9,{D"2B7=3 ^}hEԲݕ==yI\oIf(V[])@kyWFTy?д(x;-5i"̧>홮Κbrtw[ OV Aksʸt-6jl,cE˽by>=VDj~g ^_/ yV§1C`h:M8bl nI/Fu߷B)zlўM<M=!*M=n;!9b-_鈕 MuPxY#qR "-L ȳQ]5Sm((]lOF3Qd`~hƪkChop--zZWQ8=`[=؜KhWGVhaXBZKdbt kJ]y/ xZUn",\?'k@ޡ};` VԠN1XR; ~1q>>U!ND#+W a.ԚsȤZg4VEq1׻+y%CkK +X>D 4(ߜi6bީ@TT.骺Lսd l{Fc6X4|NE4eyoyZa7PJi.ʿbw"3sdR,V}w r~}ڜmv$9oQ 8nq!O+j&4AYAir΃ v˝ŏ7Ifowͮr|3x05]{Uci6%(2(?`-@f"1K}jߝ{o+k=r7U >Bp6" vc:t#}c lg50P[#ì˞s646K+[1lɥ ȽZpd,""LpDu:Ftf ҄' R>|[hv"{q'[sFϹ"*S_rH#Vx]'Rgvolhe:~%Sf)x5Łp陘}qcT}Y{Cl쐊`LT*&v IfK ʗ*ʷ9l~⤲r{0#v'i:S;-dGjk/\\FEiOx{3HDiwKcz׎[% ʫC,E]To#Ou\eZM0T w<_md4 ہzܟ-+ž*QQ: FM9dqoCߡݜ*N(|oU; E6 G+^qKz-y$Z޶ХZ:CVpϢTCWSvjZuĶKcEQN9jCS|^uh|&sBq]֥0Hwy5<ـx8Im>D^vw{F_}1k֌w/oTT`g"ϑ&F徚/w睘,zb0XG+bz%i-̰ق'yN0-bM>nGYKf82$ 7Rw {:3O BEy~zGަi0vf~+ꇃI&o豦Pkin>I\T[3TԣV,~9}u*]/Ƽ"HeϿBj;3AAu 0ߺGư]y0e "MCEi[9 v^p+Zy'#k"mX=~| x m'/f8'&2D^!FNQۓpYx'1~< 4v2[nxbg/GoC>|gW9$r$=H6T7Qh^:0o[̕3ɭwvM?-(2S u.V8IηI'4ębGO%]b)^TFNhZd9:QI7@y$FȂg{Qj$b{,\#AQVYY®V܎(1i,(z9.cmfb wdIwf9s=A G!+GpQc^ ,©ARJ,!Ż{0ȮBґ 84u6B*[͌`̺둻 Ս0ٵْNfgUcaуuKGi;PEҔh@Ε7IgfuGBjA/s:Er| 8 ڐ^'qYJD-B+aiP <$v#W&M9i8xN(k3Lٛu2w6Q|ʹĒf]2?|qu[ kqxIq=7nE4tʋW:* XWlnTo2Ĕ'*F w (1>t>}^o>%tܗ68l>;p-zO'O}=E:{P}U@_q)ğG_ŷ+dٽ2|#,A&Ob<*tyxI75MѬǁ;zmJʀrV4jp|àWfeË??vyN[~x υM‰8 e"V#Da|f/![BCA(QPZ(}n :૎{0 50цǵw+BvC3~'{=kcWp= %PjК rI't;鼄=@ES&I! OXBJR2U?iPI{]$q O?89>8̇F߳lG9&m=EO ԗ"F8M4g{w`PV#|c|3 9'h5Y| gcmVgZ5 RU>+ʣdѴ @*q0E+%t4Xiٿ|K|4\MZW]6A,U !u&蔾h`[fYX ~#qJ sp-·&ŒoN }\D {XupM&ȰzX<fأ!8(:i\ GDE'phi0uNĂd 9/BU/hOva,S, ]ĕv#$f,59I"I޷p^\d>^S@M]K ^a}sn}])>mT*LHRNCj3->Hg}I?=C#_x_io&_ݹ >JTa0`,\wnF y%FEdzӍqsZZbU4wBM$#)&/ouQM~k+Ue4[uE]h(ֈ`Yw/J"d})c,|E+&iB\2PRϯ:ۓXbDwL5@e 1Q|ho໬F__+ !&h1LqfvD|,AMMx17Ќ7WuGrC)GHΣ[ҽPQ1m(}OoswB# S?긭2pyd裉X& Z"ilxf+q^?gu>3j9sGU8jbnUe#J́> yƴEC ꨂ[ܡ*w1bfo.ifꋑu_ 擽m,R&EC۹ %i "]Nh /;97 5,e 5qWׯzT Kt縏Y?3yء?)8Ӡ*|6l^$w=z(@\vY'ñv.ib0Ғ*-j'K`@QgxΪ%+#B}\2z0rr7V =*x۠cԝS-$@I|v 8J3&f_:`̤*H2XEߏ 6hK0!ׇaj2* lyh슱qM@bz%Aet\jx^b \p %g`7=d1G=`/KSE"eg=*bhsPCؖ4QnϮ,W1NC;ූx ۆg.Y{!agl%Q|Sjn;컚ńf HV?'`;D#kG awa3s_}2z2eòuv3QFtɍ?`sKFdlNǺ}^,rsxX]ǰ{8G 1J۾"ȓI"A&EN"xdʰ-jMburu%24V[CKkj/6Y-K@Eg=O˴U- tn񓉕<EC#܊Ϗ0_rx<ǚ_k&#AV1)Kґ5hK [wF*RԔX,>/$,

HwYk6j~'3 kP6"ϘQFzU?ssB"pnh%q{&,!y5֘]e,U IC6VV 3NwOwXvDqI$_7?V#L㻲}`bH04wVeC_Zn Tݔ)I|"Ku ńH?A!՛n#tS&@᫲~]0Kv'hϞn#e/_C4}Sh_+C;C[W-[[ ɴ~yUh| )NK-""o 1Y.#E-sj/Z_~hs`"#nQg>m;!,+)K<] _a9m4ISq[ա㔴4Qrɵ\<{biiujc]pgZ #< Cn@ЦɃ?u΃ELF\Z|c{US:{[fijC!Q∪c>lILsoNj^* Dž0Sԥ1Xl"U j@0jF۝3rxR um'_MqHDJӀuBM tR%[fa Ĭ`gÃob,y`1Eڦ(xrg q'N>r|?K~g E5k~2/ȶ ( ,V쨳uUcMb(EoxP{+`SiA6!q_d+䡞oͽn!:Nxg y];ۣܶ'*ZaT Z}53doKnk:-1*&˚/"72EO.o,ۃs'_1aLⲆTD9[q,Y mN):J*Tţ/"|zꦔ0r; z;N'g1X10ՐOUe 3[r+~ endstream endobj 1052 0 obj << /Type /ObjStm /N 100 /First 974 /Length 3512 /Filter /FlateDecode >> stream x[YSI~ׯذ"&&3`|1cdhv%ofUuWT]]Ǘ_feU`TEZJߢ 8VLc]k5W04ŚFPgRa(kj*0RA"RKgD!^ P3@a\,C ,+4V ZUhSk #4 Q\Xxa ZX#ւJ:wc1O2U(pR( gVq:q4qB (O2WhMsQmF:?B &28Y sAc-`K0,f9Jr3uAC pP4z#{]Ź6rafث@q- @ #SZKrk9:0<Q4&j,8kb27 5+$xDB :Rh@P4UJ@+t(ON@b( t2+1J+h nkTi\.),!kP >L,HJ~Ҡ$(T{* *jV>q'dcPTL:e sl"XcX92 Bz>!B^h)sBdAnX`j1> }rďH2cgc 0/ 2p"zK̷ch<[o3 e6,Pj_TA- /1` <؄Onr9,b[_ú eh126;kӷk k p)cB4獪f_YI\[:$ laT^0+-/b ҏux0֜Ø4:0It4n&u[O#ZXJsO8].rqFPXjS }\@~;Q"=RzH úʲd2T-6g:/R\ 1 8C`';5CPanDiG|/xc2 6](f_ g:B=fr{ 4:ܐ3zͣ`As+nԈ3Jx eM%Na #]h&mؿ"2H`#-'V10+~j6 l)q'e[^wX?B=$̰K/0c/#r,b\-r'Wг·~(&BO. O_ aA$Y9_qDv'rF`דlg~1+ ?ZW'ZiDN$X%q9Yd9&y99\/몾9l1[IIfdAV OAx[x7;{w?ez%zo#Y6ZC]O /+ڳ%<7 @>GEF΁K/7o%Y rI.\_s2%!yWdNy ,.&r8'_ɒȪcWd5.ɚ/eI- F"w\<`^??io&+@Incҳ7;ǧ A%Xe׏dVۙķ1篎I"* q?vm,:y}ptpvVQꅯF{[kV$9[pd9:u]~b#&yc,^#d$%7uyyV7aK1$i'!/^``ltQGЏqލݘd@ 7{?zuQq,j(zabΎۉǹj;9}gxs ~ 03kЍ5ݜMtߚ<ՁOp.i\电j)GGc3Qnsh]Cr_mYfx=Zqc$@s]"oJ2.X|\٬<[\X*{ o>d::ٍX]l*k~<|GͫXEă1ͤ` u^]MDϦSUPS?T,_, nrJ{38ouֹݬ :=AŲLnvى Fr}pzNtqd{ ̆L6>Jfi%* !tZ#3jo*8>^ _}t4rmI#2z Z6$5^~!#^ma=o=wě[AGXGmSGЧ|v(ӈ GШ{ԉY6t['NrGN9H6i}( lSg^}BڇώN ;HR=iP!hZBEq#hz3(WpYfK@tUk."DF!*(Dw[ Q !1Lt V. Fm7,eb ,:F۸l,%G0,BkJ6:ު(TG˂)$:ܚhQtڨ. !qEhmh MbR1_4.? 1:]׼(#"!ݞJfP5l:GA-wBgjt @w ]IaY~odaz0t!VU L&0tMkiAu)mdUw'mdP6-a)zT$gӜǵL 7%LO/aĒ >7D?VjlTrifpirjx2Dr٣0Or18a<3g!,fX}z1Wc1ӏg:nPwʪ n&Wnm)i`<&'R=8/ir)X \Jr *WT93p0e}X:aA,aUZDbCX5TNJylkl9_Y –5v'-2o[WBHקp2 m&o ȱz22a~8[ͮC;anret2^COd想>J)7LO/eĒ ,ڇʳZe ',ڏg1C4Zdlϛٗ,e2Wҡ٢a3^$R >DJBb5w endstream endobj 1099 0 obj << /Type /ObjStm /N 100 /First 887 /Length 1921 /Filter /FlateDecode >> stream x}YO7 >!Ė?!P =PJo%3gm=I732m9Z@)Yo OR0`"rDG#j [ -7<%l,x"5 Z\ 'b[H x)!S9w%hÀ(GOQuW>zykK,螷XyurŢ%V4Xútm{n`9,`E++/QNXX+K;{%V6X*%KG+ ?gJ/v#uM+OsQeb?-ie />%V1X^\Yי܍&k9u8}̏#2;Qbu|η ''|zLir*Zm=>˪h%dIjc^$z9ydlFGd*Oe?rd{]ksfC5~iɗ}ĕʓ/=SNm _~567jݨިtv<|$ AZԫ6.ؓi5.&ksUUDz2uɎcH#MM+,>aGjVlFGJZQSv99]:iFS6(_H|͕ҕʓMkåwoEzFS6[}iFS6#zZ36[o#ӗoWop ^u^aѱE108@xG8|}`O?nた1s\"CFwgu/'lb c9/ғq(ϸjB endstream endobj 1123 0 obj << /Producer (pdfTeX-1.40.18) /Creator (TeX) /CreationDate (D:20190521123514Z) /ModDate (D:20190521123514Z) /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/Debian) kpathsea version 6.2.3) >> endobj 1104 0 obj << /Type /ObjStm /N 19 /First 179 /Length 905 /Filter /FlateDecode >> stream xڕVMo69oRE uG8=9+։}ICw-. ;IJI#PJ:10˜# kgPR,D BjH7d4T,O0y--]Vv^hJh@5Yl^l(@ą <@ nr]>m޼yJX!^/X7 eBAGU+3L`}$i } _AHUXTj@hg Yʏ )UAby˳(͵"jgE-h<#A(΄L Hgi Ȳ:vY.|%!i'E:(ҹ,)(%G>t_AIR ܸ$<$x7=UQ$U2%>1y(,|Q@͋3m}*ov=K+n7XwwԷ5їJ6>S=:1ui+_+?zHi:@Sv5+J㘢nYӼswcjNFXkkc'2m󭝫綡 E**:&.}V/Ǻ!lTlL2\TU%=^'*r:+bߓo\>(5~|8$$qI\Ⲵ\nHdbr< [ endstream endobj 1124 0 obj << /Type /XRef /Index [0 1125] /Size 1125 /W [1 3 1] /Root 1122 0 R /Info 1123 0 R /ID [<7C5D29135D04934627C5B4724ED30FC3> <7C5D29135D04934627C5B4724ED30FC3>] /Length 2583 /Filter /FlateDecode >> stream x%[h]Y~isMk6i{$MNҴI6mZ΀2LAa: 00`ADDPA}ǭKEQQr~__~uv{os3窝̗ (p d[MNs=<ǯE c|YcbPA\|eW|8 TP @=hMVS Ӡt. z  A0.1pcj~vPLts``̃%p9`LK2W f `,ep `uplM&m ]p8xl:ʂLCB! B,eTd!( 3,4P,@PGEBOBLk>PҘ4PES@j*]bPA@bp mH]$ jӣ I+ۢoA (A dO8Ԃ g0f`c*ZbG HH@@ HPp/2F1 9"$$@ T 7bAOE 1H^ aM1$ ,$5@Td!gBCE^ lSDutU"̺lP~ DdJI ]#a@|mmv4*c"kE*kTlZ?ΘH؂yM$#ՀT$RQK˓DoFb1v#h$3TD#B 69mV_gyd4$z3~p{:d ;야F3`s$48?iv7tͽ~g̽nU 6g5,$lڰd^ِdkQ&n{fᡐh]}s{848}RG-Ke@a3{Mc'-2z2PbZœ~u!$I _!m4˿I&s}QAj.~^ }G˴,gsܒ%i.,$_rYY*N5aVTYO$|:c$qIͺG$iwdvߒtlZLFCAlMTi&[fՒ|8;fӒHw͖1}K')Or7u])OvHhMgX1(2;z[ =uI76ft\=5$@#h f/ >v @bNn57Irt}-΀oZc3{Cf54KCt`qם)p \ W,`,% p5n r` l`.w>8w=pCgn5qN,|˔;YZڈA@;rV<ѦC[J˴}ZTYf}->U5]UgTYU V/T5ZѯTl펪WdOT5[?jw-Z>V[I>V\ϑ#’dsΊk'!Xkc rA5ȱ9 Xkc rVRMVYqx#;^z endstream endobj startxref 333105 %%EOF arduino-0.4.0/doc/arduino.texi0000644000000000000000000007021213470770202014447 0ustar0000000000000000\input texinfo @c -*-texinfo-*- @c Copyright (c) 2018, John Donoghue @c Octave Arduino - a somewhat Matlab compatible Arduino toolkit for GNU octave. @c For manually generating the documentation use @c LANGUAGE=en makeinfo --html --no-split arduino.texi @c %*** Start of HEADER @setfilename arduino.info @settitle Arduino Toolkit - a somewhat Matlab compatible arduino toolkit for GNU octave. @afourpaper @paragraphindent 0 @finalout @set VERSION 0.4.0 @c @afourwide @c %*** End of the HEADER @c The following macro is used for the on-line help system, but we don't @c want lots of `See also: foo, bar, and baz' strings cluttering the @c printed manual (that information should be in the supporting text for @c each group of functions and variables). @macro seealso {args} @iftex @vskip 2pt @end iftex @ifnottex @c Texinfo @sp should work but in practice produces ugly results for HTML. @c A simple blank line produces the correct behavior. @c @sp 1 @end ifnottex @noindent @strong{See also:} \args\. @end macro @c %*** Start of TITLEPAGE @titlepage @title Arduino Toolkit @value{VERSION} @subtitle a somewhat MATLAB compatible Arduino toolkit for @acronym{GNU} Octave. @author John Donoghue @page @vskip 0pt plus 1filll Copyright @copyright{} 2018 John Donoghue Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the same conditions as for modified versions. @page @heading Distribution The @acronym{GNU} Octave arduino package is @dfn{free} software. Free software is a matter of the users' freedom to run, copy, distribute, study, change and improve the software. This means that everyone is free to use it and free to redistribute it on certain conditions. The @acronym{GNU} Octave arduino package is not, however, in the public domain. It is copyrighted and there are restrictions on its distribution, but the restrictions are designed to ensure that others will have the same freedom to use and redistribute Octave that you have. The precise conditions can be found in the @acronym{GNU} General Public License that comes with the @acronym{GNU} Octave arduino package and that also appears in @ref{Copying}. To download a copy of the @acronym{GNU} Octave arduino package, please visit @url{http://octave.sourceforge.net/arduino/}. @end titlepage @c %*** End of TITLEPAGE @c %*** Start of BODY @dircategory Math @direntry * Arduino for Octave: (arduino). Arduino Toolbox for Octave @end direntry @contents @ifnottex @node Top @top Introduction The Arduino toolkit is a somewhat Matlab compatible arduino toolkit for GNU octave. @end ifnottex @menu * Installing and loading:: Installing and loading the Arduino toolkit * Hardware setup:: Setting up the Arduino hardware * Connecting to an arduino:: Making a connection to an arduino device * Basic Input and Output Overview:: Performing basic I/O * Protocol based I/O Overview:: Performing protocol based I/O * Addons Overview:: Arduino Addons * Sensors Overview:: Arduino Sensors * Examples:: Examples using the Arduino toolkit * Function Reference:: Arduino toolkit functions * Copying:: Copying * Index:: Index @end menu @c ------------------------------------------------------------------------- @node Installing and loading @chapter Installing and loading @cindex Installing and loading The Arduino toolkit must be installed and then loaded to be used. It can be installed in @acronym{GNU} Octave directly from octave-forge, or can be installed in an off-line mode via a downloaded tarball. The toolkit has a dependency on the instrument-control package, so it must be installed in order to successfully install the Arduino toolkit. The toolkit must be then be loaded once per each @acronym{GNU} Octave session in order to use its functionality. @section Online Direct install @cindex Online install With an internet connection available, the Arduino package can be installed from octave-forge using the following command within @acronym{GNU} Octave: @example pkg install -forge arduino @end example The latest released version of the toolkit will be downloaded and installed. @section Off-line install @cindex Off-line install With the arduino toolkit package already downloaded, and in the current directory when running @acronym{GNU} Octave, the package can be installed using the following command within @acronym{GNU} Octave: @example pkg install arduino-@value{VERSION}.tar.gz @end example @section Loading @cindex Loading Regardless of the method of installing the Arduino toolkit, in order to use its functions, the toolkit must be loaded using the pkg load command: @example pkg load arduino @end example The toolkit must be loaded on each @acronym{GNU} Octave session. @c ------------------------------------------------------------------------- @node Hardware setup @chapter Hardware setup @cindex Hardware setup In order to use the arduino hardware with the toolkit, it must be programmed with special firmware. @section Programming the Arduino @cindex Programming the Arduino To program the hardware, using a default configuration, run the arduinosetup command: @example arduinosetup @end example A temporary Arduino project will be created, with the Arduino toolkit files copied to it and the Arduino IDE will open. Set the board type and port correctly for the connected Arduino and press the upload button on the IDE. The sources will be compiled and then uploaded to the connected arduino board. After successful upload the Arduino IDE should be closed. @section Known Arduino Board Types @cindex Known Arduino Board Types The board type must be known in order to successfully detect and connect to the Arduino board after programming. Currently, known boards are: @itemize @bullet @item Arduino UNO @item Arduino Mega 2560 @item Arduino Nano @item Arduino Pro/Pro Mini @item Sparkfun SAMD21 @item Arduino Lilypad @item Arduino UNO WiFi rev2 *NOTE: may require modifcations to the servo package for conficts between servos and the tone library @end itemize Additional boards can be added easily, however require minor code changes. @c ------------------------------------------------------------------------- @node Connecting to an arduino @chapter Connecting to an arduino @cindex Connecting to an arduino To control an arduino device, a connection must be made to it by creating an arduino object. @section Connecting to a single arduino @cindex Connecting to a single arduino Assuming a single arduino device is connected to the computer, creating an arduino object with no arguments will find the connected arduino and connect to it: @example ar = arduino() @end example @section Connecting to a specific arduino @cindex Connecting to a specific arduino Where multiple arduinos may be connected to the computer, a specific board can be connected by specifying the name of the port it is connected to: @example ar = arduino("/dev/ttyACM0") @end example The port name will be operating system dependent. @section Querying available arduinos @cindex Querying available arduinos To list the ports of all @emph{programmed} available arduinos, the scanForArduinos function can be used: @example scanForArduinos @end example It will provide a list of all available boards it can find with the port they are connected to. @c ------------------------------------------------------------------------- @node Basic Input and Output Overview @chapter Basic Input and Output Overview @cindex Basic Input and Output Overview Basic input and output can be performed on a connected arduino device using by calling the read and write functions for a specific named pin on the arduino. A list of available pins can get found from the pins property of the connected arduino object and are also displayed as part of the default shown properties: @example ar = arduino(); % get the pin names pins = ar.availablepins @end example Pin generally follow a naming scheme of D for digital pins and A for analog pins. Digital pins can be used to read and write digital data, but can not read analog voltages. Analog pins can perform digital I/O as well as reading voltages. @section Performing Digital I/O @cindex Performing Digital I/O A pin's digital logic value can be true (1) or false (0) and can be set using the writeDigitalPin function. The following example attempts to set the D2 pin of the connected arduino object "ar" to true, waits 5 seconds and then sets it to false: @example writeDigitalPin (ar, "d2", true); pause 5 writeDigitalPin (ar, "d2", false); @end example Using the readDigitalPin will read the current logic state of the pin. @example value = readDigitalPin (ar, "d2"); @end example @section Performing Analog Input @cindex Performing Analog Input For analog pins, the voltage level can be read using a analog to digital conversion and will return a voltage level between 0 and the boards voltage (nominally 5V): @example value = readVoltage (ar, "a0"); @end example The raw digital value of the pin can also be read instead of a voltage, giving a value between 0 and 2^x where x is the number of bits used by the analog to digital converter. @example value = readAnalogPin (ar, "a0"); @end example @c ------------------------------------------------------------------------- @node Protocol based I/O Overview @chapter Protocol based I/O Overview @cindex Protocol based I/O Overview The arduino toolkit supports more complex I/O for SPI, I2C, Servo control and more. @section SPI communication @cindex SPI communication SPI communication can be performed by creating a SPI dev object and then calling the writeRead function: @example spi = spidev (ar, "d2"); @end example The function call expects a connected arduino object as the first argument, followed by the chip select pin of the SPI device. After a device is created, a write to device followed by read can can be made using the writeRead function: @example spi = spidev (ar, "d2"); data = writeRead (spi, 100); @end example @section I2C communication @cindex I2C communication I2C communication can be performed by creating an I2C dev object for a specific I2C address. The following example creates an I2C device that will communicate with a I2C device at address 100" @example i2c = i2cdev (ar, 100); @end example After creating an I2C device, data can be read and written using read, write, readRegister and writeRegister. The data to send and receive will be device dependent. @section Servo communication @cindex Servo communication Servo communication can be performed after creating a servo device object to operate on a PWM pin: @example servoobj = servo(ar, "d9", "minpulseduration", 1.0e-3, ... "maxpulseduration", 2e-3); @end example The servo function expects the connected arduino object and the PWM pin that the servo is connected to. Optional properties can be specified to control the setup of device. In the example, the min and max pulse width values are set. Using the servo object the current position and be read or set with values ranging between 0 to 1, with 0 being the minimum pulse width and 1 being the maximum. The following example sets the servo to its middle position. @example servoobj = servo(ar, "d9", "minpulseduration", 1.0e-3, ... "maxpulseduration", 2e-3); writePosition (servoobj, 0.5); @end example @section Shift Registers @cindex Shift Registers A shift register can be controlled by creating a shiftRegister object: @example registerobj = shiftRegister(ar, '74hc164', "d2", "d3"); @end example The parameters required are dependent on the type of shift register created. Once a register object has been created, it can be read and written to using the read and write functions. @section Rotary Encoders @cindex Rotary Encoder A rotary encoder can be created by creating a rotaryEncoder object. @example encoder = rotaryEncoder(ar, "d2", "d3", 180); @end example Using the created object, the rotary encoder value and speed can be read. @c ------------------------------------------------------------------------- @node Addons Overview @chapter Addons Overview @cindex Addons Overview This chapter provides an overview of the arduino package addon functionality for adding additional addons to arduino. @section Addon Introduction @cindex Addon Introduction Addons provide a way of adding additional functionality to the arduino toolkit that provides matlab access directly to the arduino hardware. Addons are implemented in two parts. @enumerate @item code running on the arduino that implments the required functionality @item a octave wrapper class that provides the matlab interface and communication to the code. @end enumerate Both parts are required to create a plugin. The arduino toolkit provides a number of pre-created addons. These can be seen using the following command: @example @code { listArduinoLibraries } @end example The command will display all known arduino libraries (addons as well as core libraries), however addons typically use a "foldername/classname" for this naming. @seealso{listArduinoLibraries} @section Creating an addon @cindex Creating an addon An addon requires at minimum 3 things: @enumerate @item A addon directory that will contain the addon files @item A matlab file within that directory that is a subclass of arduinoio.LibraryBase @item A arduino source/header file that contains the arduino code to load, subclassed for LibraryBase @end enumerate So the addon directory structure at a minimum will be: @example @code { +arduinoioaddons (dir) [somewhere in the octave load path] MyAddons (dir) MyAddon1.m MyAddon1.h } @end example @subsection Addon package directory @cindex Addon package directory The addon architecture looks for plugins in the octave load path in a package directory called +arduinoioaddons So this directory must be created somewhere within the paths that octave will check for functions. In addition, the addon architecture expects plugins to be contained in a sub directory within the +arduinoioaddons Multiple plugin .m files can be within the same sub directory. @subsection Addon package .m file @cindex Addon package .m file The matlab interface file within the addon directory provides the matlab interface for the arduino code as well as provides information about the addon. @subsubheading Class inheritance and required properties The interface file must be a subclass pf arduinoio.LibraryBase and must contain some constant properties values that provide the information. A minimum example of required is below: @example @code { classdef MyAddon1 < arduinoio.LibraryBase properties(Access = protected, Constant = true) LibraryName = 'MyAddons/MyAddon1'; CppHeaderFile = fullfile(arduinoio.FilePath(mfilename('fullpath')), 'MyAddon1.h'); CppClassName = 'MyAddon1'; endproperties . . . endclassdef } @end example The following constant properties can be set within the addon: @table @asis @item LibraryName (Required) The name of the addon. My convention this is usually the directoryname / theclassname @item CppHeaderFile (Required) The header file for the arduino code @item CppSourceFile (Optional) The source file (if any) for the arduino code @item CppClassName (Required) The classname used within the cppheaderfile for the arduino library @item DependantLibraries (Optional) Any additional addons or cores that are needed for this library to be used @item ArduinoLibraryHeaderFiles (Optional) Any additional header files that need to be included @end table @subsubheading Class constructor The matlab class constructor will be called from the addon function when creating a instance of the addon and should initialize at least two properties in inherited from arduinoio.LibraryBase: @enumerate @item Parent should be set to the first input argument (the arduino class) @item Pins should be set to a list of pins that are used for the plugin @end enumerate @example @code { classdef MyAddon1 < arduinoio.LibraryBase . . methods function obj = MyAddon1(parentObj, varargin) obj.Parent = parentObj; # no pins being used obj.Pins = []; # send any command to the arduino during setup ? endfunction . . endmethods endclassdef } @end example @subsubheading Class functions The class functions will usually communicate to the arduino and use the response for what is returned to the user. By convention, the commands sent to the arduino are defined as constants in the class file but do not have to be. @example @code { classdef MyAddon1 < arduinoio.LibraryBase properties(Access = private, Constant = true) INIT_COMMAND = hex2dec('00'); FUNC1_COMMAND = hex2dec('01'); endproperties . . methods function obj = MyAddon1(parentObj, varargin) obj.Parent = parentObj; # no pins being used obj.Pins = []; # send any command to the arduino during setup ? sendCommand(obj.Parent, obj.LibraryName, obj.INIT_COMMAND, []); endfunction function retval = func1(obj) cmdID = obj.FUNC1_COMMAND; retval = sendCommand(obj.Parent, obj.LibraryName, cmdID, []); endfunction . . endmethods endclassdef } @end example Note the sendCommand uses the objects parent for the arduino, the objects library name and the command id. @seealso{sendCommand} @subsection Addon package header file @cindex Addon package header file The header file should contain a class that matches the functionally and information of the matlab file and provides the ability to register the code on the arduino. The following things should occur in the arduino class files: @enumerate @item The class name within the file must be the same as the one set in the .m file CppClassName property. @item The libName variable must be the same as the LibraryName property. @item The constructor should call registerLibrary @item the commandHandler function to act on cmdID values that match the commands that will be sent from .m file and send data back using sendResponseMsg @item on receiving unknown cmdID values, the commandHandler should use sendUnknownCmdIDMsg @end enumerate An example, matching the previous .m file code is below: @example @code { #include "LibraryBase.h" #define MYADDON1_INIT 0x00 #define MYADDON1_FUNC1 0x01 class MyAddon1 : public LibraryBase @{ uint8_t cnt; public: MyAddon1(OctaveArduinoClass& a) @{ libName = "MyAddons/MyAddon1"; a.registerLibrary(this); @} void commandHandler(uint8_t cmdID, uint8_t* data, uint8_t datasz) @{ switch (cmdID) @{ case MYADDON_INIT: @{ cnt = 0; sendResponseMsg(cmdID, 0,0); break; @} case MYADDON_FUNC1: @{ // func 1 is just returning a uint8 count of number of times called cnt ++; sendResponseMsg(cmdID, &cnt, 1); break; @} default: @{ // notify of invalid cmd sendUnknownCmdIDMsg(); @} @} @} @} } @end example The body of functions can be in the CppSourceFile file is it is defined or within the header file as illustrated above. @subsection Verify octave can see the addon @cindex Verify octave can see the addon Use the listArduinoLibaries command to verify that the new addon appears in the list of known libraries. If it does not, ensure that the +arduinoioaddons directory is within one of the octave class paths, and that the directory structure and inheritance requirements have been met. @section Using addons @cindex Using Addons @subsection Programming the arduino with the addon @cindex Programming the arduino with the addon To use a addon, the code must be programmed onto the arduino. Using the libraries command, when creating a arduino object, the arduino can be reprogrammed if the library does not already exist on the arduino. @example @code { ar = arduino([],[], 'libraries', 'MyAddons/MyAddon1', 'forcebuild', true) } @end example The libraries property of the arduino object should list the libraries programmed on the arduino. Alternatively, the library can be added using the libraries property and arduinosetup @seealso{arduino, arduinosetup} @subsection Creating a addon object @cindex Creating a addon object An object of the addon type can be created using the addon command. @example @code { ar = arduino([],[], 'libraries', 'MyAddons/MyAddon1', 'forcebuild', true) obj = addon(ar, "MyAddons/MyAddon1"); } @end example @c ------------------------------------------------------------------------- @node Sensors Overview @chapter Sensors Overview @cindex Sensors Overview @section Sensor Overview @cindex Sensor Overview Arduino sensors are a collection of lightweight wrappers around other underlying protocols for providing specific sensor functionality. For instance a DS1307 chip communicates using I2C protocol and so a DS1307 class exists that provides the conversion/commands in order to communicate to the chip. Using the class, providing the functionality is very easy: @example @code { a = arduino() rtc = arduinosensor.DS1307(a) # get and display rtc time as a date string datestr(rtc.clock) } @end example It is lightweight compared to the addon functionality, as it only requires a wrapper class rather than add on code, however it is limited to then using available addon and core codes rather than creating new ones. Currently the are only a small number of sensors available, however this will be built upon in future versions. @section Available Sensors @cindex Available Sensors The functions for each sensor is listed in the function reference and is provides for: @table @asis @item DS1307 DS1307 RTC clock using i2c. @item MPC3002 MPC3002 ADC using SPI @item SI7021 SI7021 temperature and humidity sensor @item GUVAS12SD GUVAS12SD analog UV-B sensor @end table @c ------------------------------------------------------------------------- @node Examples @chapter Examples @cindex Examples @section Blinking an LED @cindex Blinking an LED This example shows blinking the inbuilt LED on the Arduino board. Code is available by running: @example edit examples/example_blink @end example @heading Hardware setup This example uses in the builtin LED, so requires only a connection of the Arduino board to computer for communication. @heading Create an Arduino object @example ar = arduino (); @end example If you have more than one Arduino board connected, you may need to specify the port in order to connect to the correct device. @heading Query Device for pins connected to builtin LED The pin connected to the Arduino UNO built in led if D13. @example led_pin = "d13"; @end example The connected pins can be queried programatically if desired. @example pins = getLEDTerminals (ar); @end example Connected to a Arduino UNO would return a list pins containing only one item '13'. The terminal number can be converted to a pin using getPinsFromTerminals: @example led_pin = getPinsFromTerminals (ar, pins@{1@}); @end example @heading Turn the LED off Write a 0 value to the pin to turn it off. @example writeDigitalPin (ar, led_pin, 0); @end example @heading Turn the LED on Write a 1 value to the pin to turn it on @example writeDigitalPin (ar, led_pin, 1); @end example @heading Making the LED blink Add a while loop with a pause between the changes in the pin state to blink. @example while true writeDigitalPin (ar, led_pin, 0); pause (0.5) writeDigitalPin (ar, led_pin, 1); pause (0.5) endwhile @end example @section Using I2C to communicate with an EEPROM @cindex Using I2C to communicate with an EEPROM This example shows using I2C to communicate with a EEPROM chip. Code is available by running: @example edit examples/example_i2c_eeprom @end example @heading Hardware setup Using an Arduino UNO, the board should be configured with the following connections between the board and a 24XX256 EEPROM chip: @table @asis @item A4 Connected to pin 5 of EEPROM @item A5 Connected to pin 6 of EEPROM @item 5V Connected to pin 8 of EEPROM @item GND Connected to pin 1,2,3,4 of EEPROM @end table @heading Create an Arduino object @example ar = arduino (); @end example If you have more than one Arduino board connected, you may need to specify the port in order to connect to the correct device. @heading Query I2C pins Display the I2C terminals of the board: @example getI2CTerminals(ar) @end example @heading Scan the arduino for the connected device @example scanI2Cbus(ar) @end example The devices listed should contain 0x50, the address of the EEPROM chip. @heading Create an I2C object to communicate to the EEPROM @example eeprom = i2cdev(ar, 0x50) @end example @heading Write data to the EEPROM The EEPROM expects the first byte to be the page number, the second the offset, followed by data, so to write 1 2 3 4, starting address 0 (page 0, offset 0): @example write(eeprom, [0 0 1 2 3 4]) @end example @heading Reading from the EEPROM Reading from the EEPROM requires first writing the address to read from, in this case, if we want to read the 3, 4, this would be page 0, offset 2: @example write(eeprom, [0 2]) @end example Next read the 2 bytes: @example data = read(eeprom, 2) @end example @c ------------------------------------------------------------------------- @section Using SPI to communicate with a mcp3002 10 bit ADC @cindex Using SPI to communicate with a mcp3002 10 bit ADC This example shows using SPI to communicate with an mcp3002 10 bit ADC. Code is available by running: @example edit examples/example_spi_mcp3002 @end example @heading Hardware setup Using an Arduino UNO, the board should be configured with the following connections between the board and a mcp3002 chip: @table @asis @item D10 Connected to pin 1 (CS) of MCP3002 @item D11 Connected to pin 5 (DI) of MCP3002 @item D12 Connected to pin 6 (DO) of MCP3002 @item D13 Connected to pin 7 (CLK) MCP3002 @item VCC Connected to pin 8 (VDD) MCP3002 @item GND Connected to pin 4 (VSS) MCP3002 @item Analog input Connected from pin 2 of the MCP3002 to a LOW (< 5V) voltage to measure @end table @heading Create an Arduino object @example ar = arduino (); @end example If you have more than one Arduino board connected, you may need to specify the port in order to connect to the correct device. @heading Create an SPI object to communicate to the MCP3002 @example adc = spidev(ar, "d10") @end example The d10 is the chip select pin connected from the Arduino to the MCP3002. @heading Read the ADC The MCP3002 expects specific commands in order to read a channel. For illustration for the command to read chan 0 in single ended mode: @example command (bits) in MSB mode to device: [START SGL ODN MSBF X X X X] [ X X X X X X X X ] 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 [chan 0 ] MSB data back: X X X X X 0 D D D D D D D D D D @end example D is a output data bit X is a don't care what value is input/output The first byte contains the command and start of the data read back, the second bytes is written to clock out the rest of the ADC data. In hex, this corresponds to 0xDF 0xFF, @example data = writeRead(adc, [hex2dec("DF") hex2dec("FF")]) @end example Of the data returned, the last 10 bits is the actual data, so convert data to a 16 bit value: @example val = uint16(data(1))*256 + uint16(data(2)) @end example Then bitand it to remove the non value parts, to get the ADC value: @example val = bitand (val, hex2dec('3FF')) @end example To make the value correspond to a voltage it needs to be scaled as 0 will be 0 Volts, 1023 will be 5 Volts. @example volts = double(val) * 5.0 / 1023.0; @end example @c ------------------------------------------------------------------------- @node Function Reference @chapter Function Reference @cindex Function Reference The functions currently available in the Arduino toolkit are described below; @include functions.texi @c ------------------------------------------------------------------------- @include gpl.texi @c ------------------------------------------------------------------------- @node Index @unnumbered Index @printindex cp @bye arduino-0.4.0/doc/functions.texi0000644000000000000000000022331213470770202015017 0ustar0000000000000000@c --------------------------------------------------- @node General Functions @section General Functions @cindex General Functions @c General Functions arduinosetup @c ----------------------------------------- @subsection arduinosetup @cindex arduinosetup @deftypefn {} {@var{retval} =} arduinosetup () @deftypefnx {} {@var{retval} =} arduinosetup (@var{propertyname}, @var{propertyvalue}) Open the arduino config / programming tool to program the arduino hardware for usage with the Octave arduino functions. arduinosetup will create a temporary project using the arduino IDE and allow compiling and programming of the code to an arduino. @subsubheading Inputs @var{propertyname}, @var{propertyvalue} - A sequence of property name/value pairs can be given to set defaults while programming. Currently the following properties can be set: @table @asis @item libraries The value should be the name of a library, or string array of libraries to program on the arduino board. @item arduinobinary The value should be the name/path of the arduino IDE binary for programming. If not specified, the function will attempt to find the binary itself. @end table @subsubheading Outputs @var{retval} - return 1 if arduino IDE returned without an error @seealso{arduino, __arduino_binary__} @end deftypefn @c General Functions isarduino @c ----------------------------------------- @subsection isarduino @cindex isarduino @deftypefn {} {@var{retval} =} isarduino (@var{obj}) Check if input value is an arduino object Function is essentially just a call of @code { retval = asis(obj, "arduino"); } @subsubheading Inputs @var{obj} - The object to check @subsubheading Outputs @var{retval} is true, if obj is an arduino object, false otherwise. @seealso{arduino} @end deftypefn @c General Functions listArduinoLibraries @c ----------------------------------------- @subsection listArduinoLibraries @cindex listArduinoLibraries @deftypefn {} {@var{retval} =} listArduinoLibraries () @deftypefnx {} {@var{retval} =} listArduinoLibraries (@var{libtypes}) Retrieve list of all known arduino library modules that are available. @subsubheading Inputs @var{libtypes} - optional specifier for type of libraries to list. Options are: @table @asis @item all List core and addons @item core List core only libraries @item addons List addons only @end table When no libtypes is specified, all libraries are shown. @subsubheading Outputs @var{retval} is an cell array of string library names that are available for programming to the arduino. @seealso{arduino, arduinosetup} @end deftypefn @c General Functions scanForArduinos @c ----------------------------------------- @subsection scanForArduinos @cindex scanForArduinos @deftypefn {} {@var{retval} =} scanForArduinos (@var{maxCount}) @deftypefnx {} {@var{retval} =} scanForArduinos (@var{maxCount}, @var{type}) Scan system for programmed arduino boards. scanForArduinos will scan the system for programmed arduino boards and return at most @var{maxCount} of them as a cell array in @var{retval}. @subsubheading Inputs @var{maxCount} - max number of arduino boards to detect. if @var{maxCount} is not specified, or is a less than 1, the function will return as many arduino boards as it can detect. @var{type} - optional board type to match. If specified, the board type must match for the arduino to be added to the return list. @subsubheading Outputs @var{retval} structure cell array of matching detected arduino boards. Each cell value of the cell array will contain a structure with values of: @table @asis @item port the serial port the arduino is connected to @item board the board type of the arduino @end table @seealso{arduino} @end deftypefn @c --------------------------------------------------- @node Arduino Functions @section Arduino Functions @cindex Arduino Functions @c Arduino Functions @arduino/arduino @c ----------------------------------------- @subsection @@arduino/arduino @cindex arduino @deftypefn {} {@var{retval} =} arduino () @deftypefnx {} {@var{retval} =} arduino (@var{port}) @deftypefnx {} {@var{retval} =} arduino (@var{port}, @var{board}) @deftypefnx {} {@var{retval} =} arduino (@var{port}, @var{board}[, [@var{propname}, @var{propvalue}]*) Create a arduino object with a connection to an arduino board. @subsubheading Inputs @var{port} - full path of serial port to connect to. For Linux, usually /dev/ttySXXX, for windows COMXX. @var{board} - name of board to connect (default is 'uno'). @var{propname}, @var{propvalue} - property name and value pair for additional properties to pass to the creation of the arduino object. Currently properties are ignored. if the arduino function is called without parameters, it will scan for the first available arduino it can find and connect to it. @subsubheading Outputs @var{retval} - a successfully connected arduino object. @subsubheading Properties The arduino object has the following public properties: @table @asis @item name name assigned to the arduino object @item debug true / false flag for whether debug in turned on @item port (read only) the communications port the board is connected to. @item board (read only) The name of the board type that the arduino connected to @item libraries (read only) The libraries currently programmed onto the board @item availablepins The pins available for use on the board @end table @seealso{scanForArduinos, arduinosetup} @end deftypefn @c Arduino Functions @arduino/checkI2CAddress @c ----------------------------------------- @subsection @@arduino/checkI2CAddress @cindex checkI2CAddress @deftypefn {} {@var{retval} =} checkI2CAddress (@var{ar}, @var{address}) @deftypefnx {} {@var{retval} =} checkI2CAddress (@var{ar}, @var{address}, @var{bus}) Check that an address of given address responds on the I2C bus @subsubheading Inputs @var{ar} - arduino object connected to a arduino board. @var{address} - I2C address number to check @var{bus} - bus number to check for I2C device, when multiple buses are available. If the bus is not specified, it will default to 0. @subsubheading Outputs @var{retval} - boolean value of true if address responds on the I2C bus @subsubheading Example @example @code { # create arduino connection. ar = arduino(); # scan for devices on the I2C bus checkI2CAddress (ar) # output if a device using that address is attached ans = 1 } @end example @seealso{arduino, scanI2Cbus} @end deftypefn @c Arduino Functions @arduino/configurePin @c ----------------------------------------- @subsection @@arduino/configurePin @cindex configurePin @deftypefn {} {@var{currmode} =} configurePin (@var{ar}, @var{pin}) @deftypefnx {} {} configurePin (@var{ar}, @var{pin}, @var{mode}) Set/Get pin mode for a specified pin on arduino connection. configurePin (@var{ar}, @var{pin}) will get the current mode of the specified pin. configurePin (@var{ar}, @var{pin}, @var{mode}) will attempt set the pin to the specified mode if the mode is unset. @subsubheading Inputs @var{ar} - the arduino object of the connection to an arduino board. @var{pin} - string name of the pin to set/get the mode of. @var{mode} - string mode to set the pin to. @subsubheading Outputs @var{mode} - string current mode of the pin. Valid modes can be: @itemize @bullet @item AnalogInput - Acquire analog signals from pin @item DigitalInput - Acquire digital signals from pin @item DigitalOutput - Generate digital signals from pin @item I2C - Specify a pin to use with I2C protocol @item Pullup - Specify pin to use a pullup switch @item PWM - Specify pin to use a pulse width modulator @item Servo - Specify pin to use a servo @item SPI - Specify a pin to use with SPI protocol @item Unset - Clears pin designation. The pin is no longer reserved and can be automatically set at the next operation. @end itemize @seealso{arduino} @end deftypefn @c Arduino Functions @arduino/configurePinResource @c ----------------------------------------- @subsection @@arduino/configurePinResource @cindex configurePinResource @deftypefn {} {@var{currmode} =} configurePinResource (@var{ar}, @var{pin}) @deftypefnx {} {} configurePinResource (@var{ar}, @var{pin}, @var{owner}, @var{mode}) @deftypefnx {} {} configurePinResource (@var{ar}, @var{pin}, @var{owner}, @var{mode}, @var{force}) Set/Get pin mode for a specified pin on arduino connection. configurePinResource (@var{ar}, @var{pin}) will get the current mode of the specified pin. configurePinResource (@var{ar}, @var{pin}, @var{owner}, @var{mode}) will attempt set the pin to the specified mode and owner. If the pin is already owned by another owner, the configure will fail unless the force option is used. If the mode is already set, configure will fail unless force is used. @subsubheading Inputs @var{ar} - the arduino object of the connection to an arduino board. @var{pin} - string name of the pin to set/get the mode of. @var{mode} - string mode to set the pin to. @var{owner} - string name to use as the pin owner. @var{force} - boolean to force mode change. If not set, it will be false. @subsubheading Outputs @var{currmode} - current string mode of the pin. Valid modes can be: @itemize @bullet @item AnalogInput - Acquire analog signals from pin @item DigitalInput - Acquire digital signals from pin @item DigitalOutput - Generate digital signals from pin @item I2C - Specify a pin to use with I2C protocol @item Pullup - Specify pin to use a pullup switch @item PWM - Specify pin to use a pulse width modulator @item Servo - Specify pin to use a servo @item SPI - Specify a pin to use with SPI protocol @item Reserved - Pin marked reserved, but not for of any particular mode @item Unset - Clears pin designation. The pin is no longer reserved and can be automatically set at the next operation. @end itemize @seealso{arduino, configurePin} @end deftypefn @c Arduino Functions @arduino/decrementResourceCount @c ----------------------------------------- @subsection @@arduino/decrementResourceCount @cindex decrementResourceCount @deftypefn {} {@var{count} =} decrementResourceCount (@var{ar}, @var{resource}) Decrement the count of a named resource by 1 and return the new count. @subsubheading Inputs @var{ar} - connected arduino object @var{resource} - name of resource to decrement count. @subsubheading Outputs @var{count} = count of uses registered to resource. @seealso{getResourceCount. incrementResourceCount} @end deftypefn @c Arduino Functions @arduino/display @c ----------------------------------------- @subsection @@arduino/display @cindex display @deftypefn {} {} display (@var{ar}) Display the arduino object in a verbose way, showing the board and available pins. @subsubheading Inputs @var{ar} - the arduino object. If the arduino object has debug mode set, additional information will be displayed. @seealso{arduino} @end deftypefn @c Arduino Functions @arduino/getI2CTerminals @c ----------------------------------------- @subsection @@arduino/getI2CTerminals @cindex getI2CTerminals @deftypefn {} {@var{pinlist} =} getI2CTerminals (@var{ar}) Get a cell list of pin Ids available are used for I2C mode. @subsubheading Inputs @var{ar} - the arduino object. @subsubheading Outputs @var{pinlist} - cell list of pin numbers available for I2C use. @seealso{arduino} @end deftypefn @c Arduino Functions @arduino/getLEDTerminals @c ----------------------------------------- @subsection @@arduino/getLEDTerminals @cindex getLEDTerminals @deftypefn {} {@var{pinlist} =} getLEDTerminals (@var{ar}) Get a cell list of pin Ids available are connected natively to LEDs. @subsubheading Inputs @var{ar} - the arduino object. @subsubheading Outputs @var{pinlist} - cell list of pin numbers available for LED use. @seealso{arduino} @end deftypefn @c Arduino Functions @arduino/getMCU @c ----------------------------------------- @subsection @@arduino/getMCU @cindex getMCU @deftypefn {} {@var{mcu} =} getMCU (@var{ar}) Get the MCU used by the connected arduino. @subsubheading Inputs @var{ar} - arduino object connected to a arduino board. @subsubheading Outputs @var{mcu} - string representing the mcu used by the arduino board. @seealso{arduino} @end deftypefn @c Arduino Functions @arduino/getPWMTerminals @c ----------------------------------------- @subsection @@arduino/getPWMTerminals @cindex getPWMTerminals @deftypefn {} {@var{pinlist} =} getPWMTerminals (@var{ar}) Get a cell list of pin Ids available for PWM use. @subsubheading Inputs @var{ar} - the arduino object. @subsubheading Outputs @var{pinlist} - cell list of pin numbers available for PWM use. @seealso{arduino} @end deftypefn @c Arduino Functions @arduino/getPinInfo @c ----------------------------------------- @subsection @@arduino/getPinInfo @cindex getPinInfo @deftypefn {} {@var{pininfo} =} getPinInfo (@var{ar}, @var{pin}) @deftypefnx {} {@var{pininfoarray} =} getPinInfo (@var{ar}, @var{pinarray}) Get the pin information from the input pins values. getPinInfo (@var{ar}, @var{pin}) will get information for a single pin. getPinInfo (@var{ar}, @var{pinarray}) will get a cell array of pin information @subsubheading Inputs @var{ar} - the connected arduino object. @var{pin} - a pin number or pin name. @var{pinarray} - the array of pin numbers or names The pininfo struct contains the following fields: @table @asis @item terminal Terminal number of the pin @item name String name of the pin @item owner Current item owner of the pin @item mode Current configured mode for the pin @end table @subsubheading Outputs @var{pininfo} - struct on pin information. @var{pininfolist} - cell array of pin info @seealso{arduino, configurePinResource, getResourceOwner} @end deftypefn @c Arduino Functions @arduino/getPinsFromTerminals @c ----------------------------------------- @subsection @@arduino/getPinsFromTerminals @cindex getPinsFromTerminals @deftypefn {} {@var{pinnames} =} getPinsFromTerminals (@var{ar}, @var{terminals}) Get the pin names from the input terminal values. @subsubheading Inputs @var{ar} - the connected arduino object. @var{terminals} - the numeric pin number, or array of pin numbers to get pin names. @subsubheading Outputs @var{pinnames} - the string names of each input pin. If terminals was a single value, the return will be a single string, otherwise it will return a cell array of each pin name. @seealso{arduino, getTerminalsFromPins} @end deftypefn @c Arduino Functions @arduino/getResourceCount @c ----------------------------------------- @subsection @@arduino/getResourceCount @cindex getResourceCount @deftypefn {} {@var{count} =} getResourceCount (@var{ar}, @var{resource}) Get the count of uses of a given resource. @subsubheading Inputs @var{ar} - connected arduino object @var{resource} - name of resource to get count for. @subsubheading Outputs @var{count} = count of uses registered to resource. @seealso{incrementResourceCount. decrementResourceCount} @end deftypefn @c Arduino Functions @arduino/getResourceOwner @c ----------------------------------------- @subsection @@arduino/getResourceOwner @cindex getResourceOwner @deftypefn {} {@var{owner} =} getResourceOwner (@var{ar}, @var{terminal}) Get the owner of pin allocated previously by configurePinResource. @subsubheading Inputs @var{ar} - connected arduino object @var{terminal} - terminal number to get owner of. @subsubheading Outputs @var{owner} = owner of the terminal pin, or "" if not owned. @seealso{configurePinResource} @end deftypefn @c Arduino Functions @arduino/getSPITerminals @c ----------------------------------------- @subsection @@arduino/getSPITerminals @cindex getSPITerminals @deftypefn {} {@var{pinlist} =} getSPITerminals (@var{ar}) Get a cell list of pin Ids available for SPI mode. @subsubheading Inputs @var{ar} - the arduino object. @subsubheading Outputs @var{pinlist} - cell list of pin numbers available for SPI use. @seealso{arduino} @end deftypefn @c Arduino Functions @arduino/getServoTerminals @c ----------------------------------------- @subsection @@arduino/getServoTerminals @cindex getServoTerminals @deftypefn {} {@var{pinlist} =} getServoTerminals (@var{ar}) Get a cell list of pin Ids available for servo use. @subsubheading Inputs @var{ar} - the arduino object. @subsubheading Outputs @var{pinlist} - cell list of pin numbers available for servo use. @seealso{arduino, getPWMTerminals} @end deftypefn @c Arduino Functions @arduino/getSharedResourceProperty @c ----------------------------------------- @subsection @@arduino/getSharedResourceProperty @cindex getSharedResourceProperty @deftypefn {} {@var{count} =} getSharedResourceProperty (@var{ar}, @var{resource}, @var{property}) Get the value of a property from a given resource. @subsubheading Inputs @var{ar} - connected arduino object @var{resource} - name of resource to get property for. @var{property} - name of property from the resource. @subsubheading Outputs @var{propvalue} - value of the property @seealso{getResourceCount, setSharedResourceProperty} @end deftypefn @c Arduino Functions @arduino/getTerminalMode @c ----------------------------------------- @subsection @@arduino/getTerminalMode @cindex getTerminalMode @deftypefn {} {@var{mode} =} getTerminalMode (@var{ar}, @var{terminal}) Get the mode of a pin allocated previously by configurePinResource. @subsubheading Inputs @var{ar} - connected arduino object @var{terminal} - terminal number to get owner of. @subsubheading Outputs @var{mode} - mode of the terminal pin, or "not_set" if not owned. @seealso{configurePinResource, getResourceOwner} @end deftypefn @c Arduino Functions @arduino/getTerminalsFromPins @c ----------------------------------------- @subsection @@arduino/getTerminalsFromPins @cindex getTerminalsFromPins @deftypefn {} {@var{pinnums} =} getTerminalsFromPins (@var{ar}, @var{pins}) Get the terminal number for each pin. @subsubheading Inputs @var{ar} - connected arduino object @var{pins} - single pin name or cell or vector array of pin names. @subsubheading Outputs @var{pinnums} - pin number of each named pin. If the input was a single string, returns a number. if the input pins was a vector or cell array, return a cell array of pin numbers corresponding to each input pin name. @seealso{arduino, getPinsFromTerminals} @end deftypefn @c Arduino Functions @arduino/incrementResourceCount @c ----------------------------------------- @subsection @@arduino/incrementResourceCount @cindex incrementResourceCount @deftypefn {} {@var{count} =} incrementResourceCount (@var{ar}, @var{resource}) Increment the count value of a named resource by 1 and return the new count @subsubheading Inputs @var{ar} - connected arduino object @var{resource} - name of resource to increment count. @subsubheading Outputs @var{count} = count of uses registered to resource. @seealso{getResourceCount. decrementResourceCount} @end deftypefn @c Arduino Functions @arduino/isTerminalAnalog @c ----------------------------------------- @subsection @@arduino/isTerminalAnalog @cindex isTerminalAnalog @deftypefn {} {@var{ret} = } isTerminalAnalog (@var{obj}, @var{terminal}) Return true if pin is capable of analog input @subsubheading Inputs @var{ar} - the connected arduino object @var{terminal} is a terminal number to check @subsubheading Outputs @var{ret} return 1 if terminal is a analog pin, 0 otherwise @end deftypefn @c Arduino Functions @arduino/isTerminalDigital @c ----------------------------------------- @subsection @@arduino/isTerminalDigital @cindex isTerminalDigital @deftypefn {} {@var{ret} = } isTerminalDigital(@var{obj}, @var{terminal}) Return true if pin is capable of digital functions @subsubheading Inputs @var{ar} - the connected arduino object @var{terminal} is a terminal number to check @subsubheading Outputs @var{ret} return 1 if terminal is a digital pin, 0 otherwise @end deftypefn @c Arduino Functions @arduino/playTone @c ----------------------------------------- @subsection @@arduino/playTone @cindex playTone @deftypefn {} {} playTone (@var{ar}, @var{pin}, @var{freq}, @var{duration}) Play a tone of a given frequency on a specified pin. @subsubheading Inputs @var{ar} - connected arduino object @var{pin} - digital pin to play tone on @var{freq} - frequency in hertz to play between 0 and 32767Hz. @var{duration} duration in seconds to play tone between 0 and 30 seconds If duration is 0 or not specified, tone will continue to play until next tone is commanded. If frequency is 0, tone will stop playing @strong{NOTE:} use of playTone can interfere with PWM output. @end deftypefn @c Arduino Functions @arduino/readAnalogPin @c ----------------------------------------- @subsection @@arduino/readAnalogPin @cindex readAnalogPin @deftypefn {} {@var{value} =} readAnalogPin (@var{ar}, @var{pin}) Read analog voltage of @var{pin}. @subsubheading Inputs @var{ar} - connected arduino object. @var{pin} - string name of the pin to read. @subsubheading Outputs @var{value} - analog value of the pin @subsubheading Example @example @code{ ar = arduino (); readAnalogPin(ar, "A4"); ans = 87 } @end example @seealso{arduino, readVoltage} @end deftypefn @c Arduino Functions @arduino/readDigitalPin @c ----------------------------------------- @subsection @@arduino/readDigitalPin @cindex readDigitalPin @deftypefn {} {@var{value} =} readDigitalPin (@var{obj}, @var{pin}) Read digital value from a digital I/O pin. @subsubheading Inputs @var{ar} - connected arduino object. @var{pin} - string name of the pin to read. @subsubheading Outputs @var{value} - the logical value (0, 1, true false) of the current pin state. @subsubheading Example @example @code{ a = arduino (); pinvalue = readDigitalPin (a, 'D5'); } @end example @seealso{arduino, writeDigitalPin} @end deftypefn @c Arduino Functions @arduino/readVoltage @c ----------------------------------------- @subsection @@arduino/readVoltage @cindex readVoltage @deftypefn {} {@var{voltage} =} readVoltage (@var{ar}, @var{pin}) Read analog voltage of a pin. @subsubheading Inputs @var{ar} - connected arduino. @var{pin} - pin name or number to query for voltage @subsubheading Outputs @var{voltage} - scaled pin value as a voltage @subsubheading Example @example @code{ ar = arduino (); readVoltage(ar, "A4"); ans = 1.401 } @end example @seealso{arduino, readAnalogPin} @end deftypefn @c Arduino Functions @arduino/reset @c ----------------------------------------- @subsection @@arduino/reset @cindex reset @deftypefn {} {} reset (@var{ar}) Send reset command to arduino hardware to force a hardware reset. @subsubheading Inputs @var{ar} - connected arduino object. @seealso{arduino} @end deftypefn @c Arduino Functions @arduino/sendCommand @c ----------------------------------------- @subsection @@arduino/sendCommand @cindex sendCommand @deftypefn {} {@var{outdata, outsize} =} sendCommand (@var{ar}, @var{libname}, @var{commandid}) @deftypefnx {} {@var{outdata, outsize} =} sendCommand (@var{ar}, @var{libname}, @var{commandid}, @var{data}) @deftypefnx {} {@var{outdata, outsize} =} sendCommand (@var{ar}, @var{libname}, @var{commandid}, @var{data}, @var{timeout}) Send a command with option data to the connected arduino, waiting up to a specified number of seconds for a response. @subsubheading Inputs @var{ar} - connected arduino object. @var{libname} - library sending the command. The name should match a programmed library of the arduino, or an error will be displayed. @var{commandid} - integer value for the command being sent to the arduino. @var{data} - optional data sent with the command. @var{timeout} - optional timeout to wait for data @subsubheading Outputs @var{outdata} - data returned back from the arduino in response to command @var{outsize} - size of data received If the arduino fails to respond with a valid reply, sendCommand will error. @seealso{arduino} @end deftypefn @c Arduino Functions @arduino/setSharedResourceProperty @c ----------------------------------------- @subsection @@arduino/setSharedResourceProperty @cindex setSharedResourceProperty @deftypefn {} {} setSharedResourceProperty (@var{ar}, @var{resource}, @var{propname}, @var{propvalue}) @deftypefnx {} {} setSharedResourceProperty (@var{ar}, @var{resource}, @var{propname}, @var{propvalue}, ___) Set property values for a given resource. @subsubheading Inputs @var{ar} - connected arduino object @var{resource} - name of resource to get property for. @var{propname} - name of property from the resource. @var{propvalue} - value of property from the resource. Multiple @var{propname}, @var{propvalue} pairs can be given. @subsubheading Outputs None @subsubheading Example @example @code{ ar = arduino(); setSharedResourceProperty(ar, "myresource", "myproperty", [1 2 3]) } @end example @seealso{getSharedResourceProperty} @end deftypefn @c Arduino Functions @arduino/uptime @c ----------------------------------------- @subsection @@arduino/uptime @cindex uptime @deftypefn {} {@var{sec} =} uptime (@var{ar}) Get the number of seconds the arduino board has been running concurrently. @subsubheading Inputs @var{ar} - the arduino object of the connection to an arduino board. @subsubheading Outputs @var{sec} - the number seconds the board has been running. Note that the count will wrap around after approximately 50 days. @seealso{arduino} @end deftypefn @c Arduino Functions @arduino/validatePin @c ----------------------------------------- @subsection @@arduino/validatePin @cindex validatePin @deftypefn {} {} validatePin (@var{ar}, @var{pin}, @var{type}) Validate that the mode is allowed for specified pin If the mode is not valid, and error will be thrown. @subsubheading Inputs @var{ar} - connected arduino object @var{pin} - name of pin to query mode validity of @var{mode} - mode to query Known modes are: @itemize @bullet @item 'I2C' @item 'SPI' @item 'PWM' @item 'Servo' @item 'analog' @item 'digital' @end itemize @seealso{arduino, configurePin} @end deftypefn @c Arduino Functions @arduino/version @c ----------------------------------------- @subsection @@arduino/version @cindex version @deftypefn {} {@var{ver} =} version (@var{ar}) Get version of library code installed on arduino board @subsubheading Inputs @var{ar} - the arduino object of the connection to an arduino board. @subsubheading Outputs @var{ver} - version string in format of X.Y.Z. @seealso{arduino} @end deftypefn @c Arduino Functions @arduino/writeDigitalPin @c ----------------------------------------- @subsection @@arduino/writeDigitalPin @cindex writeDigitalPin @deftypefn {} {} writeDigitalPin (@var{ar}, @var{pin}, @var{value}) Write digital value to a digital I/O pin. @subsubheading Inputs @var{ar} - connected arduino object. @var{pin} - string name of the pin to write to. @var{value} - the logical value (0, 1, true false) to write to the pin. If pin was unconfigured before using, pin is set into digital mode. @subsubheading Example @example @code{ a = arduino(); writeDigitalPin(a,'D5',1); } @end example @seealso{arduino, readDigitalPin} @end deftypefn @c Arduino Functions @arduino/writePWMDutyCycle @c ----------------------------------------- @subsection @@arduino/writePWMDutyCycle @cindex writePWMDutyCycle @deftypefn {} {} writePWMDutyCyle (@var{ar}, @var{pin}, @var{value}) Set pin to output a square wave with a specified duty cycle. @subsubheading Inputs @var{ar} - connected arduino object @var{pin} - pin to write to. @var{value} - duty cycle value where 0 = off, 0.5 = 50% on, 1 = always on. @subsubheading Example @example @code{ a = arduino(); writePWMDutyCycle(a,'D5',0.5); } @end example @seealso{arduino, writePWMVoltage} @end deftypefn @c Arduino Functions @arduino/writePWMVoltage @c ----------------------------------------- @subsection @@arduino/writePWMVoltage @cindex writePWMVoltage @deftypefn {} {} writePWMVoltage (@var{ar}, @var{pin}, @var{voltage}) Emulate an approximate voltage out of a pin using PWM. @subsubheading Inputs @var{ar} - connected arduino object @var{pin} - pin to write to. @var{voltage} - voltage to emulate with PWM, between 0 - 5.0 @subsubheading Example @example @code{ a = arduino(); writePWMVoltage(a,'D5',1.0); } @end example @seealso{arduino, writePWMDutyCycle} @end deftypefn @c --------------------------------------------------- @node Arduino I2C Functions @section Arduino I2C Functions @cindex Arduino I2C Functions @c Arduino I2C Functions @i2cdev/display @c ----------------------------------------- @subsection @@i2cdev/display @cindex display @deftypefn {} {} display (@var{dev}) Display i2cdev object. @subsubheading Inputs @var{dev} - i2cdev object @seealso{i2cdev} @end deftypefn @c Arduino I2C Functions @i2cdev/i2cdev @c ----------------------------------------- @subsection @@i2cdev/i2cdev @cindex i2cdev @deftypefn {} {@var{dev} =} i2cdev (@var{ar}, @var{address}) @deftypefnx {} {@var{dev} =} i2cdev (@var{ar}, @var{address}, @var{propname}, @var{propvalue}) Create an i2cdev object to communicate to the i2c port on a connected arduino. @subsubheading Inputs @var{ar} - connected arduino object @var{address} - address to use for device on I2C bus. @var{propname}, @var{propvalue} - property name/value pair for values to pass to devices. Currently known properties: @table @asis @item bus bus number (when arduino board supports multiple I2C buses) with value of 0 or 1. @end table @subsubheading Outputs @var{dev} - new created i2cdev object. @subsubheading Properties The i2cdev object has the following public properties: @table @asis @item parent The parent (arduino) for this device @item pins pins used by this object @item bus bus used for created object @item address I2C address set for object @end table @seealso{arduino} @end deftypefn @c Arduino I2C Functions @i2cdev/read @c ----------------------------------------- @subsection @@i2cdev/read @cindex read @deftypefn {} {@var{data} =} read (@var{dev}, @var{numbytes}) @deftypefnx {} {@var{data} =} read (@var{dev}, @var{numbytes}, @var{precision}) Read a specified number of bytes from a i2cdev object using optional precision for bytesize. @subsubheading Inputs @var{dev} - connected i2c device opened using i2cdev @var{numbytes} - number of bytes to read. @var{precision} - Optional precision for the output data read data. Currently known precision values are uint8 (default), int8, uint16, int16 @subsubheading Outputs @var{data} - data read from i2cdevice @seealso{arduino, i2cdev} @end deftypefn @c Arduino I2C Functions @i2cdev/readRegister @c ----------------------------------------- @subsection @@i2cdev/readRegister @cindex readRegister @deftypefn {} {@var{data} =} readRegister (@var{dev}, @var{reg}, @var{numbytes}) @deftypefnx {} {@var{data} =} readRegister (@var{dev}, @var{reg}, @var{numbytes}, @var{precision}) Read a specified number of bytes from a register of an i2cdev object using optional precision for bytesize. @subsubheading Inputs @var{dev} - connected i2c device opened using i2cdev @var{reg} - registry value number @var{numbytes} - number of bytes to read. @var{precision} - Optional precision for the output data read data. Currently known precision values are uint8 (default), int8, uint16, int16 @subsubheading Output @var{data} - data read from device. @seealso{arduino, i2cdev} @end deftypefn @c Arduino I2C Functions @i2cdev/subsref @c ----------------------------------------- @subsection @@i2cdev/subsref @cindex subsref @deftypefn {} {@var{val} = } subsref (@var{dev}, @var{sub}) subref for i2cdev @seealso{i2cdev} @end deftypefn @c Arduino I2C Functions @i2cdev/write @c ----------------------------------------- @subsection @@i2cdev/write @cindex write @deftypefn {} {} write (@var{dev}, @var{datain}) @deftypefnx {} {} write (@var{dev}, @var{datain}, @var{precision}) Write data to a i2cdev object using optional precision for the data byte used for the data. @subsubheading Inputs @var{dev} - connected i2c device opened using i2cdev @var{datain} - data to write to device. Datasize should not exceed the constraints of the data type specified for the precision. @var{precision} - Optional precision for the input write data. Currently known precision values are uint8 (default), int8, uint16, int16 @seealso{arduino, i2cdev, read} @end deftypefn @c Arduino I2C Functions @i2cdev/writeRegister @c ----------------------------------------- @subsection @@i2cdev/writeRegister @cindex writeRegister @deftypefn {} {} writeRegister (@var{dev}, @var{reg}, @var{datain}) @deftypefnx {} {} writeRegister (@var{dev}, @var{dev}, @var{datain}, @var{precision}) Write data to i2cdev object at a given registry position using optional precision for the data byte used for the data. @subsubheading Inputs @var{dev} - connected i2c device opened using i2cdev @var{reg} - registry position to write to. @var{datain} - data to write to device. Datasize should not exceed the constraints of the data type specified for the precision. @var{precision} - Optional precision for the input write data. Currently known precision values are uint8 (default), int8, uint16, int16 @seealso{arduino, i2cdev, read} @end deftypefn @c Arduino I2C Functions scanI2Cbus @c ----------------------------------------- @subsection scanI2Cbus @cindex scanI2Cbus @deftypefn {} {@var{retval} =} scanI2Cbus (@var{ar}) @deftypefnx {} {@var{retval} =} scanI2Cbus (@var{ar}, @var{bus}) Scan arduino for devices on the I2C bus. @subsubheading Inputs @var{ar} - arduino object connected to a arduino board. @var{bus} - bus number to scan I2C devices, when multiple buses are available. If the bus is not specified, it will default to 0. @subsubheading Outputs @var{retval} - cell array of addresses as strings in format of "0xXX". @subsubheading Example @example @code { # create arduino connection. ar = arduino(); # scan for devices on the I2C bus scanI2Cbus (ar) # output is each detected i2c address as a string ans = @{ [1,1] = 0x50 @} } @end example @seealso{arduino, i2cdev, checkI2CAddress} @end deftypefn @c --------------------------------------------------- @node Arduino Rotary Encoder Functions @section Arduino Rotary Encoder Functions @cindex Arduino Rotary Encoder Functions @c Arduino Rotary Encoder Functions @rotaryEncoder/display @c ----------------------------------------- @subsection @@rotaryEncoder/display @cindex display @deftypefn {} {@var{retval} =} display (@var{obj}) Display the rotary encoder object in a verbose way, @subsubheading Inputs @var{obj} - the arduino rotary encoder object created with rotaryEncoder @seealso{rotaryEncoder} @end deftypefn @c Arduino Rotary Encoder Functions @rotaryEncoder/readCount @c ----------------------------------------- @subsection @@rotaryEncoder/readCount @cindex readCount @deftypefn {} {[@var{count}, @var{time}] =} readCount (@var{obj}) @deftypefnx {} {[@var{count}, @var{time}] =} readCount (@var{obj}, @var{name}, @var{value}) read count value from the rotary encoder. subsubheading Inputs @var{obj} - rotary encoder object created with rotaryEncoder call. @var{name}, @var{value} - optional name,value pairs Valid option name pairs currently are: @table @asis @item reset Reset the count after reading (if true) @end table @subsubheading Outputs @var{count} - returned count read from the encoder. @var{time} - seconds since arduino started @seealso{rotaryEncoder, resetCount} @end deftypefn @c Arduino Rotary Encoder Functions @rotaryEncoder/readSpeed @c ----------------------------------------- @subsection @@rotaryEncoder/readSpeed @cindex readSpeed @deftypefn {} {@var{speed} =} readSpeed (@var{obj}) read rotational speed from the rotary encoder. @subsubheading Inputs @var{obj} - rotary encoder object created with rotaryEncoder call. @subsubheading Outputs @var{speed} - returned speed in revolutions per minute read from the encoder. @seealso{rotaryEncoder, resetCount} @end deftypefn @c Arduino Rotary Encoder Functions @rotaryEncoder/resetCount @c ----------------------------------------- @subsection @@rotaryEncoder/resetCount @cindex resetCount @deftypefn {} reset (@var{obj}) @deftypefnx {} reset (@var{obj}, @var{cnt}) reset the rotary encoder count values @subsubheading Inputs @var{obj} - the rotaryEncoder object @var{cnt} - optional count value to reset to @seealso{rotaryEncoder, readCount} @end deftypefn @c Arduino Rotary Encoder Functions @rotaryEncoder/rotaryEncoder @c ----------------------------------------- @subsection @@rotaryEncoder/rotaryEncoder @cindex rotaryEncoder @deftypefn {} {@var{obj} =} rotaryEncoder (@var{ar}, @var{chanApin}, @var{chanBpin}) @deftypefnx {} {@var{obj} =} rotaryEncoder (@var{ar}, @var{chanApin}, @var{chanBpin}, @var{ppr}) Create a rotaryEncoder object controlled by the input pins. @subsubheading Inputs @var{ar} - connected arduino object. @var{chanApin} - pin used for channel A @var{chanBpin} - pin used for channel B @var{ppr} - count of encoder pulsed required for a full revolution of the encoder. @subsubheading Outputs @var{obj} - created rotary encoder object @subsubheading Example @example a = arduino (); enc = rotaryEncoder(a, "d2", "d3", 180); @end example @subsubheading Properties The rotaryEncoder object has the following public properties: @table @asis @item parent The parent (arduino) for this device @item pins pins used by this object @item ppr Number of pulses used per rotation @end table @seealso{arduino} @end deftypefn @c Arduino Rotary Encoder Functions @rotaryEncoder/subsref @c ----------------------------------------- @subsection @@rotaryEncoder/subsref @cindex subsref @deftypefn {} {@var{val} = } subsref (@var{dev}, @var{sub}) subref for rotaryEncoder @seealso{rotaryEncoder} @end deftypefn @c --------------------------------------------------- @node Arduino Servo Functions @section Arduino Servo Functions @cindex Arduino Servo Functions @c Arduino Servo Functions @servo/display @c ----------------------------------------- @subsection @@servo/display @cindex display @deftypefn {} {} display (@var{dev}) Display servo object. @subsubheading Inputs @var{dev} - device to display @seealso{servo} @end deftypefn @c Arduino Servo Functions @servo/readPosition @c ----------------------------------------- @subsection @@servo/readPosition @cindex readPosition @deftypefn {} {@var{position} = } readPosition (@var{servo}) Read the position of a servo @subsubheading Inputs @var{servo} - servo object created from arduino.servo. @subsubheading Outputs @var{position} - value between 0 .. 1 for the current servo position, where 0 is the servo min position, 1 is the servo maximum position. @seealso{servo, writePosition} @end deftypefn @c Arduino Servo Functions @servo/servo @c ----------------------------------------- @subsection @@servo/servo @cindex servo @deftypefn {} {@var{obj} = } servo (@var{arduinoobj}, @var{pin}) @deftypefnx {} {@var{obj} = } servo (@var{arduinoobj}, @var{pin}, @var{propertyname}, @var{propertyvalue}) Create a servo object using a specified pin on a arduino board. @subsubheading Inputs @var{obj} - servo object @var{arduinoobj} - connected arduino object @var{propertyname}, @var{propertyvalue} - name value pairs for properties to pass to the created servo object. Current properties are: @table @asis @item minpulseduration min PWM pulse value in seconds. @item maxpulseduration max PWM pulse value in seconds. @end table @subsubheading Outputs @var{obj} - created servo object. @subsubheading Example @example # create arduino connection ar = arduino(); # create hobby servo (1 - 2 ms pulse range) servo = servo(ar, "d9", "minpulseduration", 1.0e-3, "maxpulseduration", 2e-3); # center the servo writePosition(servo, 0.5); @end example @subsubheading Properties The servo object has the following public properties: @table @asis @item parent The parent (arduino) for this device @item pins pins used by this object @item minpulseduration minpusleduration set for object @item maxpulseduration maxpulseduration set for object @end table @seealso{arduino, readPosition, writePosition} @end deftypefn @c Arduino Servo Functions @servo/subsref @c ----------------------------------------- @subsection @@servo/subsref @cindex subsref @deftypefn {} {@var{val} = } subsref (@var{dev}, @var{sub}) subref for servo @seealso{servo} @end deftypefn @c Arduino Servo Functions @servo/writePosition @c ----------------------------------------- @subsection @@servo/writePosition @cindex writePosition @deftypefn {} {} writePosition (@var{servo}, @var{position}) Write the position to a servo. @subsubheading Inputs @var{servo} - servo object created from arduino.servo. @var{position} - value between 0 .. 1 for the current servo position, where 0 is the servo min position, 1 is the servo maximum position. @seealso{servo, readPosition} @end deftypefn @c --------------------------------------------------- @node Arduino Shiftregister Functions @section Arduino Shiftregister Functions @cindex Arduino Shiftregister Functions @c Arduino Shiftregister Functions @shiftRegister/display @c ----------------------------------------- @subsection @@shiftRegister/display @cindex display @deftypefn {} {@var{retval} =} display (@var{register}) Display the register object in a verbose way, @subsubheading Inputs @var{register} - the arduino register object created with shiftRegister. @seealso{shiftRegister} @end deftypefn @c Arduino Shiftregister Functions @shiftRegister/read @c ----------------------------------------- @subsection @@shiftRegister/read @cindex read @deftypefn {} {@var{retval} =} read (@var{register}) @deftypefnx {} {@var{retval} =} read (@var{register}, @var{precision}) read a value from the shift register. @subsubheading Inputs @var{register} - shift register created from shiftRegister call. @var{precision} - optional precision of the data, where precision can be a number in a multiple of 8 (ie: 8,16,32) or can be a named integer type: 8 of 'uint8', 'uint16', 'uint32'. The default precision is 8. @subsubheading Outputs @var{retval} - returned data read from the register. @seealso{shiftRegister, write} @end deftypefn @c Arduino Shiftregister Functions @shiftRegister/reset @c ----------------------------------------- @subsection @@shiftRegister/reset @cindex reset @deftypefn {} reset (@var{register}) clear the shift register value. @subsubheading Inputs @var{register} - shift register created from shiftRegister call. @seealso{shiftRegister, read, write} @end deftypefn @c Arduino Shiftregister Functions @shiftRegister/shiftRegister @c ----------------------------------------- @subsection @@shiftRegister/shiftRegister @cindex shiftRegister @deftypefn {} {@var{register} =} shiftRegister (@var{ar}, @var{shifttype}, @var{dataPin}, @var{clockPin} ...) @deftypefnx {} {@var{register} =} shiftRegister (@var{ar},'74hc164', @var{dataPin}, @var{clockPin}, @var{resetPin}) @deftypefnx {} {@var{register} =} shiftRegister (@var{ar},'74hc165', @var{dataPin}, @var{clockPin}, @var{loadPin}, @var{clockEnablePin}) @deftypefnx {} {@var{register} =} shiftRegister(@var{ar},'74hc595', @var{dataPin}, @var{clockPin}, @var{latchPin} , @var{resetPin}) Create shift register of a given type, controlled by the input pins. @subsubheading Inputs Common function parameter definition: @var{ar} - connected arduino object. @var{shifttype} - string name of the shift register type. @var{dataPin} - pin used for data in/out of the device. @var{clockPin} - pin used for clocking data on the shiftRegister. Other variables are dependent on the shift register type: @table @asis @item '74hc164' Additional inputs: @var{resetPin} - optional pin for resetting the shift register. @item '74hc165' Additional inputs: @var{loadPin} - load pin to the shift register. @var{clockEnablePin} - clock enable pin. @item '74hc595' Additional inputs: @var{latchPin} - latching data to the shift register. @var{resetPin} - optional pin for resetting the shift register. @end table @subsubheading Outputs @var{register} - register object @subsubheading Properties The shiftRegister object has the following public properties: @table @asis @item parent The parent (arduino) for this device @item pins pins used by this object @item model model set for object @end table @seealso{arduino} @end deftypefn @c Arduino Shiftregister Functions @shiftRegister/subsref @c ----------------------------------------- @subsection @@shiftRegister/subsref @cindex subsref @deftypefn {} {@var{val} = } subsref (@var{dev}, @var{sub}) subref for shiftRegister @seealso{shiftRegister} @end deftypefn @c Arduino Shiftregister Functions @shiftRegister/write @c ----------------------------------------- @subsection @@shiftRegister/write @cindex write @deftypefn {} write (@var{register}, @var{dataIn}) @deftypefnx {} write (@var{register}, @var{dataIn}, @var{precision}) Write a value to the shift register. @subsubheading Inputs @var{register} - shift register created from shiftRegister call. @var{dataIn} - data to clock into the shiftRegister. @var{precision} - optional precision of the data, where precision can be a number in a multiple of 8 (ie: 8,16,32) or can be a named integer type of 'uint8', 'uint16', 'uint32'. The default precision is 8. @seealso{shiftRegister, read} @end deftypefn @c --------------------------------------------------- @node Arduino SPI Functions @section Arduino SPI Functions @cindex Arduino SPI Functions @c Arduino SPI Functions @spidev/display @c ----------------------------------------- @subsection @@spidev/display @cindex display @deftypefn {} {} display (@var{dev}) Display spidev object. @subsubheading Inputs @var{dev} - spidev object to display @seealso{spidev} @end deftypefn @c Arduino SPI Functions @spidev/spidev @c ----------------------------------------- @subsection @@spidev/spidev @cindex spidev @deftypefn {} {@var{dev} =} spidev (@var{ar}, @var{cspin}) @deftypefnx {} {@var{dev} =} spidev (@var{ar}, @var{cspin}, @var{propname}, @var{propvalue}) Create an spidev object to communicate to the SPI port on a connected arduino. @subsubheading Inputs @var{ar} - connected arduino object @var{cspin} - chip select pin for attached spi device. @var{propname}, @var{propvalue} - property name/value pair for values to pass to devices. Currently known properties: @table @asis @item bitrate bit rate speed in Mbs @item bitorder 'msbfirst' or 'lsbfirst' @item mode SPI mode 0 - 3. @end table @subsubheading Outputs @var{dev} - created spidev object @subsubheading Properties The spidev object has the following public properties: @table @asis @item parent The parent (arduino) for this device @item pins pins used by this object @item mode mode used for created object @item bitrate Bitrate set for object @item bitorder Bitorder set for object @item chipselectpin Pin used for chipselect @end table @seealso{arduino, readWrite} @end deftypefn @c Arduino SPI Functions @spidev/subsref @c ----------------------------------------- @subsection @@spidev/subsref @cindex subsref @deftypefn {} {@var{val} = } subsref (@var{dev}, @var{sub}) subref for spidev @seealso{spidev} @end deftypefn @c Arduino SPI Functions @spidev/writeRead @c ----------------------------------------- @subsection @@spidev/writeRead @cindex writeRead @deftypefn {} {@var{dataOut} =} readWrite (@var{spi}, @var{dataIn}) Write uint8 data to spi device and return back clocked out response data of same size. @subsubheading Inputs @var{spi} - connected spi device on arduino @var{dataIn} - uint8 sized data to send to spi device framed between SS frame. @subsubheading Outputs @var{dataOut} - uint8 data clocked out during send to dataIn. @seealso{arduino, spidev} @end deftypefn @c --------------------------------------------------- @node Arduino Addons @section Arduino Addons @cindex Arduino Addons @c Arduino Addons addon @c ----------------------------------------- @subsection addon @cindex addon @deftypefn {} {@var{retval} =} addon (@var{ar}, @var{addonname}) @deftypefnx {} {@var{retval} =} addon (@var{ar}, @var{addonname}, varargs) Create an addon object using the addon named class. @subsubheading Inputs @var{ar} - connected arduino object @var{addonname} - the name of the addon to create. The addon name can be a user addon or an inbuilt addon, however must appear in the listArduinoLibraries output and have been programmed onto the arduino. @var{varargs} - optional values that will be provided verbatim to the the addon class constructor. @subsubheading Outputs @var{retval} - cell array of string library names. @seealso{arduino, arduinosetup, listArduinoLibraries} @end deftypefn @c Arduino Addons arduinoioaddons.EEPRomAddon.EEPRom @c ----------------------------------------- @subsection arduinoioaddons.EEPRomAddon.EEPRom @cindex EEPRom @deftypefn {} {} arduinoioaddons.EEPRomAddon.EEPRom EEPROM addon for arduino Allows read and write of uint8 data to the onboard arduino EEPROM. @subsubheading Example Assuming eeprom addon has been programmed into the Arduino: @example a = arduino (); e = addon (a, "eepromaddon/eeprom"); write (e, 0, uint8("hello world")); str = uint8( read(e, 0, 11) ) @end example @seealso{addon} @end deftypefn @subsubheading Properties @var{length} - Size of the EEPROM. @subheading Methods @deftypefn {} {@var{eeprom} =} EEPRom () Constructor to create eeprom device. @subsubheading Outputs @var{eeprom} - created EEPROM device. @end deftypefn @deftypefn {} {} erase () Erase all values in EEPROM (Effectively setting the 0xFF) @end deftypefn @deftypefn {} {} write (@var{address}, @var{uintdata}) Write data to EEPROM at the provided address. @subsubheading Inputs @var{address} - start address to write data to, should be a integer between 0 and the size of the EEPROM. @var{uintdata} a value or array of uint8 data to write to EEPROM. @end deftypefn @deftypefn {} {@var{data} =} read (@var{address}) @deftypefnx {} {@var{data} =} read (@var{address}, @var{count}) Read data from starting address of EEPROM. @subsubheading Inputs @var{address} - start address to read data from, should be a integer between 0 and the size of the EEPROM. @var{count} - Number of uint8 values to read from the EEPROM (default is 1) @subsubheading Outputs @var{data} a value or array of uint8 data read from the EEROM. @end deftypefn @c Arduino Addons arduinoioaddons.ExampleAddon.Echo @c ----------------------------------------- @subsection arduinoioaddons.ExampleAddon.Echo @cindex Echo @deftypefn {} {} arduinoioaddons.ExampleAddon.Echo Basic Example matlab/octave code to illustrate creating a user addon. @seealso{addon} @end deftypefn @subsubheading Properties @var{Parent} - the parent arduino object. @var{Pins} - the pins allocated the addon. @subheading Methods @deftypefn {} {@var{obj} =} Echo(arObj) Constructor to create Echo addon @subsubheading Inputs @var{arObj} - the arduino parent object @subsubheading Outputs @var{obj} - created Echo object @end deftypefn @deftypefn {} {@var{response} = } shout(@var{text}) Send text to arduino and receive back the echoed reply @subsubheading Inputs @var{text} - text to send to arduino @subsubheading Outputs @var{response} - response from the arduino, which should be the same as the input text. @end deftypefn @c Arduino Addons arduinoioaddons.ExampleLCD.LCD @c ----------------------------------------- @subsection arduinoioaddons.ExampleLCD.LCD @cindex LCD @deftypefn {} {} arduinoioaddons.LCDAddon.LCD Basic Example octave addon for LCD Allows basic manipulation of an LCD as a illustration of using the addon functionality. @subsubheading Example Assuming the arduino has been programmed with the lcd addon: @example a = arduino(); lcd = addon(a, "examplelcd/lcd", "d8", "d9", "d4", "d5", "d6", "d7") clearLCD(lcd); printLCD(lcd, "Hello"); # go to next line gotoLCD(lcd, 0, 1); printLCD(lcd, "World"); @end example @seealso{addon} @end deftypefn @subsubheading Properties @var{Pins} - the pins allocated the LCD display. @subheading Methods @deftypefn {} {@var{lcd} =} LCD(arObj, rs, enable, d0, d1, d2, d3) Constructor to create LCD device @subsubheading Inputs @var{arObj} - the arduino parent object @var{rs} - the pin to use for the rs line. @var{enable} - the pin to use for the enable line. @var{d0} - the pin to use for the d0 line. @var{d1} - the pin to use for the d1 line. @var{d2} - the pin to use for the d2 line. @var{d3} - the pin to use for the d3 line. @subsubheading Outputs @var{lcd} - created LCD object @end deftypefn @deftypefn {} {} freeLCD() Free the LCD Should be called before discarding the LCD @subsubheading Inputs None. @subsubheading Outputs None. @end deftypefn @deftypefn {} {} clearLCD() Clear the LCD display and set the cursor position to the home position. @subsubheading Inputs None. @subsubheading Outputs None. @end deftypefn @deftypefn {} {} printLCD(@var{text}) Display text on LCD starting at the current cursor position. @subsubheading Inputs @var{text} - text to display on LCD @subsubheading Outputs None. @end deftypefn @deftypefn {} {} gotoLCD(@var{col}, @var{row}) Set the cursor position to row, col @subsubheading Inputs @var{col} - 0 indexed LCD column to position to. @var{row} - 0 indexed LCD row to position to. @subsubheading Outputs None. @end deftypefn @c Arduino Addons arduinoioaddons.RTCAddon.DS1307 @c ----------------------------------------- @subsection arduinoioaddons.RTCAddon.DS1307 @cindex DS1307 @deftypefn {} {} arduinoioaddons.RTCAddon.DS1307 DS1307 addon @seealso{addon} @end deftypefn @subsubheading Properties @var{Parent} - the parent arduino object. @var{Pins} - the pins allocated the addon. @subheading Methods @deftypefn {} {@var{obj} =} DS1307(@var{arObj}) @deftypefnx {} {@var{obj} =} DS1307(@var{arObj}, @var{propertyname, propertyvalue} ....) Constructor to create DS1307 addon @subsubheading Inputs @var{arObj} - the arduino parent object @var{propertyname, propertyvalue} - optional property name, value pairs. Current known properties are: @table @asis @item address I2C address of the DS1307 (default 0x68) @end table @subsubheading Outputs @var{obj} - created DS1307 object @subsubheading Example @example @code { a = arduino() rtc = addon(a, "rtcaddon/ds1307") } @end example @end deftypefn @deftypefn {} {@var{date} =} clock(@var{dsObj}) @deftypefnx {} {} clock(@var{dsObj}, @var{date}) Get/set the DS1307 clock @subsubheading Inputs @var{dsObj} - the ds1307 object @var{date} - a date vector in same format as datevec and clock @subsubheading Outputs @var{date} - a date vector in same format as datevec and clock @subsubheading Example @example @code { a = arduino() rtc = addon(a, "rtcaddon/ds1307") # get and display rtc time as a date string datestr(rtc.clock) } @end example @seealso{datevec} @end deftypefn @deftypefn {} {@var{ctrl} =} control(@var{dsObj}) @deftypefnx {} {} control(@var{dsObj}, @var{ctrl}) Get/set the DS1307 clock @subsubheading Inputs @var{dsObj} - the ds1307 object @var{ctrl} - a structure containing the control bit fields. @subsubheading Outputs @var{ctrl} - a structure containing the control bit fields. Control structure fields are: Current properties are: @table @asis @item out Out bit in the control register @item sqwe Square wave enable bit in control register @item rs The combined RS0, RS1 value @end table @end deftypefn @deftypefn {} {@var{YN} =} isstarted(@var{dsObj}) Get whether the RTC clock is currently counting time @subsubheading Inputs @var{dsObj} - the ds1307 object @subsubheading Outputs @var{YN} - returns true if the RTC is counting @seealso{start, stop} @end deftypefn @deftypefn {} {} start(@var{dsObj}) Start the RTC counting @subsubheading Inputs @var{dsObj} - the ds1307 object @subsubheading Outputs None @seealso{datevec} @end deftypefn @deftypefn {} {} stop(@var{dsObj}) Stop the RTC counting @subsubheading Inputs @var{dsObj} - the ds1307 object @subsubheading Outputs None @seealso{datevec} @end deftypefn @c Arduino Addons arduinoioaddons.adafruit.dcmotorv2 @c ----------------------------------------- @subsection arduinoioaddons.adafruit.dcmotorv2 @cindex dcmotorv2 @deftypefn {} {} arduinoioaddons.adafruit.dcmotorv2 DC Motor class for dc motor control on the adafruit motor shield @seealso{arduinoioaddons.adafruit.motorshieldv2} @end deftypefn @subsubheading Properties @var{Speed} - The speed value set for the motor @var{Parent} - The parent shield for object (read only) @var{MotorNumber} - The motor number (read only) values 1-4 @var{IsRunning} - boolean for if the motor is started (read only) @subheading Methods @deftypefn {} {@var{obj} =} dcmotorv2(@var{mObj}, @var{mnum}) @deftypefnx {} {@var{obj} =} dcmotorv2(@var{mObj}, @var{mnum}, @var{propertyname, propertyvalue} ....) Constructor to create dcmotor object @subsubheading Inputs @var{mObj} - the motor shield object @var{mnum} - The motor number (1 - 4) @var{propertyname, propertyvalue} - Optional property name/value pairs to pass to motor object. Current known properties are: @table @asis @item Speed Initial speed (default 0). Should be a value between -1 and 1. @end table @subsubheading Outputs @var{s} - a dcmotorv2 object @subsubheading Example @example @code { a = arduino() ms = addon(a, "adafruit/motorshieldv2") mtr = dcmotor(ms, 1) } @end example @end deftypefn @deftypefn {} {} start(@var{dcObj}) Start the motor moving in previously set speed/direction @subsubheading Inputs @var{dcObj} - the dcmotor object @subsubheading Outputs None @seealso{adafruit.motorshieldv2} @end deftypefn @deftypefn {} {} stop(@var{dcObj}) Stop the motor moving @subsubheading Inputs @var{dcObj} - the dcmotor object @subsubheading Outputs None @seealso{adafruit.motorshieldv2} @end deftypefn @c Arduino Addons arduinoioaddons.adafruit.motorshieldv2 @c ----------------------------------------- @subsection arduinoioaddons.adafruit.motorshieldv2 @cindex motorshieldv2 @deftypefn {} {} arduinoioaddons.adafruit.motorshieldv2 Adafruit motor shield addon @seealso{addon} @end deftypefn @subsubheading Properties @var{Parent} - the parent arduino object. @var{Pins} - the pins allocated the addon. @var{I2CAddress} - the i2c address used for accessing this shield. @var{PWMFrequency} - the set PWM frequency for this shield. @subheading Methods @deftypefn {} {@var{obj} =} motorshieldv2(@var{arObj}) @deftypefnx {} {@var{obj} =} motorshieldv2(@var{arObj}, @var{propertyname, propertyvalue} ....) Constructor to create motorshieldv2 addon object @subsubheading Inputs @var{arObj} - the arduino parent object @var{propertyname, propertyvalue} - optional property name, value pairs. Current known properties are: @table @asis @item address I2C address of the motor shield (default 0x60) @item pwmfrequency PWM Frequency to set on shield (default 1600) @end table @subsubheading Outputs @var{obj} - created motorshieldv2 object @subsubheading Example @example @code { a = arduino() mtr = addon(a, "adafruit/motorshieldv2") } @end example @end deftypefn @deftypefn {} {@var{s} =} servo(@var{mObj}, @var{mtrnum}) @deftypefnx {} {@var{s} =} servo(@var{mObj}, @var{mtrnum}, @var{propertyname}, @var{propertyvalue} ...) Create a servo object @subsubheading Inputs @var{mObj} - the motor shield object @var{mtrnum} - The servo motor number, where 1 is servo on pin "d10" and 2 is a servo on pin "d9" @var{propertyname}, @var{propertyvalue} - Optional property name/value pairs to pass to servo object. Properties are the same as the base servo object. @subsubheading Outputs @var{s} - a servo object @subsubheading Example @example @code { a = arduino() ms = addon(a, "adafruit/motorshieldv2") # get servo 1 (servo on pin D10) s = ms.servo(1) } @end example The function if the equivalent of calling the arduino.servo with the D9 or D10 pin has the input pin. @seealso{servo} @end deftypefn @deftypefn {} {@var{s} =} stepper(@var{mObj}, @var{mtrnum}, @var{stepsperrev}) @deftypefnx {} {@var{s} =} stepper(@var{mObj}, @var{mtrnum}, @var{stepsperrev}, @var{propertyname}, @var{propertyvalue} ...) Create a stepper motor object @subsubheading Inputs @var{mObj} - the motor shield object @var{mtrnum} - The stepper motor number (1 or 2) @var{stepsperrev} - Number of steps per revolution. @var{propertyname}, @var{propertyvalue} - Optional property name/value pairs to pass to stepper object. @subsubheading Outputs @var{s} - a stepper object @end deftypefn @deftypefn {} {@var{s} =} dcmotor(@var{mObj}, @var{mtrnum}) @deftypefnx {} {@var{s} =} dcmotor(@var{mObj}, @var{mtrnum}, @var{propertyname}, @var{propertyvalue} ...) Create a dcmotor motor object @subsubheading Inputs @var{mObj} - the motor shield object @var{mtrnum} - The motor number (1 - 4) @var{propertyname}, @var{propertyvalue} - Optional property name/value pairs to pass to motor object. @subsubheading Outputs @var{s} - a dcmotorv2 object @end deftypefn @c Arduino Addons arduinoioaddons.adafruit.stepper @c ----------------------------------------- @subsection arduinoioaddons.adafruit.stepper @cindex stepper @deftypefn {} {} arduinoioaddons.adafruit.stepper Stepper class for stepper control on the adafruit motor shield @seealso{arduinoioaddons.adafruit.motorshieldv2} @end deftypefn @subsubheading Properties @table @asis @item @var{RPM} The rpm value set for the stepper motor @item StepType the StepType for the stepper (string) which can be "single", "double", "interleave" or "microstep" @item StepsPerRevolution the StepsPerRevoluion for the stepper (read only) @item MotorNumber the motor number for the stepper (read only) value will be 1 or 2. @item Parent the parent shield of this stepper (read only) @end table @subheading Methods @deftypefn {} {@var{obj} =} stepper(@var{mObj}, @var{mnum}, @var{stepsperrev}) @deftypefnx {} {@var{obj} =} stepper(@var{mObj}, @var{mnum}, @var{stepsperrev}, @var{propertyname, propertyvalue} ....) Constructor to create dcmotor object @subsubheading Inputs @var{mObj} - the motor shield object @var{mnum} - The motor number (1 or 2) @var{stepsperrev} - Number of steps per revolution. @var{propertyname, propertyvalue} - Optional property name/value pairs to pass to motor object. Current known properties are: @table @asis @item RPM the RPM for the stepper (revolutions per minute) @item StepType the StepType for the stepper (string) which can be "single", "double", "interleave" or "microstep" @end table @subsubheading Outputs @var{s} - a stepper object @subsubheading Example @example @code { a = arduino() ms = addon(a, "adafruit/motorshieldv2") mtr = stepper(ms, 1, 200) } @end example @end deftypefn @deftypefn {} {} move(@var{sObj}, @var{steps}) Move the motor moving in the specified steps using the configured RPM. @subsubheading Inputs @var{sObj} - the stepper object @subsubheading Outputs None @seealso{adafruit.motorshieldv2} @end deftypefn @deftypefn {} {} release(@var{sObj}) Release this motor @subsubheading Inputs @var{sObj} - the stepper object @subsubheading Outputs None @seealso{adafruit.motorshieldv2} @end deftypefn @c --------------------------------------------------- @node Arduino Sensors @section Arduino Sensors @cindex Arduino Sensors @c Arduino Sensors arduinosensor.DS1307 @c ----------------------------------------- @subsection arduinosensor.DS1307 @cindex DS1307 @deftypefn {} {} arduinosensor.DS1307 DS1307 realtime clock sensor @end deftypefn @subheading Methods @deftypefn {} {@var{obj} =} DS1307(@var{arObj}) @deftypefnx {} {@var{obj} =} DS1307(@var{arObj}, @var{propertyname, propertyvalue} ....) Constructor to create DS1307 sensor @subsubheading Inputs @var{arObj} - the arduino parent object @var{propertyname, propertyvalue} - optional property name, value pairs. Current known properties are: Current properties are: @table @asis @item i2caddress I2C address of the DS1307 (default 0x68) @end table @subsubheading Outputs @var{obj} - created DS1307 object @subsubheading Example @example @code { a = arduino() rtc = arduinosensor.DS1307(a) } @end example @end deftypefn @deftypefn {} {@var{date} =} clock(@var{dsObj}) @deftypefnx {} {} clock(@var{dsObj}, @var{date}) Get/set the DS1307 clock @subsubheading Inputs @var{dsObj} - the ds1307 object @var{date} - a date vector in same format as datevec and clock @subsubheading Outputs @var{date} - a date vector in same format as datevec and clock @subsubheading Example @example @code { a = arduino() rtc = arduinosensor.DS1307(a) # get and display rtc time as a date string datestr(rtc.clock) } @end example @seealso{datevec} @end deftypefn @deftypefn {} {@var{ctrl} =} control(@var{dsObj}) @deftypefnx {} {} control(@var{dsObj}, @var{ctrl}) Get/set the DS1307 clock @subsubheading Inputs @var{dsObj} - the ds1307 object @var{ctrl} - a structure containing the control bit fields. @subsubheading Outputs @var{ctrl} - a structure containing the control bit fields. Control structure fields are: Current properties are: @table @asis @item out Out bit in the control register @item sqwe Square wave enble bit in control register @item rs The combined Rs0, RS1 value @end table @end deftypefn @deftypefn {} {@var{YN} =} isstarted(@var{dsObj}) Get whether the RTC clock is currently counting time @subsubheading Inputs @var{dsObj} - the ds1307 object @subsubheading Outputs @var{YN} - returns true if the RTC is counting @seealso{start, stop} @end deftypefn @deftypefn {} {} start(@var{dsObj}) Start the RTC counting @subsubheading Inputs @var{dsObj} - the ds1307 object @subsubheading Outputs None @seealso{datevec} @end deftypefn @deftypefn {} {} stop(@var{dsObj}) Stop the RTC counting @subsubheading Inputs @var{dsObj} - the ds1307 object @subsubheading Outputs None @seealso{datevec} @end deftypefn @c Arduino Sensors arduinosensor.GUVAS12SD @c ----------------------------------------- @subsection arduinosensor.GUVAS12SD @cindex GUVAS12SD @deftypefn {} {} arduinosensor.GUVAS12SD A thin wrapper for the GUVAS12SD analog UV-B sensor @end deftypefn @subheading Methods @deftypefn {} {@var{obj} =} GUVAS12SD(@var{arObj}, @var{pin}) Constructor to create GUVAS12SD sensor @subsubheading Inputs @var{arObj} - the arduino parent object @var{pin} - the analog pin that the sensor is connected to @subsubheading Outputs @var{obj} - created GUVAS12SD object @subsubheading Example @example @code { a = arduino() # create sensor attached to pin a0. sensor = arduinosensor.GUVAS12SD(a, "a0") } @end example @end deftypefn @deftypefn {} {@var{V} =} read(@var{dsObj}) Read the voltage of the sensor @subsubheading Inputs @var{dsObj} - the GUVAS12SD object @subsubheading Outputs @var{V} - read voltage - effectively equivalent to readAnalogPin(arObj, pin). @subsubheading Example @example @code { a = arduino() s = arduinosensor.GUVAS12SD(a) # voltage volts = s.read } @end example @seealso{arduinosensor.GUVAS12SD} @end deftypefn @deftypefn {} {@var{Idx} =} readIndex(@var{dsObj}) Read the UV index @subsubheading Inputs @var{dsObj} - the GUVAS12SD object @subsubheading Outputs @var{Idx} - the sensor reading as a UV index reading @end deftypefn @deftypefn {} {@var{uA} =} readuA(@var{dsObj}) Read the uA of the sensor @subsubheading Inputs @var{dsObj} - the GUVAS12SD object @subsubheading Outputs @var{uA} - the sensor reading as a uAmp value @end deftypefn @c Arduino Sensors arduinosensor.MPC3002 @c ----------------------------------------- @subsection arduinosensor.MPC3002 @cindex MPC3002 @deftypefn {} {} arduinosensor.MPC3002 MCP3002 ADC sensor @end deftypefn @subheading Methods @deftypefn {} {@var{obj} =} MPC3002(@var{arObj}, @var{selectPin}) @deftypefnx {} {@var{obj} =} MPC3002(@var{arObj}, @var{selectPin}, @var{propertyname, propertyvalue} ....) Constructor to create MPC3002 sensor @subsubheading Inputs @var{arObj} - the arduino parent object @var{selectPin} - the SPI cs select pin @var{propertyname, propertyvalue} - optional property name, value pairs. Current properties are: @table @asis @item referenceVoltage Reference voltage for scaling the ADC inputs (default 5.0) @end table @subsubheading Outputs @var{obj} - created MCP3002 object @subsubheading Example @example @code { a = arduino() sensor = arduinosensor.MPC3002(a, "d10") } @end example @end deftypefn @deftypefn {} {@var{voltage} =} readVoltage(@var{dsObj}, @var{chan}) Read the voltage from a channel @subsubheading Inputs @var{dsObj} - the MPC3002 object @var{chan} - the channel to read (0 or 1) @subsubheading Outputs @var{voltage} - read voltage. @subsubheading Example @example @code { a = arduino() s = arduinosensor.MPC3002(a, "d10") volts = readVoltage(s, 0) } @end example @seealso{arduinosensor.MPC3002} @end deftypefn @c Arduino Sensors arduinosensor.SI7021 @c ----------------------------------------- @subsection arduinosensor.SI7021 @cindex SI7021 @deftypefn {} {} arduinosensor.SI7021 SI7021 temperature and humidity sensor @end deftypefn @subheading Methods @deftypefn {} {@var{obj} =} SI7021(@var{arObj}) @deftypefnx {} {@var{obj} =} SI7021(@var{arObj}, @var{propertyname, propertyvalue} ....) Constructor to create SI7021 sensor @subsubheading Inputs @var{arObj} - the arduino parent object @var{propertyname, propertyvalue} - optional property name, value pairs. Current known properties are: Current properties are: @table @asis @item i2caddress I2C address of the SI7021 (default 0x40) @end table @subsubheading Outputs @var{obj} - created SI7020 object @subsubheading Example @example @code { a = arduino() sensor = arduinosensor.SI7021(a) } @end example @end deftypefn @deftypefn {} {@var{C} =} temperature(@var{dsObj}) Read the temperature @subsubheading Inputs @var{dsObj} - the si7021 object @subsubheading Outputs @var{C} - read temperature in deg C. @subsubheading Example @example @code { a = arduino() s = arduinosensor.SI7021(a) # get temp temp = s.temperature } @end example @seealso{arduinosensor.SI7021} @end deftypefn @deftypefn {} {@var{relH} =} humidity(@var{dsObj}) Read the relative humidity @subsubheading Inputs @var{dsObj} - the si7021 object @subsubheading Outputs @var{relH} - relative humidity as a percentage (0 - 100.0) @end deftypefn @deftypefn {} {@var{relH} =} info(@var{dsObj}) Read the sensor info @subsubheading Inputs @var{dsObj} - the si7021 object @subsubheading Outputs @var{inf} - structure containing the sensor information. Structure fields are: @table @asis @item version Chip firmware version @item id sensor id1,id2 value @item type String for detected chip type @end table @end deftypefn @c --------------------------------------------------- @node Arduino I/O package @section Arduino I/O package @cindex Arduino I/O package @c Arduino I/O package arduinoio.AddonBase @c ----------------------------------------- @subsection arduinoio.AddonBase @cindex AddonBase @deftypefn {} {} arduinoio.AddonBase Base class used for arduino library sensors @seealso{arduinoio.LibraryBase} @end deftypefn @subheading Properties Base properties are expected to be inherited and overwritten in inherited classes. and are constant in order to query through the metaobject mechanism. @var{Parent} - parent librarybase object @subheading Methods @deftypefn {} {@var{ab} =} AddonBase () Constructor of base class @subsubheading Outputs The return value @var{ab} is an object of the arduinio.AddonBase class. @seealso{arduino, addon} @end deftypefn @deftypefn {} {} display () Display the addon in a verbose way. @end deftypefn @c Arduino I/O package arduinoio.FilePath @c ----------------------------------------- @subsection arduinoio.FilePath @cindex FilePath @deftypefn {} {@var{retval} =} arduinoio.FilePath (@var{fullpathname}) Get the directory component of a pathname. @subsubheading Inputs @var{fullpathname} filepath to get directory component of. @subsubheading Outputs @var{retval} the directory part of the filename. @end deftypefn @c Arduino I/O package arduinoio.LibFiles @c ----------------------------------------- @subsection arduinoio.LibFiles @cindex LibFiles @deftypefn {} {@var{filelist} =} arduinoio.LibFiles () Get the list of files used for the building arduino library @subsubheading Outputs @var{filelist} - string cell array of files for the arduino project @end deftypefn @c Arduino I/O package arduinoio.LibraryBase @c ----------------------------------------- @subsection arduinoio.LibraryBase @cindex LibraryBase @deftypefn {} {} arduinoio.LibraryBase Base class used for arduino library plugins @seealso{arduino, listArduinoLibraries, addon} @end deftypefn @subheading Properties Base properties are expected to be inherited and overwritten in inherited classes. and are constant in order to query through the metaobject mechanism. @var{LibraryName} - name of the addon library @var{DependentLibraries} - array of dependent library names that must be included when installing this plugin. @var{CppHeaderFile} - name (if any) of header file that will be included into the arduino project when adding this library. @var{CppSourceFile} - name (if any) of source file that will be included into the arduino project when adding this library. @var{CppClassName} - name of the cpp class for the addon library. project when adding this library. @var{Pins} - pins allocated to the addon @var{Parent} - parent arduino object. @subheading Methods @deftypefn {} {@var{lb} =} LibraryBase () Constructor of base class The constructor is usually not called but called indirectly from the addon function. @subsubheading Outputs The return value @var{lb} is an object of the arduinio.LibraryBase class. @seealso{arduino, listArduinoLibraries, addon} @end deftypefn @deftypefn {} {} display () Display the addon in a verbose way. @end deftypefn @c Arduino I/O package arduinoio.getBoardConfig @c ----------------------------------------- @subsection arduinoio.getBoardConfig @cindex getBoardConfig @deftypefn {} {@var{retval} =} arduinoio.getBoardConfig (@var{boardname}) Return the configuration for a known arduino board type Function is used to get the expected pin/board configuration for a named board type which is used to verify and identify the functionality of the board. @subsubheading Inputs @var{boardname} - name of board to get configuration of ie: "uno" @subsubheading Outputs @var{retval} configuration struct. @end deftypefn @c --------------------------------------------------- @node Test Functions: @section Test Functions: @cindex Test Functions: @c Test Functions: arduino_bistsetup @c ----------------------------------------- @subsection arduino_bistsetup @cindex arduino_bistsetup @deftypefn {} {@var{retval} =} arduino_bistsetup () @deftypefnx {} {@var{retval} =} arduino_bistsetup (@var{propertyname}, @var{propertyvalue}) Install on an arduino the required core libraries to run the BIST tests As part of the setup, the arduino IDE will be opened to allow programming the arduino board. @subsubheading Inputs @var{propertyname}, @var{propertyvalue} - A sequence of property name/value pairs can be given to set defaults while programming. Currently the following properties can be set: @table @asis @item arduinobinary The value should be the name/path of the arduino IDE binary for programming. If not specified, the function will attempt to find the binary itself. @item debug Set the debug flag when checking the arduino @end table @subsubheading Outputs @var{retval} - return 1 if everything installed ok @seealso{arduino, arduinosetup} @end deftypefn arduino-0.4.0/doc/gpl.texi0000644000000000000000000010433013470770202013567 0ustar0000000000000000@node Copying @appendix GNU General Public License @cindex warranty @cindex copyright @center Version 3, 29 June 2007 @display Copyright @copyright{} 2007 Free Software Foundation, Inc. @url{http://fsf.org/} Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @end display @heading Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program---to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. @heading TERMS AND CONDITIONS @enumerate 0 @item Definitions. ``This License'' refers to version 3 of the GNU General Public License. ``Copyright'' also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. ``The Program'' refers to any copyrightable work licensed under this License. Each licensee is addressed as ``you''. ``Licensees'' and ``recipients'' may be individuals or organizations. To ``modify'' a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a ``modified version'' of the earlier work or a work ``based on'' the earlier work. A ``covered work'' means either the unmodified Program or a work based on the Program. To ``propagate'' a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To ``convey'' a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays ``Appropriate Legal Notices'' to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. @item Source Code. The ``source code'' for a work means the preferred form of the work for making modifications to it. ``Object code'' means any non-source form of a work. A ``Standard Interface'' means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The ``System Libraries'' of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A ``Major Component'', in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The ``Corresponding Source'' for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. @item Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. @item Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. @item Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. @item Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: @enumerate a @item The work must carry prominent notices stating that you modified it, and giving a relevant date. @item The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to ``keep intact all notices''. @item You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. @item If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. @end enumerate A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an ``aggregate'' if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. @item Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: @enumerate a @item Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. @item Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. @item Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. @item Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. @item Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. @end enumerate A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A ``User Product'' is either (1) a ``consumer product'', which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, ``normally used'' refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. ``Installation Information'' for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. @item Additional Terms. ``Additional permissions'' are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: @enumerate a @item Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or @item Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or @item Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or @item Limiting the use for publicity purposes of names of licensors or authors of the material; or @item Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or @item Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. @end enumerate All other non-permissive additional terms are considered ``further restrictions'' within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. @item Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. @item Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. @item Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An ``entity transaction'' is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. @item Patents. A ``contributor'' is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's ``contributor version''. A contributor's ``essential patent claims'' are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, ``control'' includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a ``patent license'' is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To ``grant'' such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. ``Knowingly relying'' means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is ``discriminatory'' if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. @item No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. @item Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. @item Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License ``or any later version'' applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. @item Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. @item Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. @item Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. @end enumerate @heading END OF TERMS AND CONDITIONS @heading How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the ``copyright'' line and a pointer to where the full notice is found. @smallexample @var{one line to give the program's name and a brief idea of what it does.} Copyright (C) @var{year} @var{name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see @url{http://www.gnu.org/licenses/}. @end smallexample Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: @smallexample @var{program} Copyright (C) @var{year} @var{name of author} This program comes with ABSOLUTELY NO WARRANTY; for details type @samp{show w}. This is free software, and you are welcome to redistribute it under certain conditions; type @samp{show c} for details. @end smallexample The hypothetical commands @samp{show w} and @samp{show c} should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an ``about box''. You should also get your employer (if you work as a programmer) or school, if any, to sign a ``copyright disclaimer'' for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see @url{http://www.gnu.org/licenses/}. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read @url{http://www.gnu.org/philosophy/why-not-lgpl.html}. arduino-0.4.0/inst/0000755000000000000000000000000013470770202012321 5ustar0000000000000000arduino-0.4.0/inst/+arduinoio/0000755000000000000000000000000013470770202014365 5ustar0000000000000000arduino-0.4.0/inst/+arduinoio/+config/0000755000000000000000000000000013470770202015705 5ustar0000000000000000arduino-0.4.0/inst/+arduinoio/+config/config_lilypad.m0000644000000000000000000000407413470770202021053 0ustar0000000000000000# configuration generated from /usr/share/arduino/hardware/arduino/avr/variants/standard/pins_arduino.h function retval = config_lilypad (initdata) retval = {}; # default board info - must be provided # will be filled in on connection. retval.board = ''; retval.mcu = ''; retval.voltref = 0; retval.libs = {}; retval.port = ''; # info expected to be provided by config. retval.description = 'lilypad arduino'; # pin config retval.pins = {}; retval.pins{end+1} = arduinoio.config.pin_info('D0', 0, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D1', 1, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D2', 2, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D3', 3, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D4', 4, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D5', 5, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D6', 6, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D7', 7, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D8', 8, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D9', 9, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D10', 10, { 'digital', 'spi_ss' }); retval.pins{end+1} = arduinoio.config.pin_info('D11', 11, { 'digital', 'spi_mosi' }); retval.pins{end+1} = arduinoio.config.pin_info('D12', 12, { 'digital', 'spi_miso' }); retval.pins{end+1} = arduinoio.config.pin_info('D13', 13, { 'digital', 'spi_sck', 'led' }); retval.pins{end+1} = arduinoio.config.pin_info('A0', 14, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A1', 15, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A2', 16, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A3', 17, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A4', 18, { 'digital', 'i2c_sda', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A5', 19, { 'digital', 'i2c_scl', 'analog' }); endfunction arduino-0.4.0/inst/+arduinoio/+config/config_mega2560.m0000644000000000000000000001547513470770202020652 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} config_mega (@var{initdata}) ## Private function for setting allowed modes of mega board pins ## @end deftypefn function retval = config_mega2560 (initdata) retval = []; # default board info - must be provided # will be filled in on connection. retval.board = ''; retval.mcu = ''; retval.voltref = 0; retval.libs = {}; retval.port = ''; # info expected to be provided by config. retval.description = 'Arduino Mega2560/1260 Board'; # pin config retval.pins = {}; retval.pins{end+1} = arduinoio.config.pin_info('D0', 0, { 'digital', 'uart' }); retval.pins{end+1} = arduinoio.config.pin_info('D1', 1, { 'digital', 'uart' }); retval.pins{end+1} = arduinoio.config.pin_info('D2', 2, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D3', 3, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D4', 4, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D5', 5, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D6', 6, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D7', 7, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D8', 8, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D9', 9, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D10', 10, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D11', 11, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D12', 12, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D13', 13, { 'digital', 'led', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D14', 14, { 'digital', 'uart3' }); retval.pins{end+1} = arduinoio.config.pin_info('D15', 15, { 'digital', 'uart3' }); retval.pins{end+1} = arduinoio.config.pin_info('D16', 16, { 'digital', 'uart2' }); retval.pins{end+1} = arduinoio.config.pin_info('D17', 17, { 'digital', 'uart2' }); retval.pins{end+1} = arduinoio.config.pin_info('D18', 18, { 'digital', 'uart1' }); retval.pins{end+1} = arduinoio.config.pin_info('D19', 19, { 'digital', 'uart1' }); retval.pins{end+1} = arduinoio.config.pin_info('D20', 20, { 'digital', 'i2c_sda' }); retval.pins{end+1} = arduinoio.config.pin_info('D21', 21, { 'digital', 'i2c_scl' }); retval.pins{end+1} = arduinoio.config.pin_info('D22', 22, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D23', 23, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D24', 24, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D25', 25, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D26', 26, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D27', 27, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D28', 28, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D29', 29, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D30', 30, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D31', 31, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D32', 32, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D33', 33, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D34', 34, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D35', 35, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D36', 36, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D37', 37, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D38', 38, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D39', 39, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D40', 40, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D41', 41, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D42', 42, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D43', 43, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D44', 44, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D45', 45, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D46', 46, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D47', 47, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D48', 48, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D49', 49, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D50', 50, { 'digital', 'spi_miso' }); retval.pins{end+1} = arduinoio.config.pin_info('D51', 51, { 'digital', 'spi_mosi' }); retval.pins{end+1} = arduinoio.config.pin_info('D52', 52, { 'digital', 'spi_sck' }); retval.pins{end+1} = arduinoio.config.pin_info('D53', 53, { 'digital', 'spi_ss' }); retval.pins{end+1} = arduinoio.config.pin_info('A0', 54, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A1', 55, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A2', 56, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A3', 57, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A4', 58, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A5', 59, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A6', 60, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A7', 61, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A8', 62, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A9', 63, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A10', 64, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A11', 65, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A12', 66, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A13', 67, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A14', 68, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A15', 69, { 'digital', 'analog' }); endfunction arduino-0.4.0/inst/+arduinoio/+config/config_nano.m0000644000000000000000000000622413470770202020347 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} config_uno (@var{initdata}) ## Private function for setting allowed modes of uno board pins ## @end deftypefn # configuration generated from /usr/share/arduino/hardware/arduino/avr/variants/standard/pins_arduino.h function retval = config_nano (initdata) retval = []; # default board info - must be provided # will be filled in on connection retval.board = "nano"; retval.mcu = ''; retval.voltref = 50; retval.libs = {}; retval.port = ""; # info expected to be provided by config. retval.description = 'Arduino Nano Board'; # pin config retval.pins = {}; retval.pins{end+1} = arduinoio.config.pin_info("D0", 0, { 'digital' , 'uart'}); retval.pins{end+1} = arduinoio.config.pin_info("D1", 1, { 'digital' , 'uart'}); retval.pins{end+1} = arduinoio.config.pin_info("D2", 2, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info("D3", 3, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info("D4", 4, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info("D5", 5, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info("D6", 6, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info("D7", 7, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info("D8", 8, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info("D9", 9, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info("D10", 10, { 'digital', 'pwm', 'spi0_ss' }); retval.pins{end+1} = arduinoio.config.pin_info("D11", 11, { 'digital', 'pwm', 'spi0_mosi' }); retval.pins{end+1} = arduinoio.config.pin_info("D12", 12, { 'digital', 'pwm', 'spi0_miso' }); retval.pins{end+1} = arduinoio.config.pin_info("D13", 13, { 'digital', 'pwm', 'spi0_sck', 'led' }); retval.pins{end+1} = arduinoio.config.pin_info("A0", 14, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info("A1", 15, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info("A2", 16, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info("A3", 17, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info("A4", 18, { 'digital', 'analog', 'i2c_sda' }); retval.pins{end+1} = arduinoio.config.pin_info("A5", 19, { 'digital', 'analog', 'i2c_scl' }); retval.pins{end+1} = arduinoio.config.pin_info("A6", 20, { 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info("A7", 21, { 'analog' }); endfunction arduino-0.4.0/inst/+arduinoio/+config/config_promini.m0000644000000000000000000000657213470770202021077 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} config_promini (@var{initdata}) ## Private function for setting allowed modes of promini board pins ## @end deftypefn function retval = config_promini (initdata) retval = []; # default board info - must be provided # will be filled in on connection retval.board = "promini"; retval.mcu = ''; retval.voltref = 0; retval.libs = {}; retval.port = ""; # info expected to be provided by config. retval.description = 'Arduino Pro/Pro Mini Board'; # pin config retval.pins = {}; #0=D0 RX retval.pins{end+1} = arduinoio.config.pin_info("D0", 0, { 'digital' , 'uart'}); #1=D1 TX retval.pins{end+1} = arduinoio.config.pin_info("D1", 1, { 'digital' , 'uart'}); #2=D2 retval.pins{end+1} = arduinoio.config.pin_info("D2", 2, { 'digital' }); #3=D3 PWM retval.pins{end+1} = arduinoio.config.pin_info("D3", 3, { 'digital', 'pwm' }); #4=D4 retval.pins{end+1} = arduinoio.config.pin_info("D4", 4, { 'digital' }); #5=D5 PWM retval.pins{end+1} = arduinoio.config.pin_info("D5", 5, { 'digital', 'pwm' }); #6=D6 PWM retval.pins{end+1} = arduinoio.config.pin_info("D6", 6, { 'digital', 'pwm' }); #7=D7 retval.pins{end+1} = arduinoio.config.pin_info("D7", 7, { 'digital' }); #8=D8 retval.pins{end+1} = arduinoio.config.pin_info("D8", 8, { 'digital' }); #9=D9 PWM retval.pins{end+1} = arduinoio.config.pin_info("D9", 9, { 'digital', 'pwm' }); #10=D10 PWM SS retval.pins{end+1} = arduinoio.config.pin_info("D10", 10, { 'digital', 'pwm', 'spi0_ss' }); #11=D11 PWM MOSI retval.pins{end+1} = arduinoio.config.pin_info("D11", 11, { 'digital', 'pwm', 'spi0_mosi' }); #12=D12 MISO retval.pins{end+1} = arduinoio.config.pin_info("D12", 12, { 'digital', 'pwm', 'spi0_miso' }); #13=D13 SCK LED retval.pins{end+1} = arduinoio.config.pin_info("D13", 13, { 'digital', 'pwm', 'spi0_sck', 'led' }); #14=D14 A0 retval.pins{end+1} = arduinoio.config.pin_info("A0", 14, { 'digital', 'analog' }); #15=D15 A1 retval.pins{end+1} = arduinoio.config.pin_info("A1", 15, { 'digital', 'analog' }); #16=D16 A2 retval.pins{end+1} = arduinoio.config.pin_info("A2", 16, { 'digital', 'analog' }); #17=D17 A3 retval.pins{end+1} = arduinoio.config.pin_info("A3", 17, { 'digital', 'analog' }); #18=D18 A4 I2C_SDA retval.pins{end+1} = arduinoio.config.pin_info("A4", 18, { 'digital', 'analog', 'i2c_sda' }); #19=D19 A5 I2C_SCL retval.pins{end+1} = arduinoio.config.pin_info("A5", 19, { 'digital', 'analog', 'i2c_scl' }); #20=D20 A6 retval.pins{end+1} = arduinoio.config.pin_info("A6", 20, { 'digital', 'analog' }); #21=D21 A7 retval.pins{end+1} = arduinoio.config.pin_info("A7", 21, { 'digital', 'analog' }); endfunction arduino-0.4.0/inst/+arduinoio/+config/config_sparkfunsamd21.m0000644000000000000000000000655213470770202022261 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} config_sparkfunsamd21 (@var{initdata}) ## Private function for setting allowed modes of sparkfun samd21 mini/dev board pins ## @end deftypefn function retval = config_sparkfunsamd21 (initdata) retval = {}; # default board info - must be provided # will be filled in on connection. retval.board = ''; retval.board = ''; retval.mcu = 'samd21'; retval.voltref = 3.3; retval.libs = {}; retval.port = ''; # info expected to be provided by config. retval.description = 'Sparkfun SAMD21 Dev/Mini Board'; # pin config retval.pins = {}; retval.pins{end+1} = arduinoio.config.pin_info('D0', 0, { 'digital', 'i2s_fs', 'uart' }); retval.pins{end+1} = arduinoio.config.pin_info('D1', 1, { 'digital', 'i2s_sck', 'uart' }); retval.pins{end+1} = arduinoio.config.pin_info('D2', 2, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D3', 3, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D4', 4, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D5', 5, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D6', 6, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D7', 7, { 'digital' }); retval.pins{end+1} = arduinoio.config.pin_info('D8', 8, { 'digital', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D9', 9, { 'digital', 'i2s_sd', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D10', 10, { 'digital', 'spi_ss', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D11', 11, { 'digital', 'spi_mosi', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D12', 12, { 'digital', 'spi_miso', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('D13', 13, { 'digital', 'led_13', 'spi_sck', 'pwm' }); retval.pins{end+1} = arduinoio.config.pin_info('A0', 14, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A1', 15, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A2', 16, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A3', 17, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A4', 18, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('A5', 19, { 'digital', 'analog' }); retval.pins{end+1} = arduinoio.config.pin_info('D20', 20, { 'digital', 'i2c_sda' }); retval.pins{end+1} = arduinoio.config.pin_info('D21', 21, { 'digital', 'i2c_scl' }); # pins 22-24 ?? retval.pins{end+1} = arduinoio.config.pin_info('D25', 25, { 'digital', 'led_rxl' }); retval.pins{end+1} = arduinoio.config.pin_info('D26', 26, { 'digital', 'led_txl' }); endfunction arduino-0.4.0/inst/+arduinoio/+config/config_uno.m0000644000000000000000000000631413470770202020215 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} config_uno (@var{initdata}) ## Private function for setting allowed modes of uno board pins ## @end deftypefn function retval = config_uno (initdata) retval = []; # default board info - must be provided # will be filled in on connection retval.board = "uno"; retval.mcu = ''; retval.voltref = 0; retval.libs = {}; retval.port = ""; # info expected to be provided by config. retval.description = 'Arduino Uno R3 Board'; # pin config retval.pins = {}; #0=D0 RX retval.pins{end+1} = arduinoio.config.pin_info("D0", 0, { 'digital' , 'uart'}); #1=D1 TX retval.pins{end+1} = arduinoio.config.pin_info("D1", 1, { 'digital' , 'uart'}); #2=D2 retval.pins{end+1} = arduinoio.config.pin_info("D2", 2, { 'digital' }); #3=D3 PWM retval.pins{end+1} = arduinoio.config.pin_info("D3", 3, { 'digital', 'pwm' }); #4=D4 retval.pins{end+1} = arduinoio.config.pin_info("D4", 4, { 'digital' }); #5=D5 PWM retval.pins{end+1} = arduinoio.config.pin_info("D5", 5, { 'digital', 'pwm' }); #6=D6 PWM retval.pins{end+1} = arduinoio.config.pin_info("D6", 6, { 'digital', 'pwm' }); #7=D7 retval.pins{end+1} = arduinoio.config.pin_info("D7", 7, { 'digital' }); #8=D8 retval.pins{end+1} = arduinoio.config.pin_info("D8", 8, { 'digital' }); #9=D9 PWM retval.pins{end+1} = arduinoio.config.pin_info("D9", 9, { 'digital', 'pwm' }); #10=D10 PWM SS retval.pins{end+1} = arduinoio.config.pin_info("D10", 10, { 'digital', 'pwm', 'spi0_ss' }); #11=D11 PWM MOSI retval.pins{end+1} = arduinoio.config.pin_info("D11", 11, { 'digital', 'pwm', 'spi0_mosi' }); #12=D12 MISO retval.pins{end+1} = arduinoio.config.pin_info("D12", 12, { 'digital', 'pwm', 'spi0_miso' }); #13=D13 SCK LED retval.pins{end+1} = arduinoio.config.pin_info("D13", 13, { 'digital', 'pwm', 'spi0_sck', 'led' }); #14=D14 A0 retval.pins{end+1} = arduinoio.config.pin_info("A0", 14, { 'digital', 'analog' }); #15=D15 A1 retval.pins{end+1} = arduinoio.config.pin_info("A1", 15, { 'digital', 'analog' }); #16=D16 A2 retval.pins{end+1} = arduinoio.config.pin_info("A2", 16, { 'digital', 'analog' }); #17=D17 A3 retval.pins{end+1} = arduinoio.config.pin_info("A3", 17, { 'digital', 'analog' }); #18=D18 A4 I2C_SDA retval.pins{end+1} = arduinoio.config.pin_info("A4", 18, { 'digital', 'analog', 'i2c_sda' }); #19=D19 A5 I2C_SCL retval.pins{end+1} = arduinoio.config.pin_info("A5", 19, { 'digital', 'analog', 'i2c_scl' }); # additionals ? #20=D20 A6 #21=D21 A7 endfunction arduino-0.4.0/inst/+arduinoio/+config/config_uno_wifi_r2.m0000644000000000000000000000777613470770202021653 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} config_uno_wifi_r2 (@var{initdata}) ## Private function for setting allowed modes of uno board pins ## @end deftypefn function retval = config_uno_wifi_r2 (initdata) retval = []; # default board info - must be provided # will be filled in on connection retval.board = "uno_wifi_r2"; retval.mcu = ''; retval.voltref = 0; retval.libs = {}; retval.port = ""; # info expected to be provided by config. retval.description = 'Arduino Uno WIFI R2 Board'; # pin config retval.pins = {}; #0=D0 RX retval.pins{end+1} = arduinoio.config.pin_info("D0", 0, { 'digital' , 'uart'}); #1=D1 TX retval.pins{end+1} = arduinoio.config.pin_info("D1", 1, { 'digital' , 'uart'}); #2=D2 retval.pins{end+1} = arduinoio.config.pin_info("D2", 2, { 'digital' }); #3=D3 PWM retval.pins{end+1} = arduinoio.config.pin_info("D3", 3, { 'digital', 'pwm' }); #4=D4 retval.pins{end+1} = arduinoio.config.pin_info("D4", 4, { 'digital' }); #5=D5 PWM retval.pins{end+1} = arduinoio.config.pin_info("D5", 5, { 'digital', 'pwm' }); #6=D6 PWM retval.pins{end+1} = arduinoio.config.pin_info("D6", 6, { 'digital', 'pwm' }); #7=D7 retval.pins{end+1} = arduinoio.config.pin_info("D7", 7, { 'digital' }); #8=D8 retval.pins{end+1} = arduinoio.config.pin_info("D8", 8, { 'digital' }); #9=D9 PWM retval.pins{end+1} = arduinoio.config.pin_info("D9", 9, { 'digital', 'pwm' }); #10=D10 PWM SS retval.pins{end+1} = arduinoio.config.pin_info("D10", 10, { 'digital', 'pwm', 'spi0_ss' }); #11=D11 retval.pins{end+1} = arduinoio.config.pin_info("D11", 11, { 'digital' }); #12=D12 retval.pins{end+1} = arduinoio.config.pin_info("D12", 12, { 'digital' }); #13=D13 retval.pins{end+1} = arduinoio.config.pin_info("D13", 13, { 'digital' }); #14=D14 A0 retval.pins{end+1} = arduinoio.config.pin_info("A0", 14, { 'digital', 'analog' }); #15=D15 A1 retval.pins{end+1} = arduinoio.config.pin_info("A1", 15, { 'digital', 'analog' }); #16=D16 A2 retval.pins{end+1} = arduinoio.config.pin_info("A2", 16, { 'digital', 'analog' }); #17=D17 A3 retval.pins{end+1} = arduinoio.config.pin_info("A3", 17, { 'digital', 'analog' }); #18=D18 A4 I2C_SDA retval.pins{end+1} = arduinoio.config.pin_info("A4", 18, { 'digital', 'analog' }); #19=D19 A5 I2C_SCL retval.pins{end+1} = arduinoio.config.pin_info("A5", 19, { 'digital', 'analog' }); # additionals ? #20=D20 retval.pins{end+1} = arduinoio.config.pin_info("D20", 20, { 'i2c_sda' }); #21=D21 retval.pins{end+1} = arduinoio.config.pin_info("D21", 21, { 'i2c_scl' }); #25=D25 retval.pins{end+1} = arduinoio.config.pin_info("D25", 25, { 'digital', 'led' }); #26=D26 retval.pins{end+1} = arduinoio.config.pin_info("D26", 26, { 'digital'}); #30=D30 retval.pins{end+1} = arduinoio.config.pin_info("D30", 30, { 'digital', 'imu_ss'}); #32=D32 retval.pins{end+1} = arduinoio.config.pin_info("D32", 32, { 'digital', 'spi0_mosi' }); #33=D33 retval.pins{end+1} = arduinoio.config.pin_info("D33", 33, { 'digital', 'spi0_miso' }); #34=D34 retval.pins{end+1} = arduinoio.config.pin_info("D34", 34, { 'digital', 'spi0_sck' }); #35=D35 retval.pins{end+1} = arduinoio.config.pin_info("D35", 35, { 'digital', 'wifi_ss' }); #39=D39 retval.pins{end+1} = arduinoio.config.pin_info("D39", 39, { 'digital' }); endfunction arduino-0.4.0/inst/+arduinoio/+config/pin_info.m0000644000000000000000000000162613470770202017671 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{value} =} pin_info (@var{name}) ## Private function ## @end deftypefn function retval = pin_info (name, id, modes) retval = []; retval.name = lower(name); retval.id = id; retval.modes = lower(modes); retval.owner = ""; retval.mode = "unset"; endfunction arduino-0.4.0/inst/+arduinoio/AddonBase.m0000644000000000000000000000342013470770202016362 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {} arduinoio.AddonBase ## Base class used for arduino library sensors ## ## @seealso{arduinoio.LibraryBase} ## @end deftypefn ## ## @subheading Properties ## Base properties are expected to be inherited and overwritten in inherited classes. ## and are constant in order to query through the metaobject mechanism. ## ## @var{Parent} - parent librarybase object ## ## @subheading Methods ## @deftypefn {} {@var{ab} =} AddonBase () ## Constructor of base class ## ## @subsubheading Outputs ## The return value @var{ab} is an object of the arduinio.AddonBase class. ## ## @seealso{arduino, addon} ## @end deftypefn ## ## @deftypefn {} {} display () ## Display the addon in a verbose way. ## @end deftypefn classdef AddonBase < handle # properties that may be overridden in # subclasses properties (GetAccess = public, SetAccess = protected) Parent = {}; endproperties methods (Access=public) # display the base class properties function display(this) printf("%s = \n", inputname(1)); endfunction endmethods endclassdef arduino-0.4.0/inst/+arduinoio/FilePath.m0000644000000000000000000000215613470770202016243 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} arduinoio.FilePath (@var{fullpathname}) ## Get the directory component of a pathname. ## ## @subsubheading Inputs ## @var{fullpathname} filepath to get directory component of. ## ## @subsubheading Outputs ## @var{retval} the directory part of the filename. ## @end deftypefn function path = FilePath(fullpathname) path = fileparts(fullpathname); endfunction arduino-0.4.0/inst/+arduinoio/LibFiles.m0000644000000000000000000000234013470770202016233 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{filelist} =} arduinoio.LibFiles () ## Get the list of files used for the building arduino library ## @subsubheading Outputs ## @var{filelist} - string cell array of files for the arduino project ## @end deftypefn function files = LibFiles() files = {}; script = mfilename('fullpath'); [path,~] = fileparts(script); filelist = dir(fullfile(path, "lib", "*.*")); for i=1:numel(filelist) files{end+1} = fullfile(fullfile(path, "lib"), filelist(i).name); endfor endfunction arduino-0.4.0/inst/+arduinoio/LibraryBase.m0000644000000000000000000000727313470770202016753 0ustar0000000000000000## Copyright (C) 2018-2019 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {} arduinoio.LibraryBase ## Base class used for arduino library plugins ## ## @seealso{arduino, listArduinoLibraries, addon} ## @end deftypefn ## ## @subheading Properties ## Base properties are expected to be inherited and overwritten in inherited classes. ## and are constant in order to query through the metaobject mechanism. ## ## @var{LibraryName} - name of the addon library ## ## @var{DependentLibraries} - array of dependent library names that must be included when ## installing this plugin. ## ## @var{CppHeaderFile} - name (if any) of header file that will be included into the arduino ## project when adding this library. ## ## @var{CppSourceFile} - name (if any) of source file that will be included into the arduino ## project when adding this library. ## ## @var{CppClassName} - name of the cpp class for the addon library. ## project when adding this library. ## ## @var{Pins} - pins allocated to the addon ## ## @var{Parent} - parent arduino object. ## ## @subheading Methods ## @deftypefn {} {@var{lb} =} LibraryBase () ## Constructor of base class ## ## The constructor is usually not called but called indirectly from the addon function. ## ## @subsubheading Outputs ## The return value @var{lb} is an object of the arduinio.LibraryBase class. ## ## @seealso{arduino, listArduinoLibraries, addon} ## @end deftypefn ## ## @deftypefn {} {} display () ## Display the addon in a verbose way. ## @end deftypefn classdef LibraryBase < handle # properties that may be overridden in # subclasses properties (Access = protected) LibraryName = ""; DependentLibraries = {}; ArduinoLibraryHeaderFiles = {}; CppHeaderFile = ""; CppSourceFile = ""; CppClassName = ""; endproperties properties (GetAccess = public, SetAccess = protected) Parent = {}; Pins = []; endproperties methods (Static) function info = AddonInfo(fullclassname) info = {}; info.libraryname = ""; info.dependentlibraries = ""; info.cppheaderfile = ""; info.cppsourcefile = ""; info.cppclassname = ""; info.arduinolibraryheaderfiles = ""; data = meta.class.fromName(fullclassname); for ic = 1:numel(data.Properties) p = data.Properties{ic}; if p.Constant pname = lower(p.Name); pvalue = p.DefaultValue; if isfield(info, pname) info.(pname) = pvalue; endif endif endfor info.classname = data.Name; endfunction endmethods methods (Access=public) # display the base class properties function display(this) printf("%s = \n", inputname(1)); printf(" %s with properties\n", class(this)); if numel(this.Pins) == 0 printf(" Pins = {}\n"); else printf(" Pins = {\n"); for i=1:numel(this.Pins) printf(" %s\n", this.Pins{i}); endfor printf(" }\n"); endif endfunction endmethods endclassdef arduino-0.4.0/inst/+arduinoio/boardTypeString.m0000644000000000000000000000301413470770202017661 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} __boardTypeString__ (@var{type}) ## Helper function to set convert board id to a (lowercase) string ## @end deftypefn function retval = boardTypeString (id) if nargin != 1 error ('expected id'); endif if ~isnumeric (id) error ('expected id as a number'); endif if ischar (id) id = int (id); endif switch (id) case 0 retval = "uno"; case 1 retval = "mega2560"; case 2 retval = "nano"; case 5 retval = "uno_wifi_r2"; case 10 retval = "lilypad"; case 20 retval = "promini"; case 41 retval = "sparkfunsamd21"; otherwise retval = "unknown"; endswitch endfunction %!test %! assert(arduinoio.boardTypeString (0), "uno") %! assert(arduinoio.boardTypeString (1), "mega2560") %! assert(arduinoio.boardTypeString (10), "lilypad") %! assert(arduinoio.boardTypeString (-1), "unknown") arduino-0.4.0/inst/+arduinoio/getBoardConfig.m0000644000000000000000000000260213470770202017420 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} arduinoio.getBoardConfig (@var{boardname}) ## Return the configuration for a known arduino board type ## ## Function is used to get the expected pin/board configuration for a named board type ## which is used to verify and identify the functionality of the board. ## ## @subsubheading Inputs ## @var{boardname} - name of board to get configuration of ie: "uno" ## ## @subsubheading Outputs ## @var{retval} configuration struct. ## @end deftypefn function config = getBoardConfig (board) config = eval(sprintf("arduinoio.config.config_%s", board)); endfunction %!test %! c = arduinoio.getBoardConfig("uno"); %! assert(c.board, "uno"); arduino-0.4.0/inst/+arduinoio/lib/0000755000000000000000000000000013470770202015133 5ustar0000000000000000arduino-0.4.0/inst/+arduinoio/lib/LibraryBase.cpp0000644000000000000000000001127713470770202020046 0ustar0000000000000000/* * Octave arduino base library * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "LibraryBase.h" #define ARDUINO_SOH 0xA5 #define STATE_SOH 0 #define STATE_EXT 1 #define STATE_CMD 2 #define STATE_SIZE 3 #define STATE_DATA 4 #define STATE_EOM 5 static const char ERRORMSG_INVALID_NUMBER_OF_ARGS[] PROGMEM = "Invalid number of args"; static const char ERRORMSG_UNKNOWN_CMDID[] PROGMEM = "Unknown cmdID"; const char * OctaveLibraryBase::getLibraryName () const { return libName.c_str(); } void OctaveLibraryBase::setup () { } void OctaveLibraryBase::loop () { } void OctaveLibraryBase::sendResponseMsg(uint8_t cmdID, const uint8_t *data, uint8_t sz) { OCTAVE_COMMS_PORT.write((uint8_t)ARDUINO_SOH); OCTAVE_COMMS_PORT.write((uint8_t)id); OCTAVE_COMMS_PORT.write(cmdID); OCTAVE_COMMS_PORT.write(sz); if(sz) { OCTAVE_COMMS_PORT.write(data, sz); } OCTAVE_COMMS_PORT.flush(); } void OctaveLibraryBase::sendWaitMsg() { sendResponseMsg(ARDUINO_WAIT, NULL, 0); } void OctaveLibraryBase::sendErrorMsg(const char *err) { // work out len to max 200 int len = 0; while(err[len] != '\0' && len < 200) len++; sendResponseMsg(ARDUINO_ERROR, (uint8_t *)err, len); } void OctaveLibraryBase::sendResponseMsg_P(uint8_t cmdID, const uint8_t *data PROGMEM, uint8_t sz) { char tmp[256]; for(int i=0;i= 0 && idx < libcount) { return libs[idx]->libName.c_str(); } return ""; } uint8_t OctaveArduinoClass::registerLibrary(LibraryBase *lib) { if(libcount < MAX_ARDUINO_LIBS) { lib->id = libcount; libs[libcount] = lib; libcount ++; return libcount-1; } return 255; } uint8_t OctaveArduinoClass::processMessage(uint8_t libid, uint8_t cmd, uint8_t *data, uint8_t sz) { if(libid < 0 || libid >= MAX_ARDUINO_LIBS || libs[libid] == 0) { // error, send reply } else { libs[libid]->commandHandler(cmd, data,sz); return 1; } return 0; } void OctaveArduinoClass::init() { OCTAVE_COMMS_PORT.begin(9600); for (int i=0;isetup(); } } void OctaveArduinoClass::runLoop() { int ch; if(OCTAVE_COMMS_PORT.available()) { ch = OCTAVE_COMMS_PORT.read(); switch (msg_state) { case STATE_SOH: msg_hdr[STATE_SOH] = ch; if(ch == ARDUINO_SOH) msg_state = STATE_EXT; break; case STATE_EXT: msg_hdr[STATE_EXT] = ch; msg_state = STATE_CMD; break; case STATE_CMD: msg_hdr[STATE_CMD] = ch; msg_state = STATE_SIZE; break; case STATE_SIZE: msg_hdr[STATE_SIZE] = ch; msg_datapos = 0; if(ch > 0) msg_state = STATE_DATA; else msg_state = STATE_EOM; break; case STATE_DATA: if(msg_datapos < sizeof(msg_data)) msg_data[msg_datapos] = ch; msg_datapos ++; if(msg_datapos == msg_hdr[STATE_SIZE]) msg_state = STATE_EOM; break; default: msg_state = STATE_SOH; break; } if(msg_state == STATE_EOM) { msg_state = STATE_SOH; processMessage(msg_hdr[STATE_EXT], msg_hdr[STATE_CMD], msg_data, msg_hdr[STATE_SIZE]); } } for (int i=0;iloop(); } } arduino-0.4.0/inst/+arduinoio/lib/LibraryBase.h0000644000000000000000000000456613470770202017516 0ustar0000000000000000/* * Octave arduino library interface * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef OCTAVE_LIBRARY_BASE_H #define OCTAVE_LIBRARY_BASE_H #include #define VERSION_MAJOR 0 #define VERSION_MINOR 4 #define VERSION_PATCH 0 // sparkfun samed21 dev/mini #if defined(SERIAL_PORT_USBVIRTUAL) # define OCTAVE_COMMS_PORT SERIAL_PORT_USBVIRTUAL #else # define OCTAVE_COMMS_PORT SERIAL_PORT_MONITOR #endif class OctaveLibraryBase { public: String libName; int id; virtual void commandHandler(uint8_t cmdID, uint8_t* inputs, uint8_t payload_size) = 0; virtual void setup(); virtual void loop(); const char * getLibraryName() const; #define ARDUINO_ERROR 255 #define ARDUINO_WAIT 254 void sendResponseMsg(uint8_t cmdID, const uint8_t *data, uint8_t sz); void sendResponseMsg_P(uint8_t cmdID, const uint8_t *data PROGMEM, uint8_t sz); void sendErrorMsg(const char *msg); void sendErrorMsg_P(const char *msg PROGMEM); void sendUnknownCmdIDMsg(); void sendInvalidNumArgsMsg(); void sendWaitMsg(); // void debugPrint(const char *,varargs); }; typedef OctaveLibraryBase LibraryBase; class OctaveArduinoClass { uint8_t msg_state; uint8_t msg_datapos; uint8_t msg_hdr[4]; uint8_t msg_data[256]; #define MAX_ARDUINO_LIBS 20 int libcount; OctaveLibraryBase *libs[MAX_ARDUINO_LIBS]; public: OctaveArduinoClass(); uint8_t registerLibrary(LibraryBase *lib); int getLibCount() const { return libcount; } const char * getLibName(uint8_t idx) const; void init(); void runLoop(); private: uint8_t processMessage(uint8_t libid, uint8_t cmd, uint8_t *data, uint8_t sz); }; // for matlab compatability typedef OctaveArduinoClass MWArduinoClass; #endif // OCTAVE_LIBRARY_BASE_H arduino-0.4.0/inst/+arduinoio/lib/OctaveCoreLibrary.cpp0000644000000000000000000001557113470770202021227 0ustar0000000000000000/* * Octave arduino core interface * Copyright (C) 2018-2019 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "settings.h" #include "OctaveCoreLibrary.h" #define ARDUINO_RESET 0 #define ARDUINO_INIT 1 #define ARDUINO_CONFIGPIN 2 #define ARDUINO_DIGITAL 3 #define ARDUINO_ANALOG 4 #define ARDUINO_PWM 5 #define ARDUINO_PLAYTONE 6 #define ARDUINO_GETLIB 8 #define ARDUINO_VERSION 20 #define ARDUINO_UPTIME 21 // TODO: how know what board we are ??? //compiler provides something like: // -DF_CPU=16000000L -DARDUINO=10805 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR // freq ide ver board arch #if defined(ARDUINO_AVR_UNO) #define BOARD_ID 0 #elif defined(ARDUINO_AVR_MEGA2560) #define BOARD_ID 1 #elif defined(ARDUINO_AVR_NANO) #define BOARD_ID 2 #elif defined(ARDUINO_AVR_UNO_WIFI_REV2) #define BOARD_ID 5 #elif defined(ARDUINO_AVR_LILYPAD) #define BOARD_ID 10 #elif defined(ARDUINO_AVR_PRO) #define BOARD_ID 20 #elif defined(ARDUINO_SAMD_ZERO) // sparkfun samed21 dev/mini #if USB_VID == 0x1B4F && USB_PID == 0x8D21 #define BOARD_ID 41 #else // Arduino Zero #define BOARD_ID 20 #endif #else #error "Unknown board type" #endif // board voltage = actualV*10 #ifndef BOARD_VOLTAGE #if defined(ARDUINO_ARCH_SAMD) #define BOARD_VOLTAGE 33 #elif defined(ARDUINO_AVR_PRO) #if F_CPU == 8000000L #define BOARD_VOLTAGE 33 #else #define BOARD_VOLTAGE 50 #endif #else #define BOARD_VOLTAGE 50 #endif #endif static const uint8_t map_config_mode[] PROGMEM = { INPUT, // unset INPUT, // analoginput INPUT, // dig in OUTPUT, // dig out INPUT_PULLUP, // pullup OUTPUT, // i2c TODO: ?? OUTPUT, // pwm OUTPUT, // servo OUTPUT, // spi TODO ? }; int get_mode(int m) { if(m >= 0 && m < sizeof(map_config_mode)) { return pgm_read_byte_near(map_config_mode + m); } return INPUT; } #define pinToAnalog(a) (a < A0 ? 0 : a-A0) #ifndef NUM_TOTAL_PINS #define NUM_TOTAL_PINS NUM_DIGITAL_PINS #endif //#ifdef UNO_WIFI_REV2_328MODE // #error ("Uno wifi firmware must be compiled without a 328 emultaion enabled") //#endif static uint8_t pinconfig[NUM_TOTAL_PINS]; #if defined (ARDUINO_ARCH_AVR) || defined (ARDUINO_ARCH_MEGAAVR) #include void reset() { wdt_enable(WDTO_1S); while(1) {} } #elif defined (ARDUINO_ARCH_SAMD) void reset() { // processor software reset NVIC_SystemReset(); } #else #error("Unimplemented architecture for reset") #endif OctaveCoreLibrary::OctaveCoreLibrary(OctaveArduinoClass &oc) : occlass(oc) { libName = "Core"; oc.registerLibrary(this); // set pins as not set for(int i = 0;i= 0 && data[1] < sizeof(map_config_mode)) { int mode = get_mode(data[1]); pinconfig[data[0]] = data[1]; pinMode(data[0], mode); sendResponseMsg(cmdID,data, 0); } else { sendInvalidNumArgsMsg(); } break; case ARDUINO_DIGITAL: if(datasz == 1) { val = digitalRead(data[0]); if(val == HIGH) data[1] = 1; else data[1] = 0; sendResponseMsg(cmdID,data, 2); } else if(datasz == 2) { digitalWrite(data[0], data[1] ? HIGH : LOW); sendResponseMsg(cmdID,data, 0); } else { sendInvalidNumArgsMsg(); } break; case ARDUINO_ANALOG: if(datasz == 1) { val = analogRead(pinToAnalog(data[0])); data[1] = (val>>8)&0xff; data[2] = (val)&0xff; sendResponseMsg(cmdID,data, 3); } else { sendInvalidNumArgsMsg(); } break; case ARDUINO_PWM: if(datasz == 2) { analogWrite(data[0], data[1]); sendResponseMsg(cmdID,data, 0); } else { sendInvalidNumArgsMsg(); } break; case ARDUINO_PLAYTONE: if(datasz == 5) { // 0 = pin // 1 = freqh // 2 = freql (hz) // 3 = durh // 4 = durl (10ths of second) unsigned long duration = (((unsigned long)(data[3]))<<8 | data[4]) * 100; unsigned int freq = (((unsigned int)(data[1]))<<8 | data[2]); if(freq == 0) { noTone(data[0]); } else { tone(data[0], freq, duration); } sendResponseMsg(cmdID,data, 0); } else { sendInvalidNumArgsMsg(); } break; case ARDUINO_VERSION: { data[0] = VERSION_MAJOR; data[1] = VERSION_MINOR; data[2] = VERSION_PATCH; sendResponseMsg(cmdID, data, 3); } break; case ARDUINO_UPTIME: { unsigned long t = millis(); data[0] = (t>>24)&0xff; data[1] = (t>>16)&0xff; data[2] = (t>>8)&0xff; data[3] = (t>>0)&0xff; sendResponseMsg(cmdID, data, 4); } break; default: sendUnknownCmdIDMsg(); break; } } arduino-0.4.0/inst/+arduinoio/lib/OctaveCoreLibrary.h0000644000000000000000000000174113470770202020666 0ustar0000000000000000/* * Octave arduino core interface * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "LibraryBase.h" class OctaveCoreLibrary : public LibraryBase { OctaveArduinoClass &occlass; public: OctaveCoreLibrary(OctaveArduinoClass &oc); void commandHandler(uint8_t cmdID, uint8_t* inputs, uint8_t payload_size); }; arduino-0.4.0/inst/+arduinoio/lib/OctaveI2CLibrary.cpp0000644000000000000000000001126613470770202020711 0ustar0000000000000000/* * Octave arduino i2c interface * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "settings.h" #include "OctaveI2CLibrary.h" #define ARDUINO_SCANI2C 0 #define ARDUINO_CONFIGI2C 1 #define ARDUINO_WRITEI2C 2 #define ARDUINO_READI2C 3 #define ARDUINO_WRITEI2CREG 4 #define ARDUINO_READI2CREG 5 #ifdef USE_I2C #include static uint8_t i2c_enabled = false; static uint8_t i2c_address = 0; #endif OctaveI2CLibrary::OctaveI2CLibrary(OctaveArduinoClass &oc) { libName = "I2C"; oc.registerLibrary(this); } void OctaveI2CLibrary::commandHandler(uint8_t cmdID, uint8_t* data, uint8_t datasz) { int val; switch (cmdID) { #ifdef USE_I2C case ARDUINO_WRITEI2C: case ARDUINO_WRITEI2CREG: { if(datasz < 2 || datasz > 32) { // address // data sendInvalidNumArgsMsg(); } else { Wire.beginTransmission(data[0]); // should be i2c_address byte c; for(c=1;c 5) sendWaitMsg(); datasz = 1; for(c=0;c<=l;c++) { if(Wire.available()) { data[datasz] = Wire.read(); datasz ++; } } sendResponseMsg(cmdID,data, datasz); } break; } case ARDUINO_READI2CREG: { if(datasz < 4) { // address // regsz // reg // numbytes sendInvalidNumArgsMsg(); } else if (datasz != data[1]+3) { sendInvalidNumArgsMsg(); } else { Wire.beginTransmission(data[0]); byte c = 0; for(c=0;c 5) sendWaitMsg(); datasz = 2; for(c=0;c<=l;c++) { if(Wire.available()) { data[datasz] = Wire.read(); datasz ++; } } sendResponseMsg(cmdID,data, datasz); } break; } case ARDUINO_SCANI2C: { if(datasz != 2) { sendInvalidNumArgsMsg(); } else { byte error; // bus 0 // address if(!i2c_enabled) Wire.begin(); Wire.beginTransmission(data[1]); error = Wire.endTransmission(); if(error == 0) data[2] = 1; else data[2] = 0; if(!i2c_enabled) Wire.end(); sendResponseMsg(cmdID, data, 3); } break; } case ARDUINO_CONFIGI2C: { if(datasz == 2 || datasz == 3) { // i2c id 0 // enable 1 // enable if(data[1] == 1) { //SPI.begin(); i2c_enabled = 1; i2c_address = 0; if (datasz == 3 && data[2] != 0) { i2c_address = data[2]; Wire.begin(i2c_address); } else Wire.begin(); } else { Wire.end(); i2c_enabled = 0; } sendResponseMsg(cmdID,data, datasz); } else if(datasz == 1) { // spi id // enable // address data[1] = i2c_enabled; data[2] = i2c_address; sendResponseMsg(cmdID,data, 3); } else { sendInvalidNumArgsMsg(); } break; } #endif default: sendUnknownCmdIDMsg(); break; } } arduino-0.4.0/inst/+arduinoio/lib/OctaveI2CLibrary.h0000644000000000000000000000167713470770202020363 0ustar0000000000000000/* * Octave arduino i2c interface * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "LibraryBase.h" class OctaveI2CLibrary : public LibraryBase { public: OctaveI2CLibrary(OctaveArduinoClass &oc); void commandHandler(uint8_t cmdID, uint8_t* inputs, uint8_t payload_size); }; arduino-0.4.0/inst/+arduinoio/lib/OctaveRotaryEncoderLibrary.cpp0000644000000000000000000001475513470770202023122 0ustar0000000000000000/* * Octave arduino encoder interface * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "settings.h" #include "OctaveRotaryEncoderLibrary.h" #define ARDUINO_RESET_ENCODER 0 #define ARDUINO_CONFIG_ENCODER 1 #define ARDUINO_READPOS_ENCODER 2 #define ARDUINO_READSPEED_ENCODER 3 static const char ERRORMSG_INVALID_ARGS[] PROGMEM = "Invalid args"; static const char ERRORMSG_CANT_READ[] PROGMEM = "Max encoder reached"; static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; #ifdef USE_ROTARYENCODER #define MAX_ROTARYENCODERS 8 class RotaryEncoder { #define USED 1 #define POLL 2 public: uint8_t flags; uint8_t pins[2]; int16_t cnt; int16_t oldcnt; uint16_t speed; uint8_t state; RotaryEncoder(); uint8_t init(uint8_t p1, uint8_t p2); uint8_t free() { flags = 0; return 0;} uint16_t readCount(); uint16_t readSpeed(); uint8_t resetCount(uint8_t h=0, uint8_t l=0); void poll(); void process(unsigned long diff); }; RotaryEncoder::RotaryEncoder() { flags = 0; } uint8_t RotaryEncoder::init(uint8_t p1, uint8_t p2) { flags = USED | POLL; state = 0; cnt = 0; oldcnt = 0; pins[0] = p1; pins[1] = p2; pinMode (pins[0], INPUT); digitalWrite(pins[0], HIGH); pinMode (pins[1], INPUT); digitalWrite(pins[1], HIGH); return 0; } uint16_t RotaryEncoder::readCount() { return cnt; } uint16_t RotaryEncoder::readSpeed() { return speed; } uint8_t RotaryEncoder::resetCount(uint8_t h, uint8_t l) { uint16_t v= ((uint16_t)h)<<8 | l; cnt = (int16_t)v; oldcnt = cnt; return 0; } void RotaryEncoder::poll() { // get curr state and prev state - gives 16 possible outcomes // wheich can then do a lookup table for detection state = (state<<2) | (digitalRead(pins[1]) ? 2 : 0) | (digitalRead(pins[0]) ? 1 : 0); int8_t dir = enc_states[state&0xf]; if(dir < 0 && cnt > -32000) cnt += dir; if(dir > 0 && cnt < 32000) cnt += dir; } void RotaryEncoder::process(unsigned long t) { //input millis long s = ((cnt - oldcnt) * 1000) / t; if(s < 0) s = -s; if(s > 32000) s = 32000; if(s != 0) speed = s; else if(speed > 0) speed --; oldcnt = cnt; } static RotaryEncoder encoders[MAX_ROTARYENCODERS]; RotaryEncoder * getRotaryEncoder(uint8_t id) { uint8_t i; RotaryEncoder * unused = 0; for(i=0;iinit(data[0], data[2]); sendResponseMsg(cmdID,data, 2); } // free else if(data[1] == 0 && reg->flags && datasz == 2) { reg->free(); sendResponseMsg(cmdID,data, 2); } else { sendErrorMsg_P(ERRORMSG_INVALID_ARGS); } } else { sendErrorMsg_P(ERRORMSG_INVALID_ARGS); } break; } case ARDUINO_RESET_ENCODER: { // 0 = id (currently using the datapin id) RotaryEncoder * reg = getRotaryEncoder(data[0]); if(reg && reg->flags) { data[1] = reg->resetCount(data[1], data[2]); sendResponseMsg(cmdID,data, 2); } else { sendErrorMsg_P(ERRORMSG_INVALID_ARGS); } break; } case ARDUINO_READPOS_ENCODER: { // 0 = id // 1 = reset flag RotaryEncoder * reg = getRotaryEncoder(data[0]); if(reg && reg->flags && datasz == 2) { uint16_t v = reg->readCount(); if(data[1] == 1) reg->resetCount(); data[1] = (v>>8)&0xff; data[2] = (v)&0xff; unsigned long t = millis(); data[3] = (t>>24)&0xff; data[4] = (t>>16)&0xff; data[5] = (t>>8)&0xff; data[6] = (t)&0xff; datasz = 7; sendResponseMsg(cmdID, data, datasz); } else { sendErrorMsg_P(ERRORMSG_INVALID_ARGS); } break; } case ARDUINO_READSPEED_ENCODER: { // 0 = id RotaryEncoder * reg = getRotaryEncoder(data[0]); if(reg && reg->flags && datasz == 1) { uint16_t v = reg->readSpeed(); datasz = 3; data[1] = (v>>8)&0xff; data[2] = (v)&0xff; sendResponseMsg(cmdID, data, datasz); } else { sendErrorMsg_P(ERRORMSG_INVALID_ARGS); } break; } #endif default: sendUnknownCmdIDMsg(); break; } } void OctaveRotaryEncoderLibrary::loop() { #ifdef USE_ROTARYENCODER static unsigned long speedtime = 0; unsigned long newtime; // any thing that needs poll for(int i=0;iflags & POLL) { enc->poll(); } } // do any periodic processing newtime = millis(); if (speedtime < newtime) { unsigned long diff = (newtime - speedtime); if(diff > 50) { speedtime = newtime; for(int i=0;iflags) { enc->process(diff); } } } } else if(speedtime > newtime) { speedtime = newtime; } #endif } arduino-0.4.0/inst/+arduinoio/lib/OctaveRotaryEncoderLibrary.h0000644000000000000000000000176713470770202022566 0ustar0000000000000000/* * Octave arduino shift register interface * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "LibraryBase.h" class OctaveRotaryEncoderLibrary : public LibraryBase { public: OctaveRotaryEncoderLibrary(OctaveArduinoClass &oc); void commandHandler(uint8_t cmdID, uint8_t* inputs, uint8_t payload_size); virtual void loop(); }; arduino-0.4.0/inst/+arduinoio/lib/OctaveSPILibrary.cpp0000644000000000000000000000702113470770202020761 0ustar0000000000000000/* * Octave arduino spi interface * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "settings.h" #include "OctaveSPILibrary.h" #define ARDUINO_CONFIGSPI 1 #define ARDUINO_READ_WRITE_SPI 2 #ifdef USE_SPI #include uint8_t spi_enabled = false; uint8_t spi_bitorder = 0; uint8_t spi_mode = 0; #endif OctaveSPILibrary::OctaveSPILibrary(OctaveArduinoClass &oc) { libName = "SPI"; oc.registerLibrary(this); } void OctaveSPILibrary::commandHandler(uint8_t cmdID, uint8_t* data, uint8_t datasz) { int val; switch (cmdID) { #ifdef USE_SPI case ARDUINO_CONFIGSPI: { if(datasz == 4) { // spi id 0 (cs pin) // enable 1 // mode ? 2 // byte order 3 // TODO: bit rate if(data[1] == 1) { //SPI.begin(); spi_mode = data[2]; spi_bitorder = data[3]; spi_enabled = 1; //if(spi_bitorder == 0) spi_bitorder = MSBFIRST; //else spi_bitorder = LSBFIRST; if(spi_mode == 0) spi_mode = SPI_MODE0; else if(spi_mode == 1) spi_mode = SPI_MODE1; else if(spi_mode == 2) spi_mode = SPI_MODE2; else if(spi_mode == 3) spi_mode = SPI_MODE3; else spi_mode = SPI_MODE0; SPI.begin(); digitalWrite(data[0], HIGH); } else { SPI.end(); spi_enabled = 0; } sendResponseMsg(cmdID,data, 2); } else if(datasz == 2) { if(data[1] == 1) { spi_enabled = 1; SPI.begin(); digitalWrite(data[0], HIGH); } else { SPI.end(); spi_enabled = 0; } sendResponseMsg(cmdID,data, 2); } else if(datasz == 1) { // spi id (cs) // enable // mode ? // byte order data[1] = spi_enabled; data[2] = spi_mode; data[3] = spi_bitorder; sendResponseMsg(cmdID,data, 4); } else { sendInvalidNumArgsMsg(); } break; } case ARDUINO_READ_WRITE_SPI: if(datasz >= 2) { uint8_t cs_pin = data[0]; // begin transaction SPI.beginTransaction(SPISettings(4000000, spi_bitorder==0 ? MSBFIRST : LSBFIRST , spi_mode)); // set CS low digitalWrite(cs_pin, LOW); delay(1); // transfer the bytes SPI.transfer(&data[1], datasz-1); // set CS hi digitalWrite(cs_pin, HIGH); delay(1); // endtransaction SPI.endTransaction(); sendResponseMsg(cmdID, data, datasz); } else { sendInvalidNumArgsMsg(); } break; #endif default: sendUnknownCmdIDMsg(); break; } } arduino-0.4.0/inst/+arduinoio/lib/OctaveSPILibrary.h0000644000000000000000000000167713470770202020441 0ustar0000000000000000/* * Octave arduino spi interface * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "LibraryBase.h" class OctaveSPILibrary : public LibraryBase { public: OctaveSPILibrary(OctaveArduinoClass &oc); void commandHandler(uint8_t cmdID, uint8_t* inputs, uint8_t payload_size); }; arduino-0.4.0/inst/+arduinoio/lib/OctaveServoLibrary.cpp0000644000000000000000000000430113470770202021422 0ustar0000000000000000/* * Octave arduino servo interface * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "settings.h" #include "OctaveServoLibrary.h" #define ARDUINO_SERVO 0 #define ARDUINO_CONFIG_SERVO 1 #ifdef USE_SERVO // NOTE: if cant fint servo.h, you probally dont have the Servo library installed // go to Sketch -> Include Library -> Manage Libraries, and select 'Servo' #include Servo servo[NUM_DIGITAL_PINS]; uint16_t servo_pos[NUM_DIGITAL_PINS]; #endif OctaveServoLibrary::OctaveServoLibrary(OctaveArduinoClass &oc) { libName = "Servo"; oc.registerLibrary(this); } void OctaveServoLibrary::commandHandler(uint8_t cmdID, uint8_t* data, uint8_t datasz) { int val; switch (cmdID) { #ifdef USE_SERVO case ARDUINO_SERVO: if(datasz == 1) { uint16_t ms = servo_pos[data[0]]; data[1] = (ms>>8); data[2] = (ms&0xff); sendResponseMsg(cmdID,data, 3); } else if(datasz == 3) { uint16_t ms = ((int)data[1]<<8) | ((int)data[2]); servo_pos[data[0]] = ms; servo[data[0]].writeMicroseconds(ms); sendResponseMsg(cmdID,data, 1); } else { sendInvalidNumArgsMsg(); } break; case ARDUINO_CONFIG_SERVO: if(datasz > 0) { // pin // conf stuff ... ? servo[data[0]].attach(data[0]); sendResponseMsg(cmdID,data, 1); } else { sendInvalidNumArgsMsg(); } break; #endif default: sendUnknownCmdIDMsg(); break; } } arduino-0.4.0/inst/+arduinoio/lib/OctaveServoLibrary.h0000644000000000000000000000170513470770202021074 0ustar0000000000000000/* * Octave arduino servo interface * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "LibraryBase.h" class OctaveServoLibrary : public LibraryBase { public: OctaveServoLibrary(OctaveArduinoClass &oc); void commandHandler(uint8_t cmdID, uint8_t* inputs, uint8_t payload_size); }; arduino-0.4.0/inst/+arduinoio/lib/OctaveShiftRegisterLibrary.cpp0000644000000000000000000002323013470770202023110 0ustar0000000000000000/* * Octave arduino shift register interface * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "settings.h" #include "OctaveShiftRegisterLibrary.h" #define ARDUINO_RESET_SHIFTREG 0 #define ARDUINO_CONFIG_SHIFTREG 1 #define ARDUINO_WRITE_SHIFTREG 2 #define ARDUINO_READ_SHIFTREG 3 #define TYPE_74HC164 0 // input p2s #define TYPE_74HC165 1 // output s2p #define TYPE_74HC595 2 #define SER_74HC595_DATA 0 #define SER_74HC595_CLK 1 #define SER_74HC595_LATCH 2 #define SER_74HC595_RESET 3 #define SER_74HC165_DATA 0 #define SER_74HC165_CLK 1 #define SER_74HC165_LOAD 2 #define SER_74HC165_CLOCKEN 3 #define SER_74HC164_DATA 0 #define SER_74HC164_CLK 1 #define SER_74HC164_RESET 2 static const char ERRORMSG_INVALID_ARGS[] PROGMEM = "Invalid args"; static const char ERRORMSG_CANT_READ[] PROGMEM = "This register cant not read"; static const char ERRORMSG_CANT_WRITE[] PROGMEM = "This register can not write"; #ifdef USE_SHIFTREG #define MAX_SHIFT_REGISTERS 8 class ShiftRegister { public: uint8_t used; uint8_t type; uint8_t pins[6]; ShiftRegister(); bool canread(); bool canwrite(); uint8_t init(); uint8_t csenable(bool en); uint8_t latch(); uint8_t read(); uint8_t free() { used = 0; return 0;} uint8_t write(uint8_t); uint8_t reset(); }; ShiftRegister::ShiftRegister() { used = 0; } bool ShiftRegister::canread() { return (type == TYPE_74HC165); } bool ShiftRegister::canwrite() { return (type == TYPE_74HC164 || type == TYPE_74HC595); } uint8_t ShiftRegister::init() { // depends on type of what need do if (type == TYPE_74HC164) { pinMode (pins[SER_74HC164_DATA], OUTPUT); pinMode (pins[SER_74HC164_CLK], OUTPUT); // have reset pin if (used > SER_74HC164_RESET) { pinMode (pins[SER_74HC164_RESET], OUTPUT); digitalWrite (pins[SER_74HC164_RESET], LOW); } digitalWrite (pins[SER_74HC595_CLK], LOW); if (used > SER_74HC164_RESET) { // have reset pin - so unset clr digitalWrite (pins[SER_74HC164_RESET], HIGH); } } if (type == TYPE_74HC165) { // serial data is input pinMode (pins[SER_74HC165_DATA], INPUT); // init with clock and load high pinMode (pins[SER_74HC165_CLK], OUTPUT); pinMode (pins[SER_74HC165_LOAD], OUTPUT); digitalWrite (pins[SER_74HC165_CLK], HIGH); digitalWrite (pins[SER_74HC165_LOAD], HIGH); } if (type == TYPE_74HC595) { pinMode(pins[SER_74HC595_DATA], OUTPUT); pinMode(pins[SER_74HC595_CLK], OUTPUT); // clk pinMode(pins[SER_74HC595_LATCH], OUTPUT); // latch // have reset pin if(used > SER_74HC595_RESET) { pinMode(pins[SER_74HC595_RESET], OUTPUT); // reset (optional) digitalWrite(pins[SER_74HC595_RESET], LOW); } // clock start high digitalWrite(pins[SER_74HC595_CLK], LOW); // latch digitalWrite(pins[SER_74HC595_LATCH], LOW); // have reset pin - so unset clr if(used > SER_74HC595_RESET) { digitalWrite(pins[SER_74HC595_RESET], HIGH); } } return 0; } uint8_t ShiftRegister::csenable(bool en) { if (type == TYPE_74HC164) { // nothing to do } if (type == TYPE_74HC165) { // enable the clock with clockenalepin digitalWrite(pins[SER_74HC165_CLOCKEN], en ? LOW : HIGH); } if (type == TYPE_74HC595) { // nothing to do } return 0; } uint8_t ShiftRegister::latch() { if (type == TYPE_74HC164) { // no latch } if (type == TYPE_74HC165) { // trigger loading, by toggle on loadpin digitalWrite(pins[SER_74HC165_LOAD], LOW); delayMicroseconds(5); digitalWrite(pins[SER_74HC165_LOAD], HIGH); delayMicroseconds(5); } if (type == TYPE_74HC595) { // latches on rising edge digitalWrite(pins[SER_74HC595_LATCH], HIGH); delayMicroseconds(5); digitalWrite(pins[SER_74HC595_LATCH], LOW); delayMicroseconds(5); } return 0; } uint8_t ShiftRegister::read() { uint8_t val = 0; if (type == TYPE_74HC165) { val = shiftIn(pins[SER_74HC165_DATA], pins[SER_74HC165_CLK], MSBFIRST); } return val; } uint8_t ShiftRegister::write(uint8_t d) { // TODO if (type == TYPE_74HC595) { shiftOut(pins[SER_74HC595_DATA], pins[SER_74HC595_CLK], MSBFIRST, d); return 1; } if (type == TYPE_74HC164) { shiftOut(pins[SER_74HC164_DATA], pins[SER_74HC164_CLK], MSBFIRST, d); return 1; } return 0; } uint8_t ShiftRegister::reset() { if (type == TYPE_74HC595) { // have reset pin - so unset clr if(used > SER_74HC595_RESET) { digitalWrite(pins[SER_74HC595_RESET], LOW); delayMicroseconds(5); digitalWrite(pins[SER_74HC595_RESET], HIGH); delayMicroseconds(5); return 1; } } if (type == TYPE_74HC164) { if(used > SER_74HC164_RESET) { digitalWrite(pins[SER_74HC164_RESET], LOW); delayMicroseconds(5); digitalWrite(pins[SER_74HC164_RESET], HIGH); delayMicroseconds(5); return 1; } } return 0; } ShiftRegister shiftregs[MAX_SHIFT_REGISTERS]; ShiftRegister * getShiftRegister(uint8_t id) { uint8_t i; ShiftRegister * unused = 0; for(i=0;i 0) { if(shiftregs[i].pins[0] == id) return &shiftregs[i]; } else if(!unused) { unused = &shiftregs[i]; } } return unused; } #endif OctaveShiftRegisterLibrary::OctaveShiftRegisterLibrary(OctaveArduinoClass &oc) { libName = "ShiftRegister"; oc.registerLibrary(this); } void OctaveShiftRegisterLibrary::commandHandler(uint8_t cmdID, uint8_t* data, uint8_t datasz) { int val; switch (cmdID) { #ifdef USE_SHIFTREG case ARDUINO_CONFIG_SHIFTREG: { // 0 = id/datapin // 1 - enable/alloc // [ 2 = type // 3 = pins [] // 4 ... ] ShiftRegister * reg = getShiftRegister(data[0]); if(reg) { // alloc if(data[1] == 1 && datasz >= 4) { // data = DATAPIN E T CLK PIN? PIN? ... // // DATAPIN (doubles as ID) // E = enable (1 vs 0) ie: alloc/free // T = type 0 = 74HC164, ... // CLK clock pin // otherpins // pins used = pins defined reg->used = datasz - 2; // 1st pin is the register id reg->pins[0] = data[0]; reg->type = data[2]; byte c = 0; for(c=0;cused-1;c++) { reg->pins[c+1] = data[3+c]; } reg->init(); sendResponseMsg(cmdID,data, 2); } // free else if(data[1] == 0 && reg->used > 0 && datasz == 2) { reg->used = 0; reg->free(); sendResponseMsg(cmdID,data, 2); } else { sendErrorMsg_P(ERRORMSG_INVALID_ARGS); } } else { sendErrorMsg_P(ERRORMSG_INVALID_ARGS); } break; } case ARDUINO_RESET_SHIFTREG: { // 0 = id (currently using the datapin id) ShiftRegister * reg = getShiftRegister(data[0]); if(reg && reg->used > 0) { data[1] = reg->reset(); sendResponseMsg(cmdID,data, 2); } else { sendErrorMsg_P(ERRORMSG_INVALID_ARGS); } break; } case ARDUINO_WRITE_SHIFTREG: { // 0 = id // byte 0 // [byte1....] ShiftRegister * reg = getShiftRegister(data[0]); if(reg && reg->used > 0 && datasz >= 2) { if(reg->canwrite()) { reg->csenable(true); byte c = 0; for(c=1;cwrite(data[c]); } // num bytes wrote data[1] = datasz-1; datasz = 2; reg->latch(); reg->csenable(false); sendResponseMsg(cmdID,data, datasz); } else { // chip cant do write sendErrorMsg_P(ERRORMSG_CANT_WRITE); } } else { sendErrorMsg_P(ERRORMSG_INVALID_ARGS); } break; } case ARDUINO_READ_SHIFTREG: { // 0 = id // 1 = numbytes ShiftRegister * reg = getShiftRegister(data[0]); if(reg && reg->used > 0 && datasz == 2) { if(reg->canread()) { reg->csenable(true); reg->latch(); byte c = 0; datasz = data[1]; for(c=1;cread(); } reg->csenable(false); sendResponseMsg(cmdID, data, datasz); } else { // cant read sendErrorMsg_P(ERRORMSG_CANT_READ); } } else { sendErrorMsg_P(ERRORMSG_INVALID_ARGS); } break; } #endif default: sendUnknownCmdIDMsg(); break; } } arduino-0.4.0/inst/+arduinoio/lib/OctaveShiftRegisterLibrary.h0000644000000000000000000000173613470770202022564 0ustar0000000000000000/* * Octave arduino shift register interface * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "LibraryBase.h" class OctaveShiftRegisterLibrary : public LibraryBase { public: OctaveShiftRegisterLibrary(OctaveArduinoClass &oc); void commandHandler(uint8_t cmdID, uint8_t* inputs, uint8_t payload_size); }; arduino-0.4.0/inst/+arduinoio/lib/octave.ino0000644000000000000000000000356113470770202017130 0ustar0000000000000000/* * Octave arduino interface * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "settings.h" #include "LibraryBase.h" // lib manager / processing static OctaveArduinoClass octavearduino; // include the base library #include "OctaveCoreLibrary.h" OctaveCoreLibrary lib0(octavearduino); #ifdef USE_I2C #include "OctaveI2CLibrary.h" OctaveI2CLibrary lib1(octavearduino); #endif #ifdef USE_SPI #include "OctaveSPILibrary.h" OctaveSPILibrary lib2(octavearduino); #endif #ifdef USE_SERVO #include "OctaveServoLibrary.h" OctaveServoLibrary lib3(octavearduino); #endif #ifdef USE_SHIFTREG #include "OctaveShiftRegisterLibrary.h" OctaveShiftRegisterLibrary lib4(octavearduino); #endif #ifdef USE_ROTARYENCODER #include "OctaveRotaryEncoderLibrary.h" OctaveRotaryEncoderLibrary lib5(octavearduino); #endif // additional addons included from generated addons.h file #include "addons.h" void setup() { #if defined(ARDUINO_ARCH_AVR) // clear watchdog //clear all flags MCUSR = 0; /* Write logical one to WDCE and WDE */ /* Keep old prescaler setting to prevent unintentional time-out */ WDTCSR |= _BV(WDCE) | _BV(WDE); WDTCSR = 0; #endif octavearduino.init(); } void loop() { octavearduino.runLoop(); } arduino-0.4.0/inst/+arduinoioaddons/0000755000000000000000000000000013470770202015556 5ustar0000000000000000arduino-0.4.0/inst/+arduinoioaddons/+EEPRomAddon/0000755000000000000000000000000013470770202017666 5ustar0000000000000000arduino-0.4.0/inst/+arduinoioaddons/+EEPRomAddon/EEPRom.m0000644000000000000000000001265413470770202021143 0ustar0000000000000000## Copyright (C) 2018-2019 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {} arduinoioaddons.EEPRomAddon.EEPRom ## EEPROM addon for arduino ## ## Allows read and write of uint8 data to the onboard arduino EEPROM. ## ## @subsubheading Example ## Assuming eeprom addon has been programmed into the Arduino: ## @example ## a = arduino (); ## e = addon (a, "eepromaddon/eeprom"); ## write (e, 0, uint8("hello world")); ## str = uint8( read(e, 0, 11) ) ## @end example ## ## @seealso{addon} ## @end deftypefn ## ## @subsubheading Properties ## @var{length} - Size of the EEPROM. ## ## @subheading Methods ## @deftypefn {} {@var{eeprom} =} EEPRom () ## Constructor to create eeprom device. ## @subsubheading Outputs ## @var{eeprom} - created EEPROM device. ## @end deftypefn ## ## @deftypefn {} {} erase () ## Erase all values in EEPROM (Effectively setting the 0xFF) ## @end deftypefn ## ## @deftypefn {} {} write (@var{address}, @var{uintdata}) ## Write data to EEPROM at the provided address. ## @subsubheading Inputs ## @var{address} - start address to write data to, should be a integer between 0 and the size of the EEPROM. ## ## @var{uintdata} a value or array of uint8 data to write to EEPROM. ## @end deftypefn ## ## @deftypefn {} {@var{data} =} read (@var{address}) ## @deftypefnx {} {@var{data} =} read (@var{address}, @var{count}) ## Read data from starting address of EEPROM. ## @subsubheading Inputs ## @var{address} - start address to read data from, should be a integer between 0 and the size of the EEPROM. ## ## @var{count} - Number of uint8 values to read from the EEPROM (default is 1) ## ## @subsubheading Outputs ## @var{data} a value or array of uint8 data read from the EEROM. ## @end deftypefn classdef EEPRom < arduinoio.LibraryBase # commands properties(Access = private) len = 0; endproperties properties(Access = private, Constant = true) INIT_COMMAND = hex2dec('00'); ERASE_COMMAND = hex2dec('01'); READ_COMMAND = hex2dec('02'); WRITE_COMMAND = hex2dec('03'); endproperties properties(Access = protected, Constant = true) LibraryName = 'EEPRomAddon/EEPRom'; DependentLibraries = {}; #ArduinoLibraryHeaderFiles = {}; CppHeaderFile = fullfile(arduinoio.FilePath(mfilename('fullpath')), 'EEPRomAddon.h'); CppClassName = 'EEPRom'; endproperties methods # constructor function obj = EEPRom(parentObj) obj.Parent = parentObj; if nargin != 1 error ("EEPRom: expected arduino parent as only argument"); endif obj.Pins = {}; data = sendCommand(obj.Parent, obj.LibraryName, obj.INIT_COMMAND, []); length = uint16(data(1))*256 + uint16(data(2)) obj.len = length; endfunction function len = length (obj) len = obj.len; endfunction function erase(obj) cmdID = obj.ERASE_COMMAND; sendCommand(obj.Parent, obj.LibraryName, cmdID, []); endfunction function value = read(obj, address, num) cmdID = obj.READ_COMMAND; if nargin != 2 && nargin != 3 error ("EEPRom: expected address and value"); endif if nargin == 2 num = 1; endif if ! isnumeric(address) || address < 0 || address >= obj.len || mod(address, 1) != 0 error ("EEProm: expected address to be between 0 and %d", obj.len); endif if ! isnumeric(num) || num < 0 || num > 128 || mod(num, 1) != 0 error ("EEProm: num expected to be integer between 0 and %d", 128); endif if address + num > obj.len error ("EEPRom: address + num (%d) is out of EEPRom bounds of %d\n", (address+num), obj.len); endif intval = uint16(address); datain = [ bitshift(intval,-8) bitand(intval, 255) num]; dataout = sendCommand(obj.Parent, obj.LibraryName, cmdID, datain); value = dataout; endfunction function write(obj, address, value) cmdID = obj.WRITE_COMMAND; if nargin != 3 error ("EEPRom: expected address and value"); endif if ! isnumeric(address) || address < 0 || address >= obj.len || mod(address, 1) != 0 error ("expected address to be between 0 and %d", obj.len); endif num = numel(value); if num < 0 || num > 128 error ("EEProm: value size expected to be between 0 and %d", 128); endif if (address + num > obj.len) error ("EEPRom: address + numel(value) (%d) is out of EEPRom bounds of %d\n", (address+num), obj.len); endif intval = uint16(address); datain = [ bitshift(intval,-8) bitand(intval, 255) value]; sendCommand(obj.Parent, obj.LibraryName, cmdID, datain); endfunction function display (obj) printf("%s = \n", inputname(1)); printf(" %s with properties\n", class(obj)); printf(" length = %d\n", obj.len); endfunction endmethods endclassdef arduino-0.4.0/inst/+arduinoioaddons/+EEPRomAddon/EEPRomAddon.h0000644000000000000000000000434113470770202022076 0ustar0000000000000000/* * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * . */ #include "LibraryBase.h" #include // arduino liquid crystal library #define EEPROM_INIT 0x00 #define EEPROM_ERASE 0x01 #define EEPROM_READ 0x02 #define EEPROM_WRITE 0x03 class EEPRom : public LibraryBase { public: EEPRom(OctaveArduinoClass& a) { libName = "EEPRomAddon/EEProm"; a.registerLibrary(this); } void commandHandler(uint8_t cmdId, uint8_t* data, uint8_t datasz) { switch(cmdId) { case EEPROM_INIT: { uint16_t sz = EEPROM.length(); data[0] = (sz>>8)&0xff; data[1] = (sz)&0xff; sendResponseMsg(cmdId, data, 2); break; } case EEPROM_ERASE: { for (int a=0;a= 3) { uint16_t addr = (uint16_t(data[0])<<8) | data[1]; datasz = datasz-2; for(int i=0;i ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {} arduinoioaddons.ExampleAddon.Echo ## Basic Example matlab/octave code to illustrate creating ## a user addon. ## ## @seealso{addon} ## @end deftypefn ## ## @subsubheading Properties ## @var{Parent} - the parent arduino object. ## ## @var{Pins} - the pins allocated the addon. ## ## @subheading Methods ## @deftypefn {} {@var{obj} =} Echo(arObj) ## Constructor to create Echo addon ## @subsubheading Inputs ## @var{arObj} - the arduino parent object ## ## @subsubheading Outputs ## @var{obj} - created Echo object ## @end deftypefn ## ## @deftypefn {} {@var{response} = } shout(@var{text}) ## Send text to arduino and receive back the echoed reply ## ## @subsubheading Inputs ## @var{text} - text to send to arduino ## ## @subsubheading Outputs ## @var{response} - response from the arduino, which should be the same as ## the input text. ## @end deftypefn # classdef Echo < arduinoio.LibraryBase # commands properties(Access = private, Constant = true) ECHO_COMMAND = hex2dec('01'); endproperties properties(Access = protected, Constant = true) LibraryName = 'ExampleAddon/Echo'; DependentLibraries = {}; ArduinoLibraryHeaderFiles = {}; CppHeaderFile = fullfile(arduinoio.FilePath(mfilename('fullpath')), 'src', 'Echo.h'); CppClassName = 'Echo'; endproperties methods # constructor function obj = Echo(parentObj) obj.Parent = parentObj; obj.Pins = []; endfunction # function addon can do function out = shout(obj, val) cmdID = obj.ECHO_COMMAND; inputs = [uint8(val)]; output = sendCommand(obj.Parent, obj.LibraryName, cmdID, inputs); # data is just an echo of what we sent out = char(output); endfunction endmethods endclassdef arduino-0.4.0/inst/+arduinoioaddons/+ExampleAddon/src/0000755000000000000000000000000013470770202020761 5ustar0000000000000000arduino-0.4.0/inst/+arduinoioaddons/+ExampleAddon/src/Echo.h0000644000000000000000000000250013470770202022005 0ustar0000000000000000/* * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * . */ #include "LibraryBase.h" const char MSG_NEEDS_VALUE[] PROGMEM = "Needs a value to echo"; class Echo : public LibraryBase { public: Echo(OctaveArduinoClass& a) { libName = "ExampleAddon/Echo"; a.registerLibrary(this); } void commandHandler(uint8_t cmdID, uint8_t* data, uint8_t datasz) { switch (cmdID) { case 0x01: { if(datasz == 0) sendErrorMsg_P(MSG_NEEDS_VALUE); else sendResponseMsg(cmdID, data, datasz); break; } default: { // notify of invalid cmd sendUnknownCmdIDMsg(); } } } }; arduino-0.4.0/inst/+arduinoioaddons/+ExampleLCD/0000755000000000000000000000000013470770202017547 5ustar0000000000000000arduino-0.4.0/inst/+arduinoioaddons/+ExampleLCD/LCD.m0000644000000000000000000001412213470770202020327 0ustar0000000000000000## Copyright (C) 2018-2019 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {} arduinoioaddons.LCDAddon.LCD ## Basic Example octave addon for LCD ## ## Allows basic manipulation of an LCD as a illustration of using ## the addon functionality. ## @subsubheading Example ## Assuming the arduino has been programmed with the lcd addon: ## @example ## a = arduino(); ## lcd = addon(a, "examplelcd/lcd", "d8", "d9", "d4", "d5", "d6", "d7") ## clearLCD(lcd); ## printLCD(lcd, "Hello"); ## # go to next line ## gotoLCD(lcd, 0, 1); ## printLCD(lcd, "World"); ## @end example ## @seealso{addon} ## @end deftypefn ## ## @subsubheading Properties ## @var{Pins} - the pins allocated the LCD display. ## ## @subheading Methods ## @deftypefn {} {@var{lcd} =} LCD(arObj, rs, enable, d0, d1, d2, d3) ## Constructor to create LCD device ## @subsubheading Inputs ## @var{arObj} - the arduino parent object ## ## @var{rs} - the pin to use for the rs line. ## ## @var{enable} - the pin to use for the enable line. ## ## @var{d0} - the pin to use for the d0 line. ## ## @var{d1} - the pin to use for the d1 line. ## ## @var{d2} - the pin to use for the d2 line. ## ## @var{d3} - the pin to use for the d3 line. ## ## @subsubheading Outputs ## @var{lcd} - created LCD object ## @end deftypefn ## ## @deftypefn {} {} freeLCD() ## Free the LCD ## ## Should be called before discarding the LCD ## @subsubheading Inputs ## None. ## ## @subsubheading Outputs ## None. ## @end deftypefn ## ## @deftypefn {} {} clearLCD() ## Clear the LCD display and set the cursor position to the home position. ## ## @subsubheading Inputs ## None. ## ## @subsubheading Outputs ## None. ## @end deftypefn ## ## @deftypefn {} {} printLCD(@var{text}) ## Display text on LCD starting at the current cursor position. ## ## @subsubheading Inputs ## @var{text} - text to display on LCD ## ## @subsubheading Outputs ## None. ## @end deftypefn ## ## @deftypefn {} {} gotoLCD(@var{col}, @var{row}) ## Set the cursor position to row, col ## ## @subsubheading Inputs ## @var{col} - 0 indexed LCD column to position to. ## ## @var{row} - 0 indexed LCD row to position to. ## ## @subsubheading Outputs ## None. ## @end deftypefn classdef LCD < arduinoio.LibraryBase # commands properties(Access = private, Constant = true) INIT_COMMAND = hex2dec('00'); FREE_COMMAND = hex2dec('01'); CLEAR_COMMAND = hex2dec('02'); PRINT_COMMAND = hex2dec('03'); SETCURSOR_COMMAND = hex2dec('04'); endproperties properties(Access = protected, Constant = true) LibraryName = 'ExampleLCD/LCD'; DependentLibraries = {}; ArduinoLibraryHeaderFiles = { 'LiquidCrystal/LiquidCrystal.h' }; CppHeaderFile = fullfile(arduinoio.FilePath(mfilename('fullpath')), 'LCDAddon.h'); CppClassName = 'LCD'; endproperties properties(Access=private) ResourceOwner = 'ExampleLCD/LCDAddon'; endproperties methods # constructor function obj = LCD(parentObj, rs, enable, d0, d1, d2, d3) obj.Parent = parentObj; if nargin < 7 error ("LCD: expected input pins rs, enable, d0, d1, d2, d3"); endif # our LCD code only allows 1 lcd at a time count = getResourceCount(obj.Parent,obj.ResourceOwner); if count > 0 error ("ExampleLCD/LCDAddon: cant have only one LCD at a time"); endif obj.Pins = {}; data = []; pindata = getPinInfo(obj.Parent, {rs enable d0 d1 d2 d3}); try for p = 1:numel(pindata) pin = pindata{p}; configurePin(obj.Parent, pin.name, "digitaloutput") obj.Pins{end+1} = pin.name; data = [data pin.terminal]; endfor catch # catch any errors and restore pins for p = 1:numel(pindata) pin = pindata{p}; configurePinResource(obj.Parent, pin.name, pin.owner, pin.mode, true) configurePin(obj.Parent, pin.name, pin.mode) endfor rethrow (lasterror); end_try_catch sendCommand(obj.Parent, obj.LibraryName, obj.INIT_COMMAND, data); incrementResourceCount(obj.Parent,obj.ResourceOwner); endfunction function freeLCD(obj) if nargin != 1 warning ("LCD: unexpected additional arguments being ignored"); endif cmdID = obj.FREE_COMMAND; sendCommand(obj.Parent, obj.LibraryName, cmdID); endfunction function printLCD(obj, text) if nargin < 2 || !ischar(text) error ("LCD: expected text to display"); endif if nargin != 2 warning ("LCD: unexpected additional arguments being ignored"); endif cmdID = obj.PRINT_COMMAND; sendCommand(obj.Parent, obj.LibraryName, cmdID, [uint8(text) 0]); endfunction function clearLCD(obj) if nargin != 1 warning ("LCD: unexpected additional arguments being ignored"); endif cmdID = obj.CLEAR_COMMAND; sendCommand(obj.Parent, obj.LibraryName, cmdID); endfunction function gotoLCD(obj, col, row) if nargin < 3 error ("LCD: col and row"); endif if nargin != 3 warning ("LCD: unexpected additional arguments being ignored"); endif if !isnumeric(col) || col < 0 || mod(col,1) != 0 error ("LCD: expected col as a numeric integer value"); endif if !isnumeric(row) || row < 0 || mod(row,1) != 0 error ("LCD: expected row as a numeric integer value"); endif cmdID = obj.SETCURSOR_COMMAND; sendCommand(obj.Parent, obj.LibraryName, cmdID, [col row]); endfunction endmethods endclassdef arduino-0.4.0/inst/+arduinoioaddons/+ExampleLCD/LCDAddon.h0000644000000000000000000000553713470770202021302 0ustar0000000000000000/* * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * . */ #include "LibraryBase.h" #include // arduino liquid crystal library static const char LCD_MSG_ALREADY_INITIALIZED[] PROGMEM = "Already initialized"; static const char LCD_MSG_NOT_INITIALIZED[] PROGMEM = "LCD not initialized"; #define LCD_INIT 0x00 #define LCD_FREE 0x01 #define LCD_CLEAR 0x02 #define LCD_PRINT 0x03 #define LCD_SETCURSOR 0x04 class LCD : public LibraryBase { private: LiquidCrystal *lcd; public: LCD(OctaveArduinoClass& a) { libName = "ExampleLCD/LCD"; a.registerLibrary(this); } void setup() { lcd = 0; } void commandHandler(uint8_t cmdId, uint8_t* data, uint8_t datasz) { switch(cmdId) { case LCD_INIT: { // 0 - 5 = pins to use if (lcd) { sendErrorMsg_P(LCD_MSG_ALREADY_INITIALIZED); } else if(datasz != 6) { sendInvalidNumArgsMsg(); } else { // rs enable, d0, d1, d2, d3 lcd = new LiquidCrystal(data[0], data[1], data[2], data[3], data[4], data[5]); lcd->begin(16, 2); lcd->clear(); sendResponseMsg(cmdId, data, 1); } break; } case LCD_FREE: { if (!lcd) { sendErrorMsg_P(LCD_MSG_NOT_INITIALIZED); } else { delete lcd; lcd = 0; sendResponseMsg(cmdId, 0, 0); } break; } case LCD_CLEAR: { if (!lcd) { sendErrorMsg_P(LCD_MSG_NOT_INITIALIZED); } else { lcd->clear(); sendResponseMsg(cmdId, 0, 0); } break; } case LCD_PRINT: { if (!lcd) { sendErrorMsg_P(LCD_MSG_NOT_INITIALIZED); } else if(datasz > 0) { lcd->print((const char *)data); sendResponseMsg(cmdId, 0, 0); } else { sendInvalidNumArgsMsg(); } break; } case LCD_SETCURSOR: { if (!lcd) { sendErrorMsg_P(LCD_MSG_NOT_INITIALIZED); } else if(datasz == 2) { lcd->setCursor(data[0], data[1]); sendResponseMsg(cmdId, 0, 0); } else { sendInvalidNumArgsMsg(); } break; } default: { // notify of invalid cmd sendUnknownCmdIDMsg(); } break; } } }; arduino-0.4.0/inst/+arduinoioaddons/+RTCAddon/0000755000000000000000000000000013470770202017227 5ustar0000000000000000arduino-0.4.0/inst/+arduinoioaddons/+RTCAddon/DS1307.m0000644000000000000000000001704513470770202020235 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {} arduinoioaddons.RTCAddon.DS1307 ## DS1307 addon ## ## @seealso{addon} ## @end deftypefn ## ## @subsubheading Properties ## @var{Parent} - the parent arduino object. ## ## @var{Pins} - the pins allocated the addon. ## ## @subheading Methods ## @deftypefn {} {@var{obj} =} DS1307(@var{arObj}) ## @deftypefnx {} {@var{obj} =} DS1307(@var{arObj}, @var{propertyname, propertyvalue} ....) ## Constructor to create DS1307 addon ## @subsubheading Inputs ## @var{arObj} - the arduino parent object ## ## @var{propertyname, propertyvalue} - optional property name, value pairs. ## Current known properties are: ## @table @asis ## @item address ## I2C address of the DS1307 (default 0x68) ## @end table ## ## @subsubheading Outputs ## @var{obj} - created DS1307 object ## ## @subsubheading Example ## @example ## @code { ## a = arduino() ## rtc = addon(a, "rtcaddon/ds1307") ## } ## @end example ## @end deftypefn ## ## @deftypefn {} {@var{date} =} clock(@var{dsObj}) ## @deftypefnx {} {} clock(@var{dsObj}, @var{date}) ## Get/set the DS1307 clock ## ## @subsubheading Inputs ## @var{dsObj} - the ds1307 object ## ## @var{date} - a date vector in same format as datevec and clock ## ## @subsubheading Outputs ## @var{date} - a date vector in same format as datevec and clock ## ## @subsubheading Example ## @example ## @code { ## a = arduino() ## rtc = addon(a, "rtcaddon/ds1307") ## # get and display rtc time as a date string ## datestr(rtc.clock) ## } ## @end example ## @seealso{datevec} ## @end deftypefn ## ## @deftypefn {} {@var{ctrl} =} control(@var{dsObj}) ## @deftypefnx {} {} control(@var{dsObj}, @var{ctrl}) ## Get/set the DS1307 clock ## ## @subsubheading Inputs ## @var{dsObj} - the ds1307 object ## ## @var{ctrl} - a structure containing the control bit fields. ## ## @subsubheading Outputs ## @var{ctrl} - a structure containing the control bit fields. ## ## Control structure fields are: ## Current properties are: ## @table @asis ## @item out ## Out bit in the control register ## @item sqwe ## Square wave enable bit in control register ## @item rs ## The combined RS0, RS1 value ## @end table ## ## @end deftypefn ## ## @deftypefn {} {@var{YN} =} isstarted(@var{dsObj}) ## Get whether the RTC clock is currently counting time ## ## @subsubheading Inputs ## @var{dsObj} - the ds1307 object ## ## @subsubheading Outputs ## @var{YN} - returns true if the RTC is counting ## ## @seealso{start, stop} ## @end deftypefn ## ## @deftypefn {} {} start(@var{dsObj}) ## Start the RTC counting ## ## @subsubheading Inputs ## @var{dsObj} - the ds1307 object ## ## @subsubheading Outputs ## None ## ## @seealso{datevec} ## @end deftypefn ## ## @deftypefn {} {} stop(@var{dsObj}) ## Stop the RTC counting ## ## @subsubheading Inputs ## @var{dsObj} - the ds1307 object ## ## @subsubheading Outputs ## None ## ## @seealso{datevec} ## @end deftypefn classdef DS1307 < arduinoio.LibraryBase # commands properties(Access = private, Constant = true) INIT_COMMAND = hex2dec('00'); endproperties properties(Access = protected, Constant = true) LibraryName = 'RTCAddon/DS1307'; DependentLibraries = { "spi" }; ArduinoLibraryHeaderFiles = {}; CppHeaderFile = fullfile(arduinoio.FilePath(mfilename('fullpath')), 'DS1307Addon.h'); CppClassName = 'DS1307Addon'; endproperties properties(Access = private) i2c; address; bcd2dec = @(v) bitshift(v, -4)*10 + bitand(v, 0xf); dec2bcd = @(v) bitshift(floor(v/10), 4) + bitand(mod(v,10), 0xf); endproperties methods # constructor function obj = DS1307(parentObj, varargin) # parse args p = inputParser(CaseSensitive=false, FunctionName='RTCAddon/DS1307'); p.addParameter('Address', 0x68, @isnumeric); p.parse(varargin{:}); # do we have the address ? address = p.Results.Address; i2caddresses = scanI2Cbus(parentObj); idx = find(cellfun ( @(x) strcmp(x, sprintf("0x%02X", address)), i2caddresses)); if isempty(idx) error('RTCAddon/DS1307: matching i2c address found on bus'); endif obj.Parent = parentObj; obj.address = p.Results.Address; obj.i2c = i2cdev(parentObj, obj.address); obj.Pins = obj.i2c.Pins; # our arduino part isn't needed as we are really just using the i2c, but # we have to have the arduino part for lib detections, so lets # send a message to it on init anyway in case sometime in the future # we end up having it do something data = sendCommand(obj.Parent, obj.LibraryName, obj.INIT_COMMAND, []); endfunction function c = clock (obj, settime) if nargin == 2 # set time wd = weekday(datenum(settime)); writeRegister(obj.i2c, 0, ... [obj.dec2bcd(floor(settime(6))), obj.dec2bcd(settime(5)), (obj.dec2bcd(settime(4))), ... wd, obj.dec2bcd(settime(3)), obj.dec2bcd(settime(2)), obj.dec2bcd(mod(settime(1),100))] ... ); else # get time data = readRegister(obj.i2c, 0, 7); secs = double(obj.bcd2dec(bitand(data(1), 0x7f))); mins = double(obj.bcd2dec(data(2))); if bitand(data(3), 0x40) != 0 # 12 hr pm = bitand(data(3), 0x20); hrs = double(obj.bcd2dec(bitand(data(3), 0x2f))); if pm hrs = double(hrs + 12); endif else hrs = double(obj.bcd2dec(bitand(data(3), 0x3f))); endif wday = double(data(4)); day = double(obj.bcd2dec(data(5))); month = double(obj.bcd2dec(data(6))); year = 2000.0 + double(obj.bcd2dec(data(7))); c = double([year, month, day, hrs, mins, secs]); endif endfunction function start(obj) data = readRegister(obj.i2c, 0, 1); data = bitset(data, 8, 0); writeRegister(obj.i2c, 0, data); endfunction function stop(obj) data = readRegister(obj.i2c, 0, 1); data = bitset(data, 8, 1); writeRegister(obj.i2c, 0, data); endfunction function val = isstarted(obj) data = readRegister(obj.i2c, 0, 1); val = bitget(data, 8) == 0; endfunction function bits = control(obj, setbits) if nargin == 1 data = readRegister(obj.i2c, 7, 1); bits = {}; bits.out = bitget(data, 8); bits.sqwe = bitget(data, 5); bits.rs = bitand(data, 0x03); else data = 0; data = bitand(setbits.rs, 0x3); if setbits.out data = data + 0x80; endif if setbits.sqwe data = data + 0x10; endif writeRegister(obj.i2c, 7, data); endif endfunction function display(this) printf("%s = \n", inputname(1)); printf(" %s with properties\n", class(this)); printf(" Address = 0x%X\n", this.address); # show i2c pins as the pins printf(" Pins = {\n"); for i=1:numel(this.Pins) printf(" %s\n", this.Pins{i}); endfor printf(" }\n"); endfunction endmethods endclassdef arduino-0.4.0/inst/+arduinoioaddons/+RTCAddon/DS1307Addon.h0000644000000000000000000000234213470770202021170 0ustar0000000000000000/* * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * . */ #include "LibraryBase.h" #define DS1307_INIT 0x00 class DS1307Addon : public LibraryBase { public: DS1307Addon(OctaveArduinoClass& a) { libName = "RTCAddon/DS1307"; a.registerLibrary(this); } void commandHandler(uint8_t cmdId, uint8_t* data, uint8_t datasz) { switch(cmdId) { case DS1307_INIT: { sendResponseMsg(cmdId, data, 1); break; } default: { // notify of invalid cmd sendUnknownCmdIDMsg(); } break; } } }; arduino-0.4.0/inst/+arduinoioaddons/+adafruit/0000755000000000000000000000000013470770202017430 5ustar0000000000000000arduino-0.4.0/inst/+arduinoioaddons/+adafruit/dcmotorv2.m0000644000000000000000000001162513470770202021532 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {} arduinoioaddons.adafruit.dcmotorv2 ## DC Motor class for dc motor control on the adafruit motor shield ## ## @seealso{arduinoioaddons.adafruit.motorshieldv2} ## @end deftypefn ## ## @subsubheading Properties ## @var{Speed} - The speed value set for the motor ## ## @var{Parent} - The parent shield for object (read only) ## ## @var{MotorNumber} - The motor number (read only) values 1-4 ## ## @var{IsRunning} - boolean for if the motor is started (read only) ## ## @subheading Methods ## @deftypefn {} {@var{obj} =} dcmotorv2(@var{mObj}, @var{mnum}) ## @deftypefnx {} {@var{obj} =} dcmotorv2(@var{mObj}, @var{mnum}, @var{propertyname, propertyvalue} ....) ## Constructor to create dcmotor object ## @subsubheading Inputs ## @var{mObj} - the motor shield object ## ## @var{mnum} - The motor number (1 - 4) ## ## @var{propertyname, propertyvalue} - Optional property name/value pairs to pass to motor object. ## ## Current known properties are: ## @table @asis ## @item Speed ## Initial speed (default 0). Should be a value between -1 and 1. ## @end table ## ## @subsubheading Outputs ## @var{s} - a dcmotorv2 object ## ## @subsubheading Example ## @example ## @code { ## a = arduino() ## ms = addon(a, "adafruit/motorshieldv2") ## mtr = dcmotor(ms, 1) ## } ## @end example ## @end deftypefn ## ## @deftypefn {} {} start(@var{dcObj}) ## Start the motor moving in previously set speed/direction ## ## @subsubheading Inputs ## @var{dcObj} - the dcmotor object ## ## @subsubheading Outputs ## None ## ## @seealso{adafruit.motorshieldv2} ## @end deftypefn ## ## @deftypefn {} {} stop(@var{dcObj}) ## Stop the motor moving ## ## @subsubheading Inputs ## @var{dcObj} - the dcmotor object ## ## @subsubheading Outputs ## None ## ## @seealso{adafruit.motorshieldv2} ## @end deftypefn classdef dcmotorv2 < arduinoio.AddonBase properties(Access = private, Constant = true) INIT_COMMAND = hex2dec('20'); FREE_COMMAND = hex2dec('21'); START_COMMAND = hex2dec('22'); STOP_COMMAND = hex2dec('23'); endproperties properties(Access = private) cleanup; endproperties properties(GetAccess = public, SetAccess = private) MotorNumber; IsRunning = false; endproperties properties(Access = public) Speed = 0; endproperties methods function this = dcmotorv2(shield, mnum, varargin) validate_shield = @(x) isa(x, "arduinoioaddons.adafruit.motorshieldv2"); validate_mtrnum = @(x) (isnumeric(x) && isscalar(x) && (x >= 1 && x <= 4)); validate_speed = @(x) (isnumeric(x) && (x <= 1 && x >= -1)); p = inputParser(CaseSensitive=false, FunctionName='adafruit/dcmotorv2'); p.addRequired('shield',validate_shield); p.addRequired('mnum',validate_mtrnum); p.addParameter('Speed', 0, validate_speed); p.parse(shield, mnum, varargin{:}); this.Parent = p.Results.shield; this.MotorNumber = p.Results.mnum; this.Speed = p.Results.Speed; sendCommand(this.Parent, this.INIT_COMMAND,[this.MotorNumber-1]); this.cleanup = onCleanup (@() sendCommand(this.Parent, this.FREE_COMMAND, [this.MotorNumber-1])); endfunction function start(this) if this.Speed < 0 direction = 0; speed = -this.Speed*255; else direction = 1; speed = this.Speed*255; endif sendCommand(this.Parent,this.START_COMMAND,[this.MotorNumber-1, direction, speed]); this.IsRunning = true; endfunction function stop(this) sendCommand(this.Parent,this.STOP_COMMAND,[this.MotorNumber-1]); this.IsRunning = false; endfunction function set.Speed(this, newspeed) # check speed -1 .. 0 ... 1 if !isnumeric(newspeed) || newspeed < -1 || newspeed > 1 error("Speed should be between -1 .. 1"); endif this.Speed = newspeed; if this.IsRunning start(this); endif endfunction function display(this) printf("%s = \n", inputname(1)); printf(" %s with properties\n", class(this)); printf(" MotorNumber = %d\n", this.MotorNumber); printf(" Speed = %d\n", this.Speed); printf(" IsRunning = %d\n", this.IsRunning); endfunction endmethods endclassdef arduino-0.4.0/inst/+arduinoioaddons/+adafruit/motorshieldv2.h0000644000000000000000000001643713470770202022415 0ustar0000000000000000/* * Copyright (C) 2018 John Donoghue * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * . */ #include "LibraryBase.h" #define MTRV2_INIT 0x00 #define MTRV2_FREE 0x01 #define MTRV2_INIT_STEPPER 0x10 #define MTRV2_FREE_STEPPER 0x11 #define MTRV2_MOVE_STEPPER 0x12 #define MTRV2_RELEASE_STEPPER 0x13 #define MTRV2_INIT_DCMOTOR 0x20 #define MTRV2_FREE_DCMOTOR 0x21 #define MTRV2_START_DCMOTOR 0x22 #define MTRV2_STOP_DCMOTOR 0x23 // must add the adatfruit morotrshieldv2 library to arduino for this to compile #include // Create the motor shield object with the default I2C address //Adafruit_MotorShield AFMS = Adafruit_MotorShield(); // Or, create it with a different I2C address (say for stacking) // Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61); // Select which 'port' M1, M2, M3 or M4. In this case, M1 //Adafruit_DCMotor *myMotor = AFMS.getMotor(0); class MotorShieldV2Addon : public LibraryBase { Adafruit_MotorShield *AFMS; Adafruit_StepperMotor *stepperMotor[2]; Adafruit_DCMotor *dcMotor[4]; public: MotorShieldV2Addon(OctaveArduinoClass& a) { libName = "adafruit/MotorShieldV2"; a.registerLibrary(this); } void init() { byte i; AFMS = 0; for (i=0;i<2;i++) { stepperMotor[i] = 0; } for (i=0;i<4;i++) { dcMotor[i] = 0; } // AFMS.getStepper(200, 2); // myMotor->setSpeed(10); // 10 rpm // myMotor->step(100, FORWARD, SINGLE); // // Adafruit_DCMotor *myMotor = AFMS.getMotor(1); // // turn on motor M1 //myMotor->setSpeed(200); //myMotor->run(RELEASE); // // servo1.attach(10); } void commandHandler(uint8_t cmdId, uint8_t* data, uint8_t datasz) { switch(cmdId) { case MTRV2_INIT: { // send in the address // (currently) we only support a single control board if(datasz != 3) { sendInvalidNumArgsMsg(); } else { // TODO: pwm speed as well AFMS = new Adafruit_MotorShield(data[0]); uint16_t freq = data[1]; freq = (freq<<8)|data[2]; AFMS->begin(freq); // input freq sendResponseMsg(cmdId, data, 1); } break; } case MTRV2_FREE: { if(AFMS) { //AFMS->release(); delete AFMS; AFMS = 0; } sendResponseMsg(cmdId, data, 1); break; } case MTRV2_INIT_DCMOTOR: { // 0 = shieldid (spiaddress) // 1 = motor num if(datasz != 2) { sendInvalidNumArgsMsg(); } else if(data[1] > 3) { // TODO invalid value sendInvalidNumArgsMsg(); } else if(AFMS) { dcMotor[data[1]] = AFMS->getMotor(data[1]+1); if(dcMotor[data[1]]) { dcMotor[data[1]]->setSpeed(0); dcMotor[data[1]]->run(FORWARD); dcMotor[data[1]]->run(RELEASE); sendResponseMsg(cmdId, data, 2); } else { sendInvalidNumArgsMsg(); } } else { sendInvalidNumArgsMsg(); } break; } case MTRV2_FREE_DCMOTOR: { // 0 = shieldid (spiaddress) // 1 = motor num if(datasz != 2) { sendInvalidNumArgsMsg(); } else if(data[1] > 3) { // TODO invalid value sendInvalidNumArgsMsg(); } else { if(dcMotor[data[1]]) { //dcMotor[data[1]]->run(RELEASE); dcMotor[data[1]]->setSpeed(0); dcMotor[data[1]]->run(RELEASE); dcMotor[data[1]] = 0; } sendResponseMsg(cmdId, data, 2); } break; } case MTRV2_STOP_DCMOTOR: { // 0 = shieldid (spiaddress) // 1 = motor num if(datasz != 2) { sendInvalidNumArgsMsg(); } else if(data[1] > 3) { // TODO invalid value sendInvalidNumArgsMsg(); } else { if(dcMotor[data[1]]) { dcMotor[data[1]]->setSpeed(0); dcMotor[data[1]]->run(RELEASE); } sendResponseMsg(cmdId, data, 2); } break; } case MTRV2_START_DCMOTOR: { // 0 = shieldid (spiaddress) // 1 = motor num // 2 = dir 1=forwrf, else reverse // 3 = speed (0..255) if(datasz != 4) { sendInvalidNumArgsMsg(); } else if(data[1] > 3) { // TODO invalid value sendInvalidNumArgsMsg(); } else { if(dcMotor[data[1]]) { dcMotor[data[1]]->setSpeed(data[3]); dcMotor[data[1]]->run((data[2] == 1) ? FORWARD : BACKWARD); sendResponseMsg(cmdId, data, 2); } else { sendInvalidNumArgsMsg(); } } break; } case MTRV2_INIT_STEPPER: { // 0 = shieldid (spiaddress) // 1 = motor num // 2,3 = stepsprerev if(datasz != 4) { sendInvalidNumArgsMsg(); } else if(data[1] > 1) { // TODO invalid value sendInvalidNumArgsMsg(); } else if(AFMS) { uint16_t cnt = data[2]; cnt = (cnt<<8)|data[3]; stepperMotor[data[1]] = AFMS->getStepper(cnt, data[1]+1); if(stepperMotor[data[1]]) { sendResponseMsg(cmdId, data, 2); } else { sendInvalidNumArgsMsg(); } } else { sendInvalidNumArgsMsg(); } break; } case MTRV2_FREE_STEPPER: { // 0 = shieldid (spiaddress) // 1 = motor num if(datasz != 2) { sendInvalidNumArgsMsg(); } else if(data[1] > 1) { // TODO invalid value sendInvalidNumArgsMsg(); } else { if(stepperMotor[data[1]]) { //dcMotor[data[1]]->run(RELEASE); stepperMotor[data[1]]->release(); stepperMotor[data[1]] = 0; } sendResponseMsg(cmdId, data, 2); } break; } case MTRV2_RELEASE_STEPPER: { // 0 = shieldid (spiaddress) // 1 = motor num if(datasz != 2) { sendInvalidNumArgsMsg(); } else if(data[1] > 1) { // TODO invalid value sendInvalidNumArgsMsg(); } else { if(stepperMotor[data[1]]) { stepperMotor[data[1]]->release(); } sendResponseMsg(cmdId, data, 2); } break; } case MTRV2_MOVE_STEPPER: { // 0 = shieldid (spiaddress) // 1 = motor num // 2 = dir 1=forward, else reverse // 3,4 uint16 rpm // 5,6 steps // 7 steptype if(datasz != 8) { sendInvalidNumArgsMsg(); } else if(data[1] > 1) { // TODO invalid value sendInvalidNumArgsMsg(); } else { if(stepperMotor[data[1]]) { uint16_t rpm = data[3]; rpm = rpm<<8 | data[4]; uint16_t steps = data[5]; steps = steps<<8 | data[6]; uint8_t style = data[7]; style = SINGLE; if(style == 1) style = DOUBLE; if(style == 2) style = INTERLEAVE; if(style == 3) style = MICROSTEP; stepperMotor[data[1]]->setSpeed(rpm); sendWaitMsg(); stepperMotor[data[1]]->step(steps, (data[2] == 1) ? FORWARD : BACKWARD, style); sendResponseMsg(cmdId, data, 2); } else { sendInvalidNumArgsMsg(); } } break; } default: { // notify of invalid cmd sendUnknownCmdIDMsg(); } break; } } }; arduino-0.4.0/inst/+arduinoioaddons/+adafruit/motorshieldv2.m0000644000000000000000000001575313470770202022422 0ustar0000000000000000## Copyright (C) 2018-2019 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {} arduinoioaddons.adafruit.motorshieldv2 ## Adafruit motor shield addon ## ## @seealso{addon} ## @end deftypefn ## ## @subsubheading Properties ## @var{Parent} - the parent arduino object. ## ## @var{Pins} - the pins allocated the addon. ## ## @var{I2CAddress} - the i2c address used for accessing this shield. ## ## @var{PWMFrequency} - the set PWM frequency for this shield. ## ## @subheading Methods ## @deftypefn {} {@var{obj} =} motorshieldv2(@var{arObj}) ## @deftypefnx {} {@var{obj} =} motorshieldv2(@var{arObj}, @var{propertyname, propertyvalue} ....) ## Constructor to create motorshieldv2 addon object ## @subsubheading Inputs ## @var{arObj} - the arduino parent object ## ## @var{propertyname, propertyvalue} - optional property name, value pairs. ## Current known properties are: ## @table @asis ## @item address ## I2C address of the motor shield (default 0x60) ## @item pwmfrequency ## PWM Frequency to set on shield (default 1600) ## @end table ## ## @subsubheading Outputs ## @var{obj} - created motorshieldv2 object ## ## @subsubheading Example ## @example ## @code { ## a = arduino() ## mtr = addon(a, "adafruit/motorshieldv2") ## } ## @end example ## @end deftypefn ## ## @deftypefn {} {@var{s} =} servo(@var{mObj}, @var{mtrnum}) ## @deftypefnx {} {@var{s} =} servo(@var{mObj}, @var{mtrnum}, @var{propertyname}, @var{propertyvalue} ...) ## Create a servo object ## ## @subsubheading Inputs ## @var{mObj} - the motor shield object ## ## @var{mtrnum} - The servo motor number, where 1 is servo on pin "d10" and 2 is a servo on pin "d9" ## ## @var{propertyname}, @var{propertyvalue} - Optional property name/value pairs to pass to servo object. ## ## Properties are the same as the base servo object. ## ## @subsubheading Outputs ## @var{s} - a servo object ## ## @subsubheading Example ## @example ## @code { ## a = arduino() ## ms = addon(a, "adafruit/motorshieldv2") ## # get servo 1 (servo on pin D10) ## s = ms.servo(1) ## } ## @end example ## ## The function if the equivalent of calling the arduino.servo with the D9 or D10 pin has the input pin. ## ## @seealso{servo} ## @end deftypefn ## ## @deftypefn {} {@var{s} =} stepper(@var{mObj}, @var{mtrnum}, @var{stepsperrev}) ## @deftypefnx {} {@var{s} =} stepper(@var{mObj}, @var{mtrnum}, @var{stepsperrev}, @var{propertyname}, @var{propertyvalue} ...) ## Create a stepper motor object ## ## @subsubheading Inputs ## @var{mObj} - the motor shield object ## ## @var{mtrnum} - The stepper motor number (1 or 2) ## ## @var{stepsperrev} - Number of steps per revolution. ## ## @var{propertyname}, @var{propertyvalue} - Optional property name/value pairs to pass to stepper object. ## ## @subsubheading Outputs ## @var{s} - a stepper object ## ## @end deftypefn ## ## @deftypefn {} {@var{s} =} dcmotor(@var{mObj}, @var{mtrnum}) ## @deftypefnx {} {@var{s} =} dcmotor(@var{mObj}, @var{mtrnum}, @var{propertyname}, @var{propertyvalue} ...) ## Create a dcmotor motor object ## ## @subsubheading Inputs ## @var{mObj} - the motor shield object ## ## @var{mtrnum} - The motor number (1 - 4) ## ## @var{propertyname}, @var{propertyvalue} - Optional property name/value pairs to pass to motor object. ## ## @subsubheading Outputs ## @var{s} - a dcmotorv2 object ## ## @end deftypefn classdef motorshieldv2 < arduinoio.LibraryBase # commands properties(Access = private, Constant = true) INIT_COMMAND = hex2dec('00'); FREE_COMMAND = hex2dec('01'); endproperties properties(Access = protected, Constant = true) LibraryName = 'adafruit/MotorShieldV2'; DependentLibraries = { "i2c", "servo" }; ArduinoLibraryHeaderFiles = {}; CppHeaderFile = fullfile(arduinoio.FilePath(mfilename('fullpath')), 'motorshieldv2.h'); CppClassName = 'MotorShieldV2Addon'; endproperties properties(Access = private) i2c; cleanup; endproperties properties(GetAccess = public, SetAccess = private) PWMFrequency; I2CAddress; endproperties methods # constructor function obj = motorshieldv2(parentObj, varargin) # parse args p = inputParser(CaseSensitive=false, FunctionName='adafruit/MotorShieldV2'); p.addParameter('I2CAddress', 0x60, @isnumeric); p.addParameter('PWMFrequency', 1600, @isnumeric); p.parse(varargin{:}); obj.Parent = parentObj; obj.I2CAddress = p.Results.I2CAddress; obj.i2c = i2cdev(parentObj, p.Results.I2CAddress); obj.Pins = obj.i2c.Pins; obj.PWMFrequency = p.Results.PWMFrequency; intval = uint16(obj.PWMFrequency); freq = [ bitshift(intval,-8) bitand(intval, 255)]; data = sendCommand(obj.Parent, obj.LibraryName, obj.INIT_COMMAND, [p.Results.I2CAddress freq]); obj.cleanup = onCleanup (@() sendCommand(obj.Parent, obj.LibraryName, obj.FREE_COMMAND, [p.Results.I2CAddress])); endfunction function s = servo (obj, mnum, varargin) if nargin < 2 error ("Expected shield and mnum") endif pinval = []; if mnum == 1 pinval = "d10"; elseif mnum == 2 pinval = "d9"; else error ("Invalid servo motor number - (should be 1 or 2)") endif s = servo(obj.Parent, pinval, varargin{:}); endfunction function s = stepper (obj, mnum, stepsperrev, varargin) if nargin < 3 error ("Expected shield and mnum and stepsperrev") endif s = arduinoioaddons.adafruit.stepper(obj, mnum, stepsperrev, varargin{:}); endfunction function m = dcmotor (obj, mnum, varargin) if nargin < 2 error ("Expected shield and mnum") endif m = arduinoioaddons.adafruit.dcmotorv2(obj, mnum, varargin{:}); endfunction function display(this) printf("%s = \n", inputname(1)); printf(" %s with properties\n", class(this)); printf(" I2CAddress = %d (0x%X)\n", this.i2c.address, this.i2c.address); # show i2c pins as the pins printf(" Pins = {\n"); for i=1:numel(this.Pins) printf(" %s\n", this.Pins{i}); endfor printf(" }\n"); printf(" PWMFrequency = %d\n", this.PWMFrequency); endfunction endmethods methods (Access = public) function data = sendCommand(obj, commandid, data) [data,~] = sendCommand(obj.Parent, obj.LibraryName, commandid, [obj.i2c.address data]); endfunction endmethods endclassdef arduino-0.4.0/inst/+arduinoioaddons/+adafruit/stepper.m0000644000000000000000000001524613470770202021300 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {} arduinoioaddons.adafruit.stepper ## Stepper class for stepper control on the adafruit motor shield ## ## @seealso{arduinoioaddons.adafruit.motorshieldv2} ## @end deftypefn ## ## @subsubheading Properties ## @table @asis ## @item @var{RPM} ## The rpm value set for the stepper motor ## @item StepType ## the StepType for the stepper (string) which can be "single", "double", "interleave" or "microstep" ## @item StepsPerRevolution ## the StepsPerRevoluion for the stepper (read only) ## @item MotorNumber ## the motor number for the stepper (read only) value will be 1 or 2. ## @item Parent ## the parent shield of this stepper (read only) ## @end table ## ## @subheading Methods ## @deftypefn {} {@var{obj} =} stepper(@var{mObj}, @var{mnum}, @var{stepsperrev}) ## @deftypefnx {} {@var{obj} =} stepper(@var{mObj}, @var{mnum}, @var{stepsperrev}, @var{propertyname, propertyvalue} ....) ## Constructor to create dcmotor object ## @subsubheading Inputs ## @var{mObj} - the motor shield object ## ## @var{mnum} - The motor number (1 or 2) ## ## @var{stepsperrev} - Number of steps per revolution. ## ## @var{propertyname, propertyvalue} - Optional property name/value pairs to pass to motor object. ## ## Current known properties are: ## @table @asis ## @item RPM ## the RPM for the stepper (revolutions per minute) ## @item StepType ## the StepType for the stepper (string) which can be "single", "double", "interleave" or "microstep" ## @end table ## ## @subsubheading Outputs ## @var{s} - a stepper object ## ## @subsubheading Example ## @example ## @code { ## a = arduino() ## ms = addon(a, "adafruit/motorshieldv2") ## mtr = stepper(ms, 1, 200) ## } ## @end example ## @end deftypefn ## ## @deftypefn {} {} move(@var{sObj}, @var{steps}) ## Move the motor moving in the specified steps using the configured RPM. ## ## @subsubheading Inputs ## @var{sObj} - the stepper object ## ## @subsubheading Outputs ## None ## ## @seealso{adafruit.motorshieldv2} ## @end deftypefn ## ## @deftypefn {} {} release(@var{sObj}) ## Release this motor ## ## @subsubheading Inputs ## @var{sObj} - the stepper object ## ## @subsubheading Outputs ## None ## ## @seealso{adafruit.motorshieldv2} ## @end deftypefn classdef stepper < arduinoio.AddonBase properties(Access = private, Constant = true) INIT_COMMAND = hex2dec('10'); FREE_COMMAND = hex2dec('11'); MOVE_COMMAND = hex2dec('12'); RELEASE_COMMAND = hex2dec('13'); endproperties properties(Access = private) cleanup; endproperties properties(GetAccess = public, SetAccess = private) MotorNumber; StepsPerRevolution = 0; endproperties properties(Access = public) RPM = 0; StepType = "single"; endproperties methods function this = stepper(shield, mnum, stepsperrev, varargin) ## if nargin < 3 ## error ("Expected shield, mnum and stepsperrev") ## endif ## ## if ~isa(shield, "arduinoioaddons.adafruit.motorshieldv2") ## error("Expected shield to be a motorshieldv2 object"); ## endif ## ## # check num is a number ## if mnum != 1 && mnum != 2 ## error("Expected motor number to be 1 or 2"); ## endif p = inputParser(CaseSensitive=false, FunctionName='adafruit/stepper'); validate_shield = @(x) isa(x, "arduinoioaddons.adafruit.motorshieldv2"); validate_mtrnum = @(x) (isnumeric(x) && isscalar(x) && (x ==1 || x ==2)); validate_steps = @(x) (isnumeric(x) && isscalar(x) && (x > 0)); validate_rpm = @(x) (isnumeric(x) && isscalar(x) && (x > 0)); p.addRequired('shield',validate_shield); p.addRequired('mnum',validate_mtrnum); p.addRequired('stepsperrev',validate_steps); p.addParameter('RPM', 0, validate_rpm); p.addParameter('StepType', "single", @(x) any(validatestring(x,{"single", "double", "interleave", "microstep"}))); p.parse(shield, mnum, stepsperrev, varargin{:}); this.Parent = p.Results.shield; this.MotorNumber = p.Results.mnum; this.StepsPerRevolution = p.Results.stepsperrev; this.RPM = p.Results.RPM; this.StepType = p.Results.StepType; intval = uint16(stepsperrev); steps = [ bitshift(intval,-8) bitand(intval, 255)]; sendCommand(this.Parent, this.INIT_COMMAND,[this.MotorNumber-1 steps]); this.cleanup = onCleanup (@() sendCommand(this.Parent, this.FREE_COMMAND, [this.MotorNumber-1 steps])); endfunction function move(this, steps) if steps < 0 direction = 0; steps = -steps; else direction = 1; endif intval = uint16(steps); steps = [ bitshift(intval,-8) bitand(intval, 255)]; intval = uint16(this.RPM); rpm = [ bitshift(intval,-8) bitand(intval, 255)]; steptype = 0; switch lower(this.StepType) case "single" steptype = 0; case "double" steptype = 1; case "interleave" steptype = 2; case "microstep" steptype = 3; endswitch sendCommand(this.Parent,this.MOVE_COMMAND,[this.MotorNumber-1, direction, rpm, steps, steptype]); endfunction function release(this) sendCommand(this.Parent,this.RELEASE_COMMAND,[this.MotorNumber-1]); endfunction function set.RPM(this, newrpm) # check rpm if !isnumeric(newrpm) || newrpm < 0 error("RPM should be a positive number"); endif this.RPM = newrpm; endfunction function set.StepType(this, val) validate_val = validatestring (val, {"single", "double", "interleave", "microstep"}); this.StepType = val; endfunction function display(this) printf("%s = \n", inputname(1)); printf(" %s with properties\n", class(this)); printf(" MotorNumber = %d\n", this.MotorNumber); printf(" RPM = %d\n", this.RPM); printf(" StepsPerRevolution = %d\n", this.StepsPerRevolution); printf(" StepType = %s\n", this.StepType); endfunction endmethods endclassdef arduino-0.4.0/inst/+arduinosensor/0000755000000000000000000000000013470770202015267 5ustar0000000000000000arduino-0.4.0/inst/+arduinosensor/DS1307.m0000644000000000000000000001507213470770202016273 0ustar0000000000000000## Copyright (C) 2019 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {} arduinosensor.DS1307 ## DS1307 realtime clock sensor ## @end deftypefn ## ## @subheading Methods ## @deftypefn {} {@var{obj} =} DS1307(@var{arObj}) ## @deftypefnx {} {@var{obj} =} DS1307(@var{arObj}, @var{propertyname, propertyvalue} ....) ## Constructor to create DS1307 sensor ## @subsubheading Inputs ## @var{arObj} - the arduino parent object ## ## @var{propertyname, propertyvalue} - optional property name, value pairs. ## Current known properties are: ## Current properties are: ## @table @asis ## @item i2caddress ## I2C address of the DS1307 (default 0x68) ## @end table ## ## @subsubheading Outputs ## @var{obj} - created DS1307 object ## ## @subsubheading Example ## @example ## @code { ## a = arduino() ## rtc = arduinosensor.DS1307(a) ## } ## @end example ## @end deftypefn ## ## @deftypefn {} {@var{date} =} clock(@var{dsObj}) ## @deftypefnx {} {} clock(@var{dsObj}, @var{date}) ## Get/set the DS1307 clock ## ## @subsubheading Inputs ## @var{dsObj} - the ds1307 object ## ## @var{date} - a date vector in same format as datevec and clock ## ## @subsubheading Outputs ## @var{date} - a date vector in same format as datevec and clock ## ## @subsubheading Example ## @example ## @code { ## a = arduino() ## rtc = arduinosensor.DS1307(a) ## # get and display rtc time as a date string ## datestr(rtc.clock) ## } ## @end example ## @seealso{datevec} ## @end deftypefn ## ## @deftypefn {} {@var{ctrl} =} control(@var{dsObj}) ## @deftypefnx {} {} control(@var{dsObj}, @var{ctrl}) ## Get/set the DS1307 clock ## ## @subsubheading Inputs ## @var{dsObj} - the ds1307 object ## ## @var{ctrl} - a structure containing the control bit fields. ## ## @subsubheading Outputs ## @var{ctrl} - a structure containing the control bit fields. ## ## Control structure fields are: ## Current properties are: ## @table @asis ## @item out ## Out bit in the control register ## @item sqwe ## Square wave enble bit in control register ## @item rs ## The combined Rs0, RS1 value ## @end table ## ## @end deftypefn ## ## @deftypefn {} {@var{YN} =} isstarted(@var{dsObj}) ## Get whether the RTC clock is currently counting time ## ## @subsubheading Inputs ## @var{dsObj} - the ds1307 object ## ## @subsubheading Outputs ## @var{YN} - returns true if the RTC is counting ## ## @seealso{start, stop} ## @end deftypefn ## ## @deftypefn {} {} start(@var{dsObj}) ## Start the RTC counting ## ## @subsubheading Inputs ## @var{dsObj} - the ds1307 object ## ## @subsubheading Outputs ## None ## ## @seealso{datevec} ## @end deftypefn ## ## @deftypefn {} {} stop(@var{dsObj}) ## Stop the RTC counting ## ## @subsubheading Inputs ## @var{dsObj} - the ds1307 object ## ## @subsubheading Outputs ## None ## ## @seealso{datevec} ## @end deftypefn classdef DS1307 < handle properties(Access = private) i2c; bcd2dec = @(v) bitshift(v, -4)*10 + bitand(v, 0xf); dec2bcd = @(v) bitshift(floor(v/10), 4) + bitand(mod(v,10), 0xf); endproperties methods # constructor function this = DS1307(parentObj, varargin) if nargin < 1 || ! isarduino(parentObj) error('arduinosensor.DS1307: expected arduino object as first parameter'); endif # parse args p = inputParser(CaseSensitive=false, FunctionName='arduinosensor.DS1307'); p.addParameter('I2CAddress', 0x68, @isnumeric); p.parse(varargin{:}); # do we have the address ? address = p.Results.I2CAddress; i2caddresses = scanI2Cbus(parentObj); idx = find(cellfun ( @(x) strcmp(x, sprintf("0x%02X", address)), i2caddresses)); if isempty(idx) error('arduinosensor.DS1307: no matching i2c address found on bus'); endif this.i2c = i2cdev(parentObj, p.Results.I2CAddress); endfunction function c = clock (this, settime) if nargin == 2 # set time wd = weekday(datenum(settime)); writeRegister(this.i2c, 0, ... [this.dec2bcd(floor(settime(6))), this.dec2bcd(settime(5)), (this.dec2bcd(settime(4))), ... wd, this.dec2bcd(settime(3)), this.dec2bcd(settime(2)), this.dec2bcd(mod(settime(1),100))] ... ); else # get time data = readRegister(this.i2c, 0, 7); secs = double(this.bcd2dec(bitand(data(1), 0x7f))); mins = double(this.bcd2dec(data(2))); if bitand(data(3), 0x40) != 0 # 12 hr pm = bitand(data(3), 0x20); hrs = double(this.bcd2dec(bitand(data(3), 0x2f))); if pm hrs = double(hrs + 12); endif else hrs = double(this.bcd2dec(bitand(data(3), 0x3f))); endif wday = double(data(4)); day = double(this.bcd2dec(data(5))); month = double(this.bcd2dec(data(6))); year = 2000.0 + double(this.bcd2dec(data(7))); c = double([year, month, day, hrs, mins, secs]); endif endfunction function start(this) data = readRegister(this.i2c, 0, 1); data = bitset(data, 8, 0); writeRegister(this.i2c, 0, data); endfunction function stop(this) data = readRegister(this.i2c, 0, 1); data = bitset(data, 8, 1); writeRegister(this.i2c, 0, data); endfunction function val = isstarted(this) data = readRegister(this.i2c, 0, 1); val = bitget(data, 8) == 0; endfunction function bits = control(this, setbits) if nargin == 1 data = readRegister(this.i2c, 7, 1); bits = {}; bits.out = bitget(data, 8); bits.sqwe = bitget(data, 5); bits.rs = bitand(data, 0x03); else data = 0; data = bitand(setbits.rs, 0x3); if setbits.out data = data + 0x80; endif if setbits.sqwe data = data + 0x10; endif writeRegister(this.i2c, 7, data); endif endfunction function display(this) printf("%s = \n", inputname(1)); printf(" %s with properties\n", class(this)); printf(" I2C Address = 0x%X\n", this.i2c.address); endfunction endmethods endclassdef arduino-0.4.0/inst/+arduinosensor/GUVAS12SD.m0000644000000000000000000000723013470770202016726 0ustar0000000000000000## Copyright (C) 2019 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {} arduinosensor.GUVAS12SD ## A thin wrapper for the GUVAS12SD analog UV-B sensor ## @end deftypefn ## ## @subheading Methods ## @deftypefn {} {@var{obj} =} GUVAS12SD(@var{arObj}, @var{pin}) ## Constructor to create GUVAS12SD sensor ## @subsubheading Inputs ## @var{arObj} - the arduino parent object ## ## @var{pin} - the analog pin that the sensor is connected to ## ## @subsubheading Outputs ## @var{obj} - created GUVAS12SD object ## ## @subsubheading Example ## @example ## @code { ## a = arduino() ## # create sensor attached to pin a0. ## sensor = arduinosensor.GUVAS12SD(a, "a0") ## } ## @end example ## @end deftypefn ## ## @deftypefn {} {@var{V} =} read(@var{dsObj}) ## Read the voltage of the sensor ## ## @subsubheading Inputs ## @var{dsObj} - the GUVAS12SD object ## ## @subsubheading Outputs ## @var{V} - read voltage - effectively equivalent to readAnalogPin(arObj, pin). ## ## @subsubheading Example ## @example ## @code { ## a = arduino() ## s = arduinosensor.GUVAS12SD(a) ## # voltage ## volts = s.read ## } ## @end example ## @seealso{arduinosensor.GUVAS12SD} ## @end deftypefn ## ## @deftypefn {} {@var{Idx} =} readIndex(@var{dsObj}) ## Read the UV index ## ## @subsubheading Inputs ## @var{dsObj} - the GUVAS12SD object ## ## @subsubheading Outputs ## @var{Idx} - the sensor reading as a UV index reading ## @end deftypefn ## ## @deftypefn {} {@var{uA} =} readuA(@var{dsObj}) ## Read the uA of the sensor ## ## @subsubheading Inputs ## @var{dsObj} - the GUVAS12SD object ## ## @subsubheading Outputs ## @var{uA} - the sensor reading as a uAmp value ## @end deftypefn classdef GUVAS12SD < handle properties(Access = private, constant = true) SCALE_UAMPS = 4.1; SCALE_INDEX = 0.1; endproperties properties(GetAccess = public, SetAccess = private) Pin; Parent; endproperties methods # constructor function this = GUVAS12SD(parentObj, pin, varargin) if nargin < 2 error('arduinosensor.GUVAS12SD: expected arduino and pin object parameters'); endif if ! isarduino(parentObj) error('arduinosensor.GUVAS12SD: expected arduino object as first parameter'); endif # check is an analog pin validatePin(parentObj, pin, "analog"); # lookup/use name for pin (in the case where a terminal num was given instead of a pin number) this.Pin = getPinInfo(parentObj, pin).name; this.Parent = parentObj; endfunction function val = read (this) # Vo = 4.3 * diodeuA # UV index = Vo/0.1 val = readAnalogPin(this.Parent, this.Pin); endfunction function val = readIndex (this) val = read(this)/this.SCALE_INDEX; endfunction function val = readuA (this) val = read(this)/this.SCALE_UAMPS; endfunction function display(this) printf("%s = \n", inputname(1)); printf(" %s with properties\n", class(this)); printf(" Pin = %s\n", this.Pin); endfunction endmethods endclassdef arduino-0.4.0/inst/+arduinosensor/MPC3002.m0000644000000000000000000000743213470770202016377 0ustar0000000000000000## Copyright (C) 2019 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {} arduinosensor.MPC3002 ## MCP3002 ADC sensor ## @end deftypefn ## ## @subheading Methods ## @deftypefn {} {@var{obj} =} MPC3002(@var{arObj}, @var{selectPin}) ## @deftypefnx {} {@var{obj} =} MPC3002(@var{arObj}, @var{selectPin}, @var{propertyname, propertyvalue} ....) ## Constructor to create MPC3002 sensor ## @subsubheading Inputs ## @var{arObj} - the arduino parent object ## ## @var{selectPin} - the SPI cs select pin ## ## @var{propertyname, propertyvalue} - optional property name, value pairs. ## ## Current properties are: ## @table @asis ## @item referenceVoltage ## Reference voltage for scaling the ADC inputs (default 5.0) ## @end table ## ## @subsubheading Outputs ## @var{obj} - created MCP3002 object ## ## @subsubheading Example ## @example ## @code { ## a = arduino() ## sensor = arduinosensor.MPC3002(a, "d10") ## } ## @end example ## @end deftypefn ## ## @deftypefn {} {@var{voltage} =} readVoltage(@var{dsObj}, @var{chan}) ## Read the voltage from a channel ## ## @subsubheading Inputs ## @var{dsObj} - the MPC3002 object ## ## @var{chan} - the channel to read (0 or 1) ## ## @subsubheading Outputs ## @var{voltage} - read voltage. ## ## @subsubheading Example ## @example ## @code { ## a = arduino() ## s = arduinosensor.MPC3002(a, "d10") ## volts = readVoltage(s, 0) ## } ## @end example ## @seealso{arduinosensor.MPC3002} ## @end deftypefn classdef MPC3002 < handle properties(Access = private, constant = true) VERSION = "0.0.1"; CHAN_0_READ = [ hex2dec("DF") hex2dec("FF") ]; CHAN_1_READ = [ hex2dec("EF") hex2dec("FF") ]; endproperties properties(Access = private) spi; reference_voltage = 5.0; endproperties methods # constructor function this = MPC3002(parentObj, selectpin, varargin) if nargin < 2 || ! isarduino(parentObj) error('arduinosensor.MPC3002: expected arduino object as first parameter, followed by a select pin'); endif # parse args p = inputParser(CaseSensitive=false, FunctionName='arduinosensor.MPC3002'); p.addParameter('referenceVoltage', 5.0, @isnumeric); p.parse(varargin{:}); this.spi = spidev(parentObj, selectpin); this.reference_voltage = p.Results.referenceVoltage; # initial read v = writeRead(this.spi, this.CHAN_1_READ); endfunction function volts = readVoltage(this, chan) if nargin < 2 || !isnumeric(chan) || (chan != 1 && chan != 0) error('arduinosensor.MPC3002 read: expected channel number 0 or 1'); endif if chan == 0 cmd = this.CHAN_0_READ; else cmd = this.CHAN_1_READ; endif v = writeRead(this.spi, cmd); adc = bitand (uint16(v(1))*256 + uint16(v(2)), hex2dec('3FF')); volts = double(adc) * this.reference_voltage / 1023.0; endfunction function display(this) printf("%s = \n", inputname(1)); printf(" %s with properties\n", class(this)); printf(" reference voltage = %f\n", this.reference_voltage); printf(" SPI cs = %s\n", this.spi.chipselectpin); endfunction endmethods endclassdef arduino-0.4.0/inst/+arduinosensor/SI7021.m0000644000000000000000000001274013470770202016276 0ustar0000000000000000## Copyright (C) 2019 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {} arduinosensor.SI7021 ## SI7021 temperature and humidity sensor ## @end deftypefn ## ## @subheading Methods ## @deftypefn {} {@var{obj} =} SI7021(@var{arObj}) ## @deftypefnx {} {@var{obj} =} SI7021(@var{arObj}, @var{propertyname, propertyvalue} ....) ## Constructor to create SI7021 sensor ## @subsubheading Inputs ## @var{arObj} - the arduino parent object ## ## @var{propertyname, propertyvalue} - optional property name, value pairs. ## Current known properties are: ## Current properties are: ## @table @asis ## @item i2caddress ## I2C address of the SI7021 (default 0x40) ## @end table ## ## @subsubheading Outputs ## @var{obj} - created SI7020 object ## ## @subsubheading Example ## @example ## @code { ## a = arduino() ## sensor = arduinosensor.SI7021(a) ## } ## @end example ## @end deftypefn ## ## @deftypefn {} {@var{C} =} temperature(@var{dsObj}) ## Read the temperature ## ## @subsubheading Inputs ## @var{dsObj} - the si7021 object ## ## @subsubheading Outputs ## @var{C} - read temperature in deg C. ## ## @subsubheading Example ## @example ## @code { ## a = arduino() ## s = arduinosensor.SI7021(a) ## # get temp ## temp = s.temperature ## } ## @end example ## @seealso{arduinosensor.SI7021} ## @end deftypefn ## ## @deftypefn {} {@var{relH} =} humidity(@var{dsObj}) ## Read the relative humidity ## ## @subsubheading Inputs ## @var{dsObj} - the si7021 object ## ## @subsubheading Outputs ## @var{relH} - relative humidity as a percentage (0 - 100.0) ## @end deftypefn ## ## @deftypefn {} {@var{relH} =} info(@var{dsObj}) ## Read the sensor info ## ## @subsubheading Inputs ## @var{dsObj} - the si7021 object ## ## @subsubheading Outputs ## @var{inf} - structure containing the sensor information. ## ## Structure fields are: ## @table @asis ## @item version ## Chip firmware version ## @item id ## sensor id1,id2 value ## @item type ## String for detected chip type ## @end table ## ## @end deftypefn classdef SI7021 < handle properties(Access = private, constant = true) SENSOR_ID_1 = [ hex2dec("FA") hex2dec("F0") ]; SENSOR_ID_2 = [ hex2dec("FC") hex2dec("C9") ]; SENSOR_VERSION = [ hex2dec("84") hex2dec("B8") ]; TEMP_MEASURE_NOHOLD = hex2dec("F3"); HUMIDITY_MEASURE_NOHOLD = hex2dec("F5"); endproperties properties(Access = private) i2c; endproperties methods # constructor function this = SI7021(parentObj, varargin) if nargin < 1 || ! isarduino(parentObj) error('arduinosensor.SI7021: expected arduino object as first parameter'); endif # parse args p = inputParser(CaseSensitive=false, FunctionName='arduinosensor.SI7021'); p.addParameter('I2CAddress', 0x40, @isnumeric); p.parse(varargin{:}); # do we have the address ? address = p.Results.I2CAddress; i2caddresses = scanI2Cbus(parentObj); idx = find(cellfun ( @(x) strcmp(x, sprintf("0x%02X", address)), i2caddresses)); if isempty(idx) error('arduinosensor.SI7021: no matching i2c address found on bus'); endif this.i2c = i2cdev(parentObj, p.Results.I2CAddress); endfunction function inf = info (this) write (this.i2c, this.SENSOR_ID_1); id1 = read(this.i2c, 1); write (this.i2c, this.SENSOR_ID_2); id2 = read(this.i2c, 1); if id2 == hex2dec("15") type = "Si7021"; elseif id2 == hex2dec("14") type = "Si7020"; elseif id2 == hex2dec("0D") type = "Si7013"; elseif id2 == hex2dec("32") type = "HTU21D"; else type = "Unknown"; endif write (this.i2c, this.SENSOR_VERSION); ver = read(this.i2c, 1); if ver == hex2dec("FF") ver = 1.0; else ver = double(ver)/10.0; endif inf = {}; inf.version = ver; inf.type = type; inf.id = int32(id1)*256 + int32(id2); endfunction function C = temperature (this) % write command to get temp write (this.i2c, uint8([this.TEMP_MEASURE_NOHOLD])); pause (0.02); data = read (this.i2c, 3); value = uint16(data(1))*256 + uint16(data(2)); value = bitand (value, hex2dec("FFFC")); temp_Code = double(value); C = (175.72*temp_Code/65536)-46.85; # F = (C * 1.8) + 32.0; endfunction function H = humidity(this) write (this.i2c, uint8([this.HUMIDITY_MEASURE_NOHOLD])); pause (0.02); data = read (this.i2c, 3); value = uint16(data(1))*256 + uint16(data(2)); value = bitand (value, hex2dec("FFFC")); humidity_Code = double(value); H = (125.0*humidity_Code/65536)-6; endfunction function display(this) printf("%s = \n", inputname(1)); printf(" %s with properties\n", class(this)); printf(" I2C Address = 0x%X\n", this.i2c.address); endfunction endmethods endclassdef arduino-0.4.0/inst/@arduino/0000755000000000000000000000000013470770202014062 5ustar0000000000000000arduino-0.4.0/inst/@arduino/__freeArduino__.m0000644000000000000000000000160213470770202017276 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} __freeArduino__ (@var{obj}) ## Private function ## @end deftypefn function retval = __freeArduino__ (obj, port, board) if(obj.connected) fclose(obj.connected); obj.connected = []; endif retval = obj; endfunction arduino-0.4.0/inst/@arduino/__initArduino__.m0000644000000000000000000000603513470770202017325 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} __initArduino__ (@var{obj}, @var{port}, @var{board}) ## Private function ## @end deftypefn function retval = __initArduino__ (obj, port, board) % send command and get back reponse ARDUINO_INIT = 1; ARDUINO_GETLIB = 8; ok = false; if !isempty(port) || !ischar(port) obj.connected = serial (port, 9600, 2); # need wait for aduino to potentially startup pause(2); [dataout, status] = __sendCommand__(obj, 0, ARDUINO_INIT); if status != 0 error ("__initArduino__: failed valid response err=%d - %s", status, char(dataout)); endif % uno r3 - atmega32 1E 95 0F sig = (uint32(dataout(1))*256*256) + (uint32(dataout(2))*256) + uint32(dataout(3)); % work out mcu switch sig case 0 mcu = ""; case { hex2dec("1E9502"), hex2dec("009502") } mcu = "atmega32"; case { hex2dec("1E950F"), hex2dec("00950F") } mcu = "atmega328p"; case { hex2dec("1E9514"), hex2dec("009514") } mcu = "atmega328pu"; case hex2dec("1E9801") mcu= "atmega2560"; case hex2dec("1E9703") mcu = "atmega1280"; case hex2dec("1E9702") mcu = "atmega128"; otherwise mcu = sprintf("unknown_mcu(%X)", sig); endswitch boardtype = arduinoio.boardTypeString(dataout(4)); voltref = double(dataout(5))/10.0; numlib = uint8(dataout(6)); % check board against config info if ~isempty(board) && (board != boardtype) warning("connected %s arduino does not match requested board type %s", boardtype, obj.board) endif obj.config = arduinoio.getBoardConfig(boardtype); # update values that could change obj.config.port = port; obj.config.board = boardtype; obj.config.voltref = voltref; if ! isempty(mcu) obj.config.mcu = mcu; elseif isempty(obj.config.mcu) obj.config.mcu = "unknown"; endif obj.config.libs = {}; # query libs for libid = 0:numlib-1 [dataout, status] = __sendCommand__(obj, 0, ARDUINO_GETLIB, [libid]); if status != 0 error ("__initArduino__: failed get lib %d err=%d - %s", libid, status, char(dataout)); else lib = {}; lib.id = libid; lib.name = lower(char(dataout(2:end))); obj.config.libs{end+1} = lib; endif endfor else error ("__initArduino__: expected a valid port"); endif retval = obj; endfunction arduino-0.4.0/inst/@arduino/arduino.m0000644000000000000000000002737413470770202015716 0ustar0000000000000000## Copyright (C) 2018-2019 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} arduino () ## @deftypefnx {} {@var{retval} =} arduino (@var{port}) ## @deftypefnx {} {@var{retval} =} arduino (@var{port}, @var{board}) ## @deftypefnx {} {@var{retval} =} arduino (@var{port}, @var{board}[, [@var{propname}, @var{propvalue}]*) ## Create a arduino object with a connection to an arduino board. ## ## @subsubheading Inputs ## @var{port} - full path of serial port to connect to. For Linux, usually /dev/ttySXXX, for windows COMXX. ## ## @var{board} - name of board to connect (default is 'uno'). ## ## @var{propname}, @var{propvalue} - property name and value pair for additional properties ## to pass to the creation of the arduino object. ## Currently properties are ignored. ## ## if the arduino function is called without parameters, it will scan for the first available ## arduino it can find and connect to it. ## ## @subsubheading Outputs ## @var{retval} - a successfully connected arduino object. ## ## @subsubheading Properties ## The arduino object has the following public properties: ## @table @asis ## @item name ## name assigned to the arduino object ## @item debug ## true / false flag for whether debug in turned on ## @item port (read only) ## the communications port the board is connected to. ## @item board (read only) ## The name of the board type that the arduino connected to ## @item libraries (read only) ## The libraries currently programmed onto the board ## @item availablepins ## The pins available for use on the board ## @end table ## @seealso{scanForArduinos, arduinosetup} ## @end deftypefn classdef arduino < handle properties (Access = private) config = {}; resources = {}; connected = false; endproperties properties (Access = public) name = ""; debug = false; endproperties methods (Access = public) function this = arduino (varargin) if (nargin == 0) arduinos = scanForArduinos (1); if isempty (arduinos) error ("arduino: No arduinos found on serial scan"); endif this.name = "arduino"; this = __initArduino__ (this, arduinos{1}.port, arduinos{1}.board); elseif (nargin == 1) arg0 = varargin{1}; if (isa (arg0, "arduino")) # copy this.config = arg0.config; this.resources = arg0.resources; this.name = arg0.name; this.connected = arg0.connected; elseif ischar(arg0) # port given this.name = "arduino"; this.connected = false; this = __initArduino__ (this, arg0, ""); else error ("arduino: port must be a string"); endif else # at least port, board [optional property pairs] port = varargin{1}; board = varargin{2}; if isempty (port) arduinos = scanForArduinos (1, board); if isempty (arduinos) error ("arduino: No matching arduinos found on serial scan"); endif port = arduinos{1}.port; board = arduinos{1}.board; elseif !ischar (port) error ("arduino: port must be a string"); endif if !ischar (port) error ("arduino: board must be a string"); endif if mod (nargin, 2) != 0 error ("arduino: expected property name, value pairs"); endif if !iscellstr (varargin (3:2:nargin)) error ("arduino: expected property names to be strings"); endif this.name = ["arduino " board]; requiredlibs = {}; forcebuild = false; for i = 3:2:nargin propname = tolower (varargin{i}); propvalue = varargin{i+1}; #printf("%s = %s\n", propname, propvalue); if strcmp (propname,"debug") if propvalue this.debug = 1; endif endif if strcmp (propname,"libraries") if ischar (propvalue) requiredlibs{end+1} = propvalue; elseif iscellstr (propvalue) requiredlibs = propvalue; else error ("arduino: expect libraries value to be a libraryname or cellarray of library names"); endif endif if strcmp (propname,"forcebuild") if islogical (propvalue) || (isnumeric(propvalue) && (propvalue == 1 || propvalue == 0)) forcebuild = propvalue; else error ("arduino: expect forcebuild to be true or false"); endif endif endfor this = __initArduino__ (this, port, board); # check have requested libs reprogram = false; for i = 1:numel (requiredlibs) lib = requiredlibs{i}; id = this.get_lib (lib); if id < 0 availablelibs = listArduinoLibraries (); idx = find( cellfun(@(x) strcmpi(x, lib), availablelibs), 1); if isempty (idx) error ('arduino: unknown library "%s"', lib); elseif forcebuild warning ('arduino: not configured with library "%s" - will need to reprogram', lib); reprogram = true; else error ('arduino: not configured with library "%s" - please rerun arduinosetup with library, or set forcebuild', lib); endif endif endfor if reprogram printf("starting reprogram process ....\n") # free arduino resources, reprom and then reinit this = __freeArduino__(this); if !arduinosetup ('libraries', requiredlibs); error ("arduinosetup returned a failure, so did not reprogram") endif this = __initArduino__ (this, port, board); endif endif endfunction endmethods methods (Hidden = true) # helper functions function set_debug (this, d) this.debug = d; endfunction function d = get_debug (this) this = this.debug; endfunction # helper functions that get/set values in the private config function m = get_mcu (this) m = this.config.mcu; endfunction function id = get_lib (this, name) idx = find( cellfun(@(x) strcmpi(x.name, name), this.config.libs), 1); if isempty (idx) id = -1; else id = this.config.libs{idx}.id; endif endfunction function set_pin (this, pin, info) if ischar(pin) idx = find (cellfun(@(x) strcmpi (x.name, pin), this.config.pins), 1); else idx = find (cellfun(@(x) (x.d == pin), this.config.pins), 1); endif if isempty (idx) error ("arduino: unknown pin"); endif this.config.pins{idx} = info; endfunction function info = get_pin (this, pin) if ischar(pin) idx = find (cellfun(@(x) strcmpi (x.name, pin), this.config.pins), 1); else idx = find (cellfun(@(x) (x.id == pin), this.config.pins), 1); endif if isempty (idx) error (["arduino: unknown pin " pin]); endif info = this.config.pins{idx}; endfunction function retval = get_group(this,type) retval = {}; for i = 1:numel (this.config.pins) pininfo = this.config.pins{i}; idx = find (cellfun(@(x) strncmpi (x, type, length (type)), pininfo.modes), 1); if !isempty(idx) values = strsplit (pininfo.modes{idx}, "_"); info = {}; info.name = pininfo.name; info.func = values{2}; info.mode = pininfo.mode; info.owner = pininfo.owner; retval{end+1}= info; endif endfor endfunction function retval = get_pingroup(this, pin, type) retval = {}; pininfo = this.get_pin(pin); idx = find (cellfun(@(x) strncmpi(x, type, length(type)), pininfo.modes), 1); if !isempty (idx) # possibly this will be in format of # type[XX]_YY where XX is a number ir: spi0, spi1 etc, ## _YY will be the pinfunction ie: scl, miso etc values = strsplit (pininfo.modes{idx}, "_"); type = values{1}; for i = 1:numel (this.config.pins) pininfo = this.config.pins{i}; idx = find (cellfun(@(x) strncmpi(x, type, length (type)), pininfo.modes), 1); if !isempty(idx) values = strsplit(pininfo.modes{idx}, "_"); info = {}; info.name = pininfo.name; info.func = values{2}; info.mode = pininfo.mode; info.owner = pininfo.owner; retval{end+1}= info; endif endfor endif endfunction function pins = availablepins(this) pins = {}; for i=1:numel (this.config.pins) pins{end+1} = this.config.pins{i}.name; endfor endfunction function libs = libraries(this) libs = {}; for i=1:numel (this.config.libs) if ! strcmpi(this.config.libs{i}.name, "core") libs{end+1} = this.config.libs{i}.name; endif endfor endfunction function p = port(this) p = this.config.port; endfunction function b = board(this) b = this.config.board; endfunction function set_resource (this, resource, res) resource = tolower (resource); # make sure noone tries to change the name used for searching res.name = resource; idx = find (cellfun(@(x) strcmp(x.name, resource), this.resources), 1); if isempty (idx) this.resources{end+1} = res; else this.resources{idx} = res; endif endfunction function res = get_resource (this, resource) resource = tolower(resource); idx = find (cellfun(@(x) strcmp(x.name, resource), this.resources), 1); if isempty (idx) # none currently res = {}; res.name = resource; res.count = 0; res.owner = ""; res.props = struct(); else res = this.resources{idx}; endif endfunction function v = board_voltage (this) v = this.config.voltref; endfunction endmethods endclassdef %!shared arduinos %! arduinos = scanForArduinos(1); %!assert(numel(arduinos), 1); %!test %! ar = arduino(); %! assert(!isempty(ar)); %! assert(ar.port, arduinos{1}.port); %! assert(ar.board, arduinos{1}.board); %! assert(numel(ar.availablepins) > 0); %!test %! ar = arduino(arduinos{1}.port); %! assert(!isempty(ar)); %! assert(ar.port, arduinos{1}.port); %! assert(ar.board, arduinos{1}.board); %!test %! ar = arduino(arduinos{1}.port, arduinos{1}.board); %! assert(!isempty(ar)); %! assert(isa(ar, "arduino")) %! assert(ar.port, arduinos{1}.port); %! assert(ar.board, arduinos{1}.board); %!test %! ar = arduino(); %! # verify have compiled support for functions we will be testing %! assert(!isempty(find(cellfun(@(x) strcmpi(x, "spi"), ar.libraries()), 1))) %! assert(!isempty(find(cellfun(@(x) strcmpi(x, "i2c"), ar.libraries()), 1))) %! assert(!isempty(find(cellfun(@(x) strcmpi(x, "servo"), ar.libraries()), 1))) %! assert(!isempty(find(cellfun(@(x) strcmpi(x, "shiftregister"), ar.libraries()), 1))) %! assert(!isempty(find(cellfun(@(x) strcmpi(x, "rotaryencoder"), ar.libraries()), 1))) arduino-0.4.0/inst/@arduino/checkI2CAddress.m0000644000000000000000000000470313470770202017125 0ustar0000000000000000## Copyright (C) 2019 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} checkI2CAddress (@var{ar}, @var{address}) ## @deftypefnx {} {@var{retval} =} checkI2CAddress (@var{ar}, @var{address}, @var{bus}) ## Check that an address of given address responds on the I2C bus ## ## @subsubheading Inputs ## @var{ar} - arduino object connected to a arduino board. ## ## @var{address} - I2C address number to check ## ## @var{bus} - bus number to check for I2C device, when multiple buses are available. ## If the bus is not specified, it will default to 0. ## ## @subsubheading Outputs ## @var{retval} - boolean value of true if address responds on the I2C bus ## ## @subsubheading Example ## @example ## @code { ## # create arduino connection. ## ar = arduino(); ## # scan for devices on the I2C bus ## checkI2CAddress (ar) ## # output if a device using that address is attached ## ans = ## 1 ## } ## @end example ## ## @seealso{arduino, scanI2Cbus} ## @end deftypefn function ret = checkI2CAddress (ar, address, bus) persistent ARDUINO_I2C_SCAN = 0; ret = false; if nargin < 2 || nargin > 3 print_usage (); endif if nargin == 2 bus = 0; elseif !isnumeric (bus) || bus < 0 || bus > 1 error ('checkI2CAddress: expected bus to be numeric and 0 or 1'); endif if (!isa (ar, "arduino")) error ("checkI2CAddress: expects arduino object as 1st argument"); endif if !isnumeric (address) || address < 1 || address > 127 error ('checkI2CAddress: expected address to be numeric 1 > address <= 127'); endif # TODO: configure SPI pins if not already done?? [tmp, sz] = sendCommand (ar, "i2c", ARDUINO_I2C_SCAN, [bus address]); if tmp(3) == 1 ret = true; endif endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! checkI2CAddress(ar, 12); arduino-0.4.0/inst/@arduino/configurePin.m0000644000000000000000000000772413470770202016702 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{currmode} =} configurePin (@var{ar}, @var{pin}) ## @deftypefnx {} {} configurePin (@var{ar}, @var{pin}, @var{mode}) ## Set/Get pin mode for a specified pin on arduino connection. ## ## configurePin (@var{ar}, @var{pin}) will get the current mode of the specified pin. ## ## configurePin (@var{ar}, @var{pin}, @var{mode}) will attempt set the pin to the specified ## mode if the mode is unset. ## ## @subsubheading Inputs ## @var{ar} - the arduino object of the connection to an arduino board. ## ## @var{pin} - string name of the pin to set/get the mode of. ## ## @var{mode} - string mode to set the pin to. ## ## @subsubheading Outputs ## @var{mode} - string current mode of the pin. ## ## Valid modes can be: ## @itemize @bullet ## @item AnalogInput ## - Acquire analog signals from pin ## @item DigitalInput ## - Acquire digital signals from pin ## @item DigitalOutput ## - Generate digital signals from pin ## @item I2C ## - Specify a pin to use with I2C protocol ## @item Pullup ## - Specify pin to use a pullup switch ## @item PWM ## - Specify pin to use a pulse width modulator ## @item Servo ## - Specify pin to use a servo ## @item SPI ## - Specify a pin to use with SPI protocol ## @item Unset ## - Clears pin designation. The pin is no longer reserved and can be automatically ## set at the next operation. ## @end itemize ## ## @seealso{arduino} ## ## @end deftypefn function retval = configurePin (obj, pin, mode) persistent ARDUINO_CONFIGPIN = 2; if nargin != 2 && nargin != 3 error ("@arduino.configurePin: expected pin name and value"); endif if !ischar (pin) && !isnumeric (pin) error ("@arduino.configurePin: expected pin name as string"); endif pininfo = obj.get_pin (pin); if nargin == 3 % set mode if !ischar (mode) error ("@arduino.configurePin: expected pin mode as string"); endif mode = tolower (mode); [pinstate, pinmode] = pinStateMode (mode); if strcmp (pinmode,"spi") # check special case of when pin is miso, make it an input idx = find (cellfun(@(x) ~isempty (strfind (x, "_miso")), pininfo.modes), 1); if !isempty (idx) pinstate = 2; endif endif % valid setting for this pin ? if !strcmpi (mode, "unset") validatePin (obj, pin, pinmode); else pinmode = getResourceOwner (obj, pin); endif % own this pin configurePinResource (obj, pin, pinmode, mode); # send config command to arduino datain = uint8 ([pininfo.id pinstate]); [dataout, status] = __sendCommand__ (obj, 0, ARDUINO_CONFIGPIN, datain); if status != 0 error ("@arduino.configurePin: failed to set pin state err=%d - %s", status, char(dataout)); endif else % get mode ? datain = uint8 ([pininfo.id]); [dataout, status] = __sendCommand__ (obj, 0, ARDUINO_CONFIGPIN, datain); if status != 0 error ("@arduino.configurePin: failed to set pin state err=%d - %s", status, char(dataout)); endif retval = pinStateMode (dataout(2)); endif endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! configurePin(ar, "d2", "digitaloutput"); %! assert(configurePin(ar, "d2"), "digitaloutput"); %! configurePin(ar, "d2", "unset"); %! assert(configurePin(ar, "d2"), "unset"); arduino-0.4.0/inst/@arduino/configurePinResource.m0000644000000000000000000001000713470770202020376 0ustar0000000000000000## Copyright (C) 2018-2019 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{currmode} =} configurePinResource (@var{ar}, @var{pin}) ## @deftypefnx {} {} configurePinResource (@var{ar}, @var{pin}, @var{owner}, @var{mode}) ## @deftypefnx {} {} configurePinResource (@var{ar}, @var{pin}, @var{owner}, @var{mode}, @var{force}) ## Set/Get pin mode for a specified pin on arduino connection. ## ## configurePinResource (@var{ar}, @var{pin}) will get the current mode of the specified pin. ## ## configurePinResource (@var{ar}, @var{pin}, @var{owner}, @var{mode}) will attempt set the pin to the specified ## mode and owner. ## ## If the pin is already owned by another owner, the configure will fail unless the force option is used. ## If the mode is already set, configure will fail unless force is used. ## ## @subsubheading Inputs ## @var{ar} - the arduino object of the connection to an arduino board. ## ## @var{pin} - string name of the pin to set/get the mode of. ## ## @var{mode} - string mode to set the pin to. ## ## @var{owner} - string name to use as the pin owner. ## ## @var{force} - boolean to force mode change. If not set, it will be false. ## ## @subsubheading Outputs ## @var{currmode} - current string mode of the pin. ## ## Valid modes can be: ## @itemize @bullet ## @item AnalogInput ## - Acquire analog signals from pin ## @item DigitalInput ## - Acquire digital signals from pin ## @item DigitalOutput ## - Generate digital signals from pin ## @item I2C ## - Specify a pin to use with I2C protocol ## @item Pullup ## - Specify pin to use a pullup switch ## @item PWM ## - Specify pin to use a pulse width modulator ## @item Servo ## - Specify pin to use a servo ## @item SPI ## - Specify a pin to use with SPI protocol ## @item Reserved ## - Pin marked reserved, but not for of any particular mode ## @item Unset ## - Clears pin designation. The pin is no longer reserved and can be automatically ## set at the next operation. ## @end itemize ## ## @seealso{arduino, configurePin} ## @end deftypefn function retval = configurePinResource (obj, pin, owner, mode, forceconfig) if nargin != 2 && nargin != 4 && nargin != 5 error ('@arduino.configurePinResource: invalid number of arduments supplied'); endif if !ischar(pin) error ("@arduino.configurePinResource: expected pin name as string"); endif pininfo = obj.get_pin (pin); if nargin == 2 % return current mode retval = pininfo.mode; else if nargin == 4 forceconfig = false; endif if !isempty (pininfo.owner) && !strcmpi (pininfo.owner, owner) && !forceconfig error ("@arduino.configurePinResource: pin already owned"); endif if !strcmpi (pininfo.mode, "unset") && !strcmpi (pininfo.mode, mode) && !forceconfig && !strcmpi (mode, "unset") error ("@arduino.configurePinResource: pin mode already set"); endif if (strcmpi (mode, "unset")) owner = ""; endif pininfo.owner = owner; pininfo.mode = mode; obj.set_pin (pin, pininfo); endif endfunction %!shared ar %! ar = arduino(); %!test %! configurePinResource(ar, "d2", "test", "digitaloutput"); %! assert(getResourceOwner(ar,"d2"), "test") %! assert(getTerminalMode(ar, "d2"), "digitaloutput"); %!test %! configurePinResource(ar, "a0", "test1", "analoginput"); %! assert(getResourceOwner(ar,"a0"), "test1") %! assert(getTerminalMode(ar, "a0"), "analoginput"); arduino-0.4.0/inst/@arduino/decrementResourceCount.m0000644000000000000000000000340313470770202020727 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{count} =} decrementResourceCount (@var{ar}, @var{resource}) ## Decrement the count of a named resource by 1 and return the ## new count. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{resource} - name of resource to decrement count. ## ## @subsubheading Outputs ## @var{count} = count of uses registered to resource. ## ## @seealso{getResourceCount. incrementResourceCount} ## @end deftypefn function retval = decrementResourceCount (ar, resource) if nargin != 2 print_usage (); endif if !ischar (resource) error ("@arduino.decrementResourceCount: expects resource name"); endif resinfo = ar.get_resource (resource); if resinfo.count == 0 error ("@arduino.decrementResourceCount: resource count is 0"); endif resinfo.count --; ar.set_resource (resource, resinfo); retval = resinfo.count; endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! assert(getResourceCount(ar,"notusedname"), 0); %! assert(incrementResourceCount(ar,"notusedname"), 1); %! assert(getResourceCount(ar,"notusedname"), 1); %! assert(decrementResourceCount(ar,"notusedname"), 0); %! assert(getResourceCount(ar,"notusedname"), 0); arduino-0.4.0/inst/@arduino/display.m0000644000000000000000000000422113470770202015704 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {} display (@var{ar}) ## Display the arduino object in a verbose way, showing the board and available pins. ## ## @subsubheading Inputs ## @var{ar} - the arduino object. ## ## If the arduino object has debug mode set, additional information will be displayed. ## ## @seealso{arduino} ## @end deftypefn function display (ar) printf ("%s = \n", inputname (1)); printf (" arduino object with fields of: \n"); printf (" port = ") disp (ar.config.port); printf (" board = ") disp (ar.config.board); printf (" libraries = {\n") libs = ar.libraries (); for i=1:numel (libs) printf (" %s\n", libs{i}); endfor printf(" }\n"); # group pins where can nextpin = ""; startpin = {}; endpin = {}; printf (" availablepins = {\n") for i=1:numel (ar.config.pins) pin = ar.config.pins{i}; if !strcmpi(nextpin, pin.name) if !isempty(endpin) printf (" %s - %s\n", startpin.name, endpin.name); elseif !isempty(startpin) printf (" %s\n", startpin.name); endif startpin = pin; endpin = {}; else if isempty(startpin) startpin = pin; else endpin = pin; endif endif parts = sscanf(pin.name, "%c %d"); nextpin = sprintf("%c%d", char(parts(1)), parts(2)+1); endfor if !isempty(endpin) printf (" %s - %s\n", startpin.name, endpin.name); elseif !isempty(startpin) printf (" %s\n", startpin.name); endif printf(" }\n"); if ar.debug printf (" config = \n"); disp (ar.config); endif endfunction arduino-0.4.0/inst/@arduino/getI2CTerminals.m0000644000000000000000000000232213470770202017173 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{pinlist} =} getI2CTerminals (@var{ar}) ## Get a cell list of pin Ids available are used for I2C mode. ## ## @subsubheading Inputs ## @var{ar} - the arduino object. ## ## @subsubheading Outputs ## @var{pinlist} - cell list of pin numbers available for I2C use. ## ## @seealso{arduino} ## @end deftypefn function retval = getI2CTerminals (obj) if nargin != 1 print_usage() endif retval = getTypeTerminals(obj, "i2c"); endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! terms = getI2CTerminals(ar); %! assert (numel(terms) > 0) %! # should be pairs of i2c pins %! assert (mod(numel(terms),2), 0) arduino-0.4.0/inst/@arduino/getLEDTerminals.m0000644000000000000000000000217413470770202017227 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{pinlist} =} getLEDTerminals (@var{ar}) ## Get a cell list of pin Ids available are connected natively to LEDs. ## ## @subsubheading Inputs ## @var{ar} - the arduino object. ## ## @subsubheading Outputs ## @var{pinlist} - cell list of pin numbers available for LED use. ## ## @seealso{arduino} ## @end deftypefn function retval = getLEDTerminals (obj) if nargin != 1 print_usage () endif retval = getTypeTerminals (obj, "led"); endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! terms = getLEDTerminals(ar); arduino-0.4.0/inst/@arduino/getMCU.m0000644000000000000000000000213513470770202015365 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{mcu} =} getMCU (@var{ar}) ## Get the MCU used by the connected arduino. ## ## @subsubheading Inputs ## @var{ar} - arduino object connected to a arduino board. ## ## @subsubheading Outputs ## @var{mcu} - string representing the mcu used by the arduino board. ## ## @seealso{arduino} ## @end deftypefn function retval = getMCU (obj) retval = obj.get_mcu (); endfunction %!test %! ar = arduino (); %! assert (!isempty (ar)); %! mcu = getMCU (ar); %! assert (ischar (mcu)) %! assert (mcu, ar.get_mcu ()) arduino-0.4.0/inst/@arduino/getPWMTerminals.m0000644000000000000000000000220413470770202017260 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{pinlist} =} getPWMTerminals (@var{ar}) ## Get a cell list of pin Ids available for PWM use. ## ## @subsubheading Inputs ## @var{ar} - the arduino object. ## ## @subsubheading Outputs ## @var{pinlist} - cell list of pin numbers available for PWM use. ## ## @seealso{arduino} ## @end deftypefn function retval = getPWMTerminals(obj) if nargin != 1 print_usage() endif retval = getTypeTerminals(obj, "pwm"); endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! terms = getPWMTerminals(ar); %! assert (numel(terms) > 0) arduino-0.4.0/inst/@arduino/getPinInfo.m0000644000000000000000000000711013470770202016301 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{pininfo} =} getPinInfo (@var{ar}, @var{pin}) ## @deftypefnx {} {@var{pininfoarray} =} getPinInfo (@var{ar}, @var{pinarray}) ## Get the pin information from the input pins values. ## ## getPinInfo (@var{ar}, @var{pin}) will get information for a single pin. ## ## getPinInfo (@var{ar}, @var{pinarray}) will get a cell array of pin information ## ## @subsubheading Inputs ## @var{ar} - the connected arduino object. ## ## @var{pin} - a pin number or pin name. ## ## @var{pinarray} - the array of pin numbers or names ## ## The pininfo struct contains the following fields: ## @table @asis ## @item terminal ## Terminal number of the pin ## @item name ## String name of the pin ## @item owner ## Current item owner of the pin ## @item mode ## Current configured mode for the pin ## @end table ## ## @subsubheading Outputs ## @var{pininfo} - struct on pin information. ## ## @var{pininfolist} - cell array of pin info ## ## @seealso{arduino, configurePinResource, getResourceOwner} ## @end deftypefn function retval = getPinInfo (obj, pins) if nargin != 2 print_usage () endif if iscell (pins) retval = {}; for i=1:numel (pins) p = obj.get_pin(pins{i}); inf = {}; inf.name = p.name; inf.terminal = p.id; inf.owner = p.owner; inf.mode = p.mode; retval{end+1} = inf; endfor elseif ischar(pins) p = obj.get_pin(pins); inf = {}; inf.name = p.name; inf.terminal = p.id; inf.owner = p.owner; inf.mode = p.mode; retval = inf; elseif isvector (pins) && numel (pins) == 1 p = obj.get_pin(pins); inf = {}; inf.name = p.name; inf.terminal = p.id; inf.owner = p.owner; inf.mode = p.mode; retval = inf; elseif isvector (pins) retval = {}; for i=1:numel (pins) p = obj.get_pin(pins(i)); inf = {}; inf.name = p.name; inf.terminal = p.id; inf.owner = p.owner; inf.mode = p.mode; retval{end+1} = inf; endfor elseif isnumeric (pins) p = obj.get_pin(pins); inf = {}; inf.name = p.name; inf.terminal = p.id; inf.owner = p.owner; inf.mode = p.mode; retval = inf; else error ("@arduino.getPinInfo: expected pins a array of numbers or names"); endif endfunction %!shared ar %! ar = arduino(); %!test %! info = getPinInfo(ar, 0); %! # terminal 0 is alwars D0 ? %! assert (isstruct (info)); %! assert (!iscell (info)); %! assert (toupper (info.name), "D0"); %! assert (info.terminal, 0); %!test %! info = getPinInfo(ar, "d0"); %! # terminal 0 is alwars D0 ? %! assert (isstruct (info)); %! assert (!iscell (info)); %! assert (toupper (info.name), "D0"); %! assert (info.terminal, 0); %!test %! info = getPinInfo(ar, [0 2]); %! assert(numel(info), 2); %! assert(iscell(info)); %! assert (toupper (info{1}.name), "D0"); %! assert (toupper (info{2}.name), "D2"); %!test %! info = getPinInfo(ar, {"d4", 5}); %! assert(numel(info), 2); %! assert(iscell(info)); %! assert (toupper (info{1}.name), "D4"); %! assert (toupper (info{2}.name), "D5"); arduino-0.4.0/inst/@arduino/getPinsFromTerminals.m0000644000000000000000000000426513470770202020363 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{pinnames} =} getPinsFromTerminals (@var{ar}, @var{terminals}) ## Get the pin names from the input terminal values. ## ## @subsubheading Inputs ## @var{ar} - the connected arduino object. ## ## @var{terminals} - the numeric pin number, or array of pin numbers to get pin names. ## ## @subsubheading Outputs ## @var{pinnames} - the string names of each input pin. If terminals was a single value, the return ## will be a single string, otherwise it will return a cell array of each pin name. ## ## @seealso{arduino, getTerminalsFromPins} ## @end deftypefn function retval = getPinsFromTerminals (obj, terminals) if nargin != 2 print_usage () endif if iscell (terminals) retval = {}; for i=1:numel (terminals) retval{end+1} = obj.get_pin (terminals{i}).name; endfor elseif isvector (terminals) && numel (terminals) == 1 retval = obj.get_pin (terminals).name; elseif isvector (terminals) retval = {}; for i=1:numel (terminals) retval{end+1} = obj.get_pin (terminals(i)).name; endfor elseif isnumeric (terminals) retval = obj.get_pin (terminals).name; else error ("@arduino.getPinsFromTerminals: expected terminals as vector"); endif endfunction %!shared ar %! ar = arduino(); %!assert(!isempty(ar)); %!test %! terms = getPinsFromTerminals(ar, 0); %! # terminal 0 is alwars D0 ? %! assert(ischar(terms)); %! assert(toupper(terms), "D0"); %!test %! terms = getPinsFromTerminals(ar, [0 2]); %! assert(numel(terms), 2); %! assert(iscell(terms)); %! assert(ischar(terms{1})); %! assert(toupper(terms{1}), "D0"); %! assert(toupper(terms{2}), "D2"); arduino-0.4.0/inst/@arduino/getResourceCount.m0000644000000000000000000000253113470770202017541 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{count} =} getResourceCount (@var{ar}, @var{resource}) ## Get the count of uses of a given resource. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{resource} - name of resource to get count for. ## ## @subsubheading Outputs ## @var{count} = count of uses registered to resource. ## ## @seealso{incrementResourceCount. decrementResourceCount} ## @end deftypefn function retval = getResourceCount (ar, resource) if nargin != 2 print_usage (); endif if !ischar(resource) error ("getResourceCount: expects resource name"); endif resinfo = ar.get_resource(resource); retval = resinfo.count; endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! assert(getResourceCount(ar,"notusedname"), 0); arduino-0.4.0/inst/@arduino/getResourceOwner.m0000644000000000000000000000276513470770202017554 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{owner} =} getResourceOwner (@var{ar}, @var{terminal}) ## Get the owner of pin allocated previously by configurePinResource. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{terminal} - terminal number to get owner of. ## ## @subsubheading Outputs ## @var{owner} = owner of the terminal pin, or "" if not owned. ## ## @seealso{configurePinResource} ## @end deftypefn function retval = getResourceOwner (obj, terminal) if nargin != 2 print_usage (); endif # note: matlab expects a number only - we will use either if or pin name if !ischar(terminal) && !isnumeric(terminal) error ("getResourceOwner: expects terminal id or pin name"); endif pininfo = obj.get_pin(terminal); retval = pininfo.owner; endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! configurePin(ar, "d2", "digitaloutput"); %! assert(getResourceOwner(ar,"d2"), "digital"); arduino-0.4.0/inst/@arduino/getSPITerminals.m0000644000000000000000000000202313470770202017247 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{pinlist} =} getSPITerminals (@var{ar}) ## Get a cell list of pin Ids available for SPI mode. ## ## @subsubheading Inputs ## @var{ar} - the arduino object. ## ## @subsubheading Outputs ## @var{pinlist} - cell list of pin numbers available for SPI use. ## ## @seealso{arduino} ## @end deftypefn function retval = getSPITerminals(obj) if nargin != 1 print_usage() endif retval = getTypeTerminals(obj, "spi"); endfunction arduino-0.4.0/inst/@arduino/getServoTerminals.m0000644000000000000000000000205313470770202017715 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{pinlist} =} getServoTerminals (@var{ar}) ## Get a cell list of pin Ids available for servo use. ## ## @subsubheading Inputs ## @var{ar} - the arduino object. ## ## @subsubheading Outputs ## @var{pinlist} - cell list of pin numbers available for servo use. ## ## @seealso{arduino, getPWMTerminals} ## @end deftypefn function retval = getServoTerminals(obj) if nargin != 1 print_usage() endif retval = getTypeTerminals(obj, "pwm"); endfunction arduino-0.4.0/inst/@arduino/getSharedResourceProperty.m0000644000000000000000000000323013470770202021421 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{count} =} getSharedResourceProperty (@var{ar}, @var{resource}, @var{property}) ## Get the value of a property from a given resource. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{resource} - name of resource to get property for. ## ## @var{property} - name of property from the resource. ## ## @subsubheading Outputs ## @var{propvalue} - value of the property ## ## @seealso{getResourceCount, setSharedResourceProperty} ## @end deftypefn function retval = getSharedResourceProperty (ar, resource, propname) if nargin != 3 print_usage (); endif if !ischar(resource) error ("getSharedResourceProperty: expects resource name"); endif if !ischar(propname) error ("getSharedResourceProperty: expects resource property name"); endif resinfo = ar.get_resource(resource); retval = resinfo.props.(tolower(propname)); endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! setSharedResourceProperty(ar, "notusedname", "propname", 16); %! assert(getSharedResourceProperty(ar,"notusedname", "propname"), 16); arduino-0.4.0/inst/@arduino/getTerminalMode.m0000644000000000000000000000270313470770202017322 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{mode} =} getTerminalMode (@var{ar}, @var{terminal}) ## Get the mode of a pin allocated previously by configurePinResource. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{terminal} - terminal number to get owner of. ## ## @subsubheading Outputs ## @var{mode} - mode of the terminal pin, or "not_set" if not owned. ## ## @seealso{configurePinResource, getResourceOwner} ## @end deftypefn function retval = getTerminalMode (obj, terminal) if nargin != 2 print_usage () endif pininfo = obj.get_pin (terminal); retval = pininfo.mode; endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! term = getTerminalsFromPins(ar, "d2"); %! configurePin(ar, "d2", "digitaloutput"); %! assert(getTerminalMode(ar, term), "digitaloutput"); %! configurePin(ar, "d2", "unset"); %! assert(getTerminalMode(ar, term), "unset"); arduino-0.4.0/inst/@arduino/getTerminalsFromPins.m0000644000000000000000000000317113470770202020356 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{pinnums} =} getTerminalsFromPins (@var{ar}, @var{pins}) ## Get the terminal number for each pin. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{pins} - single pin name or cell or vector array of pin names. ## ## @subsubheading Outputs ## @var{pinnums} - pin number of each named pin. If the input was a single string, returns a number. ## if the input pins was a vector or cell array, return a cell array of pin numbers corresponding ## to each input pin name. ## ## @seealso{arduino, getPinsFromTerminals} ## @end deftypefn function retval = getTerminalsFromPins(obj, pins) if nargin != 2 print_usage() endif if iscell (pins) retval = {}; for i=1:numel(pins) retval{end+1} = obj.get_pin(pins{i}).id; endfor elseif ischar(pins) retval = obj.get_pin(pins).id; elseif isvector (pins) retval = {}; for i=1:numel(pins) retval{end+1} = obj.get_pin(pins(i)).id; endfor else error ("getTerminalFromPins: expected pins as cell or string"); endif endfunction arduino-0.4.0/inst/@arduino/incrementResourceCount.m0000644000000000000000000000315313470770202020747 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{count} =} incrementResourceCount (@var{ar}, @var{resource}) ## Increment the count value of a named resource by 1 and return the ## new count ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{resource} - name of resource to increment count. ## ## @subsubheading Outputs ## @var{count} = count of uses registered to resource. ## ## @seealso{getResourceCount. decrementResourceCount} ## @end deftypefn function retval = incrementResourceCount (ar, resource) if nargin != 2 print_usage (); endif if !ischar (resource) error ("@arduino.getResourceCount: expects resource name"); endif resinfo = ar.get_resource (resource); resinfo.count ++; ar.set_resource (resource, resinfo); retval = resinfo.count; endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! assert(getResourceCount(ar,"notusedname"), 0); %! assert(incrementResourceCount(ar,"notusedname"), 1); %! assert(getResourceCount(ar,"notusedname"), 1); %! assert(incrementResourceCount(ar,"notusedname"), 2); arduino-0.4.0/inst/@arduino/isTerminalAnalog.m0000644000000000000000000000321113470770202017466 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{ret} = } isTerminalAnalog (@var{obj}, @var{terminal}) ## Return true if pin is capable of analog input ## ## @subsubheading Inputs ## @var{ar} - the connected arduino object ## ## @var{terminal} is a terminal number to check ## ## @subsubheading Outputs ## @var{ret} return 1 if terminal is a analog pin, 0 otherwise ## ## @end deftypefn function retvalue = isTerminalAnalog (obj, terminal) if nargin != 2 error ('@arduino.isTerminalAnalog: expected single terminal value'); endif pininfo = obj.get_pin (terminal); idx = find (cellfun(@(x) strcmpi (x, "analog"), pininfo.modes), 1); if isempty (idx) retvalue = false; else retvalue = true; endif endfunction %!shared ar %! ar = arduino(); %!assert(isTerminalAnalog(ar,"d0"), false); %!assert(isTerminalAnalog(ar,"a0"), true); %!assert(isTerminalAnalog(ar,getTerminalsFromPins(ar, "a0")), true); %!error isTerminalAnalog() %!error isTerminalAnalog(ar) %!error isTerminalAnalog(ar, "d1", 1) arduino-0.4.0/inst/@arduino/isTerminalDigital.m0000644000000000000000000000330513470770202017646 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{ret} = } isTerminalDigital(@var{obj}, @var{terminal}) ## Return true if pin is capable of digital functions ## ## @subsubheading Inputs ## @var{ar} - the connected arduino object ## ## @var{terminal} is a terminal number to check ## ## @subsubheading Outputs ## @var{ret} return 1 if terminal is a digital pin, 0 otherwise ## @end deftypefn function retvalue = isTerminalDigital (obj, terminal) if nargin != 2 error ('@arduino.isTerminalDigital: expected single terminal value'); endif pininfo = obj.get_pin (terminal); idx = find (cellfun(@(x) strcmpi (x, "digital"), pininfo.modes), 1); if isempty (idx) retvalue = false; else retvalue = true; endif endfunction %!shared ar %! ar = arduino(); %!assert(isTerminalDigital(ar,"d0"), true); %!assert(isTerminalDigital(ar,getTerminalsFromPins(ar, "d0")), true); %!assert(isTerminalDigital(ar,"a0"), true); %!error isTerminalDigital() %!error isTerminalDigital(ar) %!error isTerminalDigital(ar, "d1", 1) %!error isTerminalDigital(ar, -1) arduino-0.4.0/inst/@arduino/playTone.m0000644000000000000000000000545713470770202016046 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {} playTone (@var{ar}, @var{pin}, @var{freq}, @var{duration}) ## Play a tone of a given frequency on a specified pin. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{pin} - digital pin to play tone on ## ## @var{freq} - frequency in hertz to play between 0 and 32767Hz. ## ## @var{duration} duration in seconds to play tone between 0 and 30 seconds ## ## If duration is 0 or not specified, tone will continue to play until next tone is commanded. ## If frequency is 0, tone will stop playing ## ## @strong{NOTE:} use of playTone can interfere with PWM output. ## @end deftypefn function playTone (obj, pin, freq, duration) ARDUINO_PLAYTONE = 6; if nargin < 3 error ("@arduino.playTone: expected pin name and frequency"); endif if nargin >= 3 duration = 0; endif if !ischar(pin) && !isnumeric(pin) error ("@arduino.playTone: expected pin name as string"); endif if (!isnumeric(freq) || freq < 0 || freq > 32767) error ("@arduino.playTone: expected freq between 0 .. 32767"); endif if (!isnumeric(duration) || duration < 0 || duration > 30) error ("@arduino.playTone: expected duration between 0 .. 30"); endif pininfo = obj.get_pin(pin); # first use ? if strcmp(pininfo.mode, "unset") configurePin(obj, pin, "digitaloutput") else [pinstate, pinmode] = pinStateMode(pininfo.mode); if !strcmp(pinmode, "digital") error ("@arduino.playTone: pin is in an incompatable mode"); endif endif freq = uint16(freq); freqh = bitand(freq/256, hex2dec('FF')); freql = bitand(freq, hex2dec('FF')); duration = uint16(duration*10); durh = bitand(duration/256, hex2dec('FF')); durl = bitand(duration, hex2dec('FF')); datain = uint8([pininfo.id freqh freql durh durl]); [dataout, status] = __sendCommand__ (obj, 0, ARDUINO_PLAYTONE, datain); if status != 0 error ("@arduino.playTone: failed to set tone err=%d - %s", status, char(dataout)); endif endfunction %!shared ar %! ar = arduino(); %!test %! playTone(ar,"d2", 0, 0); %! playTone(ar,"d2", 220, 1); %! playTone(ar, "d2", 0); %!error playTone() %!error playTone(ar) %!error playTone(ar, "nopin", 220) arduino-0.4.0/inst/@arduino/private/0000755000000000000000000000000013470770202015534 5ustar0000000000000000arduino-0.4.0/inst/@arduino/private/__digitalPin__.m0000644000000000000000000000332013470770202020570 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} __digitalPin__ (@var{obj}) ## Private function ## @end deftypefn function retval = __digitalPin__(obj, pin, value) ARDUINO_DIGITAL = 3; retval = 0; if !ischar(pin) && !isnumeric(pin) error ("@arduino.digitalPin: expected pin name as string"); endif pininfo = obj.get_pin(pin); if nargin == 2 mode = "digitalinput"; datain = uint8([pininfo.id]); elseif nargin == 3 mode = "digitaloutput"; if value val = 1; else val = 0; endif datain = uint8([pininfo.id val]); endif # first use ? if strcmp(pininfo.mode, "unset") configurePin(obj, pin, mode) else [pinstate, pinmode] = pinStateMode(pininfo.mode); if !strcmp(pinmode, "digital") error ("digitalPin: pin is in incompatable mode"); endif endif [dataout, status] = __sendCommand__ (obj, 0, ARDUINO_DIGITAL, datain); if status != 0 error ("digitalPin: failed to set/get pin state err=%d", status); endif if nargin == 2 if dataout(2) != 0 retval = 1; else retval = 0; endif endif endfunction arduino-0.4.0/inst/@arduino/private/__sendCommand__.m0000644000000000000000000000716513470770202020747 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} __sendCommand__ (@var{obj}, @var{cmd}, @var{data}, @var{timeout}) ## Private function ## @end deftypefn ## Author: jdonoghue ## Created: 2018-05-15 function [dataOut, errcode] = __sendCommand__ (obj, libid, cmd, data, timeout) if nargin < 3 error ("@arduino.__sendCommand__: expected command"); endif % send command and get back reponse if !isa(obj.connected, "octave_serial") error ("@arduino.__sendCommand__: not connected to a arduino"); endif % connected yet ? % simple procol here, each field is a byte % sends A5 EXT CMD datasize [data,,,] % currently ext is 0 - may use later to identify module to send to ? % A5 00 00 00 = reset % A5 00 01 00 = req board info dataOut = []; errcode = 0; if (nargin < 4) data = []; endif if (nargin < 5) timeout = 0.5; endif set(obj.connected, "timeout", timeout*10); hdr = uint8([ hex2dec("A5") libid cmd numel(data)]); len = srl_write(obj.connected, [hdr data]); if (obj.debug) printf(">> "); printf("%d ", [hdr data]); printf("\n"); endif # TODO: current serial doesnt have a way to know if any data is awaiting # so try read what we need first without waiting ? # read in initial part [tmpdataOut, tmpdataSize] = srl_read (obj.connected, 4); if (obj.debug) printf("<< "); printf("%d ", tmpdataOut); printf("\n"); endif if tmpdataSize < 4 errcode = 1; dataOut = "Undersized packet header"; elseif tmpdataOut(1) != hex2dec("A5") || tmpdataOut(2) != libid || (tmpdataOut(3) != cmd && tmpdataOut(3) != 255 && tmpdataOut(3) != 254) errcode = 2; dataOut = "Malformed packet header"; elseif (tmpdataOut(3) == 254) # got a wait for response value - length is expected to be 0 if (obj.debug) printf("* wait for response\n"); endif set(obj.connected, "timeout", -1); [tmpdataOut, tmpdataSize] = srl_read (obj.connected, 4); if (obj.debug) printf("<< "); printf("%d ", tmpdataOut); printf("\n"); endif if tmpdataSize < 4 errcode = 1; dataOut = "Undersized packet header"; elseif tmpdataOut(1) != hex2dec("A5") || tmpdataOut(2) != libid || (tmpdataOut(3) != cmd && tmpdataOut(3) != 255) errcode = 2; dataOut = "Malformed packet header"; endif endif if(errcode == 0) expectlen = tmpdataOut(4); if expectlen > 0 [dataOut, tmpdataSize] = srl_read (obj.connected, expectlen); if (obj.debug) printf("<< "); printf("%d ", dataOut); printf("\n"); endif else tmpdataSize = 0; endif if tmpdataSize != expectlen errcode = 3; dataOut = "Malformed packet body"; elseif tmpdataOut(3) == 255 # valid packet, but was coz we got an error errcode = 10; if expectlen == 0 dataOut = "Recieved error status";; else dataOut = char(dataOut); endif else errcode = 0; # all is good endif endif endfunction arduino-0.4.0/inst/@arduino/private/getTypeTerminals.m0000644000000000000000000000217513470770202021217 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} getTypeTerminals (@var{ar}, @var{ar}) # Private function ## @end deftypefn function retval = getTypeTerminals(obj, type) if nargin != 2 print_usage() endif retval = {}; for i=1:numel(obj.config.pins) pininfo = obj.config.pins{i}; # strncmp do can patch spi from spiX_XX etc idx = find( cellfun(@(x) strncmpi(x, type, length(type)), pininfo.modes), 1); if !isempty(idx) retval{end+1}=pininfo.id; endif endfor endfunction arduino-0.4.0/inst/@arduino/private/pinStateMode.m0000644000000000000000000000376713470770202020323 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{value} =} pinStateMode (@var{pinStateVal}) ## Private function ## @end deftypefn function [pstate, pmode] = pinStateMode (pinStateVal) if ischar(pinStateVal) switch (tolower(pinStateVal)) case "unset" pstate = 0; pmode="none"; case "analoginput" pstate = 1; pmode = "analog"; case "digitalinput" pstate = 2; pmode="digital"; case "digitaloutput" pstate = 3; pmode="digital"; case "pullup" pstate = 4; pmode = "digital"; case "i2c" pstate = 5; pmode = "i2c"; case "pwm" pstate = 6; pmode="pwm"; case "servo" pstate = 7; pmode="pwm"; case "spi" pstate = 3; pmode="spi"; % for now just setting as output otherwise error ("unknown pin state %s", pinStateVal); endswitch else switch (pinStateVal) case 1 pstate = "analoginput"; pmode="analog"; case 2 pstate = "digitalinput"; pmode="digital"; case 3 pstate = "digitaloutput"; pmode="digital"; case 4 pstate = "pullup"; pmode="digital"; case 5 pstate = "i2c"; pmode="i2c"; case 6 pstate = "pwm"; pmode="pwm"; case 7 pstate = "servo"; pmode="pwm"; case 8 pstate = "spi"; pmode="spi"; otherwise pstate = "unset"; pmode=""; endswitch endif endfunction arduino-0.4.0/inst/@arduino/readAnalogPin.m0000644000000000000000000000450513470770202016750 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{value} =} readAnalogPin (@var{ar}, @var{pin}) ## Read analog voltage of @var{pin}. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object. ## ## @var{pin} - string name of the pin to read. ## ## @subsubheading Outputs ## @var{value} - analog value of the pin ## ## @subsubheading Example ## @example ## @code{ ## ar = arduino (); ## readAnalogPin(ar, "A4"); ## ans = ## 87 ## } ## @end example ## @seealso{arduino, readVoltage} ## @end deftypefn function value = readAnalogPin (obj, pin) ARDUINO_ANALOG = 4; if nargin != 2 error ("@arduino.readAnalogPin: expected pin name and value"); endif if !ischar(pin) error ("@arduino.readAnalogPin: expected pin name as string"); endif pininfo = obj.get_pin(pin); # first use ? if strcmp(pininfo.mode, "unset") configurePin(obj, pin, "analoginput") else [pinstate, pinmode] = pinStateMode(pininfo.mode); if !strcmp(pinmode, "analog") error ("readAnalogPin: pin is in incompatable mode"); endif endif datain = uint8([pininfo.id]); [dataout, status] = __sendCommand__ (obj, 0, ARDUINO_ANALOG, datain); if status != 0 error ("readVoltage: failed to set pin state err=%d - %s", status, char(dataout)); endif value = (uint16(dataout(2))*256 + uint16(dataout(3))); endfunction %!shared ar %! ar = arduino(); %!test %! readAnalogPin(ar,"a0"); %! readAnalogPin(ar,"a1"); %! readAnalogPin(ar,"a2"); %! readAnalogPin(ar,"a3"); %! readAnalogPin(ar,"a4"); %! readAnalogPin(ar,"a5"); %!error readAnalogPin(ar,"d2"); %!error readAnalogPin() %!error readAnalogPin(ar) %!error readAnalogPin(ar, "a0", 2) %!error readAnalogPin(ar, "nopin") arduino-0.4.0/inst/@arduino/readDigitalPin.m0000644000000000000000000000331413470770202017121 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{value} =} readDigitalPin (@var{obj}, @var{pin}) ## Read digital value from a digital I/O pin. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object. ## ## @var{pin} - string name of the pin to read. ## ## @subsubheading Outputs ## @var{value} - the logical value (0, 1, true false) of the current pin state. ## ## @subsubheading Example ## @example ## @code{ ## a = arduino (); ## pinvalue = readDigitalPin (a, 'D5'); ## } ## @end example ## ## @seealso{arduino, writeDigitalPin} ## @end deftypefn function retval = readDigitalPin (obj, pin) if nargin != 2 error ("@arduino.readDigitalPin: expected pin name"); endif if !ischar(pin) && !isnumeric(pin) error ("@arduino.readDigitalPin: expected pin name as string"); endif retval = __digitalPin__(obj, pin); endfunction %!shared ar %! ar = arduino(); %!test %! readDigitalPin(ar,"d2"); %! assert(readDigitalPin(ar,"d2"), readDigitalPin(ar,2)); %!error readDigitalPin() %!error readDigitalPin(ar) %!error readDigitalPin(ar, "d2", 2) %!error readDigitalPin(ar, "nopin") arduino-0.4.0/inst/@arduino/readVoltage.m0000644000000000000000000000360113470770202016475 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{voltage} =} readVoltage (@var{ar}, @var{pin}) ## Read analog voltage of a pin. ## ## @subsubheading Inputs ## @var{ar} - connected arduino. ## ## @var{pin} - pin name or number to query for voltage ## ## @subsubheading Outputs ## @var{voltage} - scaled pin value as a voltage ## ## @subsubheading Example ## @example ## @code{ ## ar = arduino (); ## readVoltage(ar, "A4"); ## ans = ## 1.401 ## } ## @end example ## @seealso{arduino, readAnalogPin} ## @end deftypefn function voltage = readVoltage (ar, pin) if nargin != 2 error ("@arduino.readVoltage: expected pin name and value"); endif if !ischar(pin) error ("@arduino.readVoltage: expected pin name as string"); endif voltage = double(readAnalogPin(ar,pin)) * (ar.board_voltage() / 1023.0); endfunction %!shared ar %! ar = arduino(); %!test %! readVoltage(ar,"a0"); %! readVoltage(ar,"a1"); %! readVoltage(ar,"a2"); %! readVoltage(ar,"a3"); %! readVoltage(ar,"a4"); %! readVoltage(ar,"a5"); %! val = readVoltage(ar,"a0"); %! assert(isnumeric(val)); %! assert(val <= 5.0); %! assert(val >= 0); %!error readVoltage(ar,"d2"); %!error readVoltage() %!error readVoltage(ar) %!error readVoltage(ar, "a0", 2) %!error readVoltage(ar, "nopin") arduino-0.4.0/inst/@arduino/reset.m0000644000000000000000000000235213470770202015364 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {} reset (@var{ar}) ## Send reset command to arduino hardware to force a hardware reset. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object. ## ## @seealso{arduino} ## @end deftypefn function reset (ar) ARDUINO_RESET = 0; if nargin != 1 error ("@arduino.reset: expected arduiono object only"); endif [dataout, status] = __sendCommand__ (ar, 0, ARDUINO_RESET, [], 0); endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! reset(ar); %! pause(1); arduino-0.4.0/inst/@arduino/sendCommand.m0000644000000000000000000000574513470770202016503 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{outdata, outsize} =} sendCommand (@var{ar}, @var{libname}, @var{commandid}) ## @deftypefnx {} {@var{outdata, outsize} =} sendCommand (@var{ar}, @var{libname}, @var{commandid}, @var{data}) ## @deftypefnx {} {@var{outdata, outsize} =} sendCommand (@var{ar}, @var{libname}, @var{commandid}, @var{data}, @var{timeout}) ## Send a command with option data to the connected arduino, waiting up to a specified number of seconds ## for a response. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object. ## ## @var{libname} - library sending the command. The name should match a programmed ## library of the arduino, or an error will be displayed. ## ## @var{commandid} - integer value for the command being sent to the arduino. ## ## @var{data} - optional data sent with the command. ## ## @var{timeout} - optional timeout to wait for data ## ## @subsubheading Outputs ## @var{outdata} - data returned back from the arduino in response to command ## ## @var{outsize} - size of data received ## ## If the arduino fails to respond with a valid reply, sendCommand will error. ## ## @seealso{arduino} ## @end deftypefn function [dataOut,payloadSize] = sendCommand (obj, libname, commandid, data, timeout) if nargin < 3 error ('sendCommand: missing expected arguments of libname, commandid'); endif if (isempty(libname)) libid = 0; else libid = obj.get_lib(libname); if libid == -1 error ("sendCommand: unknown or unprogrammed libray '%s'.", libname); endif endif if ! isnumeric (commandid) error ('sendCommand: command id should be a number'); endif if (nargin < 4) data = []; endif if (nargin < 5) timeout = 5; endif [dataOut, status] = __sendCommand__ (obj, libid, commandid, data, timeout); if status != 0 error ("sendCommand: failed err=%d: msg=%s", status, char(dataOut)); endif payloadSize = numel(dataOut); endfunction %!shared ar %! ar = arduino(); %!error sendCommand(); %!error sendCommand(ar); %!error sendCommand(ar, ""); %!error sendCommand(ar, "", "str"); %!test %! % valid config pin msg %! assert(numel(sendCommand(ar, "", 2, [2])) > 0); # valid packet, but unknown id %!error sendCommand(ar, "", 255, [2 2]); # query config pin without the data %!error sendCommand(ar, "", 2); arduino-0.4.0/inst/@arduino/setSharedResourceProperty.m0000644000000000000000000000474113470770202021445 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {} setSharedResourceProperty (@var{ar}, @var{resource}, @var{propname}, @var{propvalue}) ## @deftypefnx {} {} setSharedResourceProperty (@var{ar}, @var{resource}, @var{propname}, @var{propvalue}, ___) ## Set property values for a given resource. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{resource} - name of resource to get property for. ## ## @var{propname} - name of property from the resource. ## ## @var{propvalue} - value of property from the resource. ## ## Multiple @var{propname}, @var{propvalue} pairs can be given. ## ## @subsubheading Outputs ## None ## ## @subsubheading Example ## @example ## @code{ ## ar = arduino(); ## setSharedResourceProperty(ar, "myresource", "myproperty", [1 2 3]) ## } ## @end example ## ## @seealso{getSharedResourceProperty} ## @end deftypefn function setSharedResourceProperty (varargin) if nargin < 4 print_usage (); endif if mod(nargin, 2) != 0 error ("{getSharedResourceProperty: expected property name, value pairs"); endif if !iscellstr (varargin(3:2:nargin)) error ("{getSharedResourceProperty: expected property names to be strings"); endif ar = varargin{1}; resource = varargin{2}; if !ischar(resource) error ("getSharedResourceProperty: expects resource name"); endif resinfo = ar.get_resource(resource); for i = 3:2:nargin propname = tolower(varargin{i}); propvalue = varargin{i+1}; resinfo.props.(propname) = propvalue; endfor ar.set_resource(resource, resinfo); endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! setSharedResourceProperty(ar, "notusedname", "propname1", 16); %! setSharedResourceProperty(ar, "notusedname", "propname2", 32); %! assert(getSharedResourceProperty(ar,"notusedname", "propname1"), 16); %! setSharedResourceProperty(ar, "notusedname", "propname1", []); %! assert(getSharedResourceProperty(ar,"notusedname", "propname1"), []); arduino-0.4.0/inst/@arduino/uptime.m0000644000000000000000000000340313470770202015543 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{sec} =} uptime (@var{ar}) ## Get the number of seconds the arduino board has been running concurrently. ## ## ## @subsubheading Inputs ## @var{ar} - the arduino object of the connection to an arduino board. ## ## @subsubheading Outputs ## @var{sec} - the number seconds the board has been running. Note that the count will wrap around after ## approximately 50 days. ## ## @seealso{arduino} ## ## @end deftypefn function retval = uptime (obj) persistent ARDUINO_UPTIME = 21; if nargin != 1 error ("@arduino.version expects no arguments"); endif [dataout, status] = __sendCommand__ (obj, 0, ARDUINO_UPTIME, []); if status != 0 error ("@arduino.uptime: failed err=%d - %s", status, char(dataout)); else value = uint32(dataout(1))*256*256*256 + uint32(dataout(2))*256*256 + uint32(dataout(3))*256 + uint32(dataout(4)); retval = double(value)/1000.0; endif endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! t1 = uptime(ar); %! pause (1); %! t2 = uptime(ar); %! assert(t1 < t2); arduino-0.4.0/inst/@arduino/validatePin.m0000644000000000000000000000411313470770202016477 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {} validatePin (@var{ar}, @var{pin}, @var{type}) ## Validate that the mode is allowed for specified pin ## ## If the mode is not valid, and error will be thrown. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{pin} - name of pin to query mode validity of ## ## @var{mode} - mode to query ## ## Known modes are: ## @itemize @bullet ## @item 'I2C' ## @item 'SPI' ## @item 'PWM' ## @item 'Servo' ## @item 'analog' ## @item 'digital' ## ## @end itemize ## ## @seealso{arduino, configurePin} ## @end deftypefn function validatePin (obj, pin, type) if nargin < 3 error ("@arduino.validatePin: expected pin name and type"); endif if !ischar(pin) || !ischar(type) error ("@arduino.validatePin: expected pin name and type as string"); endif pininfo = obj.get_pin(pin); # use type length, so can find spiX_XXXX etc when looking for SPI idx = find( cellfun(@(x) strncmpi(x, type, length(type)), pininfo.modes), 1); # check with mode allowed to that pin # if isnt, error if isempty(idx) error ("@arduino.validatePin: invalid mode for this pin"); endif endfunction %!shared ar %! ar = arduino(); %!test %! validatePin(ar, "d1", "digital"); %! validatePin(ar, "a0", "digital"); %! validatePin(ar, "a0", "analog"); %!error validatePin(ar,"d1", "analog"); %!error validatePin() %!error validatePin(ar) %!error validatePin(ar, "d1") %!error validatePin(ar, "xd1", "digital") arduino-0.4.0/inst/@arduino/version.m0000644000000000000000000000304313470770202015725 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{ver} =} version (@var{ar}) ## Get version of library code installed on arduino board ## ## @subsubheading Inputs ## @var{ar} - the arduino object of the connection to an arduino board. ## ## @subsubheading Outputs ## @var{ver} - version string in format of X.Y.Z. ## ## @seealso{arduino} ## ## @end deftypefn function retval = version (obj) persistent ARDUINO_VERSION = 20; if nargin != 1 error ("@arduino.version expects no arguments"); endif [dataout, status] = __sendCommand__ (obj, 0, ARDUINO_VERSION, []); if status != 0 error ("@arduino.version: failed err=%d - %s", status, char(dataout)); else retval = sprintf("%d.%d.%d", dataout(1), dataout(2), dataout(3)); endif endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! assert(~isempty(version(ar))); arduino-0.4.0/inst/@arduino/writeDigitalPin.m0000644000000000000000000000401413470770202017336 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {} writeDigitalPin (@var{ar}, @var{pin}, @var{value}) ## Write digital value to a digital I/O pin. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object. ## ## @var{pin} - string name of the pin to write to. ## ## @var{value} - the logical value (0, 1, true false) to write to the pin. ## ## If pin was unconfigured before using, pin is set into digital mode. ## ## @subsubheading Example ## @example ## @code{ ## a = arduino(); ## writeDigitalPin(a,'D5',1); ## } ## @end example ## ## @seealso{arduino, readDigitalPin} ## ## @end deftypefn function writeDigitalPin (obj, pin, value) if nargin != 3 error ("@arduino.writeDigitalPin: expected pin name and value"); endif if !ischar(pin) && !isnumeric(pin) error ("@arduino.writeDigitalPin: expected pin name as string"); endif if (!isnumeric(value) && !islogical(value)) || (value != 1 && value != 0) error ("@arduino.writeDigitalPin: expected value as logical or 0 or 1"); endif __digitalPin__(obj,pin,value); endfunction %!shared ar %! ar = arduino(); %!test %! writeDigitalPin(ar,"d2", 1); %! writeDigitalPin(ar,"d2", 0); %! writeDigitalPin(ar,"d2", false); %! writeDigitalPin(ar,"d2", true); %! writeDigitalPin(ar,2, true); %!error writeDigitalPin() %!error writeDigitalPin(ar) %!error writeDigitalPin(ar, "d2", 1, 1) %!error writeDigitalPin(ar, "nopin", 1) arduino-0.4.0/inst/@arduino/writePWMDutyCycle.m0000644000000000000000000000505413470770202017610 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {} writePWMDutyCyle (@var{ar}, @var{pin}, @var{value}) ## Set pin to output a square wave with a specified duty cycle. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{pin} - pin to write to. ## ## @var{value} - duty cycle value where 0 = off, 0.5 = 50% on, 1 = always on. ## ## @subsubheading Example ## @example ## @code{ ## a = arduino(); ## writePWMDutyCycle(a,'D5',0.5); ## } ## @end example ## ## @seealso{arduino, writePWMVoltage} ## ## @end deftypefn function writePWMDutyCycle (obj, pin, value) ARDUINO_PWM = 5; if nargin < 3 error ("@arduino.writePWMDutyCycle: expected pin name and value"); endif if !ischar(pin) && !isnumeric(pin) error ("@arduino.writePWMDutyCycle: expected pin name as string"); endif if (!isnumeric(value) || value > 1.0 || value < 0) error ("@arduino.writePWMDutyCycle: expected value between 0 .. 1"); endif pininfo = obj.get_pin(pin); # first use ? if strcmp(pininfo.mode, "unset") configurePin(obj, pin, "pwm") else [pinstate, pinmode] = pinStateMode(pininfo.mode); if !strcmp(pinmode, "pwm") error ("@arduino.PWMDutyCycle: pin is in incompatable mode"); endif endif val = 255*value; datain = uint8([pininfo.id val]); [dataout, status] = __sendCommand__ (obj, 0, ARDUINO_PWM, datain); if status != 0 error ("@arduino.writePWMDutyCycle: failed to set pin state err=%d - %s", status, char(dataout)); endif endfunction %!shared ar, pwmpin %! ar = arduino(); %! pwmpin = getPinsFromTerminals(ar, getPWMTerminals(ar)){1}; %!test %! writePWMDutyCycle(ar, pwmpin, 0.5); %!error writePWMDutyCycle(); %!error writePWMDutyCycle(ar) %!error writePWMDutyCycle(ar, pwmpin) %!error writePWMDutyCycle(ar, "xd1", 1) %!error writePWMDutyCycle(ar, pwmpin, -1) %!error writePWMDutyCycle(ar, pwmpin, 1.1) %!test %! writePWMDutyCycle(ar, pwmpin, 0.0); arduino-0.4.0/inst/@arduino/writePWMVoltage.m0000644000000000000000000000407313470770202017304 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {} writePWMVoltage (@var{ar}, @var{pin}, @var{voltage}) ## Emulate an approximate voltage out of a pin using PWM. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{pin} - pin to write to. ## ## @var{voltage} - voltage to emulate with PWM, between 0 - 5.0 ## ## @subsubheading Example ## @example ## @code{ ## a = arduino(); ## writePWMVoltage(a,'D5',1.0); ## } ## @end example ## ## @seealso{arduino, writePWMDutyCycle} ## @end deftypefn function writePWMVoltage (obj, pin, value) if nargin < 3 error ("@arduino.writePWMVoltage: expected pin name and value"); endif # TODO: need look at board type for what voltage range is allowed # and convert maxvolts = obj.board_voltage(); if !isnumeric(value) || value < 0 || value > maxvolts error('writePWMVoltage: value must be between 0 and %f', maxvolts); endif # assuming here for now 0 .. 5V is linear to 0 - 100% pwm val = value/maxvolts; writePWMDutyCycle(obj, pin, val); endfunction %!shared ar, pwmpin %! ar = arduino(); %! pwmpin = getPinsFromTerminals(ar, getPWMTerminals(ar)){1}; %!test %! writePWMVoltage(ar, pwmpin, 5.0); %!error writePWMVoltage(); %!error writePWMVoltage(ar) %!error writePWMVoltage(ar, pwmpin) %!error writePWMVoltage(ar, "xd1", 1) %!error writePWMVoltage(ar, pwmpin, -1) %!error writePWMVoltage(ar, pwmpin, 5.1) %!test %! writePWMVoltage(ar, pwmpin, 0.0); arduino-0.4.0/inst/@i2cdev/0000755000000000000000000000000013470770202013575 5ustar0000000000000000arduino-0.4.0/inst/@i2cdev/display.m0000644000000000000000000000230013470770202015413 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {} display (@var{dev}) ## Display i2cdev object. ## ## @subsubheading Inputs ## @var{dev} - i2cdev object ## ## @seealso{i2cdev} ## @end deftypefn function display (p) printf ("%s = \n", inputname (1)); printf (" arduino i2cdev object with fields of: \n\n"); printf (" address = %d (0x%02X)\n", p.address, p.address); printf (" bus = %d\n", p.bus); printf (" bitorder = %s\n", p.bitorder); printf (" pins = "); for i=1:2 printf("%s(%s) ", p.pins{i}.name, p.pins{i}.func) endfor printf("\n"); % Mode, Bitrate, Bitorder printf ("\n"); endfunction arduino-0.4.0/inst/@i2cdev/i2cdev.m0000644000000000000000000001077013470770202015134 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{dev} =} i2cdev (@var{ar}, @var{address}) ## @deftypefnx {} {@var{dev} =} i2cdev (@var{ar}, @var{address}, @var{propname}, @var{propvalue}) ## Create an i2cdev object to communicate to the i2c port on a connected arduino. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{address} - address to use for device on I2C bus. ## ## @var{propname}, @var{propvalue} - property name/value pair for values to pass to devices. ## ## Currently known properties: ## @table @asis ## @item bus ## bus number (when arduino board supports multiple I2C buses) ## with value of 0 or 1. ## @end table ## ## @subsubheading Outputs ## @var{dev} - new created i2cdev object. ## ## @subsubheading Properties ## The i2cdev object has the following public properties: ## @table @asis ## @item parent ## The parent (arduino) for this device ## @item pins ## pins used by this object ## @item bus ## bus used for created object ## @item address ## I2C address set for object ## @end table ## ## @seealso{arduino} ## @end deftypefn function p = i2cdev(varargin) ARDUINO_I2C_CONFIG = 1; if nargin < 2 error("expects arduino object and address"); endif ar = varargin{1}; address = varargin{2}; bus = 0; bitorder = 'msbfirst'; if !isnumeric(address) || address < 0 || address > 255 error("expected address between 0 .. 255"); endif if mod(nargin, 2) != 0 error ("arduino: expected property name, value pairs"); endif if !iscellstr (varargin(3:2:nargin)) error ("arduino: expected property names to be strings"); endif for i = 3:2:nargin propname = tolower(varargin{i}); propvalue = varargin{i+1}; # printf("%s = %s\n", propname, propvalue); if strcmp (propname, "bus") if !isnumeric(propvalue) || propvalue < 0 error("bus should be a positive number") endif bus = propvalue; elseif strcmp (propname, "bitorder") if !ischar(propvalue) error("bitorder should be a 'lsbfirst' or 'msbfirst'"); endif propvalue = tolower(propvalue); if propvalue != 'lsbfirst' && propvalue != 'msbfirst' error("bitorder should be a 'lsbfirst' or 'msbfirst'"); endif bitorder = propvalue; endif endfor if (!isa (ar, "arduino")) error("expects arduino object"); endif p.address = address; p.arduinoobj = ar; p.bus = bus; p.bitorder = bitorder; % TODO on calling setup with the CS pin, returns back the other pins that we then setup as used ? % sendCommand # there only ever one port ??? with CS able to be completely independant ?? name = "i2c_"; if bus > 0 name = ["i2c" num2str(bus) "_"]; endif p.pins = ar.get_group(name); if numel(p.pins) != 2 error("expected 2 I2C pins but only have %d", numel(p.pins) ) endif # set pins try for i=1:2 configurePin(ar, p.pins{i}.name, "i2c") endfor # TODO: bitrate, order etc bitorder = 0; [tmp, sz] = sendCommand(p.arduinoobj, "i2c", ARDUINO_I2C_CONFIG, [bus 1]); catch for i=1:2 configurePinResource(ar, p.pins{i}.name, p.pins{i}.owner, p.pins{i}.mode, true) configurePin(ar, p.pins{i}.name, p.pins{i}.mode) endfor rethrow (lasterror) end_try_catch p = class (p, "i2cdev"); endfunction %!shared arduinos %! arduinos = scanForArduinos(1); %!assert(numel(arduinos), 1); %!test %! ar = arduino(); %! assert(!isempty(ar)); %! pins = getI2CTerminals(ar); %! # check pins not allocated %! for i=1:numel(pins) %! p = pins{i}; %! assert(configurePin(ar, p), "unset") %! endfor %! i2c = i2cdev(ar, 10); %! assert(!isempty(i2c)); %! assert(i2c.address, 10); %! assert(i2c.bitorder, 'msbfirst'); %! # check pins allocated %! for i=1:numel(pins) %! p = pins{i}; %! assert(!strcmpi(configurePin(ar, p), "unset")) %! endfor %! clear i2c %! # TODO check pins unallocated when we have implemented a free of shared spi bus %! #for i=1:numel(pins) %! # p = pins{i}; %! # assert(configurePin(ar, p), "unset") %! #endfor arduino-0.4.0/inst/@i2cdev/read.m0000644000000000000000000000514113470770202014667 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{data} =} read (@var{dev}, @var{numbytes}) ## @deftypefnx {} {@var{data} =} read (@var{dev}, @var{numbytes}, @var{precision}) ## Read a specified number of bytes from a i2cdev object ## using optional precision for bytesize. ## ## @subsubheading Inputs ## @var{dev} - connected i2c device opened using i2cdev ## ## @var{numbytes} - number of bytes to read. ## ## @var{precision} - Optional precision for the output data read data. ## Currently known precision values are uint8 (default), int8, uint16, int16 ## ## @subsubheading Outputs ## @var{data} - data read from i2cdevice ## ## @seealso{arduino, i2cdev} ## @end deftypefn function out = read (dev, numbytes, precision) persistent ARDUINO_I2C_READ = 3; persistent endian; if isempty(endian) [~, ~, endian] = computer (); endif if nargin < 2 || nargin > 3 print_usage (); endif if ~isnumeric (numbytes) error("@i2c.read: expected numbytes to be a number"); endif if nargin == 3 if !ischar (precision) error("@i2c.read: expected presision to be a string"); endif precision = tolower (precision); if !strcmp (precision, "uint8") && !strcmp (precision, "int8") && !strcmp (precision, "uint16") && !strcmp(precision, "int16") error ("@i2c.read: expected pression to be (u)int8 or (u)int16 string"); endif else precision = 'uint8'; endif datasize = 1; if (strcmp (precision,'uint16') || strcmp (precision,'int16')) datasize = 2; endif % read request [tmp, sz] = sendCommand (dev.arduinoobj, "i2c", ARDUINO_I2C_READ, [dev.address numbytes*datasize]); # skip address and return the data out = typecast (uint8(tmp(2:end)), precision); if (strcmp (precision,'uint16') || strcmp (precision,'int16')) sz = sz/2; if (endian == 'L' && strcmp (dev.bitorder,'msbfirst')) || (endian == 'B' && strcmp (dev.bitorder, 'lsbfirst')) out = swapbytes (out); endif else if (strcmp (precision, 'int8')) out = int8(tmp(2:end)) else out = tmp(2:end); endif endif endfunction arduino-0.4.0/inst/@i2cdev/readRegister.m0000644000000000000000000000670013470770202016376 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{data} =} readRegister (@var{dev}, @var{reg}, @var{numbytes}) ## @deftypefnx {} {@var{data} =} readRegister (@var{dev}, @var{reg}, @var{numbytes}, @var{precision}) ## Read a specified number of bytes from a register of an i2cdev object ## using optional precision for bytesize. ## ## @subsubheading Inputs ## @var{dev} - connected i2c device opened using i2cdev ## ## @var{reg} - registry value number ## ## @var{numbytes} - number of bytes to read. ## ## @var{precision} - Optional precision for the output data read data. ## Currently known precision values are uint8 (default), int8, uint16, int16 ## ## @subsubheading Output ## @var{data} - data read from device. ## ## @seealso{arduino, i2cdev} ## @end deftypefn function out = readRegister(dev, reg, numbytes, precision) persistent endian; if isempty(endian) [~, ~, endian] = computer (); endif persistent ARDUINO_I2C_READREG = 5; if nargin < 3 || nargin > 4 print_usage (); endif if ~isnumeric (reg) error ("@i2c.readRegister: expected reg to be a number"); endif if ~isnumeric (numbytes) error ("@i2c.readRegister: expected numbytes to be a number"); endif if nargin == 4 if !ischar (precision) error ("@i2c.readRegister: expected presision to be a string"); endif precision = tolower (precision); if !strcmp (precision, "uint8") && !strcmp (precision, "int8") && !strcmp (precision, "uint16") && !strcmp(precision, "int16") error ("@i2c.readRegister: expected pression to be (u)int8 or (u)int16 string"); endif else precision = 'uint8'; endif if (strcmp (precision,'uint16')) reg = uint16(reg); if (endian == 'L' && strcmp (dev.bitorder,'msbfirst')) || (endian == 'B' && strcmp (dev.bitorder, 'lsbfirst')) reg = swapbytes (reg); endif reg = typecast (reg, 'uint8'); regsz = 2; elseif (strcmp (precision,'int16')) reg = int16(reg); if (endian == 'L' && strcmp (dev.bitorder,'msbfirst')) || (endian == 'B' && strcmp (dev.bitorder, 'lsbfirst')) reg = swabytes (reg); endif reg = typecast (reg, 'uint8'); regsz = 2; else if (strcmp (precision, 'int8')) reg = typecast (int8(reg), 'uint8'); else reg = typecast (uint8(reg), 'uint8'); endif regsz = 1; endif % read reg [tmp, sz] = sendCommand (dev.arduinoobj, "i2c", ARDUINO_I2C_READREG, [dev.address regsz reg numbytes*regsz]); # skip address and and regsz and return the data out = tmp(3:end); % convert the outputs if (strcmp (precision,'uint16') || strcmp (precision,'int16')) sz = sz/2; out = typecast (out, precision); if (endian == 'L' && strcmp (dev.bitorder,'msbfirst')) || (endian == 'B' && strcmp (dev.bitorder, 'lsbfirst')) out = swapbytes (out); endif else if (strcmp (precision, 'int8')) out = int8(out); else out = uint8(out); endif endif endfunction arduino-0.4.0/inst/@i2cdev/subsref.m0000644000000000000000000000267113470770202015432 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{val} = } subsref (@var{dev}, @var{sub}) ## subref for i2cdev ## ## @seealso{i2cdev} ## @end deftypefn function val = subsref (p, s) if isempty(s) error ("i2cdev.subsref missing index"); endif if s(1).type == "." fld = tolower(s(1).subs); switch (fld) case "pins" val = {}; for i = 1:numel(p.pins) val{end+1} = p.pins{i}.name; endfor case "parent" val = p.arduinoobj; case "bus" val = p.bus; case "address" val = p.address; case "bitorder" val = p.bitorder; otherwise error ("i2cdev.subsref invalid property '%s'", fld); endswitch else error("unimplemented i2cdev.subsref type"); endif endfunction %!test %! ar = arduino(); %! i2c = i2cdev (ar, 0x22); %! assert (isarduino(i2c.parent)) %! assert (i2c.address, 0x22) %! assert (numel(i2c.pins) == 2) %! fail ("i2c.invalid") arduino-0.4.0/inst/@i2cdev/write.m0000644000000000000000000000521413470770202015107 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {} write (@var{dev}, @var{datain}) ## @deftypefnx {} {} write (@var{dev}, @var{datain}, @var{precision}) ## Write data to a i2cdev object ## using optional precision for the data byte used for the data. ## ## @subsubheading Inputs ## @var{dev} - connected i2c device opened using i2cdev ## ## @var{datain} - data to write to device. Datasize should not exceed the constraints ## of the data type specified for the precision. ## ## @var{precision} - Optional precision for the input write data. ## Currently known precision values are uint8 (default), int8, uint16, int16 ## ## @seealso{arduino, i2cdev, read} ## @end deftypefn function write (dev, datain, precision) persistent endian; if isempty(endian) [~, ~, endian] = computer (); endif persistent ARDUINO_I2C_WRITE = 2; if nargin < 2 || nargin > 3 print_usage (); endif if nargin == 3 if !ischar (precision) error ("@i2c.write: expected presision to be a atring"); endif precision = tolower (precision); if !strcmp (precision, "uint8") && !strcmp (precision, "int8") && !strcmp (precision, "uint16") && !strcmp(precision, "int16") error ("@i2c.write: expected pression to be (u)int8 or (u)int16 string"); endif else precision = 'uint8'; endif if (strcmp (precision,'uint16')) datain = uint16(datain); if (endian == 'L' && strcmp (dev.bitorder,'msbfirst')) || (endian == 'B' && strcmp (dev.bitorder, 'lsbfirst')) datain = swapbytes (datain); endif datain = typecast (datain, 'uint8'); elseif (strcmp (precision,'int16')) datain = int16(datain); if (endian == 'L' && strcmp (dev.bitorder,'msbfirst')) || (endian == 'B' && strcmp (dev.bitorder, 'lsbfirst')) datain = swapbytes (datain); endif datain = typecast (datain, 'uint8'); else if (strcmp (precision, 'int8')) datain = typecast (int8(datain), 'uint8'); else datain = typecast (uint8(datain), 'uint8'); endif endif % write request [tmp, sz] = sendCommand (dev.arduinoobj, "i2c", ARDUINO_I2C_WRITE, [dev.address datain]); endfunction arduino-0.4.0/inst/@i2cdev/writeRegister.m0000644000000000000000000000623413470770202016617 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {} writeRegister (@var{dev}, @var{reg}, @var{datain}) ## @deftypefnx {} {} writeRegister (@var{dev}, @var{dev}, @var{datain}, @var{precision}) ## Write data to i2cdev object at a given registry position ## using optional precision for the data byte used for the data. ## ## @subsubheading Inputs ## @var{dev} - connected i2c device opened using i2cdev ## ## @var{reg} - registry position to write to. ## ## @var{datain} - data to write to device. Datasize should not exceed the constraints ## of the data type specified for the precision. ## ## @var{precision} - Optional precision for the input write data. ## Currently known precision values are uint8 (default), int8, uint16, int16 ## ## @seealso{arduino, i2cdev, read} ## @end deftypefn function writeRegister (dev, reg, datain, precision) persistent endian; if isempty (endian) [~, ~, endian] = computer (); endif persistent ARDUINO_I2C_WRITEREG = 4; if nargin < 3 || nargin > 4 print_usage (); endif if ~isnumeric (reg) error("@i2c.writeRegister: expected reg to be a number"); endif if nargin == 4 if !ischar (precision) error ("@i2c.writeRegister: expected precision to be a string"); endif precision = tolower (precision); if !strcmp (precision, "uint8") && !strcmp (precision, "int8") && !strcmp (precision, "uint16") && !strcmp(precision, "int16") error("@i2c.writeRegister: expected pression to be (u)int8 or (u)int16 string"); endif else precision = 'uint8'; endif % todo convert reg, data in to correct format if (strcmp (precision,'uint16')) reg = uint16 (reg); datain = uint16 (datain); if (endian == 'L' && strcmp (dev.bitorder,'msbfirst')) || (endian == 'B' && strcmp (dev.bitorder, 'lsbfirst')) reg = swapbytes (reg); datain = swapbytes (datain); endif reg = typecast (reg, 'uint8'); datain = typecast (datain, 'uint8'); elseif (strcmp (precision,'int16')) reg = uint16 (reg); datain = int16 (datain); if (endian == 'L' && strcmp (dev.bitorder,'msbfirst')) || (endian == 'B' && strcmp(dev.bitorder, 'lsbfirst')) reg = swabytes (reg); datain = swapbytes (datain); endif reg = typecast (reg, 'uint8'); datain = typecast (datain, 'uint8'); else if (strcmp (precision, 'int8')) reg = typecast (int8(reg), 'uint8'); datain = typecast (int8(datain), 'uint8'); else reg = typecast (uint8(reg), 'uint8'); datain = typecast (uint8(datain), 'uint8'); endif endif sendCommand (dev.arduinoobj, "i2c", ARDUINO_I2C_WRITEREG, [dev.address reg datain]); endfunction arduino-0.4.0/inst/@rotaryEncoder/0000755000000000000000000000000013470770202015241 5ustar0000000000000000arduino-0.4.0/inst/@rotaryEncoder/display.m0000644000000000000000000000220213470770202017060 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} display (@var{obj}) ## Display the rotary encoder object in a verbose way, ## ## @subsubheading Inputs ## @var{obj} - the arduino rotary encoder object created with rotaryEncoder ## ## @seealso{rotaryEncoder} ## @end deftypefn function retval = display (obj) printf ("%s = \n", inputname (1)); printf (" arduino rotary object with fields of: \n"); printf (" pulsesperrevolution = ") disp(obj.ppr); for i=1:numel(obj.pins) pin = obj.pins{i}; printf (" %s = %s\n", pin.func, pin.name) endfor endfunction arduino-0.4.0/inst/@rotaryEncoder/readCount.m0000644000000000000000000000476613470770202017360 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {[@var{count}, @var{time}] =} readCount (@var{obj}) ## @deftypefnx {} {[@var{count}, @var{time}] =} readCount (@var{obj}, @var{name}, @var{value}) ## read count value from the rotary encoder. ## ## subsubheading Inputs ## @var{obj} - rotary encoder object created with rotaryEncoder call. ## ## @var{name}, @var{value} - optional name,value pairs ## ## Valid option name pairs currently are: ## @table @asis ## @item reset ## Reset the count after reading (if true) ## @end table ## ## @subsubheading Outputs ## @var{count} - returned count read from the encoder. ## ## @var{time} - seconds since arduino started ## ## @seealso{rotaryEncoder, resetCount} ## @end deftypefn function [value, time] = readCount(obj, reset, resetvalue) persistent ARDUINO_ROTARYENCODER_READCOUNT = 2; if nargin != 1 && nargin != 3 error ("arduino: expected rotaryencoder object and optional property name, value pairs"); endif if nargin != 3 reset = "reset"; resetvalue = false; endif if !strcmpi (reset, "reset") error ("arduino: expected property name of 'reset'"); endif if !(isnumeric(resetvalue) || islogical(resetvalue)) || (resetvalue != 0 && resetvalue != 1) error ("arduino: expected resetvalue of 0 or 1"); endif # attempt to clock out precision bits [tmp, sz] = sendCommand(obj.parent, "rotaryencoder", ARDUINO_ROTARYENCODER_READCOUNT, [obj.id resetvalue]); value = typecast(uint16(tmp(2))*256 + uint16(tmp(3)), 'int16'); time = uint32(tmp(4))*(256*256*256) + uint32(tmp(5))*(256*256) + uint32(tmp(6))*256 + uint32(tmp(7)); time = time/1000.0; endfunction %!test %! ar = arduino (); %! e = rotaryEncoder(ar, "d2","d3"); %! readCount(e); %! readCount(e, "reset", 0); %! readCount(e, "reset", 1); %! readCount(e, "reset", true); %!error readCount(); arduino-0.4.0/inst/@rotaryEncoder/readSpeed.m0000644000000000000000000000314013470770202017311 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{speed} =} readSpeed (@var{obj}) ## read rotational speed from the rotary encoder. ## ## @subsubheading Inputs ## @var{obj} - rotary encoder object created with rotaryEncoder call. ## ## @subsubheading Outputs ## @var{speed} - returned speed in revolutions per minute read from the encoder. ## ## @seealso{rotaryEncoder, resetCount} ## @end deftypefn function value = readSpeed(obj, varargin) persistent ARDUINO_ROTARYENCODER_READSPEED = 3; # attempt to clock out precision bits [tmp, sz] = sendCommand(obj.parent, "rotaryencoder", ARDUINO_ROTARYENCODER_READSPEED, [obj.id]); value = typecast(uint16(tmp(2))*256 + uint16(tmp(3)), 'int16'); value = (double(value)/1000.0)*60; # cnts per min if obj.ppr > 0 value = value / obj.ppr; else value = 0; endif endfunction %!test %! ar = arduino (); %! e = rotaryEncoder(ar, "d2","d3"); %! readSpeed(e); arduino-0.4.0/inst/@rotaryEncoder/resetCount.m0000644000000000000000000000303413470770202017552 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} reset (@var{obj}) ## @deftypefnx {} reset (@var{obj}, @var{cnt}) ## reset the rotary encoder count values ## ## @subsubheading Inputs ## @var{obj} - the rotaryEncoder object ## ## @var{cnt} - optional count value to reset to ## ## @seealso{rotaryEncoder, readCount} ## @end deftypefn function resetCount(obj, cnt) persistent ARDUINO_ROTARYENCODER_RESETCOUNT = 0; if nargin < 2 cnt = 0; endif if cnt < -32000 || cnt > 32000 error ("@rotaryEncoder.resetCount: reset count out of supported range"); endif cnt = uint16(cnt); [tmp, sz] = sendCommand(obj.parent, "rotaryencoder", ARDUINO_ROTARYENCODER_RESETCOUNT, [obj.id bitand(bitshift(cnt, -8),255) bitand(cnt,255)]); endfunction %!test %! ar = arduino (); %! e = rotaryEncoder(ar, "d2","d3"); %! resetCount(e); %! resetCount(e, 10); arduino-0.4.0/inst/@rotaryEncoder/rotaryEncoder.m0000644000000000000000000001054013470770202020237 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{obj} =} rotaryEncoder (@var{ar}, @var{chanApin}, @var{chanBpin}) ## @deftypefnx {} {@var{obj} =} rotaryEncoder (@var{ar}, @var{chanApin}, @var{chanBpin}, @var{ppr}) ## Create a rotaryEncoder object controlled by the input pins. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object. ## ## @var{chanApin} - pin used for channel A ## ## @var{chanBpin} - pin used for channel B ## ## @var{ppr} - count of encoder pulsed required for a full revolution of the encoder. ## ## @subsubheading Outputs ## @var{obj} - created rotary encoder object ## ## @subsubheading Example ## @example ## a = arduino (); ## enc = rotaryEncoder(a, "d2", "d3", 180); ## @end example ## ## @subsubheading Properties ## The rotaryEncoder object has the following public properties: ## @table @asis ## @item parent ## The parent (arduino) for this device ## @item pins ## pins used by this object ## @item ppr ## Number of pulses used per rotation ## @end table ## ## @seealso{arduino} ## @end deftypefn function obj = rotaryEncoder(ar, pinA, pinB, ppr) persistent ARDUINO_ROTARYENCODER_CONFIG = 1; if (nargin == 1 && isa (ar, "rotaryEncoder")) register = ar; # Copy constructor elseif nargin < 3 error ('rotaryEncoder: Expected pinA and pinB'); else p.parent = ar; pins = {}; pins{end+1} = ar.get_pin(pinA); pins{end}.func = "channela"; # pin used also to address this obj p.id = pins{1}.id; pins{end+1} = ar.get_pin(pinB); pins{end}.func = "channelb"; if nargin < 4 ppr = []; endif if isempty(ppr) ppr = 0; endif if ! isnumeric(ppr) || ppr < 0 error('rotaryEncoder: ppr should be a positive number') endif # verify pins support digital i/o for i = 1:numel(pins) pin = pins{i}.name; validatePin(ar, pin, "digital"); endfor p.pins = pins; p.ppr = ppr; name = sprintf("encoder-%d", p.id); count = getResourceCount(ar,name); if count > 0 error ("@rotaryEncoder.rotaryEncoder: already in use"); endif try for i=1:numel(pins) pin = pins{i}.name; configurePin(ar, pin, "pullup"); endfor [tmp, sz] = sendCommand(ar, "rotaryencoder", ARDUINO_ROTARYENCODER_CONFIG, [p.id 1 pins{2}.id]); incrementResourceCount(ar, name); catch # on error, restore pin state for i=1:numel(pins) pin = pins{i}; configurePinResource(ar, pin.name, pin.owner, pin.mode, true) configurePin(ar, pin.name, pin.mode) endfor rethrow (lasterror); end_try_catch # set clean up function p.cleanup = onCleanup (@() cleanupEncoder (ar, name, pins)); obj = class (p, "rotaryEncoder"); endif endfunction # private clean up allocated encoder pins function cleanupEncoder(ar, name, pins) decrementResourceCount(ar, name); for i=1:numel(pins) pin = pins{i}; configurePinResource(ar, pin.name, pin.owner, pin.mode, true) configurePin(ar, pin.name, pin.mode) endfor endfunction %!shared ar %! ar = arduino(); %!test %! assert(configurePin(ar, "d2"), "unset") %! assert(configurePin(ar, "d3"), "unset") %! enc = rotaryEncoder(ar, "d2", "d3"); %! assert (isa (enc, "rotaryEncoder")) %! assert(!strcmpi(configurePin(ar, "d2"), "unset")) %! assert(!strcmpi(configurePin(ar, "d3"), "unset")) %! clear enc %! assert(configurePin(ar, "d2"), "unset") %! assert(configurePin(ar, "d3"), "unset") %!test %! enc = rotaryEncoder(ar, "d2", "d3", 100); %! assert (isa (enc, "rotaryEncoder")) %!test %! enc = rotaryEncoder(ar, "d2", "d3"); %! fail ('rotaryEncoder(ar, "d2", "d3");', "already in use"); %!error rotaryEncoder(ar); %!error rotaryEncoder(ar, "d2"); arduino-0.4.0/inst/@rotaryEncoder/subsref.m0000644000000000000000000000275713470770202017103 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{val} = } subsref (@var{dev}, @var{sub}) ## subref for rotaryEncoder ## ## @seealso{rotaryEncoder} ## @end deftypefn function val = subsref (p, s) if isempty(s) error ("rotaryEncoder.subsref missing index"); endif if s(1).type == "." fld = tolower(s(1).subs); switch (fld) case "pins" val = {}; for i = 1:numel(p.pins) val{end+1} = p.pins{i}.name; endfor case "parent" val = p.parent; case "ppr" val = p.ppr; otherwise error ("rotaryEncoder.subsref invalid property '%s'", fld); endswitch else error("unimplemented rotaryEncoder.subsref type"); endif if (numel (s) > 1) val = subsref (val, s(2:end)); endif endfunction %!test %! ar = arduino(); %! r = rotaryEncoder (ar, "d2", "d3", 100); %! assert (isarduino(r.parent)) %! assert (ar.port, r.parent.port) %! assert (r.ppr, 100) %! assert (numel(r.pins) == 2) %! fail ("r.invalid") arduino-0.4.0/inst/@servo/0000755000000000000000000000000013470770202013557 5ustar0000000000000000arduino-0.4.0/inst/@servo/display.m0000644000000000000000000000206613470770202015406 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {} display (@var{dev}) ## Display servo object. ## ## @subsubheading Inputs ## @var{dev} - device to display ## ## @seealso{servo} ## @end deftypefn function display (this) printf ("%s = \n", inputname (1)); printf (" arduino servo object with fields of: \n\n"); printf (" pins = %s\n", this.pins{1}.name ); printf (" minpulseduration = %f\n", this.minpulseduration); printf (" maxpulseduration = %f\n", this.maxpulseduration); endfunction arduino-0.4.0/inst/@servo/private/0000755000000000000000000000000013470770202015231 5ustar0000000000000000arduino-0.4.0/inst/@servo/private/__servoPosition__.m0000644000000000000000000000321713470770202021071 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} __servoPosition__ (@var{obj}, @var{value}) ## Private function to get/set servo position ## @end deftypefn function out = __servoPosition__ (obj, value) persistent ARDUINO_SERVO_POSITION = 0; out = 0; ar = obj.arduinoobj; pininfo = obj.pins{1}; diff = obj.maxpulseduration - obj.minpulseduration; assert (diff >= 0); if nargin == 2 if !isnumeric (value) || value < 0 || value > 1.0 error("@servo.writePosition: value must be between 0 and 1"); endif # convert 0 - 1 to min - max pulse value = obj.minpulseduration + (diff*value); intval = uint16(value*1e6); datain = [ bitshift(intval,-8) bitand(intval, 255)]; [tmp, sz] = sendCommand (ar, "servo", ARDUINO_SERVO_POSITION, [pininfo.terminal datain]); else [tmp, sz] = sendCommand (ar, "servo", ARDUINO_SERVO_POSITION, [pininfo.terminal]); value = uint16(tmp(2))*256 + uint16(tmp(3)); value = double(value)/1e6; value = value - obj.minpulseduration; out = value/diff; endif endfunction arduino-0.4.0/inst/@servo/readPosition.m0000644000000000000000000000250613470770202016400 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{position} = } readPosition (@var{servo}) ## Read the position of a servo ## ## @subsubheading Inputs ## @var{servo} - servo object created from arduino.servo. ## ## @subsubheading Outputs ## @var{position} - value between 0 .. 1 for the current servo position, ## where 0 is the servo min position, 1 is the servo maximum position. ## ## @seealso{servo, writePosition} ## @end deftypefn function value = readPosition (obj) value = __servoPosition__(obj); endfunction %!shared ar %! ar = arduino(); %!test %! s = servo(ar, "d9", "minpulseduration", 1.0e-3, "maxpulseduration", 2e-3); %! writePosition(s, 1); %! assert(readPosition(s), 1); %! writePosition(s, 0); %! assert(readPosition(s), 0); %!error readPosition(); arduino-0.4.0/inst/@servo/servo.m0000644000000000000000000001030113470770202015066 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{obj} = } servo (@var{arduinoobj}, @var{pin}) ## @deftypefnx {} {@var{obj} = } servo (@var{arduinoobj}, @var{pin}, @var{propertyname}, @var{propertyvalue}) ## Create a servo object using a specified pin on a arduino board. ## ## @subsubheading Inputs ## @var{obj} - servo object ## ## @var{arduinoobj} - connected arduino object ## ## @var{propertyname}, @var{propertyvalue} - name value pairs for properties to pass ## to the created servo object. ## ## Current properties are: ## @table @asis ## @item minpulseduration ## min PWM pulse value in seconds. ## @item maxpulseduration ## max PWM pulse value in seconds. ## @end table ## ## @subsubheading Outputs ## @var{obj} - created servo object. ## ## @subsubheading Example ## @example ## # create arduino connection ## ar = arduino(); ## # create hobby servo (1 - 2 ms pulse range) ## servo = servo(ar, "d9", "minpulseduration", 1.0e-3, "maxpulseduration", 2e-3); ## # center the servo ## writePosition(servo, 0.5); ## @end example ## ## @subsubheading Properties ## The servo object has the following public properties: ## @table @asis ## @item parent ## The parent (arduino) for this device ## @item pins ## pins used by this object ## @item minpulseduration ## minpusleduration set for object ## @item maxpulseduration ## maxpulseduration set for object ## @end table ## ## @seealso{arduino, readPosition, writePosition} ## @end deftypefn function this = servo(varargin) persistent ARDUINO_SERVO_CONFIG = 1; if nargin < 2 error("expects arduino object and servo pin"); endif ar = varargin{1}; pin = varargin{2}; this.arduinoobj = []; this.minpulseduration = 5.44e-04; this.maxpulseduration = 2.40e-03; this.pins = {}; if mod (nargin, 2) != 0 error ("servo: expected property name, value pairs"); endif if !iscellstr (varargin(3:2:nargin)) error ("servo: expected property names to be strings"); endif for i = 3:2:nargin propname = tolower (varargin{i}); propvalue = varargin{i+1}; #printf("%s = %s\n", propname, propvalue); if strcmp(propname, "minpulseduration") if !isnumeric (propvalue) error ("servo: minpulseduration should be a number"); endif this.minpulseduration = propvalue; elseif strcmp(propname, "maxpulseduration") if !isnumeric (propvalue) error ("servo: maxpulseduration should be a number"); endif this.maxpulseduration = propvalue; endif endfor if (!isa (ar, "arduino")) error ("servo: expects arduino object"); endif pininfo = getPinInfo (ar, pin); this.arduinoobj = ar; validatePin (ar, pin, 'pwm'); configurePin (ar, pin, "pwm"); this.pins{end+1} = pininfo; sendCommand (ar, "servo", ARDUINO_SERVO_CONFIG, [pininfo.terminal]); # set clean up function this.cleanup = onCleanup (@() cleanupServo (ar, pininfo)); this = class (this, "servo"); endfunction # private clean up allocated pins function cleanupServo(ar, pin) configurePinResource(ar, pin.name, pin.owner, pin.mode, true); configurePin(ar, pin.name, pin.mode); endfunction %!shared ar %! ar = arduino(); %!test %! assert(configurePin(ar, "d9"), "unset") %! s = servo(ar, "d9"); %! assert(!isempty(s)); %! assert(isa(s, "servo")); %! assert(configurePin(ar, "d9"), "pwm") %! clear s %! assert(configurePin(ar, "d9"), "unset") %!error servo(); %!error servo(ar); %! s = servo(ar, "d9", "minpulseduration", 1.0e-3, "maxpulseduration", 2e-3); %! assert(!isempty(s)); %! assert(s.minpulseduration, 1.0e-3); %! assert(s.maxpulseduration, 2.0e-3); arduino-0.4.0/inst/@servo/subsref.m0000644000000000000000000000313613470770202015411 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{val} = } subsref (@var{dev}, @var{sub}) ## subref for servo ## ## @seealso{servo} ## @end deftypefn function val = subsref (p, s) if isempty(s) error ("servo.subsref missing index"); endif if s(1).type == "." fld = tolower(s(1).subs); switch (fld) case "pins" val = {}; for i = 1:numel(p.pins) val{end+1} = p.pins{i}; endfor case "parent" val = p.arduinoobj; case "minpulseduration" val = p.minpulseduration; case "maxpulseduration" val = p.maxpulseduration; case "parent" val = p.arduinoobj; otherwise error ("servo.subsref invalid property '%s'", fld); endswitch else error("unimplemented servo.subsref type"); endif if (numel (s) > 1) val = subsref (val, s(2:end)); endif endfunction %!test %! ar = arduino(); %! s = servo (ar, "d9"); %! assert (isarduino(s.parent)) %! assert (ar.port, s.parent.port) %! assert(s.minpulseduration > 0); %! assert(s.maxpulseduration > 0); %! assert (numel(s.pins) == 1) %! fail ("s.invalid") arduino-0.4.0/inst/@servo/writePosition.m0000644000000000000000000000265113470770202016620 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {} writePosition (@var{servo}, @var{position}) ## Write the position to a servo. ## ## @subsubheading Inputs ## @var{servo} - servo object created from arduino.servo. ## ## @var{position} - value between 0 .. 1 for the current servo position, ## where 0 is the servo min position, 1 is the servo maximum position. ## ## @seealso{servo, readPosition} ## @end deftypefn function writePosition (obj, value) if nargin != 2 error ("@servo.writePosition: expected value"); endif __servoPosition__(obj, value); endfunction %!shared ar, s %! ar = arduino(); %! s = servo(ar, "d9", "minpulseduration", 1.0e-3, "maxpulseduration", 2e-3); %!test %! writePosition(s, 1); %! assert(readPosition(s), 1); %! writePosition(s, 0); %! assert(readPosition(s), 0); %!error writePosition(); %! error writePosition(s); arduino-0.4.0/inst/@shiftRegister/0000755000000000000000000000000013470770202015243 5ustar0000000000000000arduino-0.4.0/inst/@shiftRegister/display.m0000644000000000000000000000222113470770202017063 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} display (@var{register}) ## Display the register object in a verbose way, ## ## @subsubheading Inputs ## @var{register} - the arduino register object created with shiftRegister. ## ## @seealso{shiftRegister} ## @end deftypefn function retval = display (register) printf ("%s = \n", inputname (1)); printf (" arduino shift register object with fields of: \n"); printf (" model = ") disp(register.model); for i=1:numel(register.pins) pin = register.pins{i}; printf (" %s = %s\n", pin.func, pin.name) endfor endfunction arduino-0.4.0/inst/@shiftRegister/read.m0000644000000000000000000000461413470770202016341 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} read (@var{register}) ## @deftypefnx {} {@var{retval} =} read (@var{register}, @var{precision}) ## read a value from the shift register. ## ## @subsubheading Inputs ## @var{register} - shift register created from shiftRegister call. ## ## @var{precision} - optional precision of the data, where precision can be a ## number in a multiple of 8 (ie: 8,16,32) or can be a named integer type: 8 ## of 'uint8', 'uint16', 'uint32'. The default precision is 8. ## ## @subsubheading Outputs ## @var{retval} - returned data read from the register. ## ## @seealso{shiftRegister, write} ## @end deftypefn function out = read(register, precision) persistent ARDUINO_SHIFTREG_READ = 3; persistent endian; if isempty(endian) [~, ~, endian] = computer (); endif if nargin < 1 || nargin > 2 print_usage (); endif if nargin == 2 if ischar(precision) precision = tolower(precision); switch(precision) case "uint8" precision = 8; case "uint16" precision = 16; case "uint32" precision = 32; otherwise error ("unknown precsison value '%s'", precision) endswitch elseif isscalar(precision) if precision <= 0 || mod(precision, 8) != 0 error ("precision should be positive number that is a muiltiple of 8"); endif endif else precision = 8; endif # attempt to clock out precision bits [tmp, sz] = sendCommand(register.parent, "shiftregister", ARDUINO_SHIFTREG_READ, [register.id precision]); out = typecast(uint8(tmp(2:end)), ['uint' num2str(precision)]); if (endian == 'L') out = swapbytes (out); endif endfunction arduino-0.4.0/inst/@shiftRegister/reset.m0000644000000000000000000000224413470770202016545 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} reset (@var{register}) ## clear the shift register value. ## ## @subsubheading Inputs ## @var{register} - shift register created from shiftRegister call. ## ## @seealso{shiftRegister, read, write} ## @end deftypefn function reset(register) persistent ARDUINO_SHIFTREG_RESET = 0; # TODO: see if we have a reset pin ? [tmp, sz] = sendCommand(register.parent, "shiftregister", ARDUINO_SHIFTREG_RESET, [register.id]); endfunction arduino-0.4.0/inst/@shiftRegister/shiftRegister.m0000644000000000000000000001401213470770202020241 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{register} =} shiftRegister (@var{ar}, @var{shifttype}, @var{dataPin}, @var{clockPin} ...) ## @deftypefnx {} {@var{register} =} shiftRegister (@var{ar},'74hc164', @var{dataPin}, @var{clockPin}, @var{resetPin}) ## @deftypefnx {} {@var{register} =} shiftRegister (@var{ar},'74hc165', @var{dataPin}, @var{clockPin}, @var{loadPin}, @var{clockEnablePin}) ## @deftypefnx {} {@var{register} =} shiftRegister(@var{ar},'74hc595', @var{dataPin}, @var{clockPin}, @var{latchPin} , @var{resetPin}) ## Create shift register of a given type, controlled by the input pins. ## ## @subsubheading Inputs ## Common function parameter definition: ## ## @var{ar} - connected arduino object. ## ## @var{shifttype} - string name of the shift register type. ## ## @var{dataPin} - pin used for data in/out of the device. ## ## @var{clockPin} - pin used for clocking data on the shiftRegister. ## ## ## Other variables are dependent on the shift register type: ## @table @asis ## @item '74hc164' ## Additional inputs: ## ## @var{resetPin} - optional pin for resetting the shift register. ## ## @item '74hc165' ## Additional inputs: ## ## @var{loadPin} - load pin to the shift register. ## @var{clockEnablePin} - clock enable pin. ## ## @item '74hc595' ## Additional inputs: ## ## @var{latchPin} - latching data to the shift register. ## @var{resetPin} - optional pin for resetting the shift register. ## ## @end table ## ## @subsubheading Outputs ## @var{register} - register object ## ## @subsubheading Properties ## The shiftRegister object has the following public properties: ## @table @asis ## @item parent ## The parent (arduino) for this device ## @item pins ## pins used by this object ## @item model ## model set for object ## @end table ## ## @seealso{arduino} ## @end deftypefn function register = shiftRegister(ar,type,dataPin,clockPin, varargin) persistent ARDUINO_SHIFTREG_CONFIG = 1; if (nargin == 1 && isa (ar, "shiftRegister")) register = ar; # Copy constructor elseif nargin < 4 error ('Expected type, dataPin and clockPin'); else p.parent = ar; p.model = toupper(type); p.datapin = dataPin; p.clockpin = clockPin; p.id = 0; pins = {}; pins{end+1} = ar.get_pin(dataPin); pins{end}.func = "datapin"; # datapin used also to address this register p.id = pins{1}.id; name = ["shiftregister_" pins{1}.name]; count = getResourceCount(ar, name); if count > 0 error ("@shiftRegister.shiftRegister: already have a shift register using this pin"); endif pins{end+1} = ar.get_pin(clockPin); pins{end}.func = "clockpin"; init_data = []; switch (p.model) case '74HC164' init_data = [0 pins{2}.id]; case '74HC165' init_data = [1 pins{2}.id]; if nargin != 6 error('74HC165 expects loadPin and clockEnablePin'); endif pins{end+1} = ar.get_pin(varargin{1}); pins{end}.func = "loadpin"; pins{end+1} = ar.get_pin(varargin{2}); pins{end}.func = "clockenablepin"; init_data = [ init_data pins{3}.id pins{4}.id ]; case '74HC595' init_data = [2 pins{2}.id]; if nargin != 5 && nargin != 6 error('74HC595 expects latchPin and optional resetPin'); endif pins{end+1} = ar.get_pin(varargin{1}); pins{end}.func = "latchpin"; init_data = [ init_data pins{end}.id ]; # optional reset if nargin == 6 pins{end+1} = ar.get_pin(varargin{2}); pins{end}.func = "resetpin"; init_data = [ init_data pins{end}.id ]; endif otherwise error ("Unknown shiftRegister type '%s'", p.model); endswitch # verify pins support digital i/o for i = 1:numel(pins) pin = pins{i}.name; validatePin(ar, pin, "digital"); endfor p.pins = pins; # TODO: save old modes and set them via force if we fail trying to alloc the whole group try for i=1:numel(pins) pin = pins{i}.name; configurePin(ar, pin, "digitaloutput"); endfor [tmp, sz] = sendCommand(ar, "shiftregister", ARDUINO_SHIFTREG_CONFIG, [p.id 1 init_data]); incrementResourceCount(ar, name); catch # restore pin state for i=1:numel(pins) pin = pins{i}; configurePinResource(ar, pin.name, pin.owner, pin.mode, true) configurePin(ar, pin.name, pin.mode) endfor rethrow (lasterror); end_try_catch p.cleanup = onCleanup (@() cleanupShiftRegister (ar, name, pins)); register = class (p, "shiftRegister"); endif endfunction # private clean up allocated pins function cleanupShiftRegister(ar, name, pins) decrementResourceCount(ar, name); for i=1:numel(pins) pin = pins{i}; configurePinResource(ar, pin.name, pin.owner, pin.mode, true); configurePin(ar, pin.name, pin.mode); endfor endfunction %!shared ar %! ar = arduino(); %!test %! # validate pins not allocated %! assert(configurePin(ar, "d2"), "unset"); %! assert(configurePin(ar, "d3"), "unset"); %! %! register = shiftRegister(ar, '74hc164', "d2", "d3"); %! assert (isa (register, "shiftRegister")) %! %! #pins allocated ? %! assert(configurePin(ar, "d2"), "digitaloutput"); %! assert(configurePin(ar, "d3"), "digitaloutput"); %! %! #free %! clear register %! assert(configurePin(ar, "d2"), "unset"); %! assert(configurePin(ar, "d3"), "unset"); arduino-0.4.0/inst/@shiftRegister/subsref.m0000644000000000000000000000300013470770202017063 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{val} = } subsref (@var{dev}, @var{sub}) ## subref for shiftRegister ## ## @seealso{shiftRegister} ## @end deftypefn function val = subsref (p, s) if isempty(s) error ("shiftRegister.subsref missing index"); endif if s(1).type == "." fld = tolower(s(1).subs); switch (fld) case "pins" val = {}; for i = 1:numel(p.pins) val{end+1} = p.pins{i}.name; endfor case "parent" val = p.parent; case "model" val = p.model; otherwise error ("shiftRegister.subsref invalid property '%s'", fld); endswitch else error("unimplemented shiftRegister.subsref type"); endif if (numel (s) > 1) val = subsref (val, s(2:end)); endif endfunction %!test %! ar = arduino(); %! r = shiftRegister(ar, '74hc164', "d2", "d3"); %! assert (isarduino(r.parent)) %! assert (ar.port, r.parent.port) %! assert (r.model, "74HC164") %! assert (numel(r.pins) == 2) %! fail ("r.invalid") arduino-0.4.0/inst/@shiftRegister/write.m0000644000000000000000000000512013470770202016551 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} write (@var{register}, @var{dataIn}) ## @deftypefnx {} write (@var{register}, @var{dataIn}, @var{precision}) ## Write a value to the shift register. ## ## @subsubheading Inputs ## @var{register} - shift register created from shiftRegister call. ## ## @var{dataIn} - data to clock into the shiftRegister. ## ## @var{precision} - optional precision of the data, where precision can be a ## number in a multiple of 8 (ie: 8,16,32) or can be a named integer type ## of 'uint8', 'uint16', 'uint32'. The default precision is 8. ## ## @seealso{shiftRegister, read} ## @end deftypefn function write(register, dataIn, precision) persistent ARDUINO_SHIFTREG_WRITE = 2; persistent endian; if isempty(endian) [~, ~, endian] = computer (); endif if nargin < 2 || nargin > 3 print_usage (); endif if nargin == 3 if ischar(precision) precision = tolower(precision); switch(precision) case "uint8" precision = 8; case "uint16" precision = 16; case "uint32" precision = 32; otherwise error ("unknown precsison value '%s'", precision) endswitch elseif isscalar(precision) if precision <= 0 || mod(precision, 8) != 0 error ("precision should be positive number that is a muiltiple of 8"); endif endif else precision = 8; endif switch (precision) case 8 dataIn = uint8(dataIn); case 16 dataIn = uint16(dataIn); if (endian == 'L') dataIn = swapbytes (dataIn); endif dataIn = typecast(dataIn, 'uint8'); case 32 dataIn = uint32(dataIn); if (endian == 'L') dataIn = swapbytes (dataIn); endif dataIn = typecast(dataIn, 'uint8'); endswitch [tmp, sz] = sendCommand(register.parent, "shiftregister", ARDUINO_SHIFTREG_WRITE, [register.id dataIn]); endfunction arduino-0.4.0/inst/@spidev/0000755000000000000000000000000013470770202013713 5ustar0000000000000000arduino-0.4.0/inst/@spidev/display.m0000644000000000000000000000236613470770202015545 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {} display (@var{dev}) ## Display spidev object. ## ## @subsubheading Inputs ## @var{dev} - spidev object to display ## ## @seealso{spidev} ## @end deftypefn function display (this) printf ("%s = \n", inputname (1)); printf (" arduino spidev object with fields of: \n\n"); printf (" chipselectpin = %s\n", this.chipselectpin); printf (" mode = %d\n", this.mode); printf (" bitorder = %s\n", this.bitorder); printf (" bitrate = %d\n", this.bitrate); printf (" pins = "); for i=1:numel(this.pins) printf("%s(%s) ", this.pins{i}.name, this.pins{i}.func) endfor printf("\n"); printf("\n"); endfunction arduino-0.4.0/inst/@spidev/spidev.m0000644000000000000000000001742413470770202015373 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{dev} =} spidev (@var{ar}, @var{cspin}) ## @deftypefnx {} {@var{dev} =} spidev (@var{ar}, @var{cspin}, @var{propname}, @var{propvalue}) ## Create an spidev object to communicate to the SPI port on a connected arduino. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{cspin} - chip select pin for attached spi device. ## ## @var{propname}, @var{propvalue} - property name/value pair for values to pass to devices. ## ## Currently known properties: ## @table @asis ## @item bitrate ## bit rate speed in Mbs ## @item bitorder ## 'msbfirst' or 'lsbfirst' ## @item mode ## SPI mode 0 - 3. ## @end table ## ## @subsubheading Outputs ## @var{dev} - created spidev object ## ## @subsubheading Properties ## The spidev object has the following public properties: ## @table @asis ## @item parent ## The parent (arduino) for this device ## @item pins ## pins used by this object ## @item mode ## mode used for created object ## @item bitrate ## Bitrate set for object ## @item bitorder ## Bitorder set for object ## @item chipselectpin ## Pin used for chipselect ## @end table ## ## @seealso{arduino, readWrite} ## @end deftypefn function this = spidev (varargin) ARDUINO_SPI_CONFIG = 1; if nargin < 2 error ("expects arduino object and chipselect pin"); endif ar = varargin{1}; cspin = varargin{2}; if mod(nargin, 2) != 0 error ("arduino: expected property name, value pairs"); endif if !iscellstr (varargin(3:2:nargin)) error ("arduino: expected property names to be strings"); endif isfirst = getResourceCount(ar,"spi") == 0; this.id = []; this.chipselectpin = ""; this.mode = 0; this.bitrate = 4000000; this.bitorder = 'msbfirst'; for i = 3:2:nargin propname = tolower(varargin{i}); propvalue = varargin{i+1}; % printf("%s = %s\n", propname, propvalue); if strcmp (propname, "bitrate") if !isnumeric (propvalue) error("bitrate should be a number") endif this.bitrate = propvalue; elseif strcmp (propname, "mode") if !isnumeric (propvalue) || propvalue < 0 || propvalue > 3 error("mode should be a number betwwen 0 - 3"); endif this.mode = propvalue; elseif strcmp (propname, "bitorder") if !ischar(propvalue) error("bitorder should be a string"); endif this.bitorder = tolower(propvalue); if this.bitorder != "msbfirst" && this.bitorder != "lsbfirst" error("bitorder should be 'msbfirst' or 'lsbfirst'"); endif endif endfor if (!isa (ar, "arduino")) error("expects arduino object"); endif this.chipselectpin = cspin; this.parent = ar; this.resourceowner = "spi"; # check if is valid CS pin that can use as output validatePin(ar, cspin, 'digital') if strcmp(getResourceOwner(ar, cspin), this.resourceowner) error ("pin %s is already in use by SPI", cspin) endif if isfirst terms = getSPITerminals(ar); tmp_pins = ar.get_pingroup(terms{1}, "SPI"); if numel(tmp_pins) != 4 error ("expected 4 SPI pins but only have %d", numel(tmp_pins)) endif setSharedResourceProperty(ar, this.resourceowner, "pins", tmp_pins); endif tmp_pins = getSharedResourceProperty(ar, this.resourceowner, "pins"); cs_is_ss = false; cspin = getPinInfo(ar, cspin); cspin.func = "cs"; for i=1:4 # verify cs pin is either SS pin, or a not a spi pin if strcmp(tolower(tmp_pins{i}.func), "ss") if strcmpi(tmp_pins{i}.name, cspin.name) cs_is_ss = true; endif else # check not trying to set CS to a spi pin if strcmpi(tmp_pins{i}.name, cspin.name) error ("can not set cspin to a SPI function pin"); endif endif endfor if !cs_is_ss tmp_pins{end+1} = cspin; endif this.pins = tmp_pins; this.id = cspin.terminal; try for i=1:numel(tmp_pins) if isfirst if strcmp(tolower(tmp_pins{i}.func), "ss") || strcmp(tolower(tmp_pins{i}.func), "cs") configurePin(ar, tmp_pins{i}.name, "digitaloutput") configurePinResource (ar, tmp_pins{i}.name, "spi", "digitaloutput", true); else configurePin(ar, tmp_pins{i}.name, "spi") endif else # only allocate cs pin if not first device if strcmp(tolower(tmp_pins{i}.func), "cs") configurePin(ar, tmp_pins{i}.name, "digitaloutput") configurePinResource (ar, tmp_pins{i}.name, "spi", "digitaloutput", true); endif endif endfor bitorder = 0; if strcmp(this.bitorder, 'lsbfirst') bitorder = 1; endif [tmp, sz] = sendCommand(this.parent, this.resourceowner, ARDUINO_SPI_CONFIG, [this.id 1 this.mode bitorder]); incrementResourceCount(ar, this.resourceowner); catch for i=1:numel(tmp_pins) if strcmp(tolower(tmp_pins{i}.func), "cs") || isfirst configurePinResource(ar, tmp_pins{i}.name, tmp_pins{i}.owner, tmp_pins{i}.mode, true) configurePin(ar, tmp_pins{i}.name, tmp_pins{i}.mode) endif endfor rethrow (lasterror); end_try_catch # set clean up function this.cleanup = onCleanup (@() cleanupSPI (ar, this.resourceowner, cspin)); this = class(this, "spidev"); endfunction # private clean up allocated pins function cleanupSPI(ar, resource, cspin) # free CS configurePinResource(ar, cspin.name, cspin.owner, cspin.mode, true); configurePin(ar, cspin.name, cspin.mode); # clean up the spi port if not used? count = getResourceCount(ar, resource); if count > 0 count = decrementResourceCount(ar, resource); if count == 0 # last user, so free pins (except ss that we already did) pins = getSharedResourceProperty(ar, resource, "pins"); for i=1:numel(pins) pin = pins{i}; configurePinResource(ar, pin.name, pin.owner, pin.mode, true); configurePin(ar, pin.name, pin.mode); endfor endif endif endfunction %!shared arduinos %! arduinos = scanForArduinos(1); %!assert(numel(arduinos), 1); %!test %! ar = arduino(); %! assert(!isempty(ar)); %! %! spipins = getSPITerminals(ar); %! assert (numel(spipins), 4); %! %! # validate SPI pins not allocated %! assert(configurePin(ar, "d10"), "unset") %! assert(configurePin(ar, spipins{1}), "unset") %! assert(configurePin(ar, spipins{2}), "unset") %! assert(configurePin(ar, spipins{3}), "unset") %! assert(configurePin(ar, spipins{4}), "unset") %! %! spi = spidev(ar, "d10"); %! assert(!isempty(spi)); %! assert(spi.chipselectpin, "d10"); %! %! # validate SPI pins allocated %! assert(configurePin(ar, "d10"), "digitaloutput") %! #assert(configurePin(ar, spipins{1}), 'digitaloutput') ## ss %! #assert(configurePin(ar, spipins{2}), 'digitaloutput') ## mosi %! #assert(configurePin(ar, spipins{3}), 'digitalinput') ## miso %! #assert(configurePin(ar, spipins{4}), 'digitaloutput') ## sck %! %! clear spi %! %! # check now pins unset %! assert(configurePin(ar, "d10"), "unset") %! assert(configurePin(ar, spipins{1}), "unset") %! assert(configurePin(ar, spipins{2}), "unset") %! assert(configurePin(ar, spipins{3}), "unset") %! assert(configurePin(ar, spipins{4}), "unset") %!test %! ar = arduino(); %! spi = spidev(ar, "d10"); %! fail ('spidev(ar, "d10");', 'pin d10 is already in use') %! spi2 = spidev(ar, "d5"); arduino-0.4.0/inst/@spidev/subsref.m0000644000000000000000000000325613470770202015550 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{val} = } subsref (@var{dev}, @var{sub}) ## subref for spidev ## ## @seealso{spidev} ## @end deftypefn function val = subsref (this, s) if isempty(s) error ("spidev.subsref missing index"); endif if s(1).type == "." fld = tolower(s(1).subs); switch (fld) case "pins" val = {}; for i = 1:numel(this.pins) val{end+1} = this.pins{i}.name; endfor case "parent" val = this.parent; case "mode" val = this.mode; case "bitrate" val = this.bitrate; case "bitorder" val = this.bitorder; case "chipselectpin" val = this.chipselectpin; otherwise error ("spidev.subsref invalid property '%s'", fld); endswitch else error("unimplemented spidev.subsref type"); endif if (numel (s) > 1) val = subsref (val, s(2:end)); endif endfunction %!test %! ar = arduino(); %! spi = spidev (ar, "d10"); %! assert (spi.chipselectpin, "d10") %! assert (isarduino(spi.parent)) %! assert (ar.port, spi.parent.port) %! assert (spi.mode, 0) %! assert (spi.bitorder, "msbfirst") %! assert (numel(spi.pins) >= 4) %! fail ("spi.invalid") arduino-0.4.0/inst/@spidev/writeRead.m0000644000000000000000000000343313470770202016022 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## -*- texinfo -*- ## @deftypefn {} {@var{dataOut} =} readWrite (@var{spi}, @var{dataIn}) ## Write uint8 data to spi device and return ## back clocked out response data of same size. ## ## @subsubheading Inputs ## @var{spi} - connected spi device on arduino ## ## @var{dataIn} - uint8 sized data to send to spi device framed between SS frame. ## ## @subsubheading Outputs ## @var{dataOut} - uint8 data clocked out during send to dataIn. ## ## @seealso{arduino, spidev} ## @end deftypefn function dataOut = writeRead (this, dataIn) dataOut = []; persistent ARDUINO_SPI_READ_WRITE = 2; if nargin < 2 error ("@spidev.writeRead: expected dataIn"); endif [tmp, sz] = sendCommand (this.parent, this.resourceowner, ARDUINO_SPI_READ_WRITE, [this.id uint8(dataIn)]); if sz > 0 dataOut = tmp(2:end); endif endfunction %!shared arduinos %! arduinos = scanForArduinos(1); %!assert(numel(arduinos), 1); %!test %! ar = arduino(); %! assert(!isempty(ar)); %! spi = spidev(ar, "d10"); %! assert(!isempty(spi)); %! data = writeRead(spi, 1); %! assert(numel(data), 1); %!test %! ar = arduino(); %! assert(!isempty(ar)); %! spi = spidev(ar, "d10"); %! assert(!isempty(spi)); %! data = writeRead(spi, [1 1 1]); %! assert(numel(data), 3); arduino-0.4.0/inst/addon.m0000644000000000000000000000605013470770202013565 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} addon (@var{ar}, @var{addonname}) ## @deftypefnx {} {@var{retval} =} addon (@var{ar}, @var{addonname}, varargs) ## Create an addon object using the addon named class. ## ## @subsubheading Inputs ## @var{ar} - connected arduino object ## ## @var{addonname} - the name of the addon to create. The addon name can be a user ## addon or an inbuilt addon, however must appear in the listArduinoLibraries ## output and have been programmed onto the arduino. ## ## @var{varargs} - optional values that will be provided verbatim to the ## the addon class constructor. ## ## @subsubheading Outputs ## @var{retval} - cell array of string library names. ## ## @seealso{arduino, arduinosetup, listArduinoLibraries} ## @end deftypefn function retval = addon (ar, addonname, varargin) if (! isa (ar, "arduino")) error("addon: expected first arguiment to be a arduino object"); endif # verify arduino has the plugin name p = ar.get_lib (addonname); if p == -1 error ("addon: arduino has not been programmed with a plugin named '%s'\n", addonname); endif availlibs = listArduinoLibraries (); addonlibs = __addons__ (); # get addonin for the requested library idx = find (cellfun(@(x) strcmpi(x.libraryname, addonname), addonlibs), 1); if isempty (idx) #if not found, was an inbuilt one ? # verify can find the lib and get/make constructor of it idx = find (cellfun(@(x) strcmpi(x, addonname), availlibs), 1); if isempty (idx) error ("addon: unknown library '%s'", addonname); endif # a known normal addon like spi if strcmpi (addonname, "spi") lib = "spidev"; elseif strcmpi (addonname, "i2c") lib = "i2cdev"; elseif strcmpi (addonname, "servo") lib = "servo"; elseif strcmpi (addonname, "shiftregister") lib = "shiftRegister"; elseif strcmpi (addonname, "rotaryencoder") lib = "rotaryEncoder"; else error ("addon: unknown builtin library '%s'", addonname); endif else # user addon constructor lib = addonlibs{idx}.classname; endif # get constructor function handle constructor = str2func (lib); # create object retval = constructor (ar, varargin{:}); endfunction %!test %! a = arduino(); %! # do equivalent of s = i2cdev(a, 10); %! s = addon(a, "i2c", 10); %! assert(class(s), "i2cdev"); arduino-0.4.0/inst/arduino_bistsetup.m0000644000000000000000000000674713470770202016260 0ustar0000000000000000## Copyright (C) 2019 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} arduino_bistsetup () ## @deftypefnx {} {@var{retval} =} arduino_bistsetup (@var{propertyname}, @var{propertyvalue}) ## Install on an arduino the required core libraries to run the BIST tests ## ## As part of the setup, the arduino IDE will be opened to allow programming ## the arduino board. ## ## @subsubheading Inputs ## ## @var{propertyname}, @var{propertyvalue} - A sequence of property name/value pairs can be given ## to set defaults while programming. ## ## Currently the following properties can be set: ## @table @asis ## @item arduinobinary ## The value should be the name/path of the arduino IDE binary for programming. If not specified, ## the function will attempt to find the binary itself. ## @item debug ## Set the debug flag when checking the arduino ## @end table ## ## @subsubheading Outputs ## @var{retval} - return 1 if everything installed ok ## ## @seealso{arduino, arduinosetup} ## @end deftypefn function retval = arduino_bistsetup (varargin) retval = 0; if mod (nargin, 2) != 0 error ("arduinosetup: expected property name, value pairs"); endif if !iscellstr (varargin(1:2:nargin)) error ("arduinosetup: expected property names to be strings"); endif arduinobinary = {}; debug = false; for i = 1:2:nargin propname = tolower (varargin{i}); propvalue = varargin{i+1}; if strcmp (propname, "arduinobinary") arduinobinary = propvalue; elseif strcmp (propname, "debug") debug = propvalue; elseif warning ("arduino_bistsetup: unknown property '%s', ignoring it", propname); endif endfor printf ("** Installing core libraries on arduino - please press upload in the IDE, and after completion, close the IDE\n"); fflush(stdout); if ! arduinosetup ('libraries', listArduinoLibraries('core'), varargin{:}) error ("Failed to program the arduino"); endif unwind_protect printf ("** Checking for any arduinos\n"); fflush(stdout); ars = scanForArduinos(); printf ("Found %d\n", numel(ars)); printf ("** Checking can open an UNO arduino\n"); fflush(stdout); ar = arduino ([], "uno", 'debug', debug); if ! isarduino(ar) error ('Couldnt load find an arduino UNO board') endif printf ("** Checking arduino version\n"); fflush(stdout); p = pkg('list', 'arduino'); if isempty(p) error ('No arduino package found'); endif ver = p{1}.version; if ! strcmp(ver, version(ar)) error ('Arduino version did not match %s : %s', ver, version(ar)); endif printf ('Arduino has been programmed and is ready for BIST testing\n'); printf (['run: __run_test_suite__({"' p{1}.dir '"}, {})\n']); fflush(stdout); ret = 1; unwind_protect_cleanup clear ar; end_unwind_protect endfunction arduino-0.4.0/inst/arduinosetup.m0000644000000000000000000001614213470770202015225 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} arduinosetup () ## @deftypefnx {} {@var{retval} =} arduinosetup (@var{propertyname}, @var{propertyvalue}) ## Open the arduino config / programming tool to program the arduino hardware for usage with ## the Octave arduino functions. ## ## arduinosetup will create a temporary project using the arduino IDE and allow ## compiling and programming of the code to an arduino. ## ## @subsubheading Inputs ## ## @var{propertyname}, @var{propertyvalue} - A sequence of property name/value pairs can be given ## to set defaults while programming. ## ## Currently the following properties can be set: ## @table @asis ## @item libraries ## The value should be the name of a library, or string array of libraries to program on the ## arduino board. ## @item arduinobinary ## The value should be the name/path of the arduino IDE binary for programming. If not specified, ## the function will attempt to find the binary itself. ## @end table ## ## @subsubheading Outputs ## @var{retval} - return 1 if arduino IDE returned without an error ## ## @seealso{arduino, __arduino_binary__} ## @end deftypefn function retval = arduinosetup (varargin) retval = 0; if mod (nargin, 2) != 0 error ("arduinosetup: expected property name, value pairs"); endif if !iscellstr (varargin(1:2:nargin)) error ("arduinosetup: expected property names to be strings"); endif libs = {}; arduinobinary = {}; debug = false; for i = 1:2:nargin propname = tolower (varargin{i}); propvalue = varargin{i+1}; if strcmp (propname, "libraries") if iscell (propvalue) libs = propvalue; elseif ischar (propvalue) libs{end+1} = propvalue; else error ("arduinosetup Expected libraries to be a cellarray or string"); endif elseif strcmp (propname, "arduinobinary") arduinobinary = propvalue; elseif strcmp (propname, "debug") debug = propvalue; elseif warning ("arduinosetup: unknown property '%s', ignoring it", propname); endif endfor if isempty(libs) # default libs if not are provided libs{end+1} = "SPI"; libs{end+1} = "I2C"; libs{end+1} = "Servo"; libs{end+1} = "ShiftRegister"; endif # we have the libs ? availlibs = listArduinoLibraries (); addonlibs = __addons__ (); # for any addons, check the dependancies and add it we need to for i = 1:numel(libs) idx = find (cellfun(@(x) strcmpi(x.libraryname, libs{i}), addonlibs), 1); if !isempty(idx) lib = addonlibs{idx}; for n = 1:numel(lib.dependentlibraries) addlib = lib.dependentlibraries{n}; idx = find (cellfun(@(x) strcmpi(x, addlib), libs), 1); if isempty(idx) libs{end+1} = addlib; if (debug) printf("arduinosetup: adding %s as a dependency\n", addlib); endif endif endfor endif endfor builtinlibs = {}; for i = 1:numel(libs) idx = find (cellfun(@(x) strcmpi(x.libraryname, libs{i}), addonlibs), 1); if isempty(idx) idx = find (cellfun(@(x) strcmpi(x, libs{i}), availlibs), 1); if isempty (idx) error ("arduinosetup: unknown library '%s'", libs{i}); elseif (debug) printf("arduinosetup: using builtin lib %s\n", libs{i}); endif builtinlibs{end+1} = libs{i}; libs{i} = []; else if (debug) printf("arduinosetup: using addon lib %s\n", libs{i}); endif libs{i} = addonlibs{idx}; endif endfor libfiles = arduinoio.LibFiles(); if isempty (libfiles) error ("arduinosetup: couldn't find library files"); endif # make a temp folder and create a arduino project in it tmpdir = tempname (); mkdir (tmpdir); unwind_protect mkdir (fullfile (tmpdir, "octave")); # copy all the libfiles copyfile (libfiles, fullfile (tmpdir, "octave")); fd = fopen (fullfile (tmpdir, "octave", "settings.h"), "w+t"); fprintf (fd, "// generated from arduinosetup for buildin library configuration\n"); fprintf (fd, "\n"); fprintf (fd, "// override target voltage (x10) by uncommenting and providing a value\n"); fprintf (fd, "//#define BOARD_VOLTAGE 50\n"); fprintf (fd, "\n"); fprintf (fd, "// builtin library support\n"); idx = find (cellfun(@(x) strcmpi(x, "SPI"), builtinlibs), 1); if !isempty(idx) fprintf (fd, "#define USE_SPI\n"); else fprintf (fd, "//#define USE_SPI\n"); endif idx = find (cellfun(@(x) strcmpi(x, "I2C"), builtinlibs), 1); if !isempty(idx) fprintf (fd, "#define USE_I2C\n"); else fprintf (fd, "//#define USE_I2C\n"); endif idx = find (cellfun(@(x) strcmpi(x, "Servo"), builtinlibs), 1); if !isempty(idx) fprintf (fd, "#define USE_SERVO\n"); else fprintf (fd, "//#define USE_SERVO\n"); endif idx = find (cellfun(@(x) strcmpi(x, "ShiftRegister"), builtinlibs), 1); if !isempty(idx) fprintf (fd, "#define USE_SHIFTREG\n"); else fprintf (fd, "//#define USE_SHIFTREG\n"); endif idx = find (cellfun(@(x) strcmpi(x, "RotaryEncoder"), builtinlibs), 1); if !isempty(idx) fprintf (fd, "#define USE_ROTARYENCODER\n"); else fprintf (fd, "//#define USE_ROTARYENCODER\n"); endif fclose (fd); # requested additional libs fd = fopen (fullfile (tmpdir, "octave", "addons.h"), "w+t"); fprintf(fd, "// generated from arduinosetup for addon library addidtions\n"); for i = 1:numel (libs) l = libs{i}; if !isempty (l) if !isempty (l.cppheaderfile) copyfile (l.cppheaderfile, fullfile(tmpdir, "octave")); [d,f,e] = fileparts (l.cppheaderfile); fprintf (fd, '#include "%s%s"\n', f,e); if !isempty (l.cppclassname) fprintf (fd, "%s addon%d(octavearduino);\n", l.cppclassname, i); endif endif if !isempty (l.cppsourcefile) copyfile (l.cppsourcefile, fullfile(tmpdir, "octave")); endif endif endfor fclose(fd); # start the arduino ide if isempty (arduinobinary) arduinobinary = __arduino_binary__ (); endif filename = fullfile (tmpdir, "octave", "octave.ino"); cmdline = sprintf ("\"%s\" \"%s\"", arduinobinary, filename); printf ("Running %s\n", cmdline); [status, ~] = system (cmdline); retval = (status == 0); unwind_protect_cleanup confirm_recursive_rmdir (false, "local"); rmdir(tmpdir, "s"); end_unwind_protect endfunction arduino-0.4.0/inst/examples/0000755000000000000000000000000013470770202014137 5ustar0000000000000000arduino-0.4.0/inst/examples/example_blink.m0000644000000000000000000000206613470770202017133 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . % blink the LED on D13 pkg load instrument-control a = arduino(); leds = getLEDTerminals(a); led = getPinsFromTerminals(a, leds{1}); unwind_protect printf("starting to blink...\n"); while (true) writeDigitalPin(a, led, 0); pause(0.5); writeDigitalPin(a, led, 1); pause(0.5); endwhile unwind_protect_cleanup clear a end_unwind_protect arduino-0.4.0/inst/examples/example_i2c_eeprom.m0000644000000000000000000000446613470770202020066 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . % example using the arduino i2c % to communicate to a 24XX256 EEPROM chip connected to an uno % % Connection of arduino to EEPROM as follows: % Arduino 24XX256 eeprom (pin) % A4 - 5 % A5 - 6 % 5V - 8 % GND - 1,2,3,4 pkg load instrument-control eeprom_address = 0x50; data = "this is eeprom data"; # open the arduino a = arduino() unwind_protect printf("i2c terminals\n") getI2CTerminals(a) printf("i2c devices attached\n") devs = scanI2Cbus(a) idx = find(devs = eeprom_address); if isempty(idx) warning ('no EEPROM device found at address') endif printf("opening i2c...\n"); i2c = i2cdev(a, eeprom_address) printf("writing i2c...\n"); # write data to address 0x0000 write(i2c, [0 0 uint8(data)]); # read from address 0x0008, which should now be 'eeprom' write(i2c, uint8([0 8])); val = read(i2c, 6); printf("reading from 0x0008 = expecting 'eeprom', and got '%s'\n", char(val)) # demo read/write register val = readRegister(i2c, 0, 2, 'uint16'); printf("reading as reg from 0x0000 = expecting %X %X, and got '%X %X'\n", typecast(data(1:2),'uint16'),typecast(data(3:4), 'uint16'), val(1), val(2)) # 2nd page write(i2c, [1 0 0 1 0 2 0 3 0 4]); write(i2c, uint8([1 0])); valu = read(i2c, 4) val = readRegister(i2c, 256, 2, 'uint16') valx = readRegister(i2c, 258, 2, 'uint16') write(i2c, uint8([1 2])); valux = read(i2c, 4) # 02 03 writeRegister(i2c, 258, [8 9], 'uint16') write(i2c, uint8([1 2])); valux = read(i2c, 4) valx = readRegister(i2c, 258, 2, 'uint16') clear i2c unwind_protect_cleanup clear a end_unwind_protect arduino-0.4.0/inst/examples/example_i2c_tempsensor.m0000644000000000000000000000625313470770202020772 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . % example using the arduino i2c to communicate to a Si7021 via a % sparkfun SparkFun Humidity and Temperature Sensor Breakout board % https://www.sparkfun.com/products/13763 % % Conection of arduino to breakout board as follows: % Arduino breakoutboard (pin) (name depending on rev of board) % A4 - 3 (DA or SDA) % A5 - 4 (CL or SCL) % 3V3 - 2 (+ or 3V3) % GND - 1 (- or GND) temp_address = 0x40; # open the arduino a = arduino () unwind_protect printf ("i2c terminals\n") getI2CTerminals (a) printf ("i2c devices attached\n") devs = scanI2Cbus (a) idx = find (devs = temp_address); if isempty (idx) warning ('no Si7021 device found at address') endif printf ("opening i2c...\n"); i2c = i2cdev (a, temp_address) SENSOR_ID_1 = [ hex2dec("FA") hex2dec("F0") ]; SENSOR_ID_2 = [ hex2dec("FC") hex2dec("C9") ]; printf ("query device...\n"); write (i2c, SENSOR_ID_1); id1 = read(i2c, 1); write (i2c, SENSOR_ID_2); id2 = read(i2c, 1); printf ("Sensor ID: %02X%02X\n", id1, id2) printf ("Sensor Type: "); if id2 == hex2dec("15") printf ("Si7021\n"); elseif id2 == hex2dec("14") printf ("Si7020\n"); elseif id2 == hex2dec("0D") printf ("Si7013\n"); elseif id2 == hex2dec("32") printf ("HTU21D\n"); else error ("unknown sensor type of %d found", id2); endif SENSOR_VERSION = [ hex2dec("84") hex2dec("B8") ]; write (i2c, SENSOR_VERSION); ver = read(i2c, 1); printf ("F/W Version: "); if ver == hex2dec("FF") printf ("Version: 1.0\n"); elseif ver == hex2dec("20") printf ("Version: 2.0\n"); else printf ("Version: %f\n", double(ver)/10.0); endif TEMP_MEASURE_NOHOLD = hex2dec("F3"); HUMIDITY_MEASURE_NOHOLD = hex2dec("F5"); % write command to get temp write (i2c, uint8([TEMP_MEASURE_NOHOLD])); pause (0.02); data = read (i2c, 3); value = uint16(data(1))*256 + uint16(data(2)); value = bitand (value, hex2dec("FFFC")); temp_Code = double(value); C = (175.72*temp_Code/65536)-46.85; F = (C * 1.8) +32.0; printf ("temperature read %f C (%f F)\n", C, F); % write command to get rel humidity write (i2c, uint8([HUMIDITY_MEASURE_NOHOLD])); pause (0.02); data = read (i2c, 3); value = uint16(data(1))*256 + uint16(data(2)); value = bitand (value, hex2dec("FFFC")); humidity_Code = double(value); humidity = (125.0*humidity_Code/65536)-6; printf ("relative humidity read %f %%\n", humidity); clear i2c unwind_protect_cleanup clear a end_unwind_protect arduino-0.4.0/inst/examples/example_i2c_tempsensor_plot.m0000644000000000000000000000766513470770202022040 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . % example using the arduino i2c to communicate to a Si7021 via a % sparkfun SparkFun Humidity and Temperature Sensor Breakout board % https://www.sparkfun.com/products/13763 % % Connection of arduino to breakout board as follows: % Arduino breakoutboard (pin) (name depending on rev of board) % A4 - 3 (DA or SDA) % A5 - 4 (CL or SCL) % 3V3 - 2 (+ or 3V3) % GND - 1 (- or GND) pkg load instrument-control temp_address = 0x40; # open the arduino a = arduino(); unwind_protect % check if can find sensor devs = scanI2Cbus(a); idx = find(devs = temp_address); if isempty(idx) warning ('no Si7021 device found at address') endif i2c = i2cdev(a, temp_address); SENSOR_ID_1 = [ hex2dec("FA") hex2dec("F0") ]; SENSOR_ID_2 = [ hex2dec("FC") hex2dec("C9") ]; write(i2c, SENSOR_ID_1); id1 = read(i2c, 1); write(i2c, SENSOR_ID_2); id2 = read(i2c, 1); printf("Device info ...\n"); printf (" Sensor ID: %02X%02X\n", id1, id2) printf (" Sensor Type: "); if id2 == hex2dec("15") printf("Si7021\n"); elseif id2 == hex2dec("14") printf("Si7020\n"); elseif id2 == hex2dec("0D") printf("Si7013\n"); elseif id2 == hex2dec("32") printf("HTU21D\n"); else error("unknown sensor type of %d found", id2); endif SENSOR_VERSION = [ hex2dec("84") hex2dec("B8") ]; write(i2c, SENSOR_VERSION); ver = read(i2c, 1); printf(" F/W Version: "); if ver == hex2dec("FF") printf("Version: 1.0\n"); elseif ver == hex2dec("20") printf("Version: 2.0\n"); else printf("Version: %f\n", double(ver)/10.0); endif sample_time = 1; history_size = 600; f = figure(); temp_data = zeros(1, history_size); hum_data = zeros(1, history_size); ax1 = subplot(2,1,1); tp = plot(ax1, temp_data); set(tp,'linewidth', 2, 'linestyle', '-', 'color', 'r'); title(ax1, "Temperature"); ylim(ax1, [0 40.0]); xlim(ax1, [1 history_size]); ylabel(ax1, "deg C"); xlabel(ax1, "history"); grid on; ax2 = subplot(2,1,2); hp = plot(ax2, hum_data); set(hp,'linewidth', 2, 'linestyle', '-', 'color', 'b'); title(ax2,"Relative Humidity"); ylim(ax2,[0 100.0]); xlim(ax2,[1 history_size]); ylabel(ax2,"%"); xlabel(ax2,"history"); grid on; TEMP_MEASURE_NOHOLD = hex2dec("F3"); HUMIDITY_MEASURE_NOHOLD = hex2dec("F5"); while(true) % write command to get temp write(i2c, uint8([TEMP_MEASURE_NOHOLD])); pause(0.02); data = read(i2c, 3); value = uint16(data(1))*256 + uint16(data(2)); value = bitand(value, hex2dec("FFFC")); temp_Code = double(value); C = (175.72*temp_Code/65536)-46.85; temp_data(2:history_size) = temp_data(1:history_size-1); temp_data(1) = C; set(tp,'ydata',temp_data); drawnow; % write command to get rel humidity write(i2c, uint8([HUMIDITY_MEASURE_NOHOLD])); pause(0.02); data = read(i2c, 3); value = uint16(data(1))*256 + uint16(data(2)); value = bitand(value, hex2dec("FFFC")); humidity_Code = double(value); humidity = (125.0*humidity_Code/65536)-6; hum_data(2:history_size) = hum_data(1:history_size-1); hum_data(1) = humidity; set(hp,'ydata',hum_data); drawnow; pause(sample_time); endwhile clear i2c unwind_protect_cleanup clear a end_unwind_protect arduino-0.4.0/inst/examples/example_lcd_plugin.m0000644000000000000000000000250013470770202020145 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . # test LCD plugin using the Arduini LinkSprite16x2 LCD LCD Keypad shield # get arduino a = arduino(); # check have the lcd addon programmed havelcd = sum(index(a.libraries, 'examplelcd/lcd')) > 0; if !havelcd error ('no LCD addon found - install it with arduinosetup'); endif # create lcd object lcd = addon(a, "examplelcd/lcd", "d8", "d9", "d4", "d5", "d6", "d7") # loop, displaying date and time on LCD while(true) gotoLCD(lcd, 0, 0); printLCD(lcd, datestr (date, "dd mmm yyyy")); t = localtime(time); gotoLCD(lcd, 0, 1); printLCD(lcd, sprintf("%02d:%02d:%02d", t.hour, t.min, t.sec)) pause(1); endwhile arduino-0.4.0/inst/examples/example_shiftreg_595.m0000644000000000000000000000251513470770202020250 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . # example using a 74HC595 shift register # breakout board https://www.sparkfun.com/products/10680 # arduino shiftRegister (sparkfun breakout) # d2 14 io (ser_in) # d3 11 clk (clock) # d4 12 latch (l_clk) # d5 10 reset (/reset) # 5V 16 vcc (Vcc) # gnd 8 gnd (Gnd) # gnd 13 oe (oe) a = arduino("","", 'Libraries', { "ShiftRegister" }) reg = shiftRegister(a, '74HC595', 'd2', 'd3', 'd4', 'd5'); reset(reg); val = uint8(1) while(true) write(reg, val); pause(1); val = val + uint8(1) endwhile arduino-0.4.0/inst/examples/example_spi_mcp3002.m0000644000000000000000000000404713470770202017774 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## test program for octave - arduino - mcp3002 10 bit ADC (spi) # Assuming connections of # Arduino MCP3002 # D10 - 1 (CS) # D11 - 5 (DI) # D12 - 6 (DO) # D13 - 7 (CLK) # VCC - 8 (VDD) # GND - 4 (VSS) # 2 (CH0) - chan 0 input # 3 (CH1) - chan 1 input unwind_protect ar = arduino(); # talk to the mpc3002 via spi - SS = D10 on uno # set msb mode spi = spidev(ar, "d10") # command (bits) in MSB mode to device # [START SGL ODN MSBF X X X X] [ X X X X X X X X ] # 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 # [chan 0 ] MSB # data back # X X X X X 0 D D D D D D D D D D printf("reading ADC @ 1 Hz...\n"); # skip first reading v = writeRead(spi, [ hex2dec("DF") hex2dec("FF") ]); while (true) pause(1); # chan 0 v = writeRead(spi, [ hex2dec("DF") hex2dec("FF") ]); adc = bitand (uint16(v(1))*256 + uint16(v(2)), hex2dec('3FF')); volts = double(adc) * 5.0 / 1023.0; printf("ch0 = 0x%04X (adc) %f (volts)\n", adc, volts) # chan 1 v = writeRead(spi, [ hex2dec("EF") hex2dec("FF") ]); adc = bitand (uint16(v(1))*256 + uint16(v(2)), hex2dec('3FF')); volts = double(adc) * 5.0 / 1023.0; printf("ch1 = 0x%04X (adc) %f (volts)\n", adc, volts) endwhile unwind_protect_cleanup clear ar end_unwind_protect arduino-0.4.0/inst/examples/example_sweep_servo.m0000644000000000000000000000257613470770202020403 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . % example control servo on D9 % scans servo between min - max position a = arduino(); unwind_protect # hobby servo with puslses between 1ms - 2 ms s = servo (a, 'd9', 'MinPulseDuration', 1e-3, 'MaxPulseDuration', 2e-3) # go mid position writePosition (s, .5); # loop, slowly going between min - max pos speed = 0.02; pauseval = .05; printf ("scanning ...\n"); while (true) pos = readPosition (s); pos = pos + speed; if(pos > 1) pos = 1; speed = -speed; endif if(pos < 0) pos = 0; speed = -speed; endif writePosition (s, pos); pause (pauseval); endwhile unwind_protect_cleanup clear a end_unwind_protect arduino-0.4.0/inst/isarduino.m0000644000000000000000000000265013470770202014477 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} isarduino (@var{obj}) ## Check if input value is an arduino object ## ## Function is essentially just a call of ## @code { ## retval = asis(obj, "arduino"); ## } ## ## @subsubheading Inputs ## @var{obj} - The object to check ## ## @subsubheading Outputs ## @var{retval} is true, if obj is an arduino object, false otherwise. ## ## @seealso{arduino} ## @end deftypefn function retval = isarduino (obj) retval = false; if nargin > 0 && isa(obj, "arduino") retval = true; endif endfunction %!test %! a = arduino(); %! assert(isarduino(a), true) %!assert(isarduino(0), false) %!assert(isarduino({}), false) %!assert(isarduino([]), false) %!assert(isarduino(), false) arduino-0.4.0/inst/listArduinoLibraries.m0000644000000000000000000000547313470770202016642 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} listArduinoLibraries () ## @deftypefnx {} {@var{retval} =} listArduinoLibraries (@var{libtypes}) ## Retrieve list of all known arduino library modules that are available. ## ## @subsubheading Inputs ## @var{libtypes} - optional specifier for type of libraries to list. ## ## Options are: ## @table @asis ## @item all ## List core and addons ## @item core ## List core only libraries ## @item addons ## List addons only ## @end table ## When no libtypes is specified, all libraries are shown. ## ## @subsubheading Outputs ## @var{retval} is an cell array of string library names that are ## available for programming to the arduino. ## ## @seealso{arduino, arduinosetup} ## @end deftypefn function retval = listArduinoLibraries (libtypes) retval = {}; if nargin == 0 libtypes = "all"; elseif ! ischar(libtypes) error ("Expected libtypes to be a string") endif if ! (strcmpi(libtypes, "all") || strcmpi(libtypes, "addons") || strcmpi(libtypes, "core")) error ("Invalid libtypes value '%s'", libtypes) endif # hardcoded libraries if strcmpi(libtypes, "all") || strcmpi(libtypes, "core") retval{end+1} = 'I2C'; retval{end+1} = 'Servo'; retval{end+1} = 'SPI'; retval{end+1} = 'ShiftRegister'; retval{end+1} = 'RotaryEncoder'; endif # add ons if strcmpi(libtypes, "all") || strcmpi(libtypes, "addons") addonfiles = __addons__ (); for i = 1:numel (addonfiles) retval{end+1} = addonfiles{i}.libraryname; endfor endif endfunction %!test %! libs = listArduinoLibraries (); %! assert (!isempty (libs)) %! assert (! isempty (find(strcmp(libs, 'SPI')))); %! assert (isempty (find(strcmp(libs, 'unknown')))); %!test %! deflibs = listArduinoLibraries (); %! alllibs = listArduinoLibraries ("all"); %! corelibs = listArduinoLibraries ("core"); %! addonlibs = listArduinoLibraries ("addons"); %! assert(numel(alllibs) == (numel(corelibs) + numel(addonlibs))) %! assert(numel(alllibs) == numel(deflibs)) %!error listArduinoLibraries(1) %!error listArduinoLibraries("invalid") arduino-0.4.0/inst/private/0000755000000000000000000000000013470770202013773 5ustar0000000000000000arduino-0.4.0/inst/private/__addons__.m0000644000000000000000000000546713470770202016231 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} __addons__ () ## Private function to get information aabout all user ## plugins ## @end deftypefn function addonfiles = __addons__ () addonfiles = {}; addonpathfix = fileparts (mfilename ('fullpath')); # how can we look for +arduinioaddons in the load path # genpath and dir_in_loadpath wont do it, so have to do it the hard way loadpaths = strsplit (path (), pathsep); addondirs = {}; for i = 1:numel (loadpaths) checkpath = fullfile (loadpaths{i}, "+arduinoioaddons"); if exist (checkpath, "dir") addondirs{end+1} = checkpath; endif endfor # we expect <+arduinoioaddons>/+AddonFolderName/ for i=1:numel (addondirs) files = dir (addondirs{i}); for j = 1:numel (files) if files(j).isdir && files(j).name(1) != '.' searchname = fullfile (addondirs{i}, files(j).name, "*.m"); f1 = files (j).name; if f1(1) == "+" f1 = f1(2:end); endif files2 = dir (searchname); folder = fileparts(searchname); for k = 1:numel (files2) finfo = {}; [d2,f2,e2] = fileparts (files2(k).name); classname = sprintf ("arduinoioaddons.%s.%s", f1, f2); if is_arduino_addon_class(classname) z = eval(sprintf ("%s.AddonInfo('%s')", classname, classname)); z.scriptfile = fullfile (folder, files2(k).name); # paths are wrong, as mfilename isnt giving use a path from within the class # so for now, fixing here z.cppheaderfile = strrep (z.cppheaderfile, addonpathfix, folder); z.cppsourcefile = strrep (z.cppsourcefile, addonpathfix, folder); addonfiles{end+1} = z; endif endfor endif endfor endfor endfunction function retval = is_arduino_addon_class(classname) classinfo = meta.class.fromName(classname); if !isempty(classinfo) idx = find( cellfun(@(x) strcmpi(x.Name, "arduinoio.LibraryBase"), classinfo.SuperClassList), 1); retval = !isempty(idx); else retval = false; endif endfunction arduino-0.4.0/inst/private/__arduino_binary__.m0000644000000000000000000000706713470770202017764 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} __arduino__binary__ (}) ## @deftypefnx {} {@var{retval} =} __arduino__binary__ (@var{newpath}) ## Private function to set arduino path ## @seealso{arduinosetup} ## @end deftypefn function retval = __arduino_binary__ (newarduinopath) persistent arduino_binary = "" if nargin == 0 if isempty(arduino_binary) arduino_binary = find_arduino_binary (); endif else % trying to set the path ? arduino_binary = newarduinopath; endif retval = arduino_binary; endfunction function arduino_binary = find_arduino_binary () # use arduino_debug.exe in windoze ? binary_name = "arduino"; arduino_binary = ""; if (isunix ()) binaries = strcat (binary_name, {"", ".exe"}); else binaries = strcat (binary_name, {".exe"}); endif n = 0; while (n < numel (binaries) && isempty (arduino_binary)) arduino_binary = file_in_path (getenv ("PATH"), binaries{++n}); endwhile % if a pc, and have the winqueryreg function, try find the path if isempty(arduino_binary) && ispc () if exist('winqueryreg') == 5 try arduino_binary = winqueryreg("HKLM", 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\arduino.exe'); end_try_catch if isempty(arduino_binary) # try win32 registry try arduino_binary = fullfile(winqueryreg("HKLM", 'SOFTWARE\WOW6432Node\Arduino', 'install_dir'), 'arduino.exe'); end_try_catch endif endif if isempty(arduino_binary) trypath = "C:\\Program Files (x86)\\Arduino\\arduino.exe"; if exist (trypath, "file") arduino_binary = trypath; endif endif endif % look for arduino prefs file if isempty (arduino_binary) if ispc () prefsfile = fullfile (getenv ("LOCALAPPDATA"), "Arduino15", "preferences.txt"); else prefsfile = fullfile (getenv ("HOME"), ".arduino15", "preferences.txt"); endif fd = fopen (prefsfile, "rt") if fd != -1 try trypaths = {}; while ! feof (fd) l = fgetl (fd); str = regexp (l, "last\.ide\.(?\\d.*)\.hardwarepath=(?.*)$", "names"); if ! isempty (str) trypaths{end+1} = str; endif endwhile if !isempty (trypaths) % sort so will try newest ver first [~, sortidx] = sort(arrayfun( @(x) x{1}.version, trypaths, 'uniformoutput', false), 'descend'); for idx = 1:length(sortidx) if isempty (arduino_binary) [trypath,~,~] = fileparts (trypaths{idx}.path); n = 0; while (n < numel (binaries) && isempty (arduino_binary)) arduino_binary = file_in_path (trypath, binaries{++n}) endwhile endif endfor endif end_try_catch fclose (fd); endif endif if isempty(arduino_binary) error ("__arduino_binary__: can not find the arduino binary"); endif endfunction arduino-0.4.0/inst/scanForArduinos.m0000644000000000000000000001027213470770202015601 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} scanForArduinos (@var{maxCount}) ## @deftypefnx {} {@var{retval} =} scanForArduinos (@var{maxCount}, @var{type}) ## Scan system for programmed arduino boards. ## ## scanForArduinos will scan the system for programmed arduino boards and return at ## most @var{maxCount} of them as a cell array in @var{retval}. ## ## @subsubheading Inputs ## @var{maxCount} - max number of arduino boards to detect. ## if @var{maxCount} is not specified, or is a less than 1, the function will return as many ## arduino boards as it can detect. ## ## @var{type} - optional board type to match. If specified, the board type must match for the arduino to be added to the ## return list. ## ## @subsubheading Outputs ## @var{retval} structure cell array of matching detected arduino boards. ## ## Each cell value of the cell array will contain a structure with values of: ## @table @asis ## @item port ## the serial port the arduino is connected to ## @item board ## the board type of the arduino ## @end table ## ## @seealso{arduino} ## @end deftypefn function arduinos = scanForArduinos (maxCount, typestr) arduinos = {}; ARDUINO_INIT_COMMAND = 1; if nargin > 2 print_usage (); elseif nargin == 1 typestr = ""; elseif nargin == 0 maxCount = 0; typestr = ""; endif if ! isnumeric (maxCount) error ("scanForArduinos expected maxCount to be a number"); endif if ! ischar (typestr) && !isempty (typestr) error ("scanForArduinos expected typestr to be a board type"); elseif ischar (typestr) typestr = tolower (typestr); else typestr = ""; endif # get list of serial ports to try ports = instrhwinfo ('serial'); for i = 1:numel (ports) try s = {}; unwind_protect if isunix portname = ["/dev/" ports{i}]; elseif ispc portname = [ "\\\\.\\" ports{i}]; else portname = ports{i}; endif s = serial (portname, 9600, 1); pause(2); hdr = uint8 ([ hex2dec("A5") 0 ARDUINO_INIT_COMMAND 0]); len = srl_write (s, hdr); [tmpdataOut, tmpdataSize] = srl_read (s, 4); if tmpdataSize == 4 && tmpdataOut(1) == hex2dec("A5") && tmpdataOut(2) == 0 && tmpdataOut(3) == ARDUINO_INIT_COMMAND && tmpdataOut(4) >= 5 expectlen = tmpdataOut(4); [dataout, datasize] = srl_read (s, expectlen); if datasize == expectlen # init returns the following info sig = (uint32 (dataout(1))*256*256) + (uint32 (dataout(2))*256) + uint32 (dataout(3)); board = dataout(4); voltref = double (dataout(5))/10.0; if isempty (typestr) || strcmpi(arduinoio.boardTypeString (board), typestr) info = {}; info.port = portname; info.board = arduinoio.boardTypeString (board); arduinos{end+1} = info; if numel (arduinos) == maxCount break; endif endif endif endif unwind_protect_cleanup if !isempty (s) srl_close (s); endif end_unwind_protect catch err % do nothing end_try_catch endfor endfunction %!test %! # assuming that to test, we have at least one board available %! arduinos = scanForArduinos(1); %! assert(numel(arduinos), 1); %! assert(!isempty(arduinos{1}.port)) %! assert(!isempty(arduinos{1}.board)) %!test %! arduinos = scanForArduinos(1, "madeuparduinoname"); %! assert(isempty(arduinos)); arduino-0.4.0/inst/scanI2Cbus.m0000644000000000000000000000432113470770202014433 0ustar0000000000000000## Copyright (C) 2018-2019 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {@var{retval} =} scanI2Cbus (@var{ar}) ## @deftypefnx {} {@var{retval} =} scanI2Cbus (@var{ar}, @var{bus}) ## Scan arduino for devices on the I2C bus. ## ## @subsubheading Inputs ## @var{ar} - arduino object connected to a arduino board. ## ## @var{bus} - bus number to scan I2C devices, when multiple buses are available. ## If the bus is not specified, it will default to 0. ## ## @subsubheading Outputs ## @var{retval} - cell array of addresses as strings in format of "0xXX". ## ## @subsubheading Example ## @example ## @code { ## # create arduino connection. ## ar = arduino(); ## # scan for devices on the I2C bus ## scanI2Cbus (ar) ## # output is each detected i2c address as a string ## ans = ## @{ ## [1,1] = 0x50 ## @} ## } ## @end example ## ## @seealso{arduino, i2cdev, checkI2CAddress} ## @end deftypefn function addr = scanI2Cbus (ar, bus) addr = {}; if nargin < 1 || nargin > 2 print_usage (); endif if nargin == 1 bus = 0; elseif !isnumeric (bus) || bus < 0 || bus > 1 error ('scanI2Cbus: expected bus to be numeric and 0 or 1'); endif if (!isa (ar, "arduino")) error ("scanI2Cbus: expects arduino object as 1st argument"); endif # TODO: configure SPI pins if not already done?? # scan each address, and add any found to cell array for i = 1:127 if checkI2CAddress (ar, i, bus) addr{end+1} = [ "0x" dec2hex(i, 2) ]; endif endfor endfunction %!test %! ar = arduino(); %! assert(!isempty(ar)); %! scanI2Cbus(ar); arduino-0.4.0/octave-arduino.metainfo.xml0000644000000000000000000000225413470770202016612 0ustar0000000000000000 octave-arduino www.octave.org-octave.desktop Arduino Toolkit

Octave to Arduino interface toolkit

Basic Octave implementation of the matlab arduino extension, allowing communication to a programmed arduino board to control its hardware.

arduino communication http://octave.sourceforge.net/arduino https://savannah.gnu.org/bugs/?func=additem&group=octave GPL-3.0+ Octave-Forge Community octave-maintainers@gnu.org FSFAP arduino-0.4.0/test/0000755000000000000000000000000013470770202012323 5ustar0000000000000000arduino-0.4.0/test/make_conf.m0000644000000000000000000001350313470770202014425 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . #Usage: octave --eval "make_conf('/usr/share/arduino/hardware/arduino/avr/variants/mega/pins_arduino.h')" function retval = make_conf (header_file) if nargin != 1 error ('Expected single input argument of header filename') endif pins = {}; ispwm = {}; isalong = {}; num_digital_pins = 0; num_analog_pins = 0; fd = fopen (header_file, "rt"); while !feof(fd) l = fgetl(fd); [t, m] = regexp(l, '#define\s+(\w+)\s+([^\s]+)$', 'tokens', 'match'); if !isempty(t) toks = t(1){1}; if numel(toks) == 2 if strcmpi(toks{1}, "NUM_DIGITAL_PINS") cnt = strrep(toks{2}, "u", ""); num_digital_pins = str2num(cnt); elseif strcmpi(toks{1}, "NUM_ANALOG_INPUTS") cnt = strrep(toks{2}, "u", ""); num_analog_pins = str2num(cnt); else idx = index(toks{1}, "PIN_"); if idx > 0 name = tolower(strtrim(toks{1}(idx+4:end))); # id have other crap in it ? id = strrep(toks{2}, "u", ""); id = str2num(id); if !isempty(id) # we have pin already ? idx = find (cellfun(@(x) (x.id == id), pins), 1); if isempty(idx) p = []; p.id = id; p.name = sprintf("D%d", id); p.modes = { 'digital' }; pins{end+1} = p; idx = numel(pins); endif if name(1) == 'a' pins{idx}.name = toupper(name); pins{idx}.modes{end+1} = "analog"; elseif strncmp(name, "wire_", 5) pins{idx}.modes{end+1} = ["i2c" name(5:end)]; elseif strncmp(name, "pin_led_", 8) pins{idx}.modes{end+1} = ["led"]; else pins{idx}.modes{end+1} = name; endif endif elseif strcmp(toks{1}, "LED_BUILTIN") id = str2num(toks{2}); if !isempty(id) idx = find (cellfun(@(x) (x.id == id), pins), 1); if isempty(idx) p = {}; p.id = id; p.name = sprintf("D%d", id); p.modes = { 'digital' }; pins{end+1} = p; idx = numel(pins); endif pins{idx}.modes{end+1} = "led"; endif endif endif endif endif [t, m] = regexp(l, '#define\s+digitalPinHasPWM\((\w+)\)\s+(.*)$', 'tokens', 'match'); if ! isempty(t) toks = t(1){1}; if numel(toks) == 2 ispwm.var = toks{1}; testv = strrep(toks{2}, "u", ""); ispwm.test = testv; ispwm = {}; endif endif [t, m] = regexp(l, '#define\s+analogInputToDigitalPin\((\w+)\)\s+(.*)$', 'tokens', 'match'); if ! isempty(t) toks = t(1){1}; if numel(toks) == 2 isanalog.var = toks{1}; testv = strrep(toks{2}, "u", ""); # simple expect analog after digital testv = sprintf("(p + %d)", num_digital_pins); isanalog.test = testv; #isanalog={}; endif endif endwhile fclose(fd); #num_digital_pins #num_analog_pins # fill in any missing digitals for i=0:num_analog_pins-1 name = sprintf("A%d", i); idx = find (cellfun(@(x) (strcmpi(x.name,name)), pins), 1); if isempty(idx) t = sprintf("%s=%i; id=(%s);", isanalog.var, i, isanalog.test); eval(t); if id >= 0 p = {}; p.id = id; p.name = sprintf("A%d", i); p.modes = { 'digital', 'analog' }; pins{end+1} = p; idx = numel(pins); endif endif endfor # fill in any missing digitals for i=0:num_digital_pins-1 idx = find (cellfun(@(x) (x.id == i), pins), 1); if isempty(idx) p = {}; p.id = i; p.name = sprintf("D%d", i); p.modes = { 'digital' }; pins{end+1} = p; idx = numel(pins); endif if !isempty(ispwm) t = sprintf("%s=%i; pwm=(%s);", ispwm.var, i, ispwm.test); eval(t); if pwm pins{idx}.modes{end+1} = "pwm"; endif endif endfor # sort by pin num (id) [tmp ind]=sort(cellfun(@(x) (x.id), pins)); # output file printf ("# configuration generated from %s\n", header_file) printf("function retval = config_XXX (initdata)\n"); printf(" retval = {};\n"); printf("\n"); printf(" # default board info - must be provided\n"); printf(" # will be filled in on connection.\n"); printf(" retval.board = '';\n"); printf(" retval.board = '';\n"); printf(" retval.mcu = '';\n"); printf(" retval.voltref = 0;\n"); printf(" retval.libs = {};\n"); printf(" retval.port = '';\n"); printf("\n"); printf(" # info expected to be provided by config.\n"); printf(" retval.description = 'a board description';\n"); printf("\n"); printf(" # pin config\n"); printf(" retval.pins = {};\n"); for i = 1:numel(ind) p = pins{ind(i)}; modes = [ "'" p.modes{1} "'"]; for m = 2:numel(p.modes) modes = [ modes ", '" p.modes{m} "'" ]; endfor printf(" retval.pins{end+1} = arduinoio.config.pin_info('%s', %d, { %s });\n", p.name, p.id, modes); endfor printf("endfunction\n"); endfunction arduino-0.4.0/test/test_exampleplugin.m0000644000000000000000000000152213470770202016412 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . #arduinosetup ('libraries', 'ExampleAddon/Echo') a = arduino(); b = addon(a, "ExampleAddon/Echo") b.shout("Hello") b.shout("World") arduino-0.4.0/test/test_jig.m0000644000000000000000000002337613470770202014324 0ustar0000000000000000## Copyright (C) 2018 John Donoghue ## ## This program is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see ## . % test_jig % expects a arduino uno to be connected via serial port % with test connections as folows: % arduino - 24XX256 EEPROM chip (i2c) % arduino - mcp3002 10 bit ADC (spi) % arduino - hobby servo % % Connection of arduino to test jig as follows: % Arduino % 24XX256 eeprom % A4 - 5 % A5 - 6 % 5V - 8 % GND - 1,2,3,4 % % Arduino MCP3002 % D10 - 1 (CS) % D11 - 5 (DI) % D12 - 6 (DO) % D13 - 7 (CLK) % VCC - 8 (VDD) % GND - 4 (VSS) % VCC 2 (CH0) - chan 0 input % D2 3 (CH1) - chan 1 input % Servo % Arduino Servo % d9 - signal % VCC - power % gnd - gnd % I/O % Arduino Arduino % A3 - D3 % D4 - D5 % D7 - Not connected % D6 - +10UF cap - GND % A0 - D6 pkg load instrument-control [~, ~, endian] = computer (); unwind_protect printf("1. opening arduino\n"); a = arduino(); if isempty(a) printf("** open failied **\n") endif assert(~isempty(a)) printf("2. I2C tests with EEPROM\n"); eeprom_address = 0x50; printf("* i2c terminals\n") terms = getI2CTerminals(a); if isempty(terms) printf("** getI2CTerminals failed **\n") endif printf("* i2c devices attached\n") devs = scanI2Cbus(a); idx = find(devs = eeprom_address); if isempty(idx) error ('scanI2bus failed - skipping eeprom tests') else printf("* opening i2c...\n"); i2c = i2cdev(a, eeprom_address); if isempty(i2c) printf("** i2cdev failed **\n") endif printf("* writing i2c bytes...\n"); # write data to address 0x0000 write(i2c, [0 0 0 1 2 3 4 5 6 7 8 9 10]); # read from address 0x0000, which should now be 0 1 2 3 4 5 6 7 printf("* reading i2c 0000 bytes...\n"); write(i2c, uint8([0 0])); val = read(i2c, 8); if val != uint8([0 1 2 3 4 5 6 7]) printf("byte read/write failed!\n"); endif printf("* reading i2c 0002 bytes...\n"); write(i2c, uint8([0 2])); val = read(i2c, 8); if val != uint8([2 3 4 5 6 7 9 10]) printf("byte read/write failed!\n"); endif printf("* reading i2c 0002 uint16...\n"); write(i2c, uint16([2]), 'uint16'); val = read(i2c, 4, 'uint16'); expected = typecast(uint8([2 3 4 5 6 7 8 9]), 'uint16'); if endian == 'L' expected = swapbytes(expected); endif if val != expected printf("uint16 read failed!\n"); endif printf("* reading i2c 0000 uint16 as register...\n"); val = readRegister(i2c, 0, 2, 'uint16'); expected = typecast(uint8([0 1 2 3]), 'uint16'); if endian == 'L' expected = swapbytes(expected); endif if val != expected printf("read reg16 failed!\n"); endif printf("* reading i2c 0001 uint16 as register...\n"); val = readRegister(i2c, 1, 2, 'uint16'); expected = typecast(uint8([1 2 3 4]), 'uint16'); if endian == 'L' expected = swapbytes(expected); endif if val != expected printf("read reg16 failed!\n"); endif printf("* writing i2c uint16 reg...\n"); writeRegister(i2c, 258, [8 9], 'uint16') printf("* reading i2c 0102 bytes...\n"); write(i2c, uint8([1 2])); val = read(i2c, 4); if val != uint8([0 8 0 9]) printf("byte read/write failed!\n"); endif printf("* reading i2c 0102 uint16 as register...\n"); val = readRegister(i2c, 258, 2, 'uint16'); expected = [8 9]; if val != expected printf("read reg16 failed!\n"); endif clear i2c; endif printf("3. SPI tests with ADC\n"); printf("* opening spi...\n"); spi = spidev(a, "d10"); if isempty(spi) printf("** spi failed **\n") endif # chan0 printf("* reading spi chan 0...\n"); val = writeRead(spi, [ hex2dec("DF") hex2dec("FF") ]); val = writeRead(spi, [ hex2dec("DF") hex2dec("FF") ]); adc = bitand (uint16(val(1))*256 + uint16(val(2)), hex2dec('3FF')); volts = double(adc) * 5.0 / 1023.0; if volts < 4.5 || volts > 5.0 printf("unexpected voltage ch0 = 0x%04X (adc) %f (volts)\n", adc, volts) endif # chan 1 printf("* reading spi chan 1 low...\n"); writeDigitalPin(a, "d2", 0); val = writeRead(spi, [ hex2dec("EF") hex2dec("FF") ]); adc = bitand (uint16(val(1))*256 + uint16(val(2)), hex2dec('3FF')); volts = double(adc) * 5.0 / 1023.0; if volts > 0.5 printf("unexpected voltage ch1 = 0x%04X (adc) %f (volts)\n", adc, volts) endif printf("* reading spi chan 1 high...\n"); writeDigitalPin(a, "d2", 1); val = writeRead(spi, [ hex2dec("EF") hex2dec("FF") ]); adc = bitand (uint16(val(1))*256 + uint16(val(2)), hex2dec('3FF')); volts = double(adc) * 5.0 / 1023.0; if volts < 4.5 printf("unexpected voltage ch1 = 0x%04X (adc) %f (volts)\n", adc, volts) endif # other SPI tests ?? clear spi printf("4. Digital I/O\n"); printf("* reading analog high to d3...\n"); writeDigitalPin(a, "a3", 1); pause(1); val = readDigitalPin(a, "d3"); if val != 1 printf("unexpected 33 value %d\n", val); endif val = readDigitalPin(a, "a3"); if val != 1 printf("unexpected A3 value %d\n", val); endif printf("* reading analog low to d3...\n"); writeDigitalPin(a, "a3", 0); pause(1); val = readDigitalPin(a, "d3"); if val != 0 printf("unexpected D3 value %d\n", val); endif val = readDigitalPin(a, "a3"); if val != 0 printf("unexpected A3 value %d\n", val); endif printf("* reading digital low to d4...\n"); writeDigitalPin(a, "d4", 0); pause(1); val = readDigitalPin(a, "d4"); if val != 0 printf("unexpected d4 value %d\n", val); endif val = readDigitalPin(a, "d5"); if val != 0 printf("unexpected d5 value %d\n", val); endif printf("* reading digital high to d4...\n"); writeDigitalPin(a, "d4", 1); pause(1); val = readDigitalPin(a, "d4"); if val != 1 printf("unexpected d4 value %d\n", val); endif val = readDigitalPin(a, "d5"); if val != 1 printf("unexpected d5 value %d\n", val); endif printf("5. Analog input\n"); configurePin(a, "d3", "unset"); writeDigitalPin(a, "d3", 0); configurePin(a, "a3", "unset"); pause(1); printf("* reading analog low a3...\n"); val = readAnalogPin(a, "a3"); if val > 200 printf("unexpected a3 value %d\n", val); endif val = readVoltage(a, "a3"); if val > 0.5 printf("unexpected a3 value %f\n", val); endif printf("* reading analog high a3...\n"); writeDigitalPin(a, "d3", 1); pause(1); val = readAnalogPin(a, "a3"); if val < 1000 printf("unexpected a3 value %d\n", val); endif val = readVoltage(a, "a3"); if val < 4.5 printf("unexpected a3 value %f\n", val); endif printf("6. Pullup I/O\n"); printf("* pullup d7...\n"); configurePin(a, "d7", "pullup"); val = readDigitalPin(a, "d7"); if val != 1 printf("unexpected d7 value %d\n", val); endif # analog output /PWM printf("7. Analog Output\n"); printf("* pwm duty cycle 0...\n"); writePWMDutyCycle(a, "d6", 0); pause(1); val = readVoltage(a, "a0"); if val > 0.1 printf("unexpected a0 value %f\n", val); endif printf("* pwm duty cycle 1...\n"); writePWMDutyCycle(a, "d6", 1); pause(1); val = readVoltage(a, "a0"); if val < 4.5 printf("unexpected a0 value %f\n", val); endif printf("* pwm duty cycle 0.5...\n"); writePWMDutyCycle(a, "d6", 0.5); pause(1); val = readVoltage(a, "a0"); if val < 2.0 || val > 3.0 printf("unexpected a0 value %f\n", val); endif printf("* pwm voltage 0...\n"); writePWMVoltage(a, "d6", 0.0); pause(1); val = readVoltage(a, "a0"); if val > 0.2 printf("unexpected a0 value %f\n", val); endif printf("* pwm voltage 5...\n"); writePWMVoltage(a, "d6", 5.0); pause(1); val = readVoltage(a, "a0"); if val < 4.5 printf("unexpected a0 value %f\n", val); endif printf("* pwm voltage 3...\n"); writePWMVoltage(a, "d6", 3.0); pause(1); val = readVoltage(a, "a0"); if val < 2.4 || val > 4.0 printf("unexpected a0 value %f\n", val); endif # TODO: servo printf("8. Servo\n"); printf("* create servo...\n"); s = servo(a, "d9", 'MinPulseDuration', 1e-3, 'MaxPulseDuration', 2e-3); if isempty(s) printf("** servo failied **\n") endif printf("* go min pos...\n"); writePosition(s, 0); val = readPosition(s); if val != 0 printf("invalid position %f\n", val); endif printf("* scan pos...\n"); for pos = [0:.01:1] writePosition(s, pos); pause(0.02); endfor printf("* go max pos...\n"); writePosition(s, 1); val = readPosition(s); if val != 1 printf("invalid position %f - expected %f\n", val, 1); endif printf("9. LEDS\n"); printf("* get pins...\n"); leds = getPinsFromTerminals(a, getLEDTerminals(a)); if isempty(leds) printf("no LED pins"); endif printf("* set leds 0\n"); for i = [1:1:numel(leds)] pin = leds{i}; configurePin(a, pin, "unset"); writeDigitalPin(a, pin, 0) endfor pause(2); printf("* set leds 1\n"); for i = [1:1:numel(leds)] pin = leds{i}; writeDigitalPin(a, pin, 1) endfor pause(2); printf("* set leds 0\n"); for i = [1:1:numel(leds)] pin = leds{i}; writeDigitalPin(a, pin, 0) endfor unwind_protect_cleanup clear a end_unwind_protect