From 73e16950d73578900d54f3470b57402a9e908c30 Mon Sep 17 00:00:00 2001 From: bzztbomb Date: Tue, 5 Apr 2011 19:57:16 -0700 Subject: Public firmware release. --- COPYING | 674 +++++++++++++++++++ Libraries/OSC/OSCDecoder.cpp | 103 +-- Libraries/OSC/OSCEncoder.cpp | 87 +-- Libraries/OSC/OSCMessage.cpp | 335 +++++----- Libraries/OSC/OSCMessage.h | 101 ++- Libraries/OSC/OSCcommon.h | 22 +- Libraries/WiShield/WiShield.cpp | 32 +- Libraries/WiShield/WiShield.h | 4 +- Libraries/WiShield/config.h | 11 +- Libraries/WiShield/g2100.c | 24 +- Libraries/WiShield/psock.c | 2 + Libraries/WiShield/stack.c | 8 + Libraries/WiShield/uip-conf.h | 2 +- Libraries/WiShield/uip-neighbor.c | 3 +- Libraries/WiShield/uip.c | 11 +- Libraries/WiShield/uip.h | 1 + Libraries/arduino/HardwareSerial.cpp | 236 +++++++ Libraries/arduino/HardwareSerial.h | 67 ++ Libraries/arduino/Print.cpp | 220 +++++++ Libraries/arduino/Print.h | 66 ++ Libraries/arduino/Stream.h | 34 + Libraries/arduino/Tone.cpp | 518 +++++++++++++++ Libraries/arduino/WConstants.h | 1 + Libraries/arduino/WInterrupts.c | 215 ++++++ Libraries/arduino/WMath.cpp | 60 ++ Libraries/arduino/WProgram.h | 62 ++ Libraries/arduino/WString.cpp | 436 +++++++++++++ Libraries/arduino/WString.h | 111 ++++ Libraries/arduino/binary.h | 515 +++++++++++++++ Libraries/arduino/main.cpp | 14 + Libraries/arduino/pins_arduino.c | 465 +++++++++++++ Libraries/arduino/pins_arduino.h | 88 +++ Libraries/arduino/wiring.c | 244 +++++++ Libraries/arduino/wiring.h | 134 ++++ Libraries/arduino/wiring_analog.c | 183 ++++++ Libraries/arduino/wiring_digital.c | 129 ++++ Libraries/arduino/wiring_private.h | 68 ++ Libraries/arduino/wiring_pulse.c | 66 ++ Libraries/arduino/wiring_shift.c | 55 ++ Libraries/avrmidi/.gitignore | 6 + Libraries/avrmidi/COPYING | 674 +++++++++++++++++++ Libraries/avrmidi/Makefile | 41 ++ Libraries/avrmidi/README | 15 + Libraries/avrmidi/bytequeue.c | 65 ++ Libraries/avrmidi/bytequeue.h | 49 ++ Libraries/avrmidi/examples/Makefile | 68 ++ Libraries/avrmidi/examples/basic.c | 127 ++++ Libraries/avrmidi/examples/lufa_midi/Descriptors.c | 329 ++++++++++ Libraries/avrmidi/examples/lufa_midi/Descriptors.h | 83 +++ Libraries/avrmidi/examples/lufa_midi/main.c | 20 + Libraries/avrmidi/examples/lufa_midi/makefile | 719 +++++++++++++++++++++ Libraries/avrmidi/examples/lufa_midi/midi_usb.c | 161 +++++ Libraries/avrmidi/examples/lufa_midi/midi_usb.h | 8 + Libraries/avrmidi/examples/serial_midi.c | 49 ++ Libraries/avrmidi/examples/serial_midi.h | 10 + Libraries/avrmidi/examples/spit.c | 18 + Libraries/avrmidi/interrupt_setting.c | 36 ++ Libraries/avrmidi/interrupt_setting.h | 31 + Libraries/avrmidi/midi.c | 252 ++++++++ Libraries/avrmidi/midi.h | 135 ++++ Libraries/avrmidi/midi_device.c | 299 +++++++++ Libraries/avrmidi/midi_device.h | 90 +++ Libraries/avrmidi/midi_function_types.h | 34 + Libraries/avrmidi/sysex_tools.c | 99 +++ Libraries/avrmidi/sysex_tools.h | 78 +++ Libraries/avrmidi/test/.gitignore | 3 + Libraries/avrmidi/test/Makefile | 28 + Libraries/avrmidi/test/avr/interrupt.h | 27 + Libraries/avrmidi/test/dummy_device.c | 283 ++++++++ Libraries/avrmidi/test/dummy_device.h | 0 Libraries/avrmidi/test/sysex_test.c | 79 +++ Libraries/twi/twi.c | 274 ++++++++ Libraries/twi/twi.h | 59 ++ MissingLink/HandleMidi.cpp | 543 ++++++++++++++++ MissingLink/HandleMidi.h | 59 ++ MissingLink/MLSerial.cpp | 255 ++++++++ MissingLink/MLSerial.h | 86 +++ MissingLink/ML_Config.c | 130 ++++ MissingLink/ML_Config.h | 88 +++ MissingLink/Makefile | 97 +++ MissingLink/MissingLink.cpp | 326 ++++++++++ MissingLink/Output.cpp | 54 ++ MissingLink/Output.h | 34 + MissingLink/Parse.cpp | 178 +++++ MissingLink/Parse.h | 36 ++ MissingLink/led.h | 29 + MissingLink/udpapp-ml.h | 25 + MissingLink/udpapp.cpp | 158 +++++ OSCSendTest/OSCSendTest.pde | 63 -- OSCSendTest/udpapp.cpp | 73 --- OSCTest/OSCTest.pde | 109 ---- OSCTest/udpapp.cpp | 103 --- bootloader/COPYING | 674 +++++++++++++++++++ bootloader/README | 32 + bootloader/avr_code/Makefile | 40 ++ bootloader/avr_code/bootloadercfg.h | 59 ++ bootloader/avr_code/main.c | 306 +++++++++ bootloader/example/Makefile | 45 ++ bootloader/example/main.c | 46 ++ bootloader/midi/.gitignore | 6 + bootloader/midi/COPYING | 674 +++++++++++++++++++ bootloader/midi/Makefile | 41 ++ bootloader/midi/README | 15 + bootloader/midi/bytequeue/COPYING | 674 +++++++++++++++++++ bootloader/midi/bytequeue/bytequeue.c | 65 ++ bootloader/midi/bytequeue/bytequeue.h | 49 ++ bootloader/midi/bytequeue/interrupt_setting.c | 36 ++ bootloader/midi/bytequeue/interrupt_setting.h | 31 + bootloader/midi/examples/Makefile | 68 ++ bootloader/midi/examples/basic.c | 127 ++++ bootloader/midi/examples/lufa_midi/Descriptors.c | 329 ++++++++++ bootloader/midi/examples/lufa_midi/Descriptors.h | 83 +++ bootloader/midi/examples/lufa_midi/main.c | 20 + bootloader/midi/examples/lufa_midi/makefile | 719 +++++++++++++++++++++ bootloader/midi/examples/lufa_midi/midi_usb.c | 161 +++++ bootloader/midi/examples/lufa_midi/midi_usb.h | 8 + bootloader/midi/examples/serial_midi.c | 49 ++ bootloader/midi/examples/serial_midi.h | 10 + bootloader/midi/examples/spit.c | 18 + bootloader/midi/midi.c | 250 +++++++ bootloader/midi/midi.h | 135 ++++ bootloader/midi/midi_device.c | 290 +++++++++ bootloader/midi/midi_device.h | 89 +++ bootloader/midi/midi_function_types.h | 34 + bootloader/midi/sysex_tools.c | 99 +++ bootloader/midi/sysex_tools.h | 78 +++ bootloader/midi/test/.gitignore | 3 + bootloader/midi/test/Makefile | 28 + bootloader/midi/test/avr/interrupt.h | 27 + bootloader/midi/test/dummy_device.c | 222 +++++++ bootloader/midi/test/dummy_device.h | 0 bootloader/midi/test/sysex_test.c | 79 +++ bootloader/midibootcommon.h | 49 ++ bootloader/uploader/Makefile | 22 + bootloader/uploader/main.cpp | 492 ++++++++++++++ readme.markdown | 24 +- 136 files changed, 17633 insertions(+), 775 deletions(-) create mode 100644 COPYING create mode 100644 Libraries/arduino/HardwareSerial.cpp create mode 100644 Libraries/arduino/HardwareSerial.h create mode 100644 Libraries/arduino/Print.cpp create mode 100644 Libraries/arduino/Print.h create mode 100644 Libraries/arduino/Stream.h create mode 100644 Libraries/arduino/Tone.cpp create mode 100644 Libraries/arduino/WConstants.h create mode 100644 Libraries/arduino/WInterrupts.c create mode 100644 Libraries/arduino/WMath.cpp create mode 100644 Libraries/arduino/WProgram.h create mode 100644 Libraries/arduino/WString.cpp create mode 100644 Libraries/arduino/WString.h create mode 100644 Libraries/arduino/binary.h create mode 100644 Libraries/arduino/main.cpp create mode 100644 Libraries/arduino/pins_arduino.c create mode 100644 Libraries/arduino/pins_arduino.h create mode 100644 Libraries/arduino/wiring.c create mode 100644 Libraries/arduino/wiring.h create mode 100644 Libraries/arduino/wiring_analog.c create mode 100644 Libraries/arduino/wiring_digital.c create mode 100644 Libraries/arduino/wiring_private.h create mode 100644 Libraries/arduino/wiring_pulse.c create mode 100644 Libraries/arduino/wiring_shift.c create mode 100644 Libraries/avrmidi/.gitignore create mode 100644 Libraries/avrmidi/COPYING create mode 100644 Libraries/avrmidi/Makefile create mode 100644 Libraries/avrmidi/README create mode 100644 Libraries/avrmidi/bytequeue.c create mode 100644 Libraries/avrmidi/bytequeue.h create mode 100644 Libraries/avrmidi/examples/Makefile create mode 100644 Libraries/avrmidi/examples/basic.c create mode 100644 Libraries/avrmidi/examples/lufa_midi/Descriptors.c create mode 100644 Libraries/avrmidi/examples/lufa_midi/Descriptors.h create mode 100644 Libraries/avrmidi/examples/lufa_midi/main.c create mode 100644 Libraries/avrmidi/examples/lufa_midi/makefile create mode 100644 Libraries/avrmidi/examples/lufa_midi/midi_usb.c create mode 100644 Libraries/avrmidi/examples/lufa_midi/midi_usb.h create mode 100644 Libraries/avrmidi/examples/serial_midi.c create mode 100644 Libraries/avrmidi/examples/serial_midi.h create mode 100644 Libraries/avrmidi/examples/spit.c create mode 100644 Libraries/avrmidi/interrupt_setting.c create mode 100644 Libraries/avrmidi/interrupt_setting.h create mode 100644 Libraries/avrmidi/midi.c create mode 100644 Libraries/avrmidi/midi.h create mode 100644 Libraries/avrmidi/midi_device.c create mode 100644 Libraries/avrmidi/midi_device.h create mode 100644 Libraries/avrmidi/midi_function_types.h create mode 100644 Libraries/avrmidi/sysex_tools.c create mode 100644 Libraries/avrmidi/sysex_tools.h create mode 100644 Libraries/avrmidi/test/.gitignore create mode 100644 Libraries/avrmidi/test/Makefile create mode 100644 Libraries/avrmidi/test/avr/interrupt.h create mode 100644 Libraries/avrmidi/test/dummy_device.c create mode 100644 Libraries/avrmidi/test/dummy_device.h create mode 100644 Libraries/avrmidi/test/sysex_test.c create mode 100644 Libraries/twi/twi.c create mode 100644 Libraries/twi/twi.h create mode 100644 MissingLink/HandleMidi.cpp create mode 100644 MissingLink/HandleMidi.h create mode 100644 MissingLink/MLSerial.cpp create mode 100644 MissingLink/MLSerial.h create mode 100644 MissingLink/ML_Config.c create mode 100644 MissingLink/ML_Config.h create mode 100644 MissingLink/Makefile create mode 100644 MissingLink/MissingLink.cpp create mode 100644 MissingLink/Output.cpp create mode 100644 MissingLink/Output.h create mode 100644 MissingLink/Parse.cpp create mode 100644 MissingLink/Parse.h create mode 100644 MissingLink/led.h create mode 100644 MissingLink/udpapp-ml.h create mode 100644 MissingLink/udpapp.cpp delete mode 100644 OSCSendTest/OSCSendTest.pde delete mode 100644 OSCSendTest/udpapp.cpp delete mode 100644 OSCTest/OSCTest.pde delete mode 100644 OSCTest/udpapp.cpp create mode 100644 bootloader/COPYING create mode 100644 bootloader/README create mode 100644 bootloader/avr_code/Makefile create mode 100644 bootloader/avr_code/bootloadercfg.h create mode 100644 bootloader/avr_code/main.c create mode 100755 bootloader/example/Makefile create mode 100644 bootloader/example/main.c create mode 100644 bootloader/midi/.gitignore create mode 100644 bootloader/midi/COPYING create mode 100644 bootloader/midi/Makefile create mode 100644 bootloader/midi/README create mode 100644 bootloader/midi/bytequeue/COPYING create mode 100644 bootloader/midi/bytequeue/bytequeue.c create mode 100644 bootloader/midi/bytequeue/bytequeue.h create mode 100644 bootloader/midi/bytequeue/interrupt_setting.c create mode 100644 bootloader/midi/bytequeue/interrupt_setting.h create mode 100644 bootloader/midi/examples/Makefile create mode 100644 bootloader/midi/examples/basic.c create mode 100644 bootloader/midi/examples/lufa_midi/Descriptors.c create mode 100644 bootloader/midi/examples/lufa_midi/Descriptors.h create mode 100644 bootloader/midi/examples/lufa_midi/main.c create mode 100644 bootloader/midi/examples/lufa_midi/makefile create mode 100644 bootloader/midi/examples/lufa_midi/midi_usb.c create mode 100644 bootloader/midi/examples/lufa_midi/midi_usb.h create mode 100644 bootloader/midi/examples/serial_midi.c create mode 100644 bootloader/midi/examples/serial_midi.h create mode 100644 bootloader/midi/examples/spit.c create mode 100644 bootloader/midi/midi.c create mode 100644 bootloader/midi/midi.h create mode 100644 bootloader/midi/midi_device.c create mode 100644 bootloader/midi/midi_device.h create mode 100644 bootloader/midi/midi_function_types.h create mode 100644 bootloader/midi/sysex_tools.c create mode 100644 bootloader/midi/sysex_tools.h create mode 100644 bootloader/midi/test/.gitignore create mode 100644 bootloader/midi/test/Makefile create mode 100644 bootloader/midi/test/avr/interrupt.h create mode 100644 bootloader/midi/test/dummy_device.c create mode 100644 bootloader/midi/test/dummy_device.h create mode 100644 bootloader/midi/test/sysex_test.c create mode 100644 bootloader/midibootcommon.h create mode 100644 bootloader/uploader/Makefile create mode 100644 bootloader/uploader/main.cpp diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + 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 +. diff --git a/Libraries/OSC/OSCDecoder.cpp b/Libraries/OSC/OSCDecoder.cpp index 0784851..4a75179 100644 --- a/Libraries/OSC/OSCDecoder.cpp +++ b/Libraries/OSC/OSCDecoder.cpp @@ -1,16 +1,16 @@ /* - + ArdOSC - OSC Library for Arduino. - + -------- Lisence ----------------------------------------------------------- - + ArdOSC - + The MIT License - + Copyright (c) 2009 - 2010 recotana( http://recotana.com ) All right reserved - - */ + + */ #include #include @@ -21,16 +21,16 @@ int16_t OSCDecoder::decode( OSCMessage::OSCMessage *mes ,const uint8_t *recData ){ - - + + //=========== BIN -> OSC Address(String) Decode =========== - + const uint8_t *packStartPtr=recData; - + mes->setOSCAddress((char*)packStartPtr); - + packStartPtr += mes->oscAdrPacSize; - + //=========== BIN -> TypeTag (String) Decode =========== @@ -41,78 +41,9 @@ int16_t OSCDecoder::decode( OSCMessage::OSCMessage *mes ,const uint8_t *recData //=========== BIN -> Auguments Decode =========== - - - if (mes->arguments!=NULL) free(mes->arguments); - mes->arguments=(void**)calloc(mes->argsNum, sizeof(void*)); - - mes->argsPacSize=0; - - uint8_t *tmpPtr; - uint16_t tmpSize; - - - - for (uint16_t i=0; i< mes->argsNum ; i++) { - - switch (mes->typeTag[i]) { - - case 'i': - - tmpPtr=(uint8_t*)calloc(1, 4); - - *(tmpPtr+3)=*(uint8_t*)packStartPtr++; - *(tmpPtr+2)=*(uint8_t*)packStartPtr++; - *(tmpPtr+1)=*(uint8_t*)packStartPtr++; - *tmpPtr=*(uint8_t*)packStartPtr++; - - mes->arguments[i]=(uint32_t*)tmpPtr; - mes->argsPacSize += 4; - break; - -#ifdef _USE_FLOAT_ - case 'f': - - tmpPtr=(uint8_t*)calloc(1, 4); - - *(tmpPtr+3)=*(uint8_t*)packStartPtr++; - *(tmpPtr+2)=*(uint8_t*)packStartPtr++; - *(tmpPtr+1)=*(uint8_t*)packStartPtr++; - *tmpPtr=*(uint8_t*)packStartPtr++; - - mes->arguments[i]=(float*)tmpPtr; - mes->argsPacSize += 4; - - break; -#endif - - -#ifdef _USE_STRING_ - case 's': - - tmpSize=strlen((char*)packStartPtr); - - if(tmpSize > kMaxStringCharactor){ - - DBG_LOGLN("decode max str err"); - return 1; - } - - - tmpPtr=(uint8_t*)calloc(tmpSize+1, 1); - strcpy((char*)tmpPtr,(char*)packStartPtr); - - mes->arguments[i]=tmpPtr; - - - tmpSize = mes->getPackSize(tmpSize); - packStartPtr += tmpSize; - mes->argsPacSize += tmpSize; - - break; -#endif - } - } - + + mes->argStart = packStartPtr; + mes->argsPacSize=mes->argsNum * 4; + return 0; } diff --git a/Libraries/OSC/OSCEncoder.cpp b/Libraries/OSC/OSCEncoder.cpp index 66dd383..79f0426 100644 --- a/Libraries/OSC/OSCEncoder.cpp +++ b/Libraries/OSC/OSCEncoder.cpp @@ -1,16 +1,16 @@ /* - + ArdOSC - OSC Library for Arduino. - + -------- Lisence ----------------------------------------------------------- - + ArdOSC - + The MIT License - + Copyright (c) 2009 - 2010 recotana( http://recotana.com ) All right reserved - - */ + + */ #include #include @@ -21,91 +21,92 @@ int16_t OSCEncoder::encode( OSCMessage::OSCMessage *mes ,uint8_t *sendData ){ - - + + uint8_t *packStartPtr=sendData; - - + + memset(sendData, 0, mes->getAllPackSize()); + //=========== OSC Address(String) -> BIN Encode =========== - - memcpy( sendData ,mes->oscAddress ,mes->oscAdrSize); + + memcpy( sendData ,mes->oscAddress ,mes->oscAdrSize); packStartPtr += mes->oscAdrPacSize; mes->allPackSize = mes->oscAdrPacSize; - + //=========== TypeTag(String) -> BIN Encode =========== - - *packStartPtr=','; - memcpy(packStartPtr+1 ,mes->typeTag ,mes->argsNum); + + *packStartPtr=','; + memcpy(packStartPtr+1 ,mes->typeTag ,mes->argsNum); packStartPtr += mes->typeTagPacSize; - + mes->allPackSize += mes->typeTagPacSize; - - + + //=========== Auguments -> BIN Encode ================== - - + + uint8_t *tmpPtr; - + uint32_t tmpInt; - + #ifdef _USE_FLOAT_ float tmpFloat; #endif - + #ifdef _USE_STRING_ uint16_t strSize; #endif - + for (int i=0; i< mes->argsNum; i++) { - + switch ( mes->typeTag[i] ) { - + case 'i': - + tmpInt = mes->getInteger32(i); tmpPtr =(uint8_t*)(&tmpInt); - + *packStartPtr++=*(tmpPtr+3); *packStartPtr++=*(tmpPtr+2); *packStartPtr++=*(tmpPtr+1); *packStartPtr++=*tmpPtr; - + mes->allPackSize += 4; break; - + #ifdef _USE_FLOAT_ case 'f': - + tmpFloat = mes->getFloat(i); tmpPtr=(uint8_t*)(&tmpFloat); - + *packStartPtr++=*(tmpPtr+3); *packStartPtr++=*(tmpPtr+2); *packStartPtr++=*(tmpPtr+1); *packStartPtr++=*tmpPtr; - + mes->allPackSize += 4; break; #endif - + #ifdef _USE_STRING_ case 's': strSize = strlen(mes->getString(i)); - + if(strSize > kMaxStringCharactor){ - + DBG_LOGLN("encode max str err"); return 1; } - - memcpy( (char*)packStartPtr ,mes->getString(i) ,strSize ); + + memcpy( (char*)packStartPtr ,mes->getString(i) ,strSize ); packStartPtr += mes->getPackSize(strSize); - + mes->allPackSize += mes->getPackSize(strSize); break; #endif - + } - } + } return 0; } diff --git a/Libraries/OSC/OSCMessage.cpp b/Libraries/OSC/OSCMessage.cpp index 5fb4d87..f3d98b1 100644 --- a/Libraries/OSC/OSCMessage.cpp +++ b/Libraries/OSC/OSCMessage.cpp @@ -1,39 +1,32 @@ /* - - ArdOSC - OSC Library for Arduino. - - -------- Lisence ----------------------------------------------------------- - - ArdOSC - - The MIT License - - Copyright (c) 2009 - 2010 recotana( http://recotana.com ) All right reserved - - */ -#include -#include -#include + ArdOSC - OSC Library for Arduino. -#include "OSCcommon.h" -#include "OSCMessage.h" + -------- Lisence ----------------------------------------------------------- + + ArdOSC + The MIT License + Copyright (c) 2009 - 2010 recotana( http://recotana.com ) All right reserved +*/ +#include +#include +#include +#include "OSCcommon.h" +#include "OSCMessage.h" OSCMessage::OSCMessage() -{ +{ DBG_LOGLN("construct message"); oscAddress=NULL; typeTag=NULL; - arguments=NULL; - + flush(); - } OSCMessage::OSCMessage(const char *_oscAddress) @@ -41,10 +34,9 @@ OSCMessage::OSCMessage(const char *_oscAddress) DBG_LOGLN("construct message with Adr"); oscAddress=NULL; typeTag=NULL; - arguments=NULL; - + flush(); - + setOSCAddress(_oscAddress); } @@ -56,54 +48,39 @@ OSCMessage::~OSCMessage() } -void OSCMessage::flush(){ - - if(oscAddress!=NULL) free(oscAddress); - +void OSCMessage::flush() +{ oscAddress=NULL; oscAdrSize=0; oscAdrPacSize=0; - - if(typeTag!=NULL) free(typeTag); - + typeTag=NULL; typeTagSize=0; typeTagPacSize=0; - - if(arguments!=NULL){ - - for (uint16_t i=0; i< argsNum; i++) { - free((void*)arguments[i]); - arguments[i]=NULL; - } - free(arguments); - } + argsNum=0; - argsPacSize=0; - - arguments=NULL; - + argsPacSize=0; + setIpAddress(0,0,0,0); portNumber=0; - + DBG_LOGLN("flush message obj"); - } void OSCMessage::setAddress(uint8_t *_ip , uint16_t _port){ - + setIpAddress(_ip); - + portNumber=_port; - + } void OSCMessage::setIpAddress(uint8_t *_ip){ - + ipAddress[0] = _ip[0]; ipAddress[1] = _ip[1]; ipAddress[2] = _ip[2]; ipAddress[3] = _ip[3]; - + DBG_LOG("set IP Adr with IParray:"); DBG_LOG((int)ipAddress[0]); DBG_LOG("."); @@ -116,12 +93,12 @@ void OSCMessage::setIpAddress(uint8_t *_ip){ } void OSCMessage::setIpAddress( uint8_t _ip1 ,uint8_t _ip2 ,uint8_t _ip3 ,uint8_t _ip4 ){ - + ipAddress[0] = _ip1; ipAddress[1] = _ip2; ipAddress[2] = _ip3; ipAddress[3] = _ip4; - + DBG_LOG("set IP Adr with IP nums:"); DBG_LOG((int)ipAddress[0]); DBG_LOG("."); @@ -130,7 +107,7 @@ void OSCMessage::setIpAddress( uint8_t _ip1 ,uint8_t _ip2 ,uint8_t _ip3 ,uint8_t DBG_LOG((int)ipAddress[2]); DBG_LOG("."); DBG_LOGLN((int)ipAddress[3]); - + } uint8_t *OSCMessage::getIpAddress(){ @@ -145,104 +122,94 @@ uint16_t OSCMessage::getPortNumber(){ return portNumber; } +int16_t OSCMessage::setOSCMessage( const char *_address ,char *types , ... ){ + va_list argsList; + DBG_LOG("set OSCMessage:"); -int16_t OSCMessage::setOSCMessage( const char *_address ,char *types , ... ){ - - va_list argsList; - - DBG_LOG("set OSCMessage:"); - - if( setOSCAddress(_address) > 0) return 1; if( setTypeTags(types) > 0) return 1; - - - - - //------------------------------------------------- - + + //------------------------------------------------- + + argStart = NULL; + argsPacSize=0; +#if 0 if (arguments!=NULL) free(arguments); arguments=(void**)calloc(argsNum, sizeof(void*)); - - - - argsPacSize=0; - + void *tmpPtr; char *tmpStr; uint16_t strSize; - - va_start( argsList, types ); - - for(uint8_t i=0 ; i < argsNum ; i++){ - - typeTag[i]=types[i]; - - + + va_start( argsList, types ); + + for(uint8_t i=0 ; i < argsNum ; i++) + { switch(types[i]){ - - case 'i': - tmpPtr=calloc(1, 4); - - memcpy(tmpPtr,(int32_t *)va_arg(argsList, int32_t *),4); - arguments[i]=(int32_t *)tmpPtr; - argsPacSize += 4; - - DBG_LOG(" int(4byte):"); - DBG_LOG(*(int32_t *)tmpPtr); - - break; - - -#ifdef _USE_FLOAT_ - case 'f': - tmpPtr=calloc(1, 4); - - memcpy(tmpPtr,(float *)va_arg(argsList, float *),4); - arguments[i]=(float *)tmpPtr; - - argsPacSize += 4; - - DBG_LOG(" float(4byte):"); - DBG_LOG(*(float *)tmpPtr); - - break; -#endif - - + + case 'i': + tmpPtr=calloc(1, 4); + + memcpy(tmpPtr,(int32_t *)va_arg(argsList, int32_t *),4); + arguments[i]=(int32_t *)tmpPtr; + argsPacSize += 4; + + DBG_LOG(" int(4byte):"); + DBG_LOG(*(int32_t *)tmpPtr); + + break; + + +#ifdef _USE_FLOAT_ + case 'f': + tmpPtr=calloc(1, 4); + + memcpy(tmpPtr,(float *)va_arg(argsList, float *),4); + arguments[i]=(float *)tmpPtr; + + argsPacSize += 4; + + DBG_LOG(" float(4byte):"); + DBG_LOG(*(float *)tmpPtr); + + break; +#endif + + #ifdef _USE_STRING_ - case 's': - tmpStr=(char *)va_arg(argsList, char *); - strSize=strlen(tmpStr); - DBG_LOGLN(strSize); - if(strSize > kMaxStringCharactor){ - - DBG_LOGLN("set args message max str err"); - return 1; - } - - tmpPtr=calloc(strSize+1, 1); - strcpy((char*)tmpPtr, tmpStr); - - arguments[i]=tmpPtr; - argsPacSize += getPackSize( strSize ); - - DBG_LOG(" String,size:"); - DBG_LOG(strSize); - DBG_LOG(" packsize:"); - DBG_LOG(getPackSize( strSize )); - DBG_LOG(" :"); - DBG_LOG((char *)tmpPtr); - - break; + case 's': + tmpStr=(char *)va_arg(argsList, char *); + strSize=strlen(tmpStr); + DBG_LOGLN(strSize); + if(strSize > kMaxStringCharactor){ + + DBG_LOGLN("set args message max str err"); + return 1; + } + + tmpPtr=calloc(strSize+1, 1); + strcpy((char*)tmpPtr, tmpStr); + + arguments[i]=tmpPtr; + argsPacSize += getPackSize( strSize ); + + DBG_LOG(" String,size:"); + DBG_LOG(strSize); + DBG_LOG(" packsize:"); + DBG_LOG(getPackSize( strSize )); + DBG_LOG(" :"); + DBG_LOG((char *)tmpPtr); + + break; #endif - + } - + } +#endif DBG_LOGLN(""); DBG_LOGLN(""); return 0; @@ -254,70 +221,58 @@ int16_t OSCMessage::setOSCMessage( const char *_address ,char *types , ... ){ int16_t OSCMessage::setOSCAddress(const char *_address){ oscAdrSize=(uint16_t)strlen(_address); - + if( oscAdrSize > kMaxOSCAdrCharactor ){ DBG_LOGLN("set OSC max OSC Adr err"); flush(); return 1; } - - if(oscAddress!=NULL) free(oscAddress); - - oscAddress=(char*)calloc(1,oscAdrSize+1); - strcpy(oscAddress,_address); - + + oscAddress = _address; oscAdrPacSize=getPackSize(oscAdrSize); - + DBG_LOG("set OSC Adr:"); DBG_LOG(oscAddress); DBG_LOG(" size:"); DBG_LOG(oscAdrSize); DBG_LOG(" packsize:"); DBG_LOGLN(oscAdrPacSize); - + return 0; } -char *OSCMessage::getOSCAddress(){ + +const char* OSCMessage::getOSCAddress(){ return oscAddress; } - - -int16_t OSCMessage::setTypeTags(const char *_tags ){ - - uint8_t maxErr=0; - +int16_t OSCMessage::setTypeTags(const char *_tags ) +{ argsNum=(uint16_t)strlen(_tags); - + if(argsNum > kMaxAugument){ DBG_LOGLN("set tags max arg err"); flush(); return 1; } - + typeTagSize = argsNum+1; - - if(typeTag!=NULL) free(typeTag); - typeTag=(char*)calloc(1,argsNum+1); - strcpy(typeTag,_tags); - + typeTag = _tags; typeTagPacSize=getPackSize(typeTagSize); - argsNum=typeTagSize; - - + + DBG_LOG("set TypeTag:"); DBG_LOG(typeTag); DBG_LOG(" size:"); DBG_LOG(typeTagSize); DBG_LOG(" packsize:"); DBG_LOGLN(typeTagPacSize); - + return 0; } -char * OSCMessage::getTypeTags(){ +const char* OSCMessage::getTypeTags(){ return typeTag; } @@ -331,56 +286,54 @@ int16_t OSCMessage::getArgsNum(){ return argsNum; } +void OSCMessage::getRaw(uint16_t _index, void* ptr) +{ + const uint8_t* source = &(argStart[_index * 4]); + uint8_t* dest = (uint8_t*) ptr; + *(dest+3) = source[0]; + *(dest+2) = source[1]; + *(dest+1) = source[2]; + *(dest+0) = source[3]; +} -int32_t OSCMessage::getInteger32(uint16_t _index){ - - int32_t *value; - if(_index > argsNum) _index=argsNum-1; - value = (int32_t *)arguments[_index]; - - return *value; - +int32_t OSCMessage::getInteger32(uint16_t _index) +{ + int32_t ret; + getRaw(_index, &ret); + return ret; } #ifdef _USE_FLOAT_ -float OSCMessage::getFloat(uint16_t _index){ - - float *value; - if(_index > argsNum) _index=argsNum-1; - value = (float *)arguments[_index]; - - return *value; - - +float OSCMessage::getFloat(uint16_t _index) +{ + float ret; + getRaw(_index, &ret); + return ret; } #endif #ifdef _USE_STRING_ char * OSCMessage::getString(uint16_t _index){ - + if(_index > argsNum) _index=argsNum-1; - + return (char *)arguments[_index]; - + } #endif uint16_t OSCMessage::getAllPackSize(){ - + return oscAdrPacSize+typeTagPacSize+argsPacSize; } uint16_t OSCMessage::getStrPackSize(const char* data){ - + return getPackSize(strlen(data)); } uint16_t OSCMessage::getPackSize(uint16_t size){ - + return (size+4)&0xfffc; } - - - - diff --git a/Libraries/OSC/OSCMessage.h b/Libraries/OSC/OSCMessage.h index 2660b91..052fe9f 100644 --- a/Libraries/OSC/OSCMessage.h +++ b/Libraries/OSC/OSCMessage.h @@ -1,88 +1,57 @@ /* - + ArdOSC - OSC Library for Arduino. - + -------- Lisence ----------------------------------------------------------- - + ArdOSC - - The MIT License - - Copyright (c) 2009 - 2010 recotana( http://recotana.com ) All right reserved - - */ + The MIT License + Copyright (c) 2009 - 2010 recotana( http://recotana.com ) All right reserved + */ #ifndef OSCMessage_h #define OSCMessage_h - #include "OSCcommon.h" - -class OSCMessage{ - -private: - - uint16_t allPackSize; // - char *oscAddress; // "/ard" - uint16_t oscAdrSize; // "/ard" ->4 - uint16_t oscAdrPacSize; // "/ard\0\0\0\0" ->8 - - char *typeTag; // "iif" - uint16_t typeTagSize; // ",iif" -> 4 - uint16_t typeTagPacSize; // ",iif\0\0\0\0" -> 8 - - - void **arguments; - uint16_t argsNum; // "iif" -> 3 - uint16_t argsPacSize; // "iif" -> 4 + 4 + 4 = 12 - - uint8_t ipAddress[4]; //{192,168,0,10} - uint16_t portNumber; //10000 - +class OSCMessage +{ public: - - - OSCMessage(); OSCMessage(const char *_oscAddress); ~OSCMessage(); void flush(); - - + uint16_t getAllPackSize(); uint16_t getStrPackSize(const char* data); - uint16_t getPackSize(uint16_t size); - - - + static uint16_t getPackSize(uint16_t size); + void setAddress(uint8_t *_ip , uint16_t _port); - - void setIpAddress( uint8_t *_ip ); + + void setIpAddress( uint8_t *_ip ); void setIpAddress( uint8_t _ip1, uint8_t _ip2, uint8_t _ip3, uint8_t _ip4); - + uint8_t *getIpAddress(); void setPortNumber(uint16_t _port); uint16_t getPortNumber(); - + int16_t setOSCMessage( const char *_address ,char *types , ... ); int16_t getArgsNum(); - + int16_t setOSCAddress(const char *_address); - char *getOSCAddress(); - + const char* getOSCAddress(); + uint16_t getOSCAddressLen() { return oscAdrSize; } + int16_t setTypeTags(const char *_tags); - char *getTypeTags(); - char getTypeTag(uint16_t _index); - - - + const char* getTypeTags(); + char getTypeTag(uint16_t _index); + int32_t getInteger32(uint16_t _index); - + #ifdef _USE_FLOAT_ float getFloat(uint16_t _index); #endif @@ -90,15 +59,29 @@ public: #ifdef _USE_STRING_ char *getString(uint16_t _index); #endif - - - + friend class OSCServer; friend class OSCClient; friend class OSCDecoder; friend class OSCEncoder; - -}; +private: + uint16_t allPackSize; // + const char* oscAddress; // "/ard" + uint16_t oscAdrSize; // "/ard" ->4 + uint16_t oscAdrPacSize; // "/ard\0\0\0\0" ->8 + + const char* typeTag; // "iif" + uint16_t typeTagSize; // ",iif" -> 4 + uint16_t typeTagPacSize; // ",iif\0\0\0\0" -> 8 + + const uint8_t* argStart; + uint16_t argsNum; // "iif" -> 3 + uint16_t argsPacSize; // "iif" -> 4 + 4 + 4 = 12 + uint8_t ipAddress[4]; //{192,168,0,10} + uint16_t portNumber; //10000 + + void getRaw(uint16_t _index, void* ptr); +}; #endif diff --git a/Libraries/OSC/OSCcommon.h b/Libraries/OSC/OSCcommon.h index 443cf86..a4745e7 100644 --- a/Libraries/OSC/OSCcommon.h +++ b/Libraries/OSC/OSCcommon.h @@ -1,16 +1,16 @@ /* - + ArdOSC - OSC Library for Arduino. - + -------- Lisence ----------------------------------------------------------- - + ArdOSC - + The MIT License - + Copyright (c) 2009 - 2010 recotana( http://recotana.com ) All right reserved - - */ + + */ @@ -22,7 +22,7 @@ //#define _DEBUG_ #define _USE_FLOAT_ -#define _USE_STRING_ +//#define _USE_STRING_ @@ -50,11 +50,11 @@ extern "C" { #define DBG_LOG(...) Serial.print(__VA_ARGS__) #else -#define DBG_LOGLN -#define DBG_LOG +#define DBG_LOGLN(...) +#define DBG_LOG(...) #endif -#endif \ No newline at end of file +#endif diff --git a/Libraries/WiShield/WiShield.cpp b/Libraries/WiShield/WiShield.cpp index 2e61afa..4488a67 100644 --- a/Libraries/WiShield/WiShield.cpp +++ b/Libraries/WiShield/WiShield.cpp @@ -41,12 +41,13 @@ extern "C" { #include "spi.h" void stack_init(void); void stack_process(void); + void stack_send_udp(void); } #include "WProgram.h" #include "WiShield.h" -void WiShield::init() +void WiShield::init(int async) { zg_init(); @@ -61,11 +62,26 @@ void WiShield::init() PCMSK0 |= (1<slot = 3; // WEP key slot cmd->keyLen = 13; // Key length: 5 bytes (64-bit WEP); 13 bytes (128-bit WEP) cmd->defID = 0; // Default key ID: Key 0, 1, 2, 3 - cmd->ssidLen = ssid_len; memset(cmd->ssid, 0x00, 32); - memcpy_P(cmd->ssid, ssid, ssid_len); - memcpy_P(cmd->key, wep_keys, ZG_MAX_ENCRYPTION_KEYS * ZG_MAX_ENCRYPTION_KEY_SIZE); + + return_ssid(cmd->ssid, &cmd->ssidLen); + return_wepkeys(cmd->key); return; } @@ -352,13 +349,13 @@ static void zg_calc_psk_key(U8* cmd_buf) zg_psk_calc_req_t* cmd = (zg_psk_calc_req_t*)cmd_buf; cmd->configBits = 0; - cmd->phraseLen = security_passphrase_len; - cmd->ssidLen = ssid_len; cmd->reserved = 0; + memset(cmd->ssid, 0x00, 32); - memcpy_P(cmd->ssid, ssid, ssid_len); memset(cmd->passPhrase, 0x00, 64); - memcpy_P(cmd->passPhrase, security_passphrase, security_passphrase_len); + + return_ssid(cmd->ssid, &cmd->ssidLen); + return_passphrase(cmd->passPhrase, &cmd->phraseLen); return; } @@ -368,9 +365,9 @@ static void zg_write_psk_key(U8* cmd_buf) zg_pmk_key_req_t* cmd = (zg_pmk_key_req_t*)cmd_buf; cmd->slot = 0; // WPA/WPA2 PSK slot - cmd->ssidLen = ssid_len; memset(cmd->ssid, 0x00, 32); - memcpy_P(cmd->ssid, ssid, cmd->ssidLen); + return_ssid(cmd->ssid, &cmd->ssidLen); + memcpy(cmd->keyData, wpa_psk_key, ZG_MAX_PMK_LEN); return; @@ -563,9 +560,8 @@ void zg_drv_process() cmd->secType = security_type; - cmd->ssidLen = ssid_len; memset(cmd->ssid, 0, 32); - memcpy_P(cmd->ssid, ssid, ssid_len); + return_ssid(cmd->ssid, &cmd->ssidLen); // units of 100 milliseconds cmd->sleepDuration = 0; diff --git a/Libraries/WiShield/psock.c b/Libraries/WiShield/psock.c index 731e8e0..0735fe7 100644 --- a/Libraries/WiShield/psock.c +++ b/Libraries/WiShield/psock.c @@ -308,7 +308,9 @@ PT_THREAD(psock_readbuf(register struct psock *psock)) do { if(psock->readlen == 0) { PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock)); +#if 0 printf("Waited for newdata\n"); +#endif psock->state = STATE_READ; psock->readptr = (u8_t *)uip_appdata; psock->readlen = uip_datalen(); diff --git a/Libraries/WiShield/stack.c b/Libraries/WiShield/stack.c index 85675f5..e95ba25 100644 --- a/Libraries/WiShield/stack.c +++ b/Libraries/WiShield/stack.c @@ -159,7 +159,15 @@ void stack_process(void) return; } +void stack_send_udp() +{ + uip_process(UIP_UDP_SEND_CONN); + uip_arp_out(); + network_send(); +} + void uip_log(char *m) { + // printf(m); //TODO: Get debug information out here somehow, does anybody know a smart way to do that? } diff --git a/Libraries/WiShield/uip-conf.h b/Libraries/WiShield/uip-conf.h index f35c895..6485416 100644 --- a/Libraries/WiShield/uip-conf.h +++ b/Libraries/WiShield/uip-conf.h @@ -135,7 +135,7 @@ typedef unsigned short uip_stats_t; * * \hideinitializer */ -#define UIP_CONF_UDP_CONNS 1 +#define UIP_CONF_UDP_CONNS 10 //Include app configuration #include "apps-conf.h" diff --git a/Libraries/WiShield/uip-neighbor.c b/Libraries/WiShield/uip-neighbor.c index 739c03e..28f8956 100644 --- a/Libraries/WiShield/uip-neighbor.c +++ b/Libraries/WiShield/uip-neighbor.c @@ -87,10 +87,11 @@ uip_neighbor_add(uip_ipaddr_t ipaddr, struct uip_neighbor_addr *addr) int i, oldest; u8_t oldest_time; +#if 0 printf("Adding neighbor with link address %02x:%02x:%02x:%02x:%02x:%02x\n", addr->addr.addr[0], addr->addr.addr[1], addr->addr.addr[2], addr->addr.addr[3], addr->addr.addr[4], addr->addr.addr[5]); - +#endif /* Find the first unused entry or the oldest used entry. */ oldest_time = 0; oldest = 0; diff --git a/Libraries/WiShield/uip.c b/Libraries/WiShield/uip.c index 6af0271..164bafe 100644 --- a/Libraries/WiShield/uip.c +++ b/Libraries/WiShield/uip.c @@ -32,7 +32,7 @@ *****************************************************************************/ -#define DEBUG_PRINTF(...) /*printf(__VA_ARGS__)*/ +#define DEBUG_PRINTF(...) /* printf(__VA_ARGS__) */ /** * \defgroup uip The uIP TCP/IP stack @@ -1149,7 +1149,8 @@ uip_process(u8_t flag) udp_found: if (uip_udp_conn->rport == 0) { - uip_udp_conn->rport = UDPBUF->srcport; + uip_udp_conn->rport = UDPBUF->srcport; + uip_ipaddr_copy(uip_udp_conn->ripaddr, BUF->srcipaddr); } uip_conn = NULL; uip_flags = UIP_NEWDATA; @@ -1913,6 +1914,12 @@ htons(u16_t val) { return HTONS(val); } + +void uip_udp_prep_buffer() +{ + uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; +} + /*---------------------------------------------------------------------------*/ void uip_send(const void *data, int len) diff --git a/Libraries/WiShield/uip.h b/Libraries/WiShield/uip.h index 9f2d843..4912ff0 100644 --- a/Libraries/WiShield/uip.h +++ b/Libraries/WiShield/uip.h @@ -1627,6 +1627,7 @@ u16_t uip_tcpchksum(void); */ u16_t uip_udpchksum(void); +void uip_udp_prep_buffer(); #endif /* __UIP_H__ */ diff --git a/Libraries/arduino/HardwareSerial.cpp b/Libraries/arduino/HardwareSerial.cpp new file mode 100644 index 0000000..e7ac21f --- /dev/null +++ b/Libraries/arduino/HardwareSerial.cpp @@ -0,0 +1,236 @@ +/* + HardwareSerial.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis +*/ + +#include +#include +#include +#include +#include "wiring.h" +#include "wiring_private.h" + +#include "HardwareSerial.h" + +// Define constants and variables for buffering incoming serial data. We're +// using a ring buffer (I think), in which rx_buffer_head is the index of the +// location to which to write the next incoming character and rx_buffer_tail +// is the index of the location from which to read. +#define RX_BUFFER_SIZE 128 + +struct ring_buffer { + unsigned char buffer[RX_BUFFER_SIZE]; + int head; + int tail; +}; + +ring_buffer rx_buffer = { { 0 }, 0, 0 }; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +ring_buffer rx_buffer1 = { { 0 }, 0, 0 }; +ring_buffer rx_buffer2 = { { 0 }, 0, 0 }; +ring_buffer rx_buffer3 = { { 0 }, 0, 0 }; +#endif + +inline void store_char(unsigned char c, ring_buffer *rx_buffer) +{ + int i = (rx_buffer->head + 1) % RX_BUFFER_SIZE; + + // if we should be storing the received character into the location + // just before the tail (meaning that the head would advance to the + // current location of the tail), we're about to overflow the buffer + // and so we don't write the character or advance the head. + if (i != rx_buffer->tail) { + rx_buffer->buffer[rx_buffer->head] = c; + rx_buffer->head = i; + } +} + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + +SIGNAL(SIG_USART0_RECV) +{ + unsigned char c = UDR0; + store_char(c, &rx_buffer); +} + +SIGNAL(SIG_USART1_RECV) +{ + unsigned char c = UDR1; + store_char(c, &rx_buffer1); +} + +SIGNAL(SIG_USART2_RECV) +{ + unsigned char c = UDR2; + store_char(c, &rx_buffer2); +} + +SIGNAL(SIG_USART3_RECV) +{ + unsigned char c = UDR3; + store_char(c, &rx_buffer3); +} + +#else + +#if defined(__AVR_ATmega8__) +SIGNAL(SIG_UART_RECV) +#else +SIGNAL(USART_RX_vect) +#endif +{ +#if defined(__AVR_ATmega8__) + unsigned char c = UDR; +#else + unsigned char c = UDR0; +#endif + store_char(c, &rx_buffer); +} + +#endif + +// Constructors //////////////////////////////////////////////////////////////// + +HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, + volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *udr, + uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x) +{ + _rx_buffer = rx_buffer; + _ubrrh = ubrrh; + _ubrrl = ubrrl; + _ucsra = ucsra; + _ucsrb = ucsrb; + _udr = udr; + _rxen = rxen; + _txen = txen; + _rxcie = rxcie; + _udre = udre; + _u2x = u2x; +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void HardwareSerial::begin(long baud) +{ + uint16_t baud_setting; + bool use_u2x; + + // U2X mode is needed for baud rates higher than (CPU Hz / 16) + if (baud > F_CPU / 16) { + use_u2x = true; + } else { + // figure out if U2X mode would allow for a better connection + + // calculate the percent difference between the baud-rate specified and + // the real baud rate for both U2X and non-U2X mode (0-255 error percent) + uint8_t nonu2x_baud_error = abs((int)(255-((F_CPU/(16*(((F_CPU/8/baud-1)/2)+1))*255)/baud))); + uint8_t u2x_baud_error = abs((int)(255-((F_CPU/(8*(((F_CPU/4/baud-1)/2)+1))*255)/baud))); + + // prefer non-U2X mode because it handles clock skew better + use_u2x = (nonu2x_baud_error > u2x_baud_error); + } + + if (use_u2x) { + *_ucsra = 1 << _u2x; + baud_setting = (F_CPU / 4 / baud - 1) / 2; + } else { + *_ucsra = 0; + baud_setting = (F_CPU / 8 / baud - 1) / 2; + } + + // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) + *_ubrrh = baud_setting >> 8; + *_ubrrl = baud_setting; + + sbi(*_ucsrb, _rxen); + sbi(*_ucsrb, _txen); + sbi(*_ucsrb, _rxcie); +} + +void HardwareSerial::end() +{ + cbi(*_ucsrb, _rxen); + cbi(*_ucsrb, _txen); + cbi(*_ucsrb, _rxcie); +} + +int HardwareSerial::available(void) +{ + return (RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RX_BUFFER_SIZE; +} + +int HardwareSerial::peek(void) +{ + if (_rx_buffer->head == _rx_buffer->tail) { + return -1; + } else { + return _rx_buffer->buffer[_rx_buffer->tail]; + } +} + +int HardwareSerial::read(void) +{ + // if the head isn't ahead of the tail, we don't have any characters + if (_rx_buffer->head == _rx_buffer->tail) { + return -1; + } else { + unsigned char c = _rx_buffer->buffer[_rx_buffer->tail]; + _rx_buffer->tail = (_rx_buffer->tail + 1) % RX_BUFFER_SIZE; + return c; + } +} + +void HardwareSerial::flush() +{ + // don't reverse this or there may be problems if the RX interrupt + // occurs after reading the value of rx_buffer_head but before writing + // the value to rx_buffer_tail; the previous value of rx_buffer_head + // may be written to rx_buffer_tail, making it appear as if the buffer + // don't reverse this or there may be problems if the RX interrupt + // occurs after reading the value of rx_buffer_head but before writing + // the value to rx_buffer_tail; the previous value of rx_buffer_head + // may be written to rx_buffer_tail, making it appear as if the buffer + // were full, not empty. + _rx_buffer->head = _rx_buffer->tail; +} + +void HardwareSerial::write(uint8_t c) +{ + while (!((*_ucsra) & (1 << _udre))) + ; + + *_udr = c; +} + +// Preinstantiate Objects ////////////////////////////////////////////////////// + +#if defined(__AVR_ATmega8__) +HardwareSerial Serial(&rx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRE, U2X); +#else +HardwareSerial Serial(&rx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0, U2X0); +#endif + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +HardwareSerial Serial1(&rx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRE1, U2X1); +HardwareSerial Serial2(&rx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UDR2, RXEN2, TXEN2, RXCIE2, UDRE2, U2X2); +HardwareSerial Serial3(&rx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRE3, U2X3); +#endif diff --git a/Libraries/arduino/HardwareSerial.h b/Libraries/arduino/HardwareSerial.h new file mode 100644 index 0000000..29898b9 --- /dev/null +++ b/Libraries/arduino/HardwareSerial.h @@ -0,0 +1,67 @@ +/* + HardwareSerial.h - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef HardwareSerial_h +#define HardwareSerial_h + +#include + +#include "Stream.h" + +struct ring_buffer; + +class HardwareSerial : public Stream +{ + private: + ring_buffer *_rx_buffer; + volatile uint8_t *_ubrrh; + volatile uint8_t *_ubrrl; + volatile uint8_t *_ucsra; + volatile uint8_t *_ucsrb; + volatile uint8_t *_udr; + uint8_t _rxen; + uint8_t _txen; + uint8_t _rxcie; + uint8_t _udre; + uint8_t _u2x; + public: + HardwareSerial(ring_buffer *rx_buffer, + volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *udr, + uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x); + void begin(long); + void end(); + virtual int available(void); + virtual int peek(void); + virtual int read(void); + virtual void flush(void); + virtual void write(uint8_t); + using Print::write; // pull in write(str) and write(buf, size) from Print +}; + +extern HardwareSerial Serial; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +extern HardwareSerial Serial1; +extern HardwareSerial Serial2; +extern HardwareSerial Serial3; +#endif + +#endif diff --git a/Libraries/arduino/Print.cpp b/Libraries/arduino/Print.cpp new file mode 100644 index 0000000..4ee556d --- /dev/null +++ b/Libraries/arduino/Print.cpp @@ -0,0 +1,220 @@ +/* + Print.cpp - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + */ + +#include +#include +#include +#include +#include "wiring.h" + +#include "Print.h" + +// Public Methods ////////////////////////////////////////////////////////////// + +/* default implementation: may be overridden */ +void Print::write(const char *str) +{ + while (*str) + write(*str++); +} + +/* default implementation: may be overridden */ +void Print::write(const uint8_t *buffer, size_t size) +{ + while (size--) + write(*buffer++); +} + +void Print::print(const String &s) +{ + for (int i = 0; i < s.length(); i++) { + write(s[i]); + } +} + +void Print::print(const char str[]) +{ + write(str); +} + +void Print::print(char c, int base) +{ + print((long) c, base); +} + +void Print::print(unsigned char b, int base) +{ + print((unsigned long) b, base); +} + +void Print::print(int n, int base) +{ + print((long) n, base); +} + +void Print::print(unsigned int n, int base) +{ + print((unsigned long) n, base); +} + +void Print::print(long n, int base) +{ + if (base == 0) { + write(n); + } else if (base == 10) { + if (n < 0) { + print('-'); + n = -n; + } + printNumber(n, 10); + } else { + printNumber(n, base); + } +} + +void Print::print(unsigned long n, int base) +{ + if (base == 0) write(n); + else printNumber(n, base); +} + +void Print::print(double n, int digits) +{ + printFloat(n, digits); +} + +void Print::println(void) +{ + print('\r'); + print('\n'); +} + +void Print::println(const String &s) +{ + print(s); + println(); +} + +void Print::println(const char c[]) +{ + print(c); + println(); +} + +void Print::println(char c, int base) +{ + print(c, base); + println(); +} + +void Print::println(unsigned char b, int base) +{ + print(b, base); + println(); +} + +void Print::println(int n, int base) +{ + print(n, base); + println(); +} + +void Print::println(unsigned int n, int base) +{ + print(n, base); + println(); +} + +void Print::println(long n, int base) +{ + print(n, base); + println(); +} + +void Print::println(unsigned long n, int base) +{ + print(n, base); + println(); +} + +void Print::println(double n, int digits) +{ + print(n, digits); + println(); +} + +// Private Methods ///////////////////////////////////////////////////////////// + +void Print::printNumber(unsigned long n, uint8_t base) +{ + unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars. + unsigned long i = 0; + + if (n == 0) { + print('0'); + return; + } + + while (n > 0) { + buf[i++] = n % base; + n /= base; + } + + for (; i > 0; i--) + print((char) (buf[i - 1] < 10 ? + '0' + buf[i - 1] : + 'A' + buf[i - 1] - 10)); +} + +void Print::printFloat(double number, uint8_t digits) +{ + // Handle negative numbers + if (number < 0.0) + { + print('-'); + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for (uint8_t i=0; i 0) + print("."); + + // Extract digits from the remainder one at a time + while (digits-- > 0) + { + remainder *= 10.0; + int toPrint = int(remainder); + print(toPrint); + remainder -= toPrint; + } +} diff --git a/Libraries/arduino/Print.h b/Libraries/arduino/Print.h new file mode 100644 index 0000000..b092ae5 --- /dev/null +++ b/Libraries/arduino/Print.h @@ -0,0 +1,66 @@ +/* + Print.h - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Print_h +#define Print_h + +#include +#include // for size_t + +#include "WString.h" + +#define DEC 10 +#define HEX 16 +#define OCT 8 +#define BIN 2 +#define BYTE 0 + +class Print +{ + private: + void printNumber(unsigned long, uint8_t); + void printFloat(double, uint8_t); + public: + virtual void write(uint8_t) = 0; + virtual void write(const char *str); + virtual void write(const uint8_t *buffer, size_t size); + + void print(const String &); + void print(const char[]); + void print(char, int = BYTE); + void print(unsigned char, int = BYTE); + void print(int, int = DEC); + void print(unsigned int, int = DEC); + void print(long, int = DEC); + void print(unsigned long, int = DEC); + void print(double, int = 2); + + void println(const String &s); + void println(const char[]); + void println(char, int = BYTE); + void println(unsigned char, int = BYTE); + void println(int, int = DEC); + void println(unsigned int, int = DEC); + void println(long, int = DEC); + void println(unsigned long, int = DEC); + void println(double, int = 2); + void println(void); +}; + +#endif diff --git a/Libraries/arduino/Stream.h b/Libraries/arduino/Stream.h new file mode 100644 index 0000000..c98759b --- /dev/null +++ b/Libraries/arduino/Stream.h @@ -0,0 +1,34 @@ +/* + Stream.h - base class for character-based streams. + Copyright (c) 2010 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Stream_h +#define Stream_h + +#include +#include "Print.h" + +class Stream : public Print +{ + public: + virtual int available() = 0; + virtual int read() = 0; + virtual void flush() = 0; +}; + +#endif diff --git a/Libraries/arduino/Tone.cpp b/Libraries/arduino/Tone.cpp new file mode 100644 index 0000000..e221ecf --- /dev/null +++ b/Libraries/arduino/Tone.cpp @@ -0,0 +1,518 @@ +/* Tone.cpp + + A Tone Generator Library + + Written by Brett Hagman + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Version Modified By Date Comments +------- ----------- -------- -------- +0001 B Hagman 09/08/02 Initial coding +0002 B Hagman 09/08/18 Multiple pins +0003 B Hagman 09/08/18 Moved initialization from constructor to begin() +0004 B Hagman 09/09/26 Fixed problems with ATmega8 +0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers + 09/11/25 Changed pin toggle method to XOR + 09/11/25 Fixed timer0 from being excluded +0006 D Mellis 09/12/29 Replaced objects with functions + +*************************************************/ + +#include +#include +#include +#include + +#if defined(__AVR_ATmega8__) +#define TCCR2A TCCR2 +#define TCCR2B TCCR2 +#define COM2A1 COM21 +#define COM2A0 COM20 +#define OCR2A OCR2 +#define TIMSK2 TIMSK +#define OCIE2A OCIE2 +#define TIMER2_COMPA_vect TIMER2_COMP_vect +#define TIMSK1 TIMSK +#endif + +// timerx_toggle_count: +// > 0 - duration specified +// = 0 - stopped +// < 0 - infinitely (until stop() method called, or new play() called) + +#if !defined(__AVR_ATmega8__) +volatile long timer0_toggle_count; +volatile uint8_t *timer0_pin_port; +volatile uint8_t timer0_pin_mask; +#endif + +volatile long timer1_toggle_count; +volatile uint8_t *timer1_pin_port; +volatile uint8_t timer1_pin_mask; +volatile long timer2_toggle_count; +volatile uint8_t *timer2_pin_port; +volatile uint8_t timer2_pin_mask; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +volatile long timer3_toggle_count; +volatile uint8_t *timer3_pin_port; +volatile uint8_t timer3_pin_mask; +volatile long timer4_toggle_count; +volatile uint8_t *timer4_pin_port; +volatile uint8_t timer4_pin_mask; +volatile long timer5_toggle_count; +volatile uint8_t *timer5_pin_port; +volatile uint8_t timer5_pin_mask; +#endif + + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + +#define AVAILABLE_TONE_PINS 1 + +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ }; + +#elif defined(__AVR_ATmega8__) + +#define AVAILABLE_TONE_PINS 1 + +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ }; + +#else + +#define AVAILABLE_TONE_PINS 1 + +// Leave timer 0 to last. +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ }; + +#endif + + + +static int8_t toneBegin(uint8_t _pin) +{ + int8_t _timer = -1; + + // if we're already using the pin, the timer should be configured. + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == _pin) { + return pgm_read_byte(tone_pin_to_timer_PGM + i); + } + } + + // search for an unused timer. + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == 255) { + tone_pins[i] = _pin; + _timer = pgm_read_byte(tone_pin_to_timer_PGM + i); + break; + } + } + + if (_timer != -1) + { + // Set timer specific stuff + // All timers in CTC mode + // 8 bit timers will require changing prescalar values, + // whereas 16 bit timers are set to either ck/1 or ck/64 prescalar + switch (_timer) + { +#if !defined(__AVR_ATmega8__) + case 0: + // 8 bit timer + TCCR0A = 0; + TCCR0B = 0; + bitWrite(TCCR0A, WGM01, 1); + bitWrite(TCCR0B, CS00, 1); + timer0_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer0_pin_mask = digitalPinToBitMask(_pin); + break; +#endif + + case 1: + // 16 bit timer + TCCR1A = 0; + TCCR1B = 0; + bitWrite(TCCR1B, WGM12, 1); + bitWrite(TCCR1B, CS10, 1); + timer1_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer1_pin_mask = digitalPinToBitMask(_pin); + break; + case 2: + // 8 bit timer + TCCR2A = 0; + TCCR2B = 0; + bitWrite(TCCR2A, WGM21, 1); + bitWrite(TCCR2B, CS20, 1); + timer2_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer2_pin_mask = digitalPinToBitMask(_pin); + break; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + case 3: + // 16 bit timer + TCCR3A = 0; + TCCR3B = 0; + bitWrite(TCCR3B, WGM32, 1); + bitWrite(TCCR3B, CS30, 1); + timer3_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer3_pin_mask = digitalPinToBitMask(_pin); + break; + case 4: + // 16 bit timer + TCCR4A = 0; + TCCR4B = 0; + bitWrite(TCCR4B, WGM42, 1); + bitWrite(TCCR4B, CS40, 1); + timer4_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer4_pin_mask = digitalPinToBitMask(_pin); + break; + case 5: + // 16 bit timer + TCCR5A = 0; + TCCR5B = 0; + bitWrite(TCCR5B, WGM52, 1); + bitWrite(TCCR5B, CS50, 1); + timer5_pin_port = portOutputRegister(digitalPinToPort(_pin)); + timer5_pin_mask = digitalPinToBitMask(_pin); + break; +#endif + } + } + + return _timer; +} + + + +// frequency (in hertz) and duration (in milliseconds). + +void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) +{ + uint8_t prescalarbits = 0b001; + long toggle_count = 0; + uint32_t ocr = 0; + int8_t _timer; + + _timer = toneBegin(_pin); + + if (_timer >= 0) + { + // Set the pinMode as OUTPUT + pinMode(_pin, OUTPUT); + + // if we are using an 8 bit timer, scan through prescalars to find the best fit + if (_timer == 0 || _timer == 2) + { + ocr = F_CPU / frequency / 2 - 1; + prescalarbits = 0b001; // ck/1: same for both timers + if (ocr > 255) + { + ocr = F_CPU / frequency / 2 / 8 - 1; + prescalarbits = 0b010; // ck/8: same for both timers + + if (_timer == 2 && ocr > 255) + { + ocr = F_CPU / frequency / 2 / 32 - 1; + prescalarbits = 0b011; + } + + if (ocr > 255) + { + ocr = F_CPU / frequency / 2 / 64 - 1; + prescalarbits = _timer == 0 ? 0b011 : 0b100; + + if (_timer == 2 && ocr > 255) + { + ocr = F_CPU / frequency / 2 / 128 - 1; + prescalarbits = 0b101; + } + + if (ocr > 255) + { + ocr = F_CPU / frequency / 2 / 256 - 1; + prescalarbits = _timer == 0 ? 0b100 : 0b110; + if (ocr > 255) + { + // can't do any better than /1024 + ocr = F_CPU / frequency / 2 / 1024 - 1; + prescalarbits = _timer == 0 ? 0b101 : 0b111; + } + } + } + } + +#if !defined(__AVR_ATmega8__) + if (_timer == 0) + TCCR0B = prescalarbits; + else +#endif + TCCR2B = prescalarbits; + } + else + { + // two choices for the 16 bit timers: ck/1 or ck/64 + ocr = F_CPU / frequency / 2 - 1; + + prescalarbits = 0b001; + if (ocr > 0xffff) + { + ocr = F_CPU / frequency / 2 / 64 - 1; + prescalarbits = 0b011; + } + + if (_timer == 1) + TCCR1B = (TCCR1B & 0b11111000) | prescalarbits; +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + else if (_timer == 3) + TCCR3B = (TCCR3B & 0b11111000) | prescalarbits; + else if (_timer == 4) + TCCR4B = (TCCR4B & 0b11111000) | prescalarbits; + else if (_timer == 5) + TCCR5B = (TCCR5B & 0b11111000) | prescalarbits; +#endif + + } + + + // Calculate the toggle count + if (duration > 0) + { + toggle_count = 2 * frequency * duration / 1000; + } + else + { + toggle_count = -1; + } + + // Set the OCR for the given timer, + // set the toggle count, + // then turn on the interrupts + switch (_timer) + { + +#if !defined(__AVR_ATmega8__) + case 0: + OCR0A = ocr; + timer0_toggle_count = toggle_count; + bitWrite(TIMSK0, OCIE0A, 1); + break; +#endif + + case 1: + OCR1A = ocr; + timer1_toggle_count = toggle_count; + bitWrite(TIMSK1, OCIE1A, 1); + break; + case 2: + OCR2A = ocr; + timer2_toggle_count = toggle_count; + bitWrite(TIMSK2, OCIE2A, 1); + break; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + case 3: + OCR3A = ocr; + timer3_toggle_count = toggle_count; + bitWrite(TIMSK3, OCIE3A, 1); + break; + case 4: + OCR4A = ocr; + timer4_toggle_count = toggle_count; + bitWrite(TIMSK4, OCIE4A, 1); + break; + case 5: + OCR5A = ocr; + timer5_toggle_count = toggle_count; + bitWrite(TIMSK5, OCIE5A, 1); + break; +#endif + + } + } +} + + +// XXX: this function only works properly for timer 2 (the only one we use +// currently). for the others, it should end the tone, but won't restore +// proper PWM functionality for the timer. +void disableTimer(uint8_t _timer) +{ + switch (_timer) + { +#if !defined(__AVR_ATmega8__) + case 0: + TIMSK0 = 0; + break; +#endif + case 1: + bitWrite(TIMSK1, OCIE1A, 0); + break; + case 2: + bitWrite(TIMSK2, OCIE2A, 0); // disable interrupt + TCCR2A = (1 << WGM20); + TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22); + OCR2A = 0; + break; +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + case 3: + TIMSK3 = 0; + break; + case 4: + TIMSK4 = 0; + break; + case 5: + TIMSK5 = 0; + break; +#endif + } +} + + +void noTone(uint8_t _pin) +{ + int8_t _timer = -1; + + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == _pin) { + _timer = pgm_read_byte(tone_pin_to_timer_PGM + i); + tone_pins[i] = 255; + } + } + + disableTimer(_timer); + + digitalWrite(_pin, 0); +} + +#if 0 +#if !defined(__AVR_ATmega8__) +ISR(TIMER0_COMPA_vect) +{ + if (timer0_toggle_count != 0) + { + // toggle the pin + *timer0_pin_port ^= timer0_pin_mask; + + if (timer0_toggle_count > 0) + timer0_toggle_count--; + } + else + { + disableTimer(0); + *timer0_pin_port &= ~(timer0_pin_mask); // keep pin low after stop + } +} +#endif + + +ISR(TIMER1_COMPA_vect) +{ + if (timer1_toggle_count != 0) + { + // toggle the pin + *timer1_pin_port ^= timer1_pin_mask; + + if (timer1_toggle_count > 0) + timer1_toggle_count--; + } + else + { + disableTimer(1); + *timer1_pin_port &= ~(timer1_pin_mask); // keep pin low after stop + } +} +#endif + + +ISR(TIMER2_COMPA_vect) +{ + + if (timer2_toggle_count != 0) + { + // toggle the pin + *timer2_pin_port ^= timer2_pin_mask; + + if (timer2_toggle_count > 0) + timer2_toggle_count--; + } + else + { + disableTimer(2); + *timer2_pin_port &= ~(timer2_pin_mask); // keep pin low after stop + } +} + + + +//#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#if 0 + +ISR(TIMER3_COMPA_vect) +{ + if (timer3_toggle_count != 0) + { + // toggle the pin + *timer3_pin_port ^= timer3_pin_mask; + + if (timer3_toggle_count > 0) + timer3_toggle_count--; + } + else + { + disableTimer(3); + *timer3_pin_port &= ~(timer3_pin_mask); // keep pin low after stop + } +} + +ISR(TIMER4_COMPA_vect) +{ + if (timer4_toggle_count != 0) + { + // toggle the pin + *timer4_pin_port ^= timer4_pin_mask; + + if (timer4_toggle_count > 0) + timer4_toggle_count--; + } + else + { + disableTimer(4); + *timer4_pin_port &= ~(timer4_pin_mask); // keep pin low after stop + } +} + +ISR(TIMER5_COMPA_vect) +{ + if (timer5_toggle_count != 0) + { + // toggle the pin + *timer5_pin_port ^= timer5_pin_mask; + + if (timer5_toggle_count > 0) + timer5_toggle_count--; + } + else + { + disableTimer(5); + *timer5_pin_port &= ~(timer5_pin_mask); // keep pin low after stop + } +} + +#endif diff --git a/Libraries/arduino/WConstants.h b/Libraries/arduino/WConstants.h new file mode 100644 index 0000000..3e19ac4 --- /dev/null +++ b/Libraries/arduino/WConstants.h @@ -0,0 +1 @@ +#include "wiring.h" diff --git a/Libraries/arduino/WInterrupts.c b/Libraries/arduino/WInterrupts.c new file mode 100644 index 0000000..9c57411 --- /dev/null +++ b/Libraries/arduino/WInterrupts.c @@ -0,0 +1,215 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.uniandes.edu.co + + Copyright (c) 2004-05 Hernando Barragan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + Modified 24 November 2006 by David A. Mellis +*/ + +#include +#include +#include +#include +#include + +#include "WConstants.h" +#include "wiring_private.h" + +volatile static voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS]; +// volatile static voidFuncPtr twiIntFunc; + +#if defined(__AVR_ATmega8__) +#define EICRA MCUCR +#define EIMSK GICR +#endif + +void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) { + if(interruptNum < EXTERNAL_NUM_INTERRUPTS) { + intFunc[interruptNum] = userFunc; + + // Configure the interrupt mode (trigger on low input, any change, rising + // edge, or falling edge). The mode constants were chosen to correspond + // to the configuration bits in the hardware register, so we simply shift + // the mode into place. + + // Enable the interrupt. + + switch (interruptNum) { +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + case 2: + EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00); + EIMSK |= (1 << INT0); + break; + case 3: + EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10); + EIMSK |= (1 << INT1); + break; + case 4: + EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20); + EIMSK |= (1 << INT2); + break; + case 5: + EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30); + EIMSK |= (1 << INT3); + break; + case 0: + EICRB = (EICRB & ~((1 << ISC40) | (1 << ISC41))) | (mode << ISC40); + EIMSK |= (1 << INT4); + break; + case 1: + EICRB = (EICRB & ~((1 << ISC50) | (1 << ISC51))) | (mode << ISC50); + EIMSK |= (1 << INT5); + break; + case 6: + EICRB = (EICRB & ~((1 << ISC60) | (1 << ISC61))) | (mode << ISC60); + EIMSK |= (1 << INT6); + break; + case 7: + EICRB = (EICRB & ~((1 << ISC70) | (1 << ISC71))) | (mode << ISC70); + EIMSK |= (1 << INT7); + break; +#else + case 0: + EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00); + EIMSK |= (1 << INT0); + break; + case 1: + EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10); + EIMSK |= (1 << INT1); + break; +#endif + } + } +} + +void detachInterrupt(uint8_t interruptNum) { + if(interruptNum < EXTERNAL_NUM_INTERRUPTS) { + // Disable the interrupt. (We can't assume that interruptNum is equal + // to the number of the EIMSK bit to clear, as this isn't true on the + // ATmega8. There, INT0 is 6 and INT1 is 7.) + switch (interruptNum) { +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + case 2: + EIMSK &= ~(1 << INT0); + break; + case 3: + EIMSK &= ~(1 << INT1); + break; + case 4: + EIMSK &= ~(1 << INT2); + break; + case 5: + EIMSK &= ~(1 << INT3); + break; + case 0: + EIMSK &= ~(1 << INT4); + break; + case 1: + EIMSK &= ~(1 << INT5); + break; + case 6: + EIMSK &= ~(1 << INT6); + break; + case 7: + EIMSK &= ~(1 << INT7); + break; +#else + case 0: + EIMSK &= ~(1 << INT0); + break; + case 1: + EIMSK &= ~(1 << INT1); + break; +#endif + } + + intFunc[interruptNum] = 0; + } +} + +/* +void attachInterruptTwi(void (*userFunc)(void) ) { + twiIntFunc = userFunc; +} +*/ + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + +SIGNAL(INT0_vect) { + if(intFunc[EXTERNAL_INT_2]) + intFunc[EXTERNAL_INT_2](); +} + +SIGNAL(INT1_vect) { + if(intFunc[EXTERNAL_INT_3]) + intFunc[EXTERNAL_INT_3](); +} + +SIGNAL(INT2_vect) { + if(intFunc[EXTERNAL_INT_4]) + intFunc[EXTERNAL_INT_4](); +} + +SIGNAL(INT3_vect) { + if(intFunc[EXTERNAL_INT_5]) + intFunc[EXTERNAL_INT_5](); +} + +SIGNAL(INT4_vect) { + if(intFunc[EXTERNAL_INT_0]) + intFunc[EXTERNAL_INT_0](); +} + +SIGNAL(INT5_vect) { + if(intFunc[EXTERNAL_INT_1]) + intFunc[EXTERNAL_INT_1](); +} + +SIGNAL(INT6_vect) { + if(intFunc[EXTERNAL_INT_6]) + intFunc[EXTERNAL_INT_6](); +} + +SIGNAL(INT7_vect) { + if(intFunc[EXTERNAL_INT_7]) + intFunc[EXTERNAL_INT_7](); +} + +#else + +SIGNAL(INT0_vect) { + if(intFunc[EXTERNAL_INT_0]) + intFunc[EXTERNAL_INT_0](); +} + +SIGNAL(INT1_vect) { + if(intFunc[EXTERNAL_INT_1]) + intFunc[EXTERNAL_INT_1](); +} + +#endif + +/* +SIGNAL(SIG_2WIRE_SERIAL) { + if(twiIntFunc) + twiIntFunc(); +} +*/ + diff --git a/Libraries/arduino/WMath.cpp b/Libraries/arduino/WMath.cpp new file mode 100644 index 0000000..2120c4c --- /dev/null +++ b/Libraries/arduino/WMath.cpp @@ -0,0 +1,60 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.org.co + Copyright (c) 2004-06 Hernando Barragan + Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/ + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id$ +*/ + +extern "C" { + #include "stdlib.h" +} + +void randomSeed(unsigned int seed) +{ + if (seed != 0) { + srandom(seed); + } +} + +long random(long howbig) +{ + if (howbig == 0) { + return 0; + } + return random() % howbig; +} + +long random(long howsmall, long howbig) +{ + if (howsmall >= howbig) { + return howsmall; + } + long diff = howbig - howsmall; + return random(diff) + howsmall; +} + +long map(long x, long in_min, long in_max, long out_min, long out_max) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +unsigned int makeWord(unsigned int w) { return w; } +unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; } \ No newline at end of file diff --git a/Libraries/arduino/WProgram.h b/Libraries/arduino/WProgram.h new file mode 100644 index 0000000..5afecb4 --- /dev/null +++ b/Libraries/arduino/WProgram.h @@ -0,0 +1,62 @@ +#ifndef WProgram_h +#define WProgram_h + +#include +#include +#include + +#include + +#include "wiring.h" + +#ifdef __cplusplus +#include "WString.h" +#include "HardwareSerial.h" + +uint16_t makeWord(uint16_t w); +uint16_t makeWord(byte h, byte l); + +#define word(...) makeWord(__VA_ARGS__) + +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); + +void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0); +void noTone(uint8_t _pin); + +// WMath prototypes +long random(long); +long random(long, long); +void randomSeed(unsigned int); +long map(long, long, long, long, long); + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +const static uint8_t A0 = 54; +const static uint8_t A1 = 55; +const static uint8_t A2 = 56; +const static uint8_t A3 = 57; +const static uint8_t A4 = 58; +const static uint8_t A5 = 59; +const static uint8_t A6 = 60; +const static uint8_t A7 = 61; +const static uint8_t A8 = 62; +const static uint8_t A9 = 63; +const static uint8_t A10 = 64; +const static uint8_t A11 = 65; +const static uint8_t A12 = 66; +const static uint8_t A13 = 67; +const static uint8_t A14 = 68; +const static uint8_t A15 = 69; +#else +const static uint8_t A0 = 14; +const static uint8_t A1 = 15; +const static uint8_t A2 = 16; +const static uint8_t A3 = 17; +const static uint8_t A4 = 18; +const static uint8_t A5 = 19; +const static uint8_t A6 = 20; +const static uint8_t A7 = 21; +#endif + +#endif + +#endif \ No newline at end of file diff --git a/Libraries/arduino/WString.cpp b/Libraries/arduino/WString.cpp new file mode 100644 index 0000000..2718956 --- /dev/null +++ b/Libraries/arduino/WString.cpp @@ -0,0 +1,436 @@ +/* + WString.cpp - String library for Wiring & Arduino + Copyright (c) 2009-10 Hernando Barragan. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "WProgram.h" +#include "WString.h" + + +String::String( const char *value ) +{ + if ( value == NULL ) + value = ""; + getBuffer( _length = strlen( value ) ); + if ( _buffer != NULL ) + strcpy( _buffer, value ); +} + +String::String( const String &value ) +{ + getBuffer( _length = value._length ); + if ( _buffer != NULL ) + strcpy( _buffer, value._buffer ); +} + +String::String( const char value ) +{ + _length = 1; + getBuffer(1); + if ( _buffer != NULL ) { + _buffer[0] = value; + _buffer[1] = 0; + } +} + +String::String( const unsigned char value ) +{ + _length = 1; + getBuffer(1); + if ( _buffer != NULL) { + _buffer[0] = value; + _buffer[1] = 0; + } +} + +String::String( const int value, const int base ) +{ + char buf[33]; + itoa((signed long)value, buf, base); + getBuffer( _length = strlen(buf) ); + if ( _buffer != NULL ) + strcpy( _buffer, buf ); +} + +String::String( const unsigned int value, const int base ) +{ + char buf[33]; + ultoa((unsigned long)value, buf, base); + getBuffer( _length = strlen(buf) ); + if ( _buffer != NULL ) + strcpy( _buffer, buf ); +} + +String::String( const long value, const int base ) +{ + char buf[33]; + ltoa(value, buf, base); + getBuffer( _length = strlen(buf) ); + if ( _buffer != NULL ) + strcpy( _buffer, buf ); +} + +String::String( const unsigned long value, const int base ) +{ + char buf[33]; + ultoa(value, buf, 10); + getBuffer( _length = strlen(buf) ); + if ( _buffer != NULL ) + strcpy( _buffer, buf ); +} + +char String::charAt( unsigned int loc ) const +{ + return operator[]( loc ); +} + +void String::setCharAt( unsigned int loc, const char aChar ) +{ + if(_buffer == NULL) return; + if(_length > loc) { + _buffer[loc] = aChar; + } +} + +int String::compareTo( const String &s2 ) const +{ + return strcmp( _buffer, s2._buffer ); +} + +const String & String::concat( const String &s2 ) +{ + return (*this) += s2; +} + +const String & String::operator=( const String &rhs ) +{ + if ( this == &rhs ) + return *this; + + if ( rhs._length > _length ) + { + free(_buffer); + getBuffer( rhs._length ); + } + + if ( _buffer != NULL ) { + _length = rhs._length; + strcpy( _buffer, rhs._buffer ); + } + return *this; +} + +//const String & String::operator+=( const char aChar ) +//{ +// if ( _length == _capacity ) +// doubleBuffer(); +// +// _buffer[ _length++ ] = aChar; +// _buffer[ _length ] = '\0'; +// return *this; +//} + +const String & String::operator+=( const String &other ) +{ + _length += other._length; + if ( _length > _capacity ) + { + char *temp = _buffer; + getBuffer( _length ); + if ( _buffer != NULL ) + strcpy( _buffer, temp ); + free(temp); + } + if ( _buffer != NULL ) + strcat( _buffer, other._buffer ); + return *this; +} + + +int String::operator==( const String &rhs ) const +{ + return ( _length == rhs._length && strcmp( _buffer, rhs._buffer ) == 0 ); +} + +int String::operator!=( const String &rhs ) const +{ + return ( _length != rhs.length() || strcmp( _buffer, rhs._buffer ) != 0 ); +} + +int String::operator<( const String &rhs ) const +{ + return strcmp( _buffer, rhs._buffer ) < 0; +} + +int String::operator>( const String &rhs ) const +{ + return strcmp( _buffer, rhs._buffer ) > 0; +} + +int String::operator<=( const String &rhs ) const +{ + return strcmp( _buffer, rhs._buffer ) <= 0; +} + +int String::operator>=( const String & rhs ) const +{ + return strcmp( _buffer, rhs._buffer ) >= 0; +} + +char & String::operator[]( unsigned int index ) +{ + static char dummy_writable_char; + if (index >= _length || !_buffer) { + dummy_writable_char = 0; + return dummy_writable_char; + } + return _buffer[ index ]; +} + +char String::operator[]( unsigned int index ) const +{ + // need to check for valid index, to do later + return _buffer[ index ]; +} + +boolean String::endsWith( const String &s2 ) const +{ + if ( _length < s2._length ) + return 0; + + return strcmp( &_buffer[ _length - s2._length], s2._buffer ) == 0; +} + +boolean String::equals( const String &s2 ) const +{ + return ( _length == s2._length && strcmp( _buffer,s2._buffer ) == 0 ); +} + +boolean String::equalsIgnoreCase( const String &s2 ) const +{ + if ( this == &s2 ) + return true; //1; + else if ( _length != s2._length ) + return false; //0; + + return strcmp(toLowerCase()._buffer, s2.toLowerCase()._buffer) == 0; +} + +String String::replace( char findChar, char replaceChar ) +{ + if ( _buffer == NULL ) return *this; + String theReturn = _buffer; + char* temp = theReturn._buffer; + while( (temp = strchr( temp, findChar )) != 0 ) + *temp = replaceChar; + + return theReturn; +} + +String String::replace( const String& match, const String& replace ) +{ + if ( _buffer == NULL ) return *this; + String temp = _buffer, newString; + + int loc; + while ( (loc = temp.indexOf( match )) != -1 ) + { + newString += temp.substring( 0, loc ); + newString += replace; + temp = temp.substring( loc + match._length ); + } + newString += temp; + return newString; +} + +int String::indexOf( char temp ) const +{ + return indexOf( temp, 0 ); +} + +int String::indexOf( char ch, unsigned int fromIndex ) const +{ + if ( fromIndex >= _length ) + return -1; + + const char* temp = strchr( &_buffer[fromIndex], ch ); + if ( temp == NULL ) + return -1; + + return temp - _buffer; +} + +int String::indexOf( const String &s2 ) const +{ + return indexOf( s2, 0 ); +} + +int String::indexOf( const String &s2, unsigned int fromIndex ) const +{ + if ( fromIndex >= _length ) + return -1; + + const char *theFind = strstr( &_buffer[ fromIndex ], s2._buffer ); + + if ( theFind == NULL ) + return -1; + + return theFind - _buffer; // pointer subtraction +} + +int String::lastIndexOf( char theChar ) const +{ + return lastIndexOf( theChar, _length - 1 ); +} + +int String::lastIndexOf( char ch, unsigned int fromIndex ) const +{ + if ( fromIndex >= _length ) + return -1; + + char tempchar = _buffer[fromIndex + 1]; + _buffer[fromIndex + 1] = '\0'; + char* temp = strrchr( _buffer, ch ); + _buffer[fromIndex + 1] = tempchar; + + if ( temp == NULL ) + return -1; + + return temp - _buffer; +} + +int String::lastIndexOf( const String &s2 ) const +{ + return lastIndexOf( s2, _length - s2._length ); +} + +int String::lastIndexOf( const String &s2, unsigned int fromIndex ) const +{ + // check for empty strings + if ( s2._length == 0 || s2._length - 1 > fromIndex || fromIndex >= _length ) + return -1; + + // matching first character + char temp = s2[ 0 ]; + + for ( int i = fromIndex; i >= 0; i-- ) + { + if ( _buffer[ i ] == temp && (*this).substring( i, i + s2._length ).equals( s2 ) ) + return i; + } + return -1; +} + +boolean String::startsWith( const String &s2 ) const +{ + if ( _length < s2._length ) + return 0; + + return startsWith( s2, 0 ); +} + +boolean String::startsWith( const String &s2, unsigned int offset ) const +{ + if ( offset > _length - s2._length ) + return 0; + + return strncmp( &_buffer[offset], s2._buffer, s2._length ) == 0; +} + +String String::substring( unsigned int left ) const +{ + return substring( left, _length ); +} + +String String::substring( unsigned int left, unsigned int right ) const +{ + if ( left > right ) + { + int temp = right; + right = left; + left = temp; + } + + if ( right > _length ) + { + right = _length; + } + + char temp = _buffer[ right ]; // save the replaced character + _buffer[ right ] = '\0'; + String outPut = ( _buffer + left ); // pointer arithmetic + _buffer[ right ] = temp; //restore character + return outPut; +} + +String String::toLowerCase() const +{ + String temp = _buffer; + + for ( unsigned int i = 0; i < _length; i++ ) + temp._buffer[ i ] = (char)tolower( temp._buffer[ i ] ); + return temp; +} + +String String::toUpperCase() const +{ + String temp = _buffer; + + for ( unsigned int i = 0; i < _length; i++ ) + temp._buffer[ i ] = (char)toupper( temp._buffer[ i ] ); + return temp; +} + +String String::trim() const +{ + if ( _buffer == NULL ) return *this; + String temp = _buffer; + unsigned int i,j; + + for ( i = 0; i < _length; i++ ) + { + if ( !isspace(_buffer[i]) ) + break; + } + + for ( j = temp._length - 1; j > i; j-- ) + { + if ( !isspace(_buffer[j]) ) + break; + } + + return temp.substring( i, j + 1); +} + +void String::getBytes(unsigned char *buf, unsigned int bufsize) +{ + if (!bufsize || !buf) return; + unsigned int len = bufsize - 1; + if (len > _length) len = _length; + strncpy((char *)buf, _buffer, len); + buf[len] = 0; +} + +void String::toCharArray(char *buf, unsigned int bufsize) +{ + if (!bufsize || !buf) return; + unsigned int len = bufsize - 1; + if (len > _length) len = _length; + strncpy(buf, _buffer, len); + buf[len] = 0; +} diff --git a/Libraries/arduino/WString.h b/Libraries/arduino/WString.h new file mode 100644 index 0000000..fb87c52 --- /dev/null +++ b/Libraries/arduino/WString.h @@ -0,0 +1,111 @@ +/* + WString.h - String library for Wiring & Arduino + Copyright (c) 2009-10 Hernando Barragan. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef String_h +#define String_h + +//#include "WProgram.h" +#include +#include +#include + +class String +{ + public: + // constructors + String( const char *value = "" ); + String( const String &value ); + String( const char ); + String( const unsigned char ); + String( const int, const int base=10); + String( const unsigned int, const int base=10 ); + String( const long, const int base=10 ); + String( const unsigned long, const int base=10 ); + ~String() { free(_buffer); _length = _capacity = 0;} //added _length = _capacity = 0; + + // operators + const String & operator = ( const String &rhs ); + const String & operator +=( const String &rhs ); + //const String & operator +=( const char ); + int operator ==( const String &rhs ) const; + int operator !=( const String &rhs ) const; + int operator < ( const String &rhs ) const; + int operator > ( const String &rhs ) const; + int operator <=( const String &rhs ) const; + int operator >=( const String &rhs ) const; + char operator []( unsigned int index ) const; + char& operator []( unsigned int index ); + //operator const char *() const { return _buffer; } + + // general methods + char charAt( unsigned int index ) const; + int compareTo( const String &anotherString ) const; + unsigned char endsWith( const String &suffix ) const; + unsigned char equals( const String &anObject ) const; + unsigned char equalsIgnoreCase( const String &anotherString ) const; + int indexOf( char ch ) const; + int indexOf( char ch, unsigned int fromIndex ) const; + int indexOf( const String &str ) const; + int indexOf( const String &str, unsigned int fromIndex ) const; + int lastIndexOf( char ch ) const; + int lastIndexOf( char ch, unsigned int fromIndex ) const; + int lastIndexOf( const String &str ) const; + int lastIndexOf( const String &str, unsigned int fromIndex ) const; + const unsigned int length( ) const { return _length; } + void setCharAt(unsigned int index, const char ch); + unsigned char startsWith( const String &prefix ) const; + unsigned char startsWith( const String &prefix, unsigned int toffset ) const; + String substring( unsigned int beginIndex ) const; + String substring( unsigned int beginIndex, unsigned int endIndex ) const; + String toLowerCase( ) const; + String toUpperCase( ) const; + String trim( ) const; + void getBytes(unsigned char *buf, unsigned int bufsize); + void toCharArray(char *buf, unsigned int bufsize); + const String& concat( const String &str ); + String replace( char oldChar, char newChar ); + String replace( const String& match, const String& replace ); + friend String operator + ( String lhs, const String &rhs ); + + protected: + char *_buffer; // the actual char array + unsigned int _capacity; // the array length minus one (for the '\0') + unsigned int _length; // the String length (not counting the '\0') + + void getBuffer(unsigned int maxStrLen); + + private: + +}; + +// allocate buffer space +inline void String::getBuffer(unsigned int maxStrLen) +{ + _capacity = maxStrLen; + _buffer = (char *) malloc(_capacity + 1); + if (_buffer == NULL) _length = _capacity = 0; +} + +inline String operator+( String lhs, const String &rhs ) +{ + return lhs += rhs; +} + + +#endif diff --git a/Libraries/arduino/binary.h b/Libraries/arduino/binary.h new file mode 100644 index 0000000..af14980 --- /dev/null +++ b/Libraries/arduino/binary.h @@ -0,0 +1,515 @@ +#ifndef Binary_h +#define Binary_h + +#define B0 0 +#define B00 0 +#define B000 0 +#define B0000 0 +#define B00000 0 +#define B000000 0 +#define B0000000 0 +#define B00000000 0 +#define B1 1 +#define B01 1 +#define B001 1 +#define B0001 1 +#define B00001 1 +#define B000001 1 +#define B0000001 1 +#define B00000001 1 +#define B10 2 +#define B010 2 +#define B0010 2 +#define B00010 2 +#define B000010 2 +#define B0000010 2 +#define B00000010 2 +#define B11 3 +#define B011 3 +#define B0011 3 +#define B00011 3 +#define B000011 3 +#define B0000011 3 +#define B00000011 3 +#define B100 4 +#define B0100 4 +#define B00100 4 +#define B000100 4 +#define B0000100 4 +#define B00000100 4 +#define B101 5 +#define B0101 5 +#define B00101 5 +#define B000101 5 +#define B0000101 5 +#define B00000101 5 +#define B110 6 +#define B0110 6 +#define B00110 6 +#define B000110 6 +#define B0000110 6 +#define B00000110 6 +#define B111 7 +#define B0111 7 +#define B00111 7 +#define B000111 7 +#define B0000111 7 +#define B00000111 7 +#define B1000 8 +#define B01000 8 +#define B001000 8 +#define B0001000 8 +#define B00001000 8 +#define B1001 9 +#define B01001 9 +#define B001001 9 +#define B0001001 9 +#define B00001001 9 +#define B1010 10 +#define B01010 10 +#define B001010 10 +#define B0001010 10 +#define B00001010 10 +#define B1011 11 +#define B01011 11 +#define B001011 11 +#define B0001011 11 +#define B00001011 11 +#define B1100 12 +#define B01100 12 +#define B001100 12 +#define B0001100 12 +#define B00001100 12 +#define B1101 13 +#define B01101 13 +#define B001101 13 +#define B0001101 13 +#define B00001101 13 +#define B1110 14 +#define B01110 14 +#define B001110 14 +#define B0001110 14 +#define B00001110 14 +#define B1111 15 +#define B01111 15 +#define B001111 15 +#define B0001111 15 +#define B00001111 15 +#define B10000 16 +#define B010000 16 +#define B0010000 16 +#define B00010000 16 +#define B10001 17 +#define B010001 17 +#define B0010001 17 +#define B00010001 17 +#define B10010 18 +#define B010010 18 +#define B0010010 18 +#define B00010010 18 +#define B10011 19 +#define B010011 19 +#define B0010011 19 +#define B00010011 19 +#define B10100 20 +#define B010100 20 +#define B0010100 20 +#define B00010100 20 +#define B10101 21 +#define B010101 21 +#define B0010101 21 +#define B00010101 21 +#define B10110 22 +#define B010110 22 +#define B0010110 22 +#define B00010110 22 +#define B10111 23 +#define B010111 23 +#define B0010111 23 +#define B00010111 23 +#define B11000 24 +#define B011000 24 +#define B0011000 24 +#define B00011000 24 +#define B11001 25 +#define B011001 25 +#define B0011001 25 +#define B00011001 25 +#define B11010 26 +#define B011010 26 +#define B0011010 26 +#define B00011010 26 +#define B11011 27 +#define B011011 27 +#define B0011011 27 +#define B00011011 27 +#define B11100 28 +#define B011100 28 +#define B0011100 28 +#define B00011100 28 +#define B11101 29 +#define B011101 29 +#define B0011101 29 +#define B00011101 29 +#define B11110 30 +#define B011110 30 +#define B0011110 30 +#define B00011110 30 +#define B11111 31 +#define B011111 31 +#define B0011111 31 +#define B00011111 31 +#define B100000 32 +#define B0100000 32 +#define B00100000 32 +#define B100001 33 +#define B0100001 33 +#define B00100001 33 +#define B100010 34 +#define B0100010 34 +#define B00100010 34 +#define B100011 35 +#define B0100011 35 +#define B00100011 35 +#define B100100 36 +#define B0100100 36 +#define B00100100 36 +#define B100101 37 +#define B0100101 37 +#define B00100101 37 +#define B100110 38 +#define B0100110 38 +#define B00100110 38 +#define B100111 39 +#define B0100111 39 +#define B00100111 39 +#define B101000 40 +#define B0101000 40 +#define B00101000 40 +#define B101001 41 +#define B0101001 41 +#define B00101001 41 +#define B101010 42 +#define B0101010 42 +#define B00101010 42 +#define B101011 43 +#define B0101011 43 +#define B00101011 43 +#define B101100 44 +#define B0101100 44 +#define B00101100 44 +#define B101101 45 +#define B0101101 45 +#define B00101101 45 +#define B101110 46 +#define B0101110 46 +#define B00101110 46 +#define B101111 47 +#define B0101111 47 +#define B00101111 47 +#define B110000 48 +#define B0110000 48 +#define B00110000 48 +#define B110001 49 +#define B0110001 49 +#define B00110001 49 +#define B110010 50 +#define B0110010 50 +#define B00110010 50 +#define B110011 51 +#define B0110011 51 +#define B00110011 51 +#define B110100 52 +#define B0110100 52 +#define B00110100 52 +#define B110101 53 +#define B0110101 53 +#define B00110101 53 +#define B110110 54 +#define B0110110 54 +#define B00110110 54 +#define B110111 55 +#define B0110111 55 +#define B00110111 55 +#define B111000 56 +#define B0111000 56 +#define B00111000 56 +#define B111001 57 +#define B0111001 57 +#define B00111001 57 +#define B111010 58 +#define B0111010 58 +#define B00111010 58 +#define B111011 59 +#define B0111011 59 +#define B00111011 59 +#define B111100 60 +#define B0111100 60 +#define B00111100 60 +#define B111101 61 +#define B0111101 61 +#define B00111101 61 +#define B111110 62 +#define B0111110 62 +#define B00111110 62 +#define B111111 63 +#define B0111111 63 +#define B00111111 63 +#define B1000000 64 +#define B01000000 64 +#define B1000001 65 +#define B01000001 65 +#define B1000010 66 +#define B01000010 66 +#define B1000011 67 +#define B01000011 67 +#define B1000100 68 +#define B01000100 68 +#define B1000101 69 +#define B01000101 69 +#define B1000110 70 +#define B01000110 70 +#define B1000111 71 +#define B01000111 71 +#define B1001000 72 +#define B01001000 72 +#define B1001001 73 +#define B01001001 73 +#define B1001010 74 +#define B01001010 74 +#define B1001011 75 +#define B01001011 75 +#define B1001100 76 +#define B01001100 76 +#define B1001101 77 +#define B01001101 77 +#define B1001110 78 +#define B01001110 78 +#define B1001111 79 +#define B01001111 79 +#define B1010000 80 +#define B01010000 80 +#define B1010001 81 +#define B01010001 81 +#define B1010010 82 +#define B01010010 82 +#define B1010011 83 +#define B01010011 83 +#define B1010100 84 +#define B01010100 84 +#define B1010101 85 +#define B01010101 85 +#define B1010110 86 +#define B01010110 86 +#define B1010111 87 +#define B01010111 87 +#define B1011000 88 +#define B01011000 88 +#define B1011001 89 +#define B01011001 89 +#define B1011010 90 +#define B01011010 90 +#define B1011011 91 +#define B01011011 91 +#define B1011100 92 +#define B01011100 92 +#define B1011101 93 +#define B01011101 93 +#define B1011110 94 +#define B01011110 94 +#define B1011111 95 +#define B01011111 95 +#define B1100000 96 +#define B01100000 96 +#define B1100001 97 +#define B01100001 97 +#define B1100010 98 +#define B01100010 98 +#define B1100011 99 +#define B01100011 99 +#define B1100100 100 +#define B01100100 100 +#define B1100101 101 +#define B01100101 101 +#define B1100110 102 +#define B01100110 102 +#define B1100111 103 +#define B01100111 103 +#define B1101000 104 +#define B01101000 104 +#define B1101001 105 +#define B01101001 105 +#define B1101010 106 +#define B01101010 106 +#define B1101011 107 +#define B01101011 107 +#define B1101100 108 +#define B01101100 108 +#define B1101101 109 +#define B01101101 109 +#define B1101110 110 +#define B01101110 110 +#define B1101111 111 +#define B01101111 111 +#define B1110000 112 +#define B01110000 112 +#define B1110001 113 +#define B01110001 113 +#define B1110010 114 +#define B01110010 114 +#define B1110011 115 +#define B01110011 115 +#define B1110100 116 +#define B01110100 116 +#define B1110101 117 +#define B01110101 117 +#define B1110110 118 +#define B01110110 118 +#define B1110111 119 +#define B01110111 119 +#define B1111000 120 +#define B01111000 120 +#define B1111001 121 +#define B01111001 121 +#define B1111010 122 +#define B01111010 122 +#define B1111011 123 +#define B01111011 123 +#define B1111100 124 +#define B01111100 124 +#define B1111101 125 +#define B01111101 125 +#define B1111110 126 +#define B01111110 126 +#define B1111111 127 +#define B01111111 127 +#define B10000000 128 +#define B10000001 129 +#define B10000010 130 +#define B10000011 131 +#define B10000100 132 +#define B10000101 133 +#define B10000110 134 +#define B10000111 135 +#define B10001000 136 +#define B10001001 137 +#define B10001010 138 +#define B10001011 139 +#define B10001100 140 +#define B10001101 141 +#define B10001110 142 +#define B10001111 143 +#define B10010000 144 +#define B10010001 145 +#define B10010010 146 +#define B10010011 147 +#define B10010100 148 +#define B10010101 149 +#define B10010110 150 +#define B10010111 151 +#define B10011000 152 +#define B10011001 153 +#define B10011010 154 +#define B10011011 155 +#define B10011100 156 +#define B10011101 157 +#define B10011110 158 +#define B10011111 159 +#define B10100000 160 +#define B10100001 161 +#define B10100010 162 +#define B10100011 163 +#define B10100100 164 +#define B10100101 165 +#define B10100110 166 +#define B10100111 167 +#define B10101000 168 +#define B10101001 169 +#define B10101010 170 +#define B10101011 171 +#define B10101100 172 +#define B10101101 173 +#define B10101110 174 +#define B10101111 175 +#define B10110000 176 +#define B10110001 177 +#define B10110010 178 +#define B10110011 179 +#define B10110100 180 +#define B10110101 181 +#define B10110110 182 +#define B10110111 183 +#define B10111000 184 +#define B10111001 185 +#define B10111010 186 +#define B10111011 187 +#define B10111100 188 +#define B10111101 189 +#define B10111110 190 +#define B10111111 191 +#define B11000000 192 +#define B11000001 193 +#define B11000010 194 +#define B11000011 195 +#define B11000100 196 +#define B11000101 197 +#define B11000110 198 +#define B11000111 199 +#define B11001000 200 +#define B11001001 201 +#define B11001010 202 +#define B11001011 203 +#define B11001100 204 +#define B11001101 205 +#define B11001110 206 +#define B11001111 207 +#define B11010000 208 +#define B11010001 209 +#define B11010010 210 +#define B11010011 211 +#define B11010100 212 +#define B11010101 213 +#define B11010110 214 +#define B11010111 215 +#define B11011000 216 +#define B11011001 217 +#define B11011010 218 +#define B11011011 219 +#define B11011100 220 +#define B11011101 221 +#define B11011110 222 +#define B11011111 223 +#define B11100000 224 +#define B11100001 225 +#define B11100010 226 +#define B11100011 227 +#define B11100100 228 +#define B11100101 229 +#define B11100110 230 +#define B11100111 231 +#define B11101000 232 +#define B11101001 233 +#define B11101010 234 +#define B11101011 235 +#define B11101100 236 +#define B11101101 237 +#define B11101110 238 +#define B11101111 239 +#define B11110000 240 +#define B11110001 241 +#define B11110010 242 +#define B11110011 243 +#define B11110100 244 +#define B11110101 245 +#define B11110110 246 +#define B11110111 247 +#define B11111000 248 +#define B11111001 249 +#define B11111010 250 +#define B11111011 251 +#define B11111100 252 +#define B11111101 253 +#define B11111110 254 +#define B11111111 255 + +#endif diff --git a/Libraries/arduino/main.cpp b/Libraries/arduino/main.cpp new file mode 100644 index 0000000..cc6e81d --- /dev/null +++ b/Libraries/arduino/main.cpp @@ -0,0 +1,14 @@ +#include + +int main(void) +{ + init(); + + setup(); + + for (;;) + loop(); + + return 0; +} + diff --git a/Libraries/arduino/pins_arduino.c b/Libraries/arduino/pins_arduino.c new file mode 100644 index 0000000..0c816e9 --- /dev/null +++ b/Libraries/arduino/pins_arduino.c @@ -0,0 +1,465 @@ +/* + pins_arduino.c - pin definitions for the Arduino board + Part of Arduino / Wiring Lite + + Copyright (c) 2005 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id$ +*/ + +#include +#include "wiring_private.h" +#include "pins_arduino.h" + +// On the Arduino board, digital pins are also used +// for the analog output (software PWM). Analog input +// pins are a separate set. + +// ATMEL ATMEGA8 & 168 / ARDUINO +// +// +-\/-+ +// PC6 1| |28 PC5 (AI 5) +// (D 0) PD0 2| |27 PC4 (AI 4) +// (D 1) PD1 3| |26 PC3 (AI 3) +// (D 2) PD2 4| |25 PC2 (AI 2) +// PWM+ (D 3) PD3 5| |24 PC1 (AI 1) +// (D 4) PD4 6| |23 PC0 (AI 0) +// VCC 7| |22 GND +// GND 8| |21 AREF +// PB6 9| |20 AVCC +// PB7 10| |19 PB5 (D 13) +// PWM+ (D 5) PD5 11| |18 PB4 (D 12) +// PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM +// (D 7) PD7 13| |16 PB2 (D 10) PWM +// (D 8) PB0 14| |15 PB1 (D 9) PWM +// +----+ +// +// (PWM+ indicates the additional PWM pins on the ATmega168.) + +// ATMEL ATMEGA1280 / ARDUINO +// +// 0-7 PE0-PE7 works +// 8-13 PB0-PB5 works +// 14-21 PA0-PA7 works +// 22-29 PH0-PH7 works +// 30-35 PG5-PG0 works +// 36-43 PC7-PC0 works +// 44-51 PJ7-PJ0 works +// 52-59 PL7-PL0 works +// 60-67 PD7-PD0 works +// A0-A7 PF0-PF7 +// A8-A15 PK0-PK7 + +#define PA 1 +#define PB 2 +#define PC 3 +#define PD 4 +#define PE 5 +#define PF 6 +#define PG 7 +#define PH 8 +#define PJ 10 +#define PK 11 +#define PL 12 + + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +const uint16_t PROGMEM port_to_mode_PGM[] = { + NOT_A_PORT, + &DDRA, + &DDRB, + &DDRC, + &DDRD, + &DDRE, + &DDRF, + &DDRG, + &DDRH, + NOT_A_PORT, + &DDRJ, + &DDRK, + &DDRL, +}; + +const uint16_t PROGMEM port_to_output_PGM[] = { + NOT_A_PORT, + &PORTA, + &PORTB, + &PORTC, + &PORTD, + &PORTE, + &PORTF, + &PORTG, + &PORTH, + NOT_A_PORT, + &PORTJ, + &PORTK, + &PORTL, +}; + +const uint16_t PROGMEM port_to_input_PGM[] = { + NOT_A_PIN, + &PINA, + &PINB, + &PINC, + &PIND, + &PINE, + &PINF, + &PING, + &PINH, + NOT_A_PIN, + &PINJ, + &PINK, + &PINL, +}; + +const uint8_t PROGMEM digital_pin_to_port_PGM[] = { + // PORTLIST + // ------------------------------------------- + PE , // PE 0 ** 0 ** USART0_RX + PE , // PE 1 ** 1 ** USART0_TX + PE , // PE 4 ** 2 ** PWM2 + PE , // PE 5 ** 3 ** PWM3 + PG , // PG 5 ** 4 ** PWM4 + PE , // PE 3 ** 5 ** PWM5 + PH , // PH 3 ** 6 ** PWM6 + PH , // PH 4 ** 7 ** PWM7 + PH , // PH 5 ** 8 ** PWM8 + PH , // PH 6 ** 9 ** PWM9 + PB , // PB 4 ** 10 ** PWM10 + PB , // PB 5 ** 11 ** PWM11 + PB , // PB 6 ** 12 ** PWM12 + PB , // PB 7 ** 13 ** PWM13 + PJ , // PJ 1 ** 14 ** USART3_TX + PJ , // PJ 0 ** 15 ** USART3_RX + PH , // PH 1 ** 16 ** USART2_TX + PH , // PH 0 ** 17 ** USART2_RX + PD , // PD 3 ** 18 ** USART1_TX + PD , // PD 2 ** 19 ** USART1_RX + PD , // PD 1 ** 20 ** I2C_SDA + PD , // PD 0 ** 21 ** I2C_SCL + PA , // PA 0 ** 22 ** D22 + PA , // PA 1 ** 23 ** D23 + PA , // PA 2 ** 24 ** D24 + PA , // PA 3 ** 25 ** D25 + PA , // PA 4 ** 26 ** D26 + PA , // PA 5 ** 27 ** D27 + PA , // PA 6 ** 28 ** D28 + PA , // PA 7 ** 29 ** D29 + PC , // PC 7 ** 30 ** D30 + PC , // PC 6 ** 31 ** D31 + PC , // PC 5 ** 32 ** D32 + PC , // PC 4 ** 33 ** D33 + PC , // PC 3 ** 34 ** D34 + PC , // PC 2 ** 35 ** D35 + PC , // PC 1 ** 36 ** D36 + PC , // PC 0 ** 37 ** D37 + PD , // PD 7 ** 38 ** D38 + PG , // PG 2 ** 39 ** D39 + PG , // PG 1 ** 40 ** D40 + PG , // PG 0 ** 41 ** D41 + PL , // PL 7 ** 42 ** D42 + PL , // PL 6 ** 43 ** D43 + PL , // PL 5 ** 44 ** D44 + PL , // PL 4 ** 45 ** D45 + PL , // PL 3 ** 46 ** D46 + PL , // PL 2 ** 47 ** D47 + PL , // PL 1 ** 48 ** D48 + PL , // PL 0 ** 49 ** D49 + PB , // PB 3 ** 50 ** SPI_MISO + PB , // PB 2 ** 51 ** SPI_MOSI + PB , // PB 1 ** 52 ** SPI_SCK + PB , // PB 0 ** 53 ** SPI_SS + PF , // PF 0 ** 54 ** A0 + PF , // PF 1 ** 55 ** A1 + PF , // PF 2 ** 56 ** A2 + PF , // PF 3 ** 57 ** A3 + PF , // PF 4 ** 58 ** A4 + PF , // PF 5 ** 59 ** A5 + PF , // PF 6 ** 60 ** A6 + PF , // PF 7 ** 61 ** A7 + PK , // PK 0 ** 62 ** A8 + PK , // PK 1 ** 63 ** A9 + PK , // PK 2 ** 64 ** A10 + PK , // PK 3 ** 65 ** A11 + PK , // PK 4 ** 66 ** A12 + PK , // PK 5 ** 67 ** A13 + PK , // PK 6 ** 68 ** A14 + PK , // PK 7 ** 69 ** A15 +}; + +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { + // PIN IN PORT + // ------------------------------------------- + _BV( 0 ) , // PE 0 ** 0 ** USART0_RX + _BV( 1 ) , // PE 1 ** 1 ** USART0_TX + _BV( 4 ) , // PE 4 ** 2 ** PWM2 + _BV( 5 ) , // PE 5 ** 3 ** PWM3 + _BV( 5 ) , // PG 5 ** 4 ** PWM4 + _BV( 3 ) , // PE 3 ** 5 ** PWM5 + _BV( 3 ) , // PH 3 ** 6 ** PWM6 + _BV( 4 ) , // PH 4 ** 7 ** PWM7 + _BV( 5 ) , // PH 5 ** 8 ** PWM8 + _BV( 6 ) , // PH 6 ** 9 ** PWM9 + _BV( 4 ) , // PB 4 ** 10 ** PWM10 + _BV( 5 ) , // PB 5 ** 11 ** PWM11 + _BV( 6 ) , // PB 6 ** 12 ** PWM12 + _BV( 7 ) , // PB 7 ** 13 ** PWM13 + _BV( 1 ) , // PJ 1 ** 14 ** USART3_TX + _BV( 0 ) , // PJ 0 ** 15 ** USART3_RX + _BV( 1 ) , // PH 1 ** 16 ** USART2_TX + _BV( 0 ) , // PH 0 ** 17 ** USART2_RX + _BV( 3 ) , // PD 3 ** 18 ** USART1_TX + _BV( 2 ) , // PD 2 ** 19 ** USART1_RX + _BV( 1 ) , // PD 1 ** 20 ** I2C_SDA + _BV( 0 ) , // PD 0 ** 21 ** I2C_SCL + _BV( 0 ) , // PA 0 ** 22 ** D22 + _BV( 1 ) , // PA 1 ** 23 ** D23 + _BV( 2 ) , // PA 2 ** 24 ** D24 + _BV( 3 ) , // PA 3 ** 25 ** D25 + _BV( 4 ) , // PA 4 ** 26 ** D26 + _BV( 5 ) , // PA 5 ** 27 ** D27 + _BV( 6 ) , // PA 6 ** 28 ** D28 + _BV( 7 ) , // PA 7 ** 29 ** D29 + _BV( 7 ) , // PC 7 ** 30 ** D30 + _BV( 6 ) , // PC 6 ** 31 ** D31 + _BV( 5 ) , // PC 5 ** 32 ** D32 + _BV( 4 ) , // PC 4 ** 33 ** D33 + _BV( 3 ) , // PC 3 ** 34 ** D34 + _BV( 2 ) , // PC 2 ** 35 ** D35 + _BV( 1 ) , // PC 1 ** 36 ** D36 + _BV( 0 ) , // PC 0 ** 37 ** D37 + _BV( 7 ) , // PD 7 ** 38 ** D38 + _BV( 2 ) , // PG 2 ** 39 ** D39 + _BV( 1 ) , // PG 1 ** 40 ** D40 + _BV( 0 ) , // PG 0 ** 41 ** D41 + _BV( 7 ) , // PL 7 ** 42 ** D42 + _BV( 6 ) , // PL 6 ** 43 ** D43 + _BV( 5 ) , // PL 5 ** 44 ** D44 + _BV( 4 ) , // PL 4 ** 45 ** D45 + _BV( 3 ) , // PL 3 ** 46 ** D46 + _BV( 2 ) , // PL 2 ** 47 ** D47 + _BV( 1 ) , // PL 1 ** 48 ** D48 + _BV( 0 ) , // PL 0 ** 49 ** D49 + _BV( 3 ) , // PB 3 ** 50 ** SPI_MISO + _BV( 2 ) , // PB 2 ** 51 ** SPI_MOSI + _BV( 1 ) , // PB 1 ** 52 ** SPI_SCK + _BV( 0 ) , // PB 0 ** 53 ** SPI_SS + _BV( 0 ) , // PF 0 ** 54 ** A0 + _BV( 1 ) , // PF 1 ** 55 ** A1 + _BV( 2 ) , // PF 2 ** 56 ** A2 + _BV( 3 ) , // PF 3 ** 57 ** A3 + _BV( 4 ) , // PF 4 ** 58 ** A4 + _BV( 5 ) , // PF 5 ** 59 ** A5 + _BV( 6 ) , // PF 6 ** 60 ** A6 + _BV( 7 ) , // PF 7 ** 61 ** A7 + _BV( 0 ) , // PK 0 ** 62 ** A8 + _BV( 1 ) , // PK 1 ** 63 ** A9 + _BV( 2 ) , // PK 2 ** 64 ** A10 + _BV( 3 ) , // PK 3 ** 65 ** A11 + _BV( 4 ) , // PK 4 ** 66 ** A12 + _BV( 5 ) , // PK 5 ** 67 ** A13 + _BV( 6 ) , // PK 6 ** 68 ** A14 + _BV( 7 ) , // PK 7 ** 69 ** A15 +}; + +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { + // TIMERS + // ------------------------------------------- + NOT_ON_TIMER , // PE 0 ** 0 ** USART0_RX + NOT_ON_TIMER , // PE 1 ** 1 ** USART0_TX + TIMER3B , // PE 4 ** 2 ** PWM2 + TIMER3C , // PE 5 ** 3 ** PWM3 + TIMER0B , // PG 5 ** 4 ** PWM4 + TIMER3A , // PE 3 ** 5 ** PWM5 + TIMER4A , // PH 3 ** 6 ** PWM6 + TIMER4B , // PH 4 ** 7 ** PWM7 + TIMER4C , // PH 5 ** 8 ** PWM8 + TIMER2B , // PH 6 ** 9 ** PWM9 + TIMER2A , // PB 4 ** 10 ** PWM10 + TIMER1A , // PB 5 ** 11 ** PWM11 + TIMER1B , // PB 6 ** 12 ** PWM12 + TIMER0A , // PB 7 ** 13 ** PWM13 + NOT_ON_TIMER , // PJ 1 ** 14 ** USART3_TX + NOT_ON_TIMER , // PJ 0 ** 15 ** USART3_RX + NOT_ON_TIMER , // PH 1 ** 16 ** USART2_TX + NOT_ON_TIMER , // PH 0 ** 17 ** USART2_RX + NOT_ON_TIMER , // PD 3 ** 18 ** USART1_TX + NOT_ON_TIMER , // PD 2 ** 19 ** USART1_RX + NOT_ON_TIMER , // PD 1 ** 20 ** I2C_SDA + NOT_ON_TIMER , // PD 0 ** 21 ** I2C_SCL + NOT_ON_TIMER , // PA 0 ** 22 ** D22 + NOT_ON_TIMER , // PA 1 ** 23 ** D23 + NOT_ON_TIMER , // PA 2 ** 24 ** D24 + NOT_ON_TIMER , // PA 3 ** 25 ** D25 + NOT_ON_TIMER , // PA 4 ** 26 ** D26 + NOT_ON_TIMER , // PA 5 ** 27 ** D27 + NOT_ON_TIMER , // PA 6 ** 28 ** D28 + NOT_ON_TIMER , // PA 7 ** 29 ** D29 + NOT_ON_TIMER , // PC 7 ** 30 ** D30 + NOT_ON_TIMER , // PC 6 ** 31 ** D31 + NOT_ON_TIMER , // PC 5 ** 32 ** D32 + NOT_ON_TIMER , // PC 4 ** 33 ** D33 + NOT_ON_TIMER , // PC 3 ** 34 ** D34 + NOT_ON_TIMER , // PC 2 ** 35 ** D35 + NOT_ON_TIMER , // PC 1 ** 36 ** D36 + NOT_ON_TIMER , // PC 0 ** 37 ** D37 + NOT_ON_TIMER , // PD 7 ** 38 ** D38 + NOT_ON_TIMER , // PG 2 ** 39 ** D39 + NOT_ON_TIMER , // PG 1 ** 40 ** D40 + NOT_ON_TIMER , // PG 0 ** 41 ** D41 + NOT_ON_TIMER , // PL 7 ** 42 ** D42 + NOT_ON_TIMER , // PL 6 ** 43 ** D43 + TIMER5C , // PL 5 ** 44 ** D44 + TIMER5B , // PL 4 ** 45 ** D45 + TIMER5A , // PL 3 ** 46 ** D46 + NOT_ON_TIMER , // PL 2 ** 47 ** D47 + NOT_ON_TIMER , // PL 1 ** 48 ** D48 + NOT_ON_TIMER , // PL 0 ** 49 ** D49 + NOT_ON_TIMER , // PB 3 ** 50 ** SPI_MISO + NOT_ON_TIMER , // PB 2 ** 51 ** SPI_MOSI + NOT_ON_TIMER , // PB 1 ** 52 ** SPI_SCK + NOT_ON_TIMER , // PB 0 ** 53 ** SPI_SS + NOT_ON_TIMER , // PF 0 ** 54 ** A0 + NOT_ON_TIMER , // PF 1 ** 55 ** A1 + NOT_ON_TIMER , // PF 2 ** 56 ** A2 + NOT_ON_TIMER , // PF 3 ** 57 ** A3 + NOT_ON_TIMER , // PF 4 ** 58 ** A4 + NOT_ON_TIMER , // PF 5 ** 59 ** A5 + NOT_ON_TIMER , // PF 6 ** 60 ** A6 + NOT_ON_TIMER , // PF 7 ** 61 ** A7 + NOT_ON_TIMER , // PK 0 ** 62 ** A8 + NOT_ON_TIMER , // PK 1 ** 63 ** A9 + NOT_ON_TIMER , // PK 2 ** 64 ** A10 + NOT_ON_TIMER , // PK 3 ** 65 ** A11 + NOT_ON_TIMER , // PK 4 ** 66 ** A12 + NOT_ON_TIMER , // PK 5 ** 67 ** A13 + NOT_ON_TIMER , // PK 6 ** 68 ** A14 + NOT_ON_TIMER , // PK 7 ** 69 ** A15 +}; +#else +// these arrays map port names (e.g. port B) to the +// appropriate addresses for various functions (e.g. reading +// and writing) +const uint16_t PROGMEM port_to_mode_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + &DDRB, + &DDRC, + &DDRD, +}; + +const uint16_t PROGMEM port_to_output_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + &PORTB, + &PORTC, + &PORTD, +}; + +const uint16_t PROGMEM port_to_input_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + &PINB, + &PINC, + &PIND, +}; + +const uint8_t PROGMEM digital_pin_to_port_PGM[] = { + PD, /* 0 */ + PD, + PD, + PD, + PD, + PD, + PD, + PD, + PB, /* 8 */ + PB, + PB, + PB, + PB, + PB, + PC, /* 14 */ + PC, + PC, + PC, + PC, + PC, +}; + +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { + _BV(0), /* 0, port D */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), + _BV(6), + _BV(7), + _BV(0), /* 8, port B */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), + _BV(0), /* 14, port C */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), +}; + +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { + NOT_ON_TIMER, /* 0 - port D */ + NOT_ON_TIMER, + NOT_ON_TIMER, + // on the ATmega168, digital pin 3 has hardware pwm +#if defined(__AVR_ATmega8__) + NOT_ON_TIMER, +#else + TIMER2B, +#endif + NOT_ON_TIMER, + // on the ATmega168, digital pins 5 and 6 have hardware pwm +#if defined(__AVR_ATmega8__) + NOT_ON_TIMER, + NOT_ON_TIMER, +#else + TIMER0B, + TIMER0A, +#endif + NOT_ON_TIMER, + NOT_ON_TIMER, /* 8 - port B */ + TIMER1A, + TIMER1B, +#if defined(__AVR_ATmega8__) + TIMER2, +#else + TIMER2A, +#endif + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, /* 14 - port C */ + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, +}; +#endif diff --git a/Libraries/arduino/pins_arduino.h b/Libraries/arduino/pins_arduino.h new file mode 100644 index 0000000..bc931c5 --- /dev/null +++ b/Libraries/arduino/pins_arduino.h @@ -0,0 +1,88 @@ +/* + pins_arduino.h - Pin definition functions for Arduino + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2007 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $ +*/ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define NOT_A_PIN 0 +#define NOT_A_PORT 0 + +#define NOT_ON_TIMER 0 +#define TIMER0A 1 +#define TIMER0B 2 +#define TIMER1A 3 +#define TIMER1B 4 +#define TIMER2 5 +#define TIMER2A 6 +#define TIMER2B 7 + +#define TIMER3A 8 +#define TIMER3B 9 +#define TIMER3C 10 +#define TIMER4A 11 +#define TIMER4B 12 +#define TIMER4C 13 +#define TIMER5A 14 +#define TIMER5B 15 +#define TIMER5C 16 + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +const static uint8_t SS = 53; +const static uint8_t MOSI = 51; +const static uint8_t MISO = 50; +const static uint8_t SCK = 52; +#else +const static uint8_t SS = 10; +const static uint8_t MOSI = 11; +const static uint8_t MISO = 12; +const static uint8_t SCK = 13; +#endif + +// On the ATmega1280, the addresses of some of the port registers are +// greater than 255, so we can't store them in uint8_t's. +extern const uint16_t PROGMEM port_to_mode_PGM[]; +extern const uint16_t PROGMEM port_to_input_PGM[]; +extern const uint16_t PROGMEM port_to_output_PGM[]; + +extern const uint8_t PROGMEM digital_pin_to_port_PGM[]; +// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[]; +extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[]; +extern const uint8_t PROGMEM digital_pin_to_timer_PGM[]; + +// Get the bit location within the hardware port of the given virtual pin. +// This comes from the pins_*.c file for the active board configuration. +// +// These perform slightly better as macros compared to inline functions +// +#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) ) +#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) ) +#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) ) +#define analogInPinToBit(P) (P) +#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) ) +#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) +#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) ) + +#endif diff --git a/Libraries/arduino/wiring.c b/Libraries/arduino/wiring.c new file mode 100644 index 0000000..479f947 --- /dev/null +++ b/Libraries/arduino/wiring.c @@ -0,0 +1,244 @@ +/* + wiring.c - Partial implementation of the Wiring API for the ATmega8. + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id$ +*/ + +#include "wiring_private.h" + +// the prescaler is set so that timer0 ticks every 64 clock cycles, and the +// the overflow handler is called every 256 ticks. +#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256)) + +// the whole number of milliseconds per timer0 overflow +#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000) + +// the fractional number of milliseconds per timer0 overflow. we shift right +// by three to fit these numbers into a byte. (for the clock speeds we care +// about - 8 and 16 MHz - this doesn't lose precision.) +#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3) +#define FRACT_MAX (1000 >> 3) + +volatile unsigned long timer0_overflow_count = 0; +volatile unsigned long timer0_millis = 0; +static unsigned char timer0_fract = 0; + +SIGNAL(TIMER0_OVF_vect) +{ + // copy these to local variables so they can be stored in registers + // (volatile variables must be read from memory on every access) + unsigned long m = timer0_millis; + unsigned char f = timer0_fract; + + m += MILLIS_INC; + f += FRACT_INC; + if (f >= FRACT_MAX) { + f -= FRACT_MAX; + m += 1; + } + + timer0_fract = f; + timer0_millis = m; + timer0_overflow_count++; +} + +unsigned long millis() +{ + unsigned long m; + uint8_t oldSREG = SREG; + + // disable interrupts while we read timer0_millis or we might get an + // inconsistent value (e.g. in the middle of a write to timer0_millis) + cli(); + m = timer0_millis; + SREG = oldSREG; + + return m; +} + +unsigned long micros() { + unsigned long m; + uint8_t oldSREG = SREG, t; + + cli(); + m = timer0_overflow_count; + t = TCNT0; + +#ifdef TIFR0 + if ((TIFR0 & _BV(TOV0)) && (t < 255)) + m++; +#else + if ((TIFR & _BV(TOV0)) && (t < 255)) + m++; +#endif + + SREG = oldSREG; + + return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); +} + +void delay(unsigned long ms) +{ + uint16_t start = (uint16_t)micros(); + + while (ms > 0) { + if (((uint16_t)micros() - start) >= 1000) { + ms--; + start += 1000; + } + } +} + +/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */ +void delayMicroseconds(unsigned int us) +{ + // calling avrlib's delay_us() function with low values (e.g. 1 or + // 2 microseconds) gives delays longer than desired. + //delay_us(us); + +#if F_CPU >= 16000000L + // for the 16 MHz clock on most Arduino boards + + // for a one-microsecond delay, simply return. the overhead + // of the function call yields a delay of approximately 1 1/8 us. + if (--us == 0) + return; + + // the following loop takes a quarter of a microsecond (4 cycles) + // per iteration, so execute it four times for each microsecond of + // delay requested. + us <<= 2; + + // account for the time taken in the preceeding commands. + us -= 2; +#else + // for the 8 MHz internal clock on the ATmega168 + + // for a one- or two-microsecond delay, simply return. the overhead of + // the function calls takes more than two microseconds. can't just + // subtract two, since us is unsigned; we'd overflow. + if (--us == 0) + return; + if (--us == 0) + return; + + // the following loop takes half of a microsecond (4 cycles) + // per iteration, so execute it twice for each microsecond of + // delay requested. + us <<= 1; + + // partially compensate for the time taken by the preceeding commands. + // we can't subtract any more than this or we'd overflow w/ small delays. + us--; +#endif + + // busy wait + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" // 2 cycles + "brne 1b" : "=w" (us) : "0" (us) // 2 cycles + ); +} + +void init() +{ + // this needs to be called before setup() or some functions won't + // work there + sei(); + + // on the ATmega168, timer 0 is also used for fast hardware pwm + // (using phase-correct PWM would mean that timer 0 overflowed half as often + // resulting in different millis() behavior on the ATmega8 and ATmega168) +#if !defined(__AVR_ATmega8__) + sbi(TCCR0A, WGM01); + sbi(TCCR0A, WGM00); +#endif + // set timer 0 prescale factor to 64 +#if defined(__AVR_ATmega8__) + sbi(TCCR0, CS01); + sbi(TCCR0, CS00); +#else + sbi(TCCR0B, CS01); + sbi(TCCR0B, CS00); +#endif + // enable timer 0 overflow interrupt +#if defined(__AVR_ATmega8__) + sbi(TIMSK, TOIE0); +#else + sbi(TIMSK0, TOIE0); +#endif + + // timers 1 and 2 are used for phase-correct hardware pwm + // this is better for motors as it ensures an even waveform + // note, however, that fast pwm mode can achieve a frequency of up + // 8 MHz (with a 16 MHz clock) at 50% duty cycle + + TCCR1B = 0; + + // set timer 1 prescale factor to 64 + sbi(TCCR1B, CS11); + sbi(TCCR1B, CS10); + // put timer 1 in 8-bit phase correct pwm mode + sbi(TCCR1A, WGM10); + + // set timer 2 prescale factor to 64 +#if defined(__AVR_ATmega8__) + sbi(TCCR2, CS22); +#else + sbi(TCCR2B, CS22); +#endif + // configure timer 2 for phase correct pwm (8-bit) +#if defined(__AVR_ATmega8__) + sbi(TCCR2, WGM20); +#else + sbi(TCCR2A, WGM20); +#endif + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + // set timer 3, 4, 5 prescale factor to 64 + sbi(TCCR3B, CS31); sbi(TCCR3B, CS30); + sbi(TCCR4B, CS41); sbi(TCCR4B, CS40); + sbi(TCCR5B, CS51); sbi(TCCR5B, CS50); + // put timer 3, 4, 5 in 8-bit phase correct pwm mode + sbi(TCCR3A, WGM30); + sbi(TCCR4A, WGM40); + sbi(TCCR5A, WGM50); +#endif + + // set a2d prescale factor to 128 + // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range. + // XXX: this will not work properly for other clock speeds, and + // this code should use F_CPU to determine the prescale factor. + sbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + + // enable a2d conversions + sbi(ADCSRA, ADEN); + + // the bootloader connects pins 0 and 1 to the USART; disconnect them + // here so they can be used as normal digital i/o; they will be + // reconnected in Serial.begin() +#if defined(__AVR_ATmega8__) + UCSRB = 0; +#else + UCSR0B = 0; +#endif +} diff --git a/Libraries/arduino/wiring.h b/Libraries/arduino/wiring.h new file mode 100644 index 0000000..7245797 --- /dev/null +++ b/Libraries/arduino/wiring.h @@ -0,0 +1,134 @@ +/* + wiring.h - Partial implementation of the Wiring API for the ATmega8. + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id$ +*/ + +#ifndef Wiring_h +#define Wiring_h + +#include +#include +#include "binary.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#define HIGH 0x1 +#define LOW 0x0 + +#define INPUT 0x0 +#define OUTPUT 0x1 + +#define true 0x1 +#define false 0x0 + +#define PI 3.1415926535897932384626433832795 +#define HALF_PI 1.5707963267948966192313216916398 +#define TWO_PI 6.283185307179586476925286766559 +#define DEG_TO_RAD 0.017453292519943295769236907684886 +#define RAD_TO_DEG 57.295779513082320876798154814105 + +#define SERIAL 0x0 +#define DISPLAY 0x1 + +#define LSBFIRST 0 +#define MSBFIRST 1 + +#define CHANGE 1 +#define FALLING 2 +#define RISING 3 + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#define INTERNAL1V1 2 +#define INTERNAL2V56 3 +#else +#define INTERNAL 3 +#endif +#define DEFAULT 1 +#define EXTERNAL 0 + +// undefine stdlib's abs if encountered +#ifdef abs +#undef abs +#endif + +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) +#define abs(x) ((x)>0?(x):-(x)) +#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) +#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) +#define radians(deg) ((deg)*DEG_TO_RAD) +#define degrees(rad) ((rad)*RAD_TO_DEG) +#define sq(x) ((x)*(x)) + +#define interrupts() sei() +#define noInterrupts() cli() + +#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L ) +#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() ) +#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() ) + +#define lowByte(w) ((uint8_t) ((w) & 0xff)) +#define highByte(w) ((uint8_t) ((w) >> 8)) + +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) + +typedef unsigned int word; + +#define bit(b) (1UL << (b)) + +typedef uint8_t boolean; +typedef uint8_t byte; + +void init(void); + +void pinMode(uint8_t, uint8_t); +void digitalWrite(uint8_t, uint8_t); +int digitalRead(uint8_t); +int analogRead(uint8_t); +void analogReference(uint8_t mode); +void analogWrite(uint8_t, int); + +unsigned long millis(void); +unsigned long micros(void); +void delay(unsigned long); +void delayMicroseconds(unsigned int us); +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); + +void attachInterrupt(uint8_t, void (*)(void), int mode); +void detachInterrupt(uint8_t); + +void setup(void); +void loop(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/Libraries/arduino/wiring_analog.c b/Libraries/arduino/wiring_analog.c new file mode 100644 index 0000000..da0cf07 --- /dev/null +++ b/Libraries/arduino/wiring_analog.c @@ -0,0 +1,183 @@ +/* + wiring_analog.c - analog input and output + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ +*/ + +#include "wiring_private.h" +#include "pins_arduino.h" + +uint8_t analog_reference = DEFAULT; + +void analogReference(uint8_t mode) +{ + // can't actually set the register here because the default setting + // will connect AVCC and the AREF pin, which would cause a short if + // there's something connected to AREF. + analog_reference = mode; +} + +int analogRead(uint8_t pin) +{ + uint8_t low, high; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + if (pin >= 54) pin -= 54; // allow for channel or pin numbers + + // the MUX5 bit of ADCSRB selects whether we're reading from channels + // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high). + ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); +#else + if (pin >= 14) pin -= 14; // allow for channel or pin numbers +#endif + + // set the analog reference (high two bits of ADMUX) and select the + // channel (low 4 bits). this also sets ADLAR (left-adjust result) + // to 0 (the default). + ADMUX = (analog_reference << 6) | (pin & 0x07); + + // without a delay, we seem to read from the wrong channel + //delay(1); + + // start the conversion + sbi(ADCSRA, ADSC); + + // ADSC is cleared when the conversion finishes + while (bit_is_set(ADCSRA, ADSC)); + + // we have to read ADCL first; doing so locks both ADCL + // and ADCH until ADCH is read. reading ADCL second would + // cause the results of each conversion to be discarded, + // as ADCL and ADCH would be locked when it completed. + low = ADCL; + high = ADCH; + + // combine the two bytes + return (high << 8) | low; +} + +// Right now, PWM output only works on the pins with +// hardware support. These are defined in the appropriate +// pins_*.c file. For the rest of the pins, we default +// to digital output. +void analogWrite(uint8_t pin, int val) +{ + // We need to make sure the PWM output is enabled for those pins + // that support it, as we turn it off when digitally reading or + // writing with them. Also, make sure the pin is in output mode + // for consistenty with Wiring, which doesn't require a pinMode + // call for the analog output pins. + pinMode(pin, OUTPUT); + + if (digitalPinToTimer(pin) == TIMER1A) { + // connect pwm to pin on timer 1, channel A + sbi(TCCR1A, COM1A1); + // set pwm duty + OCR1A = val; + } else if (digitalPinToTimer(pin) == TIMER1B) { + // connect pwm to pin on timer 1, channel B + sbi(TCCR1A, COM1B1); + // set pwm duty + OCR1B = val; +#if defined(__AVR_ATmega8__) + } else if (digitalPinToTimer(pin) == TIMER2) { + // connect pwm to pin on timer 2, channel B + sbi(TCCR2, COM21); + // set pwm duty + OCR2 = val; +#else + } else if (digitalPinToTimer(pin) == TIMER0A) { + if (val == 0) { + digitalWrite(pin, LOW); + } else { + // connect pwm to pin on timer 0, channel A + sbi(TCCR0A, COM0A1); + // set pwm duty + OCR0A = val; + } + } else if (digitalPinToTimer(pin) == TIMER0B) { + if (val == 0) { + digitalWrite(pin, LOW); + } else { + // connect pwm to pin on timer 0, channel B + sbi(TCCR0A, COM0B1); + // set pwm duty + OCR0B = val; + } + } else if (digitalPinToTimer(pin) == TIMER2A) { + // connect pwm to pin on timer 2, channel A + sbi(TCCR2A, COM2A1); + // set pwm duty + OCR2A = val; + } else if (digitalPinToTimer(pin) == TIMER2B) { + // connect pwm to pin on timer 2, channel B + sbi(TCCR2A, COM2B1); + // set pwm duty + OCR2B = val; +#endif +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + // XXX: need to handle other timers here + } else if (digitalPinToTimer(pin) == TIMER3A) { + // connect pwm to pin on timer 3, channel A + sbi(TCCR3A, COM3A1); + // set pwm duty + OCR3A = val; + } else if (digitalPinToTimer(pin) == TIMER3B) { + // connect pwm to pin on timer 3, channel B + sbi(TCCR3A, COM3B1); + // set pwm duty + OCR3B = val; + } else if (digitalPinToTimer(pin) == TIMER3C) { + // connect pwm to pin on timer 3, channel C + sbi(TCCR3A, COM3C1); + // set pwm duty + OCR3C = val; + } else if (digitalPinToTimer(pin) == TIMER4A) { + // connect pwm to pin on timer 4, channel A + sbi(TCCR4A, COM4A1); + // set pwm duty + OCR4A = val; + } else if (digitalPinToTimer(pin) == TIMER4B) { + // connect pwm to pin on timer 4, channel B + sbi(TCCR4A, COM4B1); + // set pwm duty + OCR4B = val; + } else if (digitalPinToTimer(pin) == TIMER4C) { + // connect pwm to pin on timer 4, channel C + sbi(TCCR4A, COM4C1); + // set pwm duty + OCR4C = val; + } else if (digitalPinToTimer(pin) == TIMER5A) { + // connect pwm to pin on timer 5, channel A + sbi(TCCR5A, COM5A1); + // set pwm duty + OCR5A = val; + } else if (digitalPinToTimer(pin) == TIMER5B) { + // connect pwm to pin on timer 5, channel B + sbi(TCCR5A, COM5B1); + // set pwm duty + OCR5B = val; +#endif + } else if (val < 128) + digitalWrite(pin, LOW); + else + digitalWrite(pin, HIGH); +} diff --git a/Libraries/arduino/wiring_digital.c b/Libraries/arduino/wiring_digital.c new file mode 100644 index 0000000..1475f0c --- /dev/null +++ b/Libraries/arduino/wiring_digital.c @@ -0,0 +1,129 @@ +/* + wiring_digital.c - digital input and output functions + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ +*/ + +#include "wiring_private.h" +#include "pins_arduino.h" + +void pinMode(uint8_t pin, uint8_t mode) +{ + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + volatile uint8_t *reg; + + if (port == NOT_A_PIN) return; + + // JWS: can I let the optimizer do this? + reg = portModeRegister(port); + + if (mode == INPUT) { + uint8_t oldSREG = SREG; + cli(); + *reg &= ~bit; + SREG = oldSREG; + } else { + uint8_t oldSREG = SREG; + cli(); + *reg |= bit; + SREG = oldSREG; + } +} + +// Forcing this inline keeps the callers from having to push their own stuff +// on the stack. It is a good performance win and only takes 1 more byte per +// user than calling. (It will take more bytes on the 168.) +// +// But shouldn't this be moved into pinMode? Seems silly to check and do on +// each digitalread or write. +// +static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline)); +static inline void turnOffPWM(uint8_t timer) +{ + if (timer == TIMER1A) cbi(TCCR1A, COM1A1); + if (timer == TIMER1B) cbi(TCCR1A, COM1B1); + +#if defined(__AVR_ATmega8__) + if (timer == TIMER2) cbi(TCCR2, COM21); +#else + if (timer == TIMER0A) cbi(TCCR0A, COM0A1); + if (timer == TIMER0B) cbi(TCCR0A, COM0B1); + if (timer == TIMER2A) cbi(TCCR2A, COM2A1); + if (timer == TIMER2B) cbi(TCCR2A, COM2B1); +#endif + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + if (timer == TIMER3A) cbi(TCCR3A, COM3A1); + if (timer == TIMER3B) cbi(TCCR3A, COM3B1); + if (timer == TIMER3C) cbi(TCCR3A, COM3C1); + if (timer == TIMER4A) cbi(TCCR4A, COM4A1); + if (timer == TIMER4B) cbi(TCCR4A, COM4B1); + if (timer == TIMER4C) cbi(TCCR4A, COM4C1); + if (timer == TIMER5A) cbi(TCCR5A, COM5A1); + if (timer == TIMER5B) cbi(TCCR5A, COM5B1); + if (timer == TIMER5C) cbi(TCCR5A, COM5C1); +#endif +} + +void digitalWrite(uint8_t pin, uint8_t val) +{ + uint8_t timer = digitalPinToTimer(pin); + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + volatile uint8_t *out; + + if (port == NOT_A_PIN) return; + + // If the pin that support PWM output, we need to turn it off + // before doing a digital write. + if (timer != NOT_ON_TIMER) turnOffPWM(timer); + + out = portOutputRegister(port); + + if (val == LOW) { + uint8_t oldSREG = SREG; + cli(); + *out &= ~bit; + SREG = oldSREG; + } else { + uint8_t oldSREG = SREG; + cli(); + *out |= bit; + SREG = oldSREG; + } +} + +int digitalRead(uint8_t pin) +{ + uint8_t timer = digitalPinToTimer(pin); + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + + if (port == NOT_A_PIN) return LOW; + + // If the pin that support PWM output, we need to turn it off + // before getting a digital reading. + if (timer != NOT_ON_TIMER) turnOffPWM(timer); + + if (*portInputRegister(port) & bit) return HIGH; + return LOW; +} diff --git a/Libraries/arduino/wiring_private.h b/Libraries/arduino/wiring_private.h new file mode 100644 index 0000000..11f6f00 --- /dev/null +++ b/Libraries/arduino/wiring_private.h @@ -0,0 +1,68 @@ +/* + wiring_private.h - Internal header file. + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.h 239 2007-01-12 17:58:39Z mellis $ +*/ + +#ifndef WiringPrivate_h +#define WiringPrivate_h + +#include +#include +#include +#include +#include + +#include "wiring.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + +#define EXTERNAL_INT_0 0 +#define EXTERNAL_INT_1 1 +#define EXTERNAL_INT_2 2 +#define EXTERNAL_INT_3 3 +#define EXTERNAL_INT_4 4 +#define EXTERNAL_INT_5 5 +#define EXTERNAL_INT_6 6 +#define EXTERNAL_INT_7 7 + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#define EXTERNAL_NUM_INTERRUPTS 8 +#else +#define EXTERNAL_NUM_INTERRUPTS 2 +#endif + +typedef void (*voidFuncPtr)(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/Libraries/arduino/wiring_pulse.c b/Libraries/arduino/wiring_pulse.c new file mode 100644 index 0000000..8f232f1 --- /dev/null +++ b/Libraries/arduino/wiring_pulse.c @@ -0,0 +1,66 @@ +/* + wiring_pulse.c - pulseIn() function + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ +*/ + +#include "wiring_private.h" +#include "pins_arduino.h" + +/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH + * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds + * to 3 minutes in length, but must be called at least a few dozen microseconds + * before the start of the pulse. */ +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) +{ + // cache the port and bit of the pin in order to speed up the + // pulse width measuring loop and achieve finer resolution. calling + // digitalRead() instead yields much coarser resolution. + uint8_t bit = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + uint8_t stateMask = (state ? bit : 0); + unsigned long width = 0; // keep initialization out of time critical area + + // convert the timeout from microseconds to a number of times through + // the initial loop; it takes 16 clock cycles per iteration. + unsigned long numloops = 0; + unsigned long maxloops = microsecondsToClockCycles(timeout) / 16; + + // wait for any previous pulse to end + while ((*portInputRegister(port) & bit) == stateMask) + if (numloops++ == maxloops) + return 0; + + // wait for the pulse to start + while ((*portInputRegister(port) & bit) != stateMask) + if (numloops++ == maxloops) + return 0; + + // wait for the pulse to stop + while ((*portInputRegister(port) & bit) == stateMask) + width++; + + // convert the reading to microseconds. The loop has been determined + // to be 10 clock cycles long and have about 16 clocks between the edge + // and the start of the loop. There will be some error introduced by + // the interrupt handlers. + return clockCyclesToMicroseconds(width * 10 + 16); +} diff --git a/Libraries/arduino/wiring_shift.c b/Libraries/arduino/wiring_shift.c new file mode 100644 index 0000000..cfe7867 --- /dev/null +++ b/Libraries/arduino/wiring_shift.c @@ -0,0 +1,55 @@ +/* + wiring_shift.c - shiftOut() function + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ +*/ + +#include "wiring_private.h" + +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) { + uint8_t value = 0; + uint8_t i; + + for (i = 0; i < 8; ++i) { + digitalWrite(clockPin, HIGH); + if (bitOrder == LSBFIRST) + value |= digitalRead(dataPin) << i; + else + value |= digitalRead(dataPin) << (7 - i); + digitalWrite(clockPin, LOW); + } + return value; +} + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) +{ + uint8_t i; + + for (i = 0; i < 8; i++) { + if (bitOrder == LSBFIRST) + digitalWrite(dataPin, !!(val & (1 << i))); + else + digitalWrite(dataPin, !!(val & (1 << (7 - i)))); + + digitalWrite(clockPin, HIGH); + digitalWrite(clockPin, LOW); + } +} diff --git a/Libraries/avrmidi/.gitignore b/Libraries/avrmidi/.gitignore new file mode 100644 index 0000000..e53a2a5 --- /dev/null +++ b/Libraries/avrmidi/.gitignore @@ -0,0 +1,6 @@ +*.o +*.hex +*.out +*.map +*.swp +*.gz diff --git a/Libraries/avrmidi/COPYING b/Libraries/avrmidi/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/Libraries/avrmidi/COPYING @@ -0,0 +1,674 @@ + 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 +. diff --git a/Libraries/avrmidi/Makefile b/Libraries/avrmidi/Makefile new file mode 100644 index 0000000..e292826 --- /dev/null +++ b/Libraries/avrmidi/Makefile @@ -0,0 +1,41 @@ +MCU=atmega8 +CC=avr-gcc +OBJCOPY=avr-objcopy +# optimize for size: +CFLAGS=-g -mmcu=$(MCU) -Wall -Wstrict-prototypes -Os -mcall-prologues +PORT=/dev/ttyUSB0 +PART=ATmega8 +UISP = uisp -dprog=stk500 -dserial=/dev/ttyUSB0 -dpart=$(PART) + +VERSION = 0.2.develop +DISTDIR = avr-midi.${VERSION} + +#------------------- +current: examples +#------------------- + +examples: + cd examples && make + +.c.o: + @echo CC $< + @$(CC) -c $(CFLAGS) -Os -o $*.o $< + +dist: clean + mkdir -p ${DISTDIR} + cp -R COPYING Makefile *.c *.h README examples/ test/ bytequeue/ ${DISTDIR} + tar -czf ${DISTDIR}.tar.gz ${DISTDIR} + rm -rf ${DISTDIR} + +post: dist + scp ${DISTDIR}.tar.gz x37v.info:x37v.info/projects/microcontroller/avr-midi/files/ + scp basic.c x37v.info:x37v.info/projects/microcontroller/avr-midi/ + +clean: + rm -f *.o *.map *.out *.hex *.tar.gz */*.o + cd examples/ && make clean + cd test/ && make clean + +.PHONY: examples + +all: examples diff --git a/Libraries/avrmidi/README b/Libraries/avrmidi/README new file mode 100644 index 0000000..d253a94 --- /dev/null +++ b/Libraries/avrmidi/README @@ -0,0 +1,15 @@ +embedded midi is a library written by Alex Norman. + +This project used to be called avr-midi but it should be useful for other C +projects, thought it is intended for embedded work, so that is why it has been +renamed. + +It is licenced with the GPL v3 licence, see the file "COPYING" for more info. + +Please send me bug info, bug fixes, general improvements, etc. alex@x37v.info + +This is the development version which has only been tested on a atmega32u2. + +my website is here: +http://www.x37v.info + diff --git a/Libraries/avrmidi/bytequeue.c b/Libraries/avrmidi/bytequeue.c new file mode 100644 index 0000000..e434956 --- /dev/null +++ b/Libraries/avrmidi/bytequeue.c @@ -0,0 +1,65 @@ +//this is a single reader [maybe multiple writer?] byte queue +//Copyright 2008 Alex Norman +//writen by Alex Norman +// +//This file is part of avr-bytequeue. +// +//avr-bytequeue 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. +// +//avr-bytequeue 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 avr-bytequeue. If not, see . + +#include "bytequeue.h" +#include "interrupt_setting.h" + +void bytequeue_init(byteQueue_t * queue, uint8_t * dataArray, byteQueueIndex_t arrayLen){ + queue->length = arrayLen; + queue->data = dataArray; + queue->start = queue->end = 0; +} + +bool bytequeue_enqueue(byteQueue_t * queue, uint8_t item){ + interrupt_setting_t setting = store_and_clear_interrupt(); + //full + if(((queue->end + 1) % queue->length) == queue->start){ + restore_interrupt_setting(setting); + return false; + } else { + queue->data[queue->end] = item; + queue->end = (queue->end + 1) % queue->length; + restore_interrupt_setting(setting); + return true; + } +} + +byteQueueIndex_t bytequeue_length(byteQueue_t * queue){ + byteQueueIndex_t len; + interrupt_setting_t setting = store_and_clear_interrupt(); + if(queue->end >= queue->start) + len = queue->end - queue->start; + else + len = (queue->length - queue->start) + queue->end; + restore_interrupt_setting(setting); + return len; +} + +//we don't need to avoid interrupts if there is only one reader +uint8_t bytequeue_get(byteQueue_t * queue, byteQueueIndex_t index){ + return queue->data[(queue->start + index) % queue->length]; +} + +//we just update the start index to remove elements +void bytequeue_remove(byteQueue_t * queue, byteQueueIndex_t numToRemove){ + interrupt_setting_t setting = store_and_clear_interrupt(); + queue->start = (queue->start + numToRemove) % queue->length; + restore_interrupt_setting(setting); +} + diff --git a/Libraries/avrmidi/bytequeue.h b/Libraries/avrmidi/bytequeue.h new file mode 100644 index 0000000..d12df50 --- /dev/null +++ b/Libraries/avrmidi/bytequeue.h @@ -0,0 +1,49 @@ +//this is a single reader [maybe multiple writer?] byte queue +//Copyright 2008 Alex Norman +//writen by Alex Norman +// +//This file is part of avr-bytequeue. +// +//avr-bytequeue 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. +// +//avr-bytequeue 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 avr-bytequeue. If not, see . +#ifndef BYTEQUEUE_H +#define BYTEQUEUE_H +#include +#include + +typedef uint8_t byteQueueIndex_t; + +typedef struct { + byteQueueIndex_t start; + byteQueueIndex_t end; + byteQueueIndex_t length; + uint8_t * data; +} byteQueue_t; + +//you must have a queue, an array of data which the queue will use, and the length of that array +void bytequeue_init(byteQueue_t * queue, uint8_t * dataArray, byteQueueIndex_t arrayLen); + +//add an item to the queue, returns false if the queue is full +bool bytequeue_enqueue(byteQueue_t * queue, uint8_t item); + +//get the length of the queue +byteQueueIndex_t bytequeue_length(byteQueue_t * queue); + +//this grabs data at the index given [starting at queue->start] +uint8_t bytequeue_get(byteQueue_t * queue, byteQueueIndex_t index); + +//update the index in the queue to reflect data that has been dealt with +void bytequeue_remove(byteQueue_t * queue, byteQueueIndex_t numToRemove); + +#endif + diff --git a/Libraries/avrmidi/examples/Makefile b/Libraries/avrmidi/examples/Makefile new file mode 100644 index 0000000..00470da --- /dev/null +++ b/Libraries/avrmidi/examples/Makefile @@ -0,0 +1,68 @@ +MCU=atmega8 +CC=avr-gcc +OBJCOPY=avr-objcopy +# optimize for size: +CFLAGS=-g -mmcu=$(MCU) -Wall -Wstrict-prototypes -Os -mcall-prologues -I../ +PORT=/dev/ttyUSB0 +PART=ATmega8 +UISP = uisp -dprog=stk500 -dserial=/dev/ttyUSB0 -dpart=$(PART) + +#------------------- +current: basic.hex +#------------------- + +BASICSRC = basic.c ../midi.c ../midi_device.c ../bytequeue.c ../interrupt_setting.c serial_midi.c +SPITSRC = spit.c ../midi.c serial_midi.c + +BASICOBJ = ${BASICSRC:.c=.o} +SPITOBJ = ${SPITSRC:.c=.o} + +.c.o: + @echo CC $< + @$(CC) -c $(CFLAGS) -Os -o $*.o $< + + +basic.bin : basic.out + $(OBJCOPY) -R .eeprom -O binary basic.out basic.bin + +basic.hex : basic.out + $(OBJCOPY) -R .eeprom -O ihex basic.out basic.hex + +basic.out : $(BASICOBJ) + $(CC) $(CFLAGS) -o basic.out -Wl,-Map,basic.map $(BASICOBJ) + +# load (program) the software +load_basic: basic.hex + $(UISP) --erase + $(UISP) --upload --verify if=basic.hex -v=3 --hash=32 + + +spit.bin : spit.out + $(OBJCOPY) -R .eeprom -O binary spit.out spit.bin + +spit.hex : spit.out + $(OBJCOPY) -R .eeprom -O ihex spit.out spit.hex + +spit.out : $(SPITOBJ) + $(CC) $(CFLAGS) -o spit.out -Wl,-Map,spit.map $(SPITOBJ) + +load_spit: spit.hex + $(UISP) --erase + $(UISP) --upload --verify if=spit.hex -v=3 --hash=32 + + +fuse_mega16: + $(UISP) --wr_fuse_l=0x9f --wr_fuse_h=0xd0 + +fuse_mega8: + $(UISP) --wr_fuse_l=0xef --wr_fuse_h=0xc9 + +check_fuse: + $(UISP) --rd_fuses + +#------------------- +clean: + rm -f *.o *.map *.out *.hex *.tar.gz +#------------------- + +all: spit.hex basic.hex diff --git a/Libraries/avrmidi/examples/basic.c b/Libraries/avrmidi/examples/basic.c new file mode 100644 index 0000000..a4a844c --- /dev/null +++ b/Libraries/avrmidi/examples/basic.c @@ -0,0 +1,127 @@ +/* + + Here is an example of how to use avr-midi + this was written for an atmega16 using a 12Mhz clock in an stk500 + the switch inputs of the STK500 are connected to PORTC + + switch 0 and 1 increment and decrement [respectively] a midi program and + send the appropriate midi program change + + switch 2 sends a note on message when the button is pushed and a note off + when the button is released + + the rest of the switches send CC messages, a 1 when the button is down and a + 0 when the button is released + +*/ + +#include +#include +#include +#include "serial_midi.h" + +#define MIDI_CLOCK_12MHZ_OSC 23 +#define MIDI_CLOCK_RATE MIDI_CLOCK_12MHZ_OSC + +//how many times to we read the buttons before we say they're valid +#define INPUT_HISTORY 4 + +//this is the midi channel we'll be sending on.. 0 is midi channel 1 +#define MIDI_CHAN 0 + +int main(void) { + //index for looping + uint8_t i, j; + bool consistent; + //is the button up + bool up; + //midi program + uint8_t program = 0; + //button inputs, for debouncing + uint8_t inputs[INPUT_HISTORY]; + uint8_t curInput = 0; + uint8_t lastInput = 0; + uint8_t historyIndex = 0; + + //PORTC is in input with internal pullups + DDRC = 0x00; + PORTC = 0xFF; + + //init the button history + for(i = 0; i < INPUT_HISTORY; i++) + inputs[i] = 0; + + //init midi, give the clock rate setting, indicate that we want only output + MidiDevice * midi_device = serial_midi_init(MIDI_CLOCK_RATE, true, false); + + while(1){ + + //grab the inputs + inputs[historyIndex] = PINC; + curInput = lastInput; + + //debounce inputs + //for each input + for(i = 0; i < 8; i++){ + consistent = true; + //the STK500 has 1 for up and 0 for down if you're using the on board buttons + up = (bool)(0x1 & (inputs[0] >> i)); + //check the history to make sure we have the same value for this input + //for the whole history + for(j = 1; j < INPUT_HISTORY; j++){ + if(up != (bool)(0x1 & (inputs[j] >> i))){ + consistent = false; + break; + } + } + //if we have the same value for the whole history then store it in + //curInput + if(consistent){ + if(up) { + //store the current input state + curInput |= (1 << i); + //if the last input was a 0 and the current is a 1 + if(((lastInput >> i) & 0x1) == 0){ + //we don't do anything on up for the first two buttons + //send the appropriate midi data + if(i == 2){ + midi_send_noteoff(midi_device, MIDI_CHAN, 64, 30); + } else if(i > 1) + midi_send_cc(midi_device, MIDI_CHAN, i - 3, 0); + } + } else { + //store the current input state + curInput &= ~(1 << i); + //if the last input was a 1 and the current is a 0 + if(((lastInput >> i) & 0x1) == 1){ + //send the appropriate midi data + switch(i){ + case 0: + program = (program + 1) % 128; + midi_send_programchange(midi_device, MIDI_CHAN, program); + break; + case 1: + program = (program - 1) % 128; + midi_send_programchange(midi_device, MIDI_CHAN, program); + break; + case 2: + midi_send_noteon(midi_device, MIDI_CHAN, 64, 127); + break; + default: + midi_send_cc(midi_device, MIDI_CHAN, i - 3, 1); + break; + } + } + } + } + } + + //update the history index + historyIndex = (historyIndex + 1) % INPUT_HISTORY; + //store the curInput as lastInput for the next loop + lastInput = curInput; + } + + return 0; +} + diff --git a/Libraries/avrmidi/examples/lufa_midi/Descriptors.c b/Libraries/avrmidi/examples/lufa_midi/Descriptors.c new file mode 100644 index 0000000..8405b55 --- /dev/null +++ b/Libraries/avrmidi/examples/lufa_midi/Descriptors.c @@ -0,0 +1,329 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * USB Device Descriptors, for library use when in USB device mode. Descriptors are special + * computer-readable structures which the host requests upon device enumeration, to determine + * the device's capabilities and functions. + */ + +#include "Descriptors.h" + +/** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall + * device characteristics, including the supported USB version, control endpoint size and the + * number of device configurations. The descriptor is read out by the USB host when the enumeration + * process begins. + */ +USB_Descriptor_Device_t PROGMEM DeviceDescriptor = +{ + .Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device}, + + .USBSpecification = VERSION_BCD(01.10), + .Class = USB_CSCP_NoDeviceClass, + .SubClass = USB_CSCP_NoDeviceSubclass, + .Protocol = USB_CSCP_NoDeviceProtocol, + + .Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE, + + .VendorID = 0x03EB, + .ProductID = 0x2048, + .ReleaseNumber = VERSION_BCD(00.01), + + .ManufacturerStrIndex = 0x01, + .ProductStrIndex = 0x02, + .SerialNumStrIndex = NO_DESCRIPTOR, + + .NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS +}; + +/** Configuration descriptor structure. This descriptor, located in FLASH memory, describes the usage + * of the device in one of its supported configurations, including information about any device interfaces + * and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting + * a configuration so that the host may correctly communicate with the USB device. + */ +USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = +{ + .Config = + { + .Header = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration}, + + .TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t), + .TotalInterfaces = 2, + + .ConfigurationNumber = 1, + .ConfigurationStrIndex = NO_DESCRIPTOR, + + .ConfigAttributes = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELFPOWERED), + + .MaxPowerConsumption = USB_CONFIG_POWER_MA(100) + }, + + .Audio_ControlInterface = + { + .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, + + .InterfaceNumber = 0, + .AlternateSetting = 0, + + .TotalEndpoints = 0, + + .Class = AUDIO_CSCP_AudioClass, + .SubClass = AUDIO_CSCP_ControlSubclass, + .Protocol = AUDIO_CSCP_ControlProtocol, + + .InterfaceStrIndex = NO_DESCRIPTOR + }, + + .Audio_ControlInterface_SPC = + { + .Header = {.Size = sizeof(USB_Audio_Descriptor_Interface_AC_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_Header, + + .ACSpecification = VERSION_BCD(01.00), + .TotalLength = sizeof(USB_Audio_Descriptor_Interface_AC_t), + + .InCollection = 1, + .InterfaceNumber = 1, + }, + + .Audio_StreamInterface = + { + .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, + + .InterfaceNumber = 1, + .AlternateSetting = 0, + + .TotalEndpoints = 2, + + .Class = AUDIO_CSCP_AudioClass, + .SubClass = AUDIO_CSCP_MIDIStreamingSubclass, + .Protocol = AUDIO_CSCP_StreamingProtocol, + + .InterfaceStrIndex = NO_DESCRIPTOR + }, + + .Audio_StreamInterface_SPC = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_AudioInterface_AS_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_General, + + .AudioSpecification = VERSION_BCD(01.00), + + .TotalLength = (sizeof(USB_Descriptor_Configuration_t) - + offsetof(USB_Descriptor_Configuration_t, Audio_StreamInterface_SPC)) + }, + + .MIDI_In_Jack_Emb = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_InputJack_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_InputTerminal, + + .JackType = MIDI_JACKTYPE_Embedded, + .JackID = 0x01, + + .JackStrIndex = NO_DESCRIPTOR + }, + + .MIDI_In_Jack_Ext = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_InputJack_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_InputTerminal, + + .JackType = MIDI_JACKTYPE_External, + .JackID = 0x02, + + .JackStrIndex = NO_DESCRIPTOR + }, + + .MIDI_Out_Jack_Emb = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_OutputJack_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_OutputTerminal, + + .JackType = MIDI_JACKTYPE_Embedded, + .JackID = 0x03, + + .NumberOfPins = 1, + .SourceJackID = {0x02}, + .SourcePinID = {0x01}, + + .JackStrIndex = NO_DESCRIPTOR + }, + + .MIDI_Out_Jack_Ext = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_OutputJack_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_OutputTerminal, + + .JackType = MIDI_JACKTYPE_External, + .JackID = 0x04, + + .NumberOfPins = 1, + .SourceJackID = {0x01}, + .SourcePinID = {0x01}, + + .JackStrIndex = NO_DESCRIPTOR + }, + + .MIDI_In_Jack_Endpoint = + { + .Endpoint = + { + .Header = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_OUT | MIDI_STREAM_OUT_EPNUM), + .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = MIDI_STREAM_EPSIZE, + .PollingIntervalMS = 0 + }, + + .Refresh = 0, + .SyncEndpointNumber = 0 + }, + + .MIDI_In_Jack_Endpoint_SPC = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t), .Type = DTYPE_CSEndpoint}, + .Subtype = AUDIO_DSUBTYPE_CSEndpoint_General, + + .TotalEmbeddedJacks = 0x01, + .AssociatedJackID = {0x01} + }, + + .MIDI_Out_Jack_Endpoint = + { + .Endpoint = + { + .Header = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_IN | MIDI_STREAM_IN_EPNUM), + .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = MIDI_STREAM_EPSIZE, + .PollingIntervalMS = 0 + }, + + .Refresh = 0, + .SyncEndpointNumber = 0 + }, + + .MIDI_Out_Jack_Endpoint_SPC = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t), .Type = DTYPE_CSEndpoint}, + .Subtype = AUDIO_DSUBTYPE_CSEndpoint_General, + + .TotalEmbeddedJacks = 0x01, + .AssociatedJackID = {0x03} + } +}; + +/** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests + * the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate + * via the language ID table available at USB.org what languages the device supports for its string descriptors. + */ +USB_Descriptor_String_t PROGMEM LanguageString = +{ + .Header = {.Size = USB_STRING_LEN(1), .Type = DTYPE_String}, + + .UnicodeString = {LANGUAGE_ID_ENG} +}; + +/** Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable + * form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device + * Descriptor. + */ +USB_Descriptor_String_t PROGMEM ManufacturerString = +{ + .Header = {.Size = USB_STRING_LEN(11), .Type = DTYPE_String}, + + .UnicodeString = L"Dean Camera" +}; + +/** Product descriptor string. This is a Unicode string containing the product's details in human readable form, + * and is read out upon request by the host when the appropriate string ID is requested, listed in the Device + * Descriptor. + */ +USB_Descriptor_String_t PROGMEM ProductString = +{ + .Header = {.Size = USB_STRING_LEN(17), .Type = DTYPE_String}, + + .UnicodeString = L"embedded usb midi" +}; + +/** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" + * documentation) by the application code so that the address and size of a requested descriptor can be given + * to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function + * is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the + * USB host. + */ +uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, + const uint8_t wIndex, + const void** const DescriptorAddress) +{ + const uint8_t DescriptorType = (wValue >> 8); + const uint8_t DescriptorNumber = (wValue & 0xFF); + + const void* Address = NULL; + uint16_t Size = NO_DESCRIPTOR; + + switch (DescriptorType) + { + case DTYPE_Device: + Address = &DeviceDescriptor; + Size = sizeof(USB_Descriptor_Device_t); + break; + case DTYPE_Configuration: + Address = &ConfigurationDescriptor; + Size = sizeof(USB_Descriptor_Configuration_t); + break; + case DTYPE_String: + switch (DescriptorNumber) + { + case 0x00: + Address = &LanguageString; + Size = pgm_read_byte(&LanguageString.Header.Size); + break; + case 0x01: + Address = &ManufacturerString; + Size = pgm_read_byte(&ManufacturerString.Header.Size); + break; + case 0x02: + Address = &ProductString; + Size = pgm_read_byte(&ProductString.Header.Size); + break; + } + + break; + } + + *DescriptorAddress = Address; + return Size; +} + diff --git a/Libraries/avrmidi/examples/lufa_midi/Descriptors.h b/Libraries/avrmidi/examples/lufa_midi/Descriptors.h new file mode 100644 index 0000000..b56fb6f --- /dev/null +++ b/Libraries/avrmidi/examples/lufa_midi/Descriptors.h @@ -0,0 +1,83 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for Descriptors.c. + */ + +#ifndef _DESCRIPTORS_H_ +#define _DESCRIPTORS_H_ + + /* Includes: */ + #include + + #include + + /* Macros: */ + /** Endpoint number of the MIDI streaming data IN endpoint, for device-to-host data transfers. */ + #define MIDI_STREAM_IN_EPNUM 2 + + /** Endpoint number of the MIDI streaming data OUT endpoint, for host-to-device data transfers. */ + #define MIDI_STREAM_OUT_EPNUM 1 + + /** Endpoint size in bytes of the Audio isochronous streaming data IN and OUT endpoints. */ + #define MIDI_STREAM_EPSIZE 64 + + /* Type Defines: */ + /** Type define for the device configuration descriptor structure. This must be defined in the + * application code, as the configuration descriptor contains several sub-descriptors which + * vary between devices, and which describe the device's usage to the host. + */ + typedef struct + { + USB_Descriptor_Configuration_Header_t Config; + USB_Descriptor_Interface_t Audio_ControlInterface; + USB_Audio_Descriptor_Interface_AC_t Audio_ControlInterface_SPC; + USB_Descriptor_Interface_t Audio_StreamInterface; + USB_MIDI_Descriptor_AudioInterface_AS_t Audio_StreamInterface_SPC; + USB_MIDI_Descriptor_InputJack_t MIDI_In_Jack_Emb; + USB_MIDI_Descriptor_InputJack_t MIDI_In_Jack_Ext; + USB_MIDI_Descriptor_OutputJack_t MIDI_Out_Jack_Emb; + USB_MIDI_Descriptor_OutputJack_t MIDI_Out_Jack_Ext; + USB_Audio_Descriptor_StreamEndpoint_Std_t MIDI_In_Jack_Endpoint; + USB_MIDI_Descriptor_Jack_Endpoint_t MIDI_In_Jack_Endpoint_SPC; + USB_Audio_Descriptor_StreamEndpoint_Std_t MIDI_Out_Jack_Endpoint; + USB_MIDI_Descriptor_Jack_Endpoint_t MIDI_Out_Jack_Endpoint_SPC; + } USB_Descriptor_Configuration_t; + + /* Function Prototypes: */ + uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, + const uint8_t wIndex, + const void** const DescriptorAddress) + ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); + +#endif + diff --git a/Libraries/avrmidi/examples/lufa_midi/main.c b/Libraries/avrmidi/examples/lufa_midi/main.c new file mode 100644 index 0000000..09732e6 --- /dev/null +++ b/Libraries/avrmidi/examples/lufa_midi/main.c @@ -0,0 +1,20 @@ +#include "midi_usb.h" + +//this example simply echos midi back, for now + +void fallthrough_callback(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + midi_send_data(device, cnt, byte0, byte1, byte2); +} + +int main(void) { + MidiDevice usb_midi; + + midi_usb_init(&usb_midi); + midi_register_fallthrough_callback(&usb_midi, fallthrough_callback); + + while(1){ + midi_device_process(&usb_midi); + } + + return 0; +} diff --git a/Libraries/avrmidi/examples/lufa_midi/makefile b/Libraries/avrmidi/examples/lufa_midi/makefile new file mode 100644 index 0000000..954c8fd --- /dev/null +++ b/Libraries/avrmidi/examples/lufa_midi/makefile @@ -0,0 +1,719 @@ +# Hey Emacs, this is a -*- makefile -*- +#---------------------------------------------------------------------------- +# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al. +# >> Modified for use with the LUFA project. << +# +# Released to the Public Domain +# +# Additional material for this makefile was written by: +# Peter Fleury +# Tim Henigan +# Colin O'Flynn +# Reiner Patommel +# Markus Pfaff +# Sander Pool +# Frederik Rouleau +# Carlos Lamas +# Dean Camera +# Opendous Inc. +# Denver Gingerich +# +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device, using avrdude. +# Please customize the avrdude settings below first! +# +# make dfu = Download the hex file to the device, using dfu-programmer (must +# have dfu-programmer installed). +# +# make flip = Download the hex file to the device, using Atmel FLIP (must +# have Atmel FLIP installed). +# +# make dfu-ee = Download the eeprom file to the device, using dfu-programmer +# (must have dfu-programmer installed). +# +# make flip-ee = Download the eeprom file to the device, using Atmel FLIP +# (must have Atmel FLIP installed). +# +# make doxygen = Generate DoxyGen documentation for the project (must have +# DoxyGen installed) +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + + +# MCU name +MCU = atmega32u2 + + +# Target board (see library "Board Types" documentation, NONE for projects not requiring +# LUFA board drivers). If USER is selected, put custom board drivers in a directory called +# "Board" inside the application directory. +BOARD = NONE + + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_CLOCK below, as it is sourced by +# F_CLOCK after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + + +# Input clock frequency. +# This will define a symbol, F_CLOCK, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_CLOCK = $(F_CPU) + + +# Output format. (can be srec, ihex, binary) +FORMAT = ihex + + +# Target file name (without extension). +TARGET = MIDI + + +# Object files directory +# To put object files in current directory, use a dot (.), do NOT make +# this an empty or blank macro! +OBJDIR = . + + +# Path to the LUFA library +LUFA_PATH = ../../../lufa_101122_beta3/ + + +# LUFA library compile-time options and predefined tokens +LUFA_OPTS = -D USB_DEVICE_ONLY +LUFA_OPTS += -D FIXED_CONTROL_ENDPOINT_SIZE=8 +LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1 +LUFA_OPTS += -D USE_FLASH_DESCRIPTORS +LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" + + +# Create the LUFA source path variables by including the LUFA root makefile +include $(LUFA_PATH)/LUFA/makefile + + +# List C source files here. (C dependencies are automatically generated.) +SRC = midi_usb.c \ + Descriptors.c \ + main.c \ + ../../midi.c \ + ../../midi_device.c \ + ../../bytequeue/bytequeue.c \ + ../../bytequeue/interrupt_setting.c \ + $(LUFA_SRC_USB) \ + $(LUFA_SRC_USBCLASS) + + +# List C++ source files here. (C dependencies are automatically generated.) +CPPSRC = + + +# List Assembler source files here. +# Make them always end in a capital .S. Files ending in a lowercase .s +# will not be considered source files but generated files (assembler +# output from the compiler), and will be deleted upon "make clean"! +# Even though the DOS/Win* filesystem matches both .s and .S the same, +# it will preserve the spelling of the filenames, and gcc itself does +# care about how the name is spelled on its command-line. +ASRC = + + +# Optimization level, can be [0, 1, 2, 3, s]. +# 0 = turn off optimization. s = optimize for size. +# (Note: 3 is not always the best optimization level. See avr-libc FAQ.) +OPT = s + + +# Debugging format. +# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs. +# AVR Studio 4.10 requires dwarf-2. +# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run. +DEBUG = dwarf-2 + + +# List any extra directories to look for include files here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRAINCDIRS = $(LUFA_PATH)/ ../../ + + +# Compiler flag to set the C Standard level. +# c89 = "ANSI" C +# gnu89 = c89 plus GCC extensions +# c99 = ISO C99 standard (not yet fully implemented) +# gnu99 = c99 plus GCC extensions +CSTANDARD = -std=c99 + + +# Place -D or -U options here for C sources +CDEFS = -DF_CPU=$(F_CPU)UL +CDEFS += -DF_CLOCK=$(F_CLOCK)UL +CDEFS += -DBOARD=BOARD_$(BOARD) +CDEFS += $(LUFA_OPTS) + + +# Place -D or -U options here for ASM sources +ADEFS = -DF_CPU=$(F_CPU) +ADEFS += -DF_CLOCK=$(F_CLOCK)UL +ADEFS += -DBOARD=BOARD_$(BOARD) +ADEFS += $(LUFA_OPTS) + +# Place -D or -U options here for C++ sources +CPPDEFS = -DF_CPU=$(F_CPU)UL +CPPDEFS += -DF_CLOCK=$(F_CLOCK)UL +CPPDEFS += -DBOARD=BOARD_$(BOARD) +CPPDEFS += $(LUFA_OPTS) +#CPPDEFS += -D__STDC_LIMIT_MACROS +#CPPDEFS += -D__STDC_CONSTANT_MACROS + + + +#---------------- Compiler Options C ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CFLAGS = -g$(DEBUG) +CFLAGS += $(CDEFS) +CFLAGS += -O$(OPT) +CFLAGS += -funsigned-char +CFLAGS += -funsigned-bitfields +CFLAGS += -ffunction-sections +CFLAGS += -fno-inline-small-functions +CFLAGS += -fpack-struct +CFLAGS += -fshort-enums +CFLAGS += -fno-strict-aliasing +CFLAGS += -Wall +CFLAGS += -Wstrict-prototypes +#CFLAGS += -mshort-calls +#CFLAGS += -fno-unit-at-a-time +#CFLAGS += -Wundef +#CFLAGS += -Wunreachable-code +#CFLAGS += -Wsign-compare +CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst) +CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +CFLAGS += $(CSTANDARD) + + +#---------------- Compiler Options C++ ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CPPFLAGS = -g$(DEBUG) +CPPFLAGS += $(CPPDEFS) +CPPFLAGS += -O$(OPT) +CPPFLAGS += -funsigned-char +CPPFLAGS += -funsigned-bitfields +CPPFLAGS += -fpack-struct +CPPFLAGS += -fshort-enums +CPPFLAGS += -fno-exceptions +CPPFLAGS += -Wall +CPPFLAGS += -Wundef +#CPPFLAGS += -mshort-calls +#CPPFLAGS += -fno-unit-at-a-time +#CPPFLAGS += -Wstrict-prototypes +#CPPFLAGS += -Wunreachable-code +#CPPFLAGS += -Wsign-compare +CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst) +CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +#CPPFLAGS += $(CSTANDARD) + + +#---------------- Assembler Options ---------------- +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns: create listing +# -gstabs: have the assembler create line number information; note that +# for use in COFF files, additional information about filenames +# and function names needs to be present in the assembler source +# files -- see avr-libc docs [FIXME: not yet described there] +# -listing-cont-lines: Sets the maximum number of continuation lines of hex +# dump that will be displayed for a given single line of source input. +ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100 + + +#---------------- Library Options ---------------- +# Minimalistic printf version +PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min + +# Floating point printf version (requires MATH_LIB = -lm below) +PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt + +# If this is left blank, then it will use the Standard printf version. +PRINTF_LIB = +#PRINTF_LIB = $(PRINTF_LIB_MIN) +#PRINTF_LIB = $(PRINTF_LIB_FLOAT) + + +# Minimalistic scanf version +SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min + +# Floating point + %[ scanf version (requires MATH_LIB = -lm below) +SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt + +# If this is left blank, then it will use the Standard scanf version. +SCANF_LIB = +#SCANF_LIB = $(SCANF_LIB_MIN) +#SCANF_LIB = $(SCANF_LIB_FLOAT) + + +MATH_LIB = -lm + + +# List any extra directories to look for libraries here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRALIBDIRS = + + + +#---------------- External Memory Options ---------------- + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# used for variables (.data/.bss) and heap (malloc()). +#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# only used for heap (malloc()). +#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff + +EXTMEMOPTS = + + + +#---------------- Linker Options ---------------- +# -Wl,...: tell GCC to pass this to linker. +# -Map: create map file +# --cref: add cross reference to map file +LDFLAGS = -Wl,-Map=$(TARGET).map,--cref +LDFLAGS += -Wl,--relax +LDFLAGS += -Wl,--gc-sections +LDFLAGS += $(EXTMEMOPTS) +LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS)) +LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) +#LDFLAGS += -T linker_script.x + + + +#---------------- Programming Options (avrdude) ---------------- + +# Programming hardware +# Type: avrdude -c ? +# to get a full listing. +# +AVRDUDE_PROGRAMMER = jtagmkII + +# com1 = serial port. Use lpt1 to connect to parallel port. +AVRDUDE_PORT = usb + +AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex +#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep + + +# Uncomment the following if you want avrdude's erase cycle counter. +# Note that this counter needs to be initialized first using -Yn, +# see avrdude manual. +#AVRDUDE_ERASE_COUNTER = -y + +# Uncomment the following if you do /not/ wish a verification to be +# performed after programming the device. +#AVRDUDE_NO_VERIFY = -V + +# Increase verbosity level. Please use this when submitting bug +# reports about avrdude. See +# to submit bug reports. +#AVRDUDE_VERBOSE = -v -v + +AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) +AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) +AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) +AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) + + + +#---------------- Debugging Options ---------------- + +# For simulavr only - target MCU frequency. +DEBUG_MFREQ = $(F_CPU) + +# Set the DEBUG_UI to either gdb or insight. +# DEBUG_UI = gdb +DEBUG_UI = insight + +# Set the debugging back-end to either avarice, simulavr. +DEBUG_BACKEND = avarice +#DEBUG_BACKEND = simulavr + +# GDB Init Filename. +GDBINIT_FILE = __avr_gdbinit + +# When using avarice settings for the JTAG +JTAG_DEV = /dev/com1 + +# Debugging port used to communicate between GDB / avarice / simulavr. +DEBUG_PORT = 4242 + +# Debugging host used to communicate between GDB / avarice / simulavr, normally +# just set to localhost unless doing some sort of crazy debugging when +# avarice is running on a different computer. +DEBUG_HOST = localhost + + + +#============================================================================ + + +# Define programs and commands. +SHELL = sh +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +AR = avr-ar rcs +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +REMOVEDIR = rm -rf +COPY = cp +WINSHELL = cmd + + +# Define Messages +# English +MSG_ERRORS_NONE = Errors: none +MSG_BEGIN = -------- begin -------- +MSG_END = -------- end -------- +MSG_SIZE_BEFORE = Size before: +MSG_SIZE_AFTER = Size after: +MSG_COFF = Converting to AVR COFF: +MSG_EXTENDED_COFF = Converting to AVR Extended COFF: +MSG_FLASH = Creating load file for Flash: +MSG_EEPROM = Creating load file for EEPROM: +MSG_EXTENDED_LISTING = Creating Extended Listing: +MSG_SYMBOL_TABLE = Creating Symbol Table: +MSG_LINKING = Linking: +MSG_COMPILING = Compiling C: +MSG_COMPILING_CPP = Compiling C++: +MSG_ASSEMBLING = Assembling: +MSG_CLEANING = Cleaning project: +MSG_CREATING_LIBRARY = Creating library: + + + + +# Define all object files. +OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o) + +# Define all listing files. +LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst) + + +# Compiler flags to generate dependency files. +GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d + + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS) +ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + + + + +# Default target. +all: begin gccversion sizebefore build sizeafter end + +# Change the build target to build a HEX file or a library. +build: elf hex eep lss sym +#build: lib + + +elf: $(TARGET).elf +hex: $(TARGET).hex +eep: $(TARGET).eep +lss: $(TARGET).lss +sym: $(TARGET).sym +LIBNAME=lib$(TARGET).a +lib: $(LIBNAME) + + + +# Eye candy. +# AVR Studio 3.x does not check make's exit code but relies on +# the following magic strings to be generated by the compile job. +begin: + @echo + @echo $(MSG_BEGIN) + +end: + @echo $(MSG_END) + @echo + + +# Display size of file. +HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex +ELFSIZE = $(SIZE) $(MCU_FLAG) $(FORMAT_FLAG) $(TARGET).elf +MCU_FLAG = $(shell $(SIZE) --help | grep -- --mcu > /dev/null && echo --mcu=$(MCU) ) +FORMAT_FLAG = $(shell $(SIZE) --help | grep -- --format=.*avr > /dev/null && echo --format=avr ) + + +sizebefore: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \ + 2>/dev/null; echo; fi + +sizeafter: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \ + 2>/dev/null; echo; fi + + + +# Display compiler version information. +gccversion : + @$(CC) --version + + +# Program the device. +program: $(TARGET).hex $(TARGET).eep + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) + +flip: $(TARGET).hex + batchisp -hardware usb -device $(MCU) -operation erase f + batchisp -hardware usb -device $(MCU) -operation loadbuffer $(TARGET).hex program + batchisp -hardware usb -device $(MCU) -operation start reset 0 + +dfu: $(TARGET).hex + dfu-programmer $(MCU) erase + dfu-programmer $(MCU) flash $(TARGET).hex + dfu-programmer $(MCU) reset + +flip-ee: $(TARGET).hex $(TARGET).eep + $(COPY) $(TARGET).eep $(TARGET)eep.hex + batchisp -hardware usb -device $(MCU) -operation memory EEPROM erase + batchisp -hardware usb -device $(MCU) -operation memory EEPROM loadbuffer $(TARGET)eep.hex program + batchisp -hardware usb -device $(MCU) -operation start reset 0 + $(REMOVE) $(TARGET)eep.hex + +dfu-ee: $(TARGET).hex $(TARGET).eep + dfu-programmer $(MCU) eeprom-flash $(TARGET).eep + dfu-programmer $(MCU) reset + + +# Generate avr-gdb config/init file which does the following: +# define the reset signal, load the target file, connect to target, and set +# a breakpoint at main(). +gdb-config: + @$(REMOVE) $(GDBINIT_FILE) + @echo define reset >> $(GDBINIT_FILE) + @echo SIGNAL SIGHUP >> $(GDBINIT_FILE) + @echo end >> $(GDBINIT_FILE) + @echo file $(TARGET).elf >> $(GDBINIT_FILE) + @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE) +ifeq ($(DEBUG_BACKEND),simulavr) + @echo load >> $(GDBINIT_FILE) +endif + @echo break main >> $(GDBINIT_FILE) + +debug: gdb-config $(TARGET).elf +ifeq ($(DEBUG_BACKEND), avarice) + @echo Starting AVaRICE - Press enter when "waiting to connect" message displays. + @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \ + $(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT) + @$(WINSHELL) /c pause + +else + @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \ + $(DEBUG_MFREQ) --port $(DEBUG_PORT) +endif + @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE) + + + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT = $(OBJCOPY) --debugging +COFFCONVERT += --change-section-address .data-0x800000 +COFFCONVERT += --change-section-address .bss-0x800000 +COFFCONVERT += --change-section-address .noinit-0x800000 +COFFCONVERT += --change-section-address .eeprom-0x810000 + + + +coff: $(TARGET).elf + @echo + @echo $(MSG_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-avr $< $(TARGET).cof + + +extcoff: $(TARGET).elf + @echo + @echo $(MSG_EXTENDED_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof + + + +# Create final output files (.hex, .eep) from ELF output file. +%.hex: %.elf + @echo + @echo $(MSG_FLASH) $@ + $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock $< $@ + +%.eep: %.elf + @echo + @echo $(MSG_EEPROM) $@ + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0 + +# Create extended listing file from ELF output file. +%.lss: %.elf + @echo + @echo $(MSG_EXTENDED_LISTING) $@ + $(OBJDUMP) -h -S -z $< > $@ + +# Create a symbol table from ELF output file. +%.sym: %.elf + @echo + @echo $(MSG_SYMBOL_TABLE) $@ + $(NM) -n $< > $@ + + + +# Create library from object files. +.SECONDARY : $(TARGET).a +.PRECIOUS : $(OBJ) +%.a: $(OBJ) + @echo + @echo $(MSG_CREATING_LIBRARY) $@ + $(AR) $@ $(OBJ) + + +# Link: create ELF output file from object files. +.SECONDARY : $(TARGET).elf +.PRECIOUS : $(OBJ) +%.elf: $(OBJ) + @echo + @echo $(MSG_LINKING) $@ + $(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS) + + +# Compile: create object files from C source files. +$(OBJDIR)/%.o : %.c + @echo + @echo $(MSG_COMPILING) $< + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create object files from C++ source files. +$(OBJDIR)/%.o : %.cpp + @echo + @echo $(MSG_COMPILING_CPP) $< + $(CC) -c $(ALL_CPPFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +%.s : %.c + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C++ source files. +%.s : %.cpp + $(CC) -S $(ALL_CPPFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +$(OBJDIR)/%.o : %.S + @echo + @echo $(MSG_ASSEMBLING) $< + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + +# Create preprocessed source for use in sending a bug report. +%.i : %.c + $(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@ + + +# Target: clean project. +clean: begin clean_list end + +clean_list : + @echo + @echo $(MSG_CLEANING) + $(REMOVE) $(TARGET).hex + $(REMOVE) $(TARGET).eep + $(REMOVE) $(TARGET).cof + $(REMOVE) $(TARGET).elf + $(REMOVE) $(TARGET).map + $(REMOVE) $(TARGET).sym + $(REMOVE) $(TARGET).lss + $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o) + $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst) + $(REMOVE) $(SRC:.c=.s) + $(REMOVE) $(SRC:.c=.d) + $(REMOVE) $(SRC:.c=.i) + $(REMOVEDIR) .dep + $(REMOVE) main + +doxygen: + @echo Generating Project Documentation... + @doxygen Doxygen.conf + @echo Documentation Generation Complete. + +clean_doxygen: + rm -rf Documentation + +# Create object files directory +$(shell mkdir $(OBJDIR) 2>/dev/null) + + +# Include the dependency files. +-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) + + +# Listing of phony targets. +.PHONY : all begin finish end sizebefore sizeafter gccversion \ +build elf hex eep lss sym coff extcoff doxygen clean \ +clean_list clean_doxygen program dfu flip flip-ee dfu-ee \ +debug gdb-config + diff --git a/Libraries/avrmidi/examples/lufa_midi/midi_usb.c b/Libraries/avrmidi/examples/lufa_midi/midi_usb.c new file mode 100644 index 0000000..4a045c8 --- /dev/null +++ b/Libraries/avrmidi/examples/lufa_midi/midi_usb.c @@ -0,0 +1,161 @@ +/* + * Modified by Alex Norman (x37v.info) from Dean Camera's MIDI LUFA demo + * Original Copyright below + */ + +/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org + */ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. + */ + +#include "midi_usb.h" + +#include +#include +#include +#include +#include + +#include "Descriptors.h" + +#include +#include + +/* Function Prototypes: */ +void SetupHardware(void); + +void EVENT_USB_Device_Connect(void); +void EVENT_USB_Device_Disconnect(void); +void EVENT_USB_Device_ConfigurationChanged(void); +void EVENT_USB_Device_ControlRequest(void); + +/** LUFA MIDI Class driver interface configuration and state information. This structure is + * passed to all MIDI Class driver functions, so that multiple instances of the same class + * within a device can be differentiated from one another. + */ + +USB_ClassInfo_MIDI_Device_t USB_MIDI_Interface = +{ + .Config = + { + .StreamingInterfaceNumber = 1, + + .DataINEndpointNumber = MIDI_STREAM_IN_EPNUM, + .DataINEndpointSize = MIDI_STREAM_EPSIZE, + .DataINEndpointDoubleBank = false, + + .DataOUTEndpointNumber = MIDI_STREAM_OUT_EPNUM, + .DataOUTEndpointSize = MIDI_STREAM_EPSIZE, + .DataOUTEndpointDoubleBank = false, + }, + }; + +//we disregard cnt because we assume all other bytes are zero and we always send 4 bytes +void usb_send_func(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) { + MIDI_EventPacket_t event; + event.CableNumber = 0; + event.Command = byte0 >> 4; + event.Data1 = byte0; + event.Data2 = byte1; + event.Data3 = byte2; + + MIDI_Device_SendEventPacket(&USB_MIDI_Interface, &event); + MIDI_Device_Flush(&USB_MIDI_Interface); + MIDI_Device_USBTask(&USB_MIDI_Interface); + USB_USBTask(); +} + +void usb_get_midi(MidiDevice * device) { + /* Select the MIDI OUT stream */ + Endpoint_SelectEndpoint(MIDI_STREAM_OUT_EPNUM); + + MIDI_EventPacket_t event; + while (MIDI_Device_ReceiveEventPacket(&USB_MIDI_Interface, &event)) { + + midi_packet_length_t length = midi_packet_length(event.Data1); + + //pass the data to the device input function + //not dealing with sysex yet + if (length != UNDEFINED) + midi_device_input(device, length, event.Data1, event.Data2, event.Data3); + + } + MIDI_Device_USBTask(&USB_MIDI_Interface); + USB_USBTask(); +} + +void midi_usb_init(MidiDevice * device){ + midi_device_init(device); + midi_device_set_send_func(device, usb_send_func); + midi_device_set_pre_input_process_func(device, usb_get_midi); + + SetupHardware(); + sei(); +} + +/** Configures the board hardware and chip peripherals for the demo's functionality. */ +void SetupHardware(void) +{ + /* Disable watchdog if enabled by bootloader/fuses */ + MCUSR &= ~(1 << WDRF); + wdt_disable(); + + /* Disable clock division */ + clock_prescale_set(clock_div_1); + + /* Hardware Initialization */ + USB_Init(); +} + +/** Event handler for the library USB Connection event. */ +void EVENT_USB_Device_Connect(void) +{ + //set some LED? +} + +/** Event handler for the library USB Disconnection event. */ +void EVENT_USB_Device_Disconnect(void) +{ + //set some LED? +} + +/** Event handler for the library USB Configuration Changed event. */ +void EVENT_USB_Device_ConfigurationChanged(void) +{ + bool ConfigSuccess = true; + + ConfigSuccess &= MIDI_Device_ConfigureEndpoints(&USB_MIDI_Interface); + //set some LED? +} + +/** Event handler for the library USB Control Request reception event. */ +void EVENT_USB_Device_ControlRequest(void) +{ + MIDI_Device_ProcessControlRequest(&USB_MIDI_Interface); +} + diff --git a/Libraries/avrmidi/examples/lufa_midi/midi_usb.h b/Libraries/avrmidi/examples/lufa_midi/midi_usb.h new file mode 100644 index 0000000..551c8e0 --- /dev/null +++ b/Libraries/avrmidi/examples/lufa_midi/midi_usb.h @@ -0,0 +1,8 @@ +#ifndef MIDI_USB_H +#define MIDI_USB_H + +#include "midi.h" + +void midi_usb_init(MidiDevice * device); + +#endif diff --git a/Libraries/avrmidi/examples/serial_midi.c b/Libraries/avrmidi/examples/serial_midi.c new file mode 100644 index 0000000..49c57a6 --- /dev/null +++ b/Libraries/avrmidi/examples/serial_midi.c @@ -0,0 +1,49 @@ +#include "serial_midi.h" +#include +#include "stdlib.h" + +static MidiDevice midi_device; + +void serial_midi_send(MidiDevice * device, uint8_t cnt, uint8_t inByte0, uint8_t inByte1, uint8_t inByte2){ + //we always send the first byte + while ( !(UCSRA & _BV(UDRE)) ); // Wait for empty transmit buffer + UDR = inByte0; + //if cnt == 2 or 3 we send the send byte + if(cnt > 1) { + while ( !(UCSRA & _BV(UDRE)) ); // Wait for empty transmit buffer + UDR = inByte1; + } + //if cnt == 3 we send the third byte + if(cnt == 3) { + while ( !(UCSRA & _BV(UDRE)) ); // Wait for empty transmit buffer + UDR = inByte2; + } +} + +MidiDevice * serial_midi_device(void) { + return &midi_device; +} + +MidiDevice* serial_midi_init(uint16_t clockScale, bool out, bool in){ + //send up the device + midi_device_init(&midi_device); + midi_device_set_send_func(&midi_device, serial_midi_send); + + // Set baud rate + UBRRH = (uint8_t)(clockScale >> 8); + UBRRL = (uint8_t)(clockScale & 0xFF); + // Enable transmitter + if(out) + UCSRB |= _BV(TXEN); + if(in) { + //Enable receiver + //RX Complete Interrupt Enable (user must provide routine) + UCSRB |= _BV(RXEN) | _BV(RXCIE); + } + //Set frame format: Async, 8data, 1 stop bit, 1 start bit, no parity + //needs to have URSEL set in order to write into this reg + UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0); + + return serial_midi_device(); +} + diff --git a/Libraries/avrmidi/examples/serial_midi.h b/Libraries/avrmidi/examples/serial_midi.h new file mode 100644 index 0000000..38abd4e --- /dev/null +++ b/Libraries/avrmidi/examples/serial_midi.h @@ -0,0 +1,10 @@ +#ifndef SERIAL_MIDI_H +#define SERIAL_MIDI_H + +#include +#include "midi.h" + +//initialize serial midi and return the device pointer +MidiDevice* serial_midi_init(uint16_t clockScale, bool out, bool in); + +#endif diff --git a/Libraries/avrmidi/examples/spit.c b/Libraries/avrmidi/examples/spit.c new file mode 100644 index 0000000..d8c989b --- /dev/null +++ b/Libraries/avrmidi/examples/spit.c @@ -0,0 +1,18 @@ +#include +#include "serial_midi.h" + +#define MIDI_CLOCK_12MHZ_OSC 23 +#define MIDI_CLOCK_RATE MIDI_CLOCK_12MHZ_OSC + +int main(void){ + //init midi, give the clock rate setting, indicate that we want only output + MidiDevice * midi_device = serial_midi_init(MIDI_CLOCK_RATE, true, false); + + uint8_t cnt = 0; + + while (1) { + midi_send_cc(midi_device, 0, 0, cnt); + cnt = (cnt + 1) & 0x7F; + } + return 0; +} diff --git a/Libraries/avrmidi/interrupt_setting.c b/Libraries/avrmidi/interrupt_setting.c new file mode 100644 index 0000000..eafef52 --- /dev/null +++ b/Libraries/avrmidi/interrupt_setting.c @@ -0,0 +1,36 @@ +//Copyright 20010 Alex Norman +//writen by Alex Norman +// +//This file is part of avr-bytequeue. +// +//avr-bytequeue 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. +// +//avr-bytequeue 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 avr-bytequeue. If not, see . + + +//AVR specific code +//should be able to port to other systems by simply providing chip specific +//implementations of the typedef and these functions + +#include "interrupt_setting.h" +#include + +interrupt_setting_t store_and_clear_interrupt(void) { + uint8_t sreg = SREG; + cli(); + return sreg; +} + +void restore_interrupt_setting(interrupt_setting_t setting) { + SREG = setting; +} + diff --git a/Libraries/avrmidi/interrupt_setting.h b/Libraries/avrmidi/interrupt_setting.h new file mode 100644 index 0000000..3d2a163 --- /dev/null +++ b/Libraries/avrmidi/interrupt_setting.h @@ -0,0 +1,31 @@ +//Copyright 20010 Alex Norman +//writen by Alex Norman +// +//This file is part of avr-bytequeue. +// +//avr-bytequeue 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. +// +//avr-bytequeue 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 avr-bytequeue. If not, see . + +#ifndef INTERRUPT_SETTING_H +#define INTERRUPT_SETTING_H + +#include + +//AVR specific typedef +typedef uint8_t interrupt_setting_t; + +interrupt_setting_t store_and_clear_interrupt(void); +void restore_interrupt_setting(interrupt_setting_t setting); + +#endif + diff --git a/Libraries/avrmidi/midi.c b/Libraries/avrmidi/midi.c new file mode 100644 index 0000000..e58fb19 --- /dev/null +++ b/Libraries/avrmidi/midi.c @@ -0,0 +1,252 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#include "midi.h" +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) + +#ifndef NULL +#define NULL 0 +#endif + +bool midi_is_statusbyte(uint8_t theByte){ + return (bool)(theByte & MIDI_STATUSMASK); +} + +bool midi_is_realtime(uint8_t theByte){ + return (theByte >= MIDI_CLOCK); +} + +midi_packet_length_t midi_packet_length(uint8_t status){ + // Filter out low bit for status bytes that contain channel number, keep it for + // status bytes which use all 8 bits. (0xF0-0xF7) + switch(status < 0xF0 ? status & 0xF0 : status){ + case MIDI_CC: + case MIDI_NOTEON: + case MIDI_NOTEOFF: + case MIDI_AFTERTOUCH: + case MIDI_PITCHBEND: + case MIDI_SONGPOSITION: + return THREE; + case MIDI_PROGCHANGE: + case MIDI_CHANPRESSURE: + case MIDI_SONGSELECT: + case MIDI_TC_QUATERFRAME: + return TWO; + case MIDI_CLOCK: + case MIDI_TICK: + case MIDI_START: + case MIDI_CONTINUE: + case MIDI_STOP: + case MIDI_ACTIVESENSE: + case MIDI_RESET: + case MIDI_TUNEREQUEST: + return ONE; + case SYSEX_END: + case SYSEX_BEGIN: + default: + return UNDEFINED; + } +} + +void midi_send_cc(MidiDevice * device, uint8_t chan, uint8_t num, uint8_t val){ + //CC Status: 0xB0 to 0xBF where the low nibble is the MIDI channel. + //CC Data: Controller Num, Controller Val + device->send_func(device, 3, + MIDI_CC | (chan & MIDI_CHANMASK), + num & 0x7F, + val & 0x7F); +} + +void midi_send_noteon(MidiDevice * device, uint8_t chan, uint8_t num, uint8_t vel){ + //Note Data: Note Num, Note Velocity + device->send_func(device, 3, + MIDI_NOTEON | (chan & MIDI_CHANMASK), + num & 0x7F, + vel & 0x7F); +} + +void midi_send_noteoff(MidiDevice * device, uint8_t chan, uint8_t num, uint8_t vel){ + //Note Data: Note Num, Note Velocity + device->send_func(device, 3, + MIDI_NOTEOFF | (chan & MIDI_CHANMASK), + num & 0x7F, + vel & 0x7F); +} + +void midi_send_aftertouch(MidiDevice * device, uint8_t chan, uint8_t note_num, uint8_t amt){ + device->send_func(device, 3, + MIDI_AFTERTOUCH | (chan & MIDI_CHANMASK), + note_num & 0x7F, + amt & 0x7F); +} + +//XXX does this work right? +//amt in range -0x2000, 0x1fff +//uAmt should be in range.. +//0x0000 to 0x3FFF +void midi_send_pitchbend(MidiDevice * device, uint8_t chan, int16_t amt){ + uint16_t uAmt; + //check range + if(amt > 0x1fff){ + uAmt = 0x3FFF; + } else if(amt < -0x2000){ + uAmt = 0; + } else { + uAmt = amt + 0x2000; + } + device->send_func(device, 3, + MIDI_PITCHBEND | (chan & MIDI_CHANMASK), + uAmt & 0x7F, + (uAmt >> 7) & 0x7F); +} + +void midi_send_programchange(MidiDevice * device, uint8_t chan, uint8_t num){ + device->send_func(device, 2, + MIDI_PROGCHANGE | (chan & MIDI_CHANMASK), + num & 0x7F, + 0); +} + +void midi_send_channelpressure(MidiDevice * device, uint8_t chan, uint8_t amt){ + device->send_func(device, 2, + MIDI_CHANPRESSURE | (chan & MIDI_CHANMASK), + amt & 0x7F, + 0); +} + +void midi_send_clock(MidiDevice * device){ + device->send_func(device, 1, MIDI_CLOCK, 0, 0); +} + +void midi_send_tick(MidiDevice * device){ + device->send_func(device, 1, MIDI_TICK, 0, 0); +} + +void midi_send_start(MidiDevice * device){ + device->send_func(device, 1, MIDI_START, 0, 0); +} + +void midi_send_continue(MidiDevice * device){ + device->send_func(device, 1, MIDI_CONTINUE, 0, 0); +} + +void midi_send_stop(MidiDevice * device){ + device->send_func(device, 1, MIDI_STOP, 0, 0); +} + +void midi_send_activesense(MidiDevice * device){ + device->send_func(device, 1, MIDI_ACTIVESENSE, 0, 0); +} + +void midi_send_reset(MidiDevice * device){ + device->send_func(device, 1, MIDI_RESET, 0, 0); +} + +void midi_send_tcquaterframe(MidiDevice * device, uint8_t time){ + device->send_func(device, 2, + MIDI_TC_QUATERFRAME, + time & 0x7F, + 0); +} + +//XXX is this right? +void midi_send_songposition(MidiDevice * device, uint16_t pos){ + device->send_func(device, 3, + MIDI_SONGPOSITION, + pos & 0x7F, + (pos >> 7) & 0x7F); +} + +void midi_send_songselect(MidiDevice * device, uint8_t song){ + device->send_func(device, 2, + MIDI_SONGSELECT, + song & 0x7F, + 0); +} + +void midi_send_tunerequest(MidiDevice * device){ + device->send_func(device, 1, MIDI_TUNEREQUEST, 0, 0); +} + +void midi_send_byte(MidiDevice * device, uint8_t b){ + device->send_func(device, 1, b, 0, 0); +} + + void midi_send_data(MidiDevice * device, uint8_t count, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + if (count > 3) + count = 3; + device->send_func(device, count, byte0, byte1, byte2); + } + + +void midi_register_cc_callback(MidiDevice * device, midi_three_byte_func_t func){ + device->input_cc_callback = func; +} + +void midi_register_noteon_callback(MidiDevice * device, midi_three_byte_func_t func){ + device->input_noteon_callback = func; +} + +void midi_register_noteoff_callback(MidiDevice * device, midi_three_byte_func_t func){ + device->input_noteoff_callback = func; +} + +void midi_register_aftertouch_callback(MidiDevice * device, midi_three_byte_func_t func){ + device->input_aftertouch_callback = func; +} + +void midi_register_pitchbend_callback(MidiDevice * device, midi_three_byte_func_t func){ + device->input_pitchbend_callback = func; +} + +void midi_register_songposition_callback(MidiDevice * device, midi_three_byte_func_t func){ + device->input_songposition_callback = func; +} + +void midi_register_progchange_callback(MidiDevice * device, midi_two_byte_func_t func) { + device->input_progchange_callback = func; +} + +void midi_register_chanpressure_callback(MidiDevice * device, midi_two_byte_func_t func) { + device->input_chanpressure_callback = func; +} + +void midi_register_songselect_callback(MidiDevice * device, midi_two_byte_func_t func) { + device->input_songselect_callback = func; +} + +void midi_register_tc_quarterframe_callback(MidiDevice * device, midi_two_byte_func_t func) { + device->input_tc_quaterframe_callback = func; +} + +void midi_register_realtime_callback(MidiDevice * device, midi_one_byte_func_t func){ + device->input_realtime_callback = func; +} + +void midi_register_tunerequest_callback(MidiDevice * device, midi_one_byte_func_t func){ + device->input_tunerequest_callback = func; +} + +void midi_register_fallthrough_callback(MidiDevice * device, midi_var_byte_func_t func){ + device->input_fallthrough_callback = func; +} + +void midi_register_catchall_callback(MidiDevice * device, midi_var_byte_func_t func){ + device->input_catchall_callback = func; +} + diff --git a/Libraries/avrmidi/midi.h b/Libraries/avrmidi/midi.h new file mode 100644 index 0000000..292cf68 --- /dev/null +++ b/Libraries/avrmidi/midi.h @@ -0,0 +1,135 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#ifndef AVR_MIDI_H +#define AVR_MIDI_H + +#include "midi_device.h" +#include "midi_function_types.h" + +typedef enum { + UNDEFINED = 0, + ONE = 1, + TWO = 2, + THREE = 3} midi_packet_length_t; + +//general information [device independent] **************** +//returns true if the byte given is a midi status byte +bool midi_is_statusbyte(uint8_t theByte); +//returns true if the byte given is a realtime status byte +bool midi_is_realtime(uint8_t theByte); +//returns the length of the packet associated with the status byte given +midi_packet_length_t midi_packet_length(uint8_t status); + + +//initialize midi device +void midi_device_init(MidiDevice * device); // [implementation in midi_device.c] + +//process input data +//you need to call this if you expect your input callbacks to be called +void midi_device_process(MidiDevice * device); // [implementation in midi_device.c] + + +//send functions ********************** +void midi_send_cc(MidiDevice * device, uint8_t chan, uint8_t num, uint8_t val); +void midi_send_noteon(MidiDevice * device, uint8_t chan, uint8_t num, uint8_t vel); +void midi_send_noteoff(MidiDevice * device, uint8_t chan, uint8_t num, uint8_t vel); +void midi_send_aftertouch(MidiDevice * device, uint8_t chan, uint8_t note_num, uint8_t amt); +void midi_send_pitchbend(MidiDevice * device, uint8_t chan, int16_t amt); //range -8192, 8191 +void midi_send_programchange(MidiDevice * device, uint8_t chan, uint8_t num); +void midi_send_channelpressure(MidiDevice * device, uint8_t chan, uint8_t amt); + +//realtime +void midi_send_clock(MidiDevice * device); +void midi_send_tick(MidiDevice * device); +void midi_send_start(MidiDevice * device); +void midi_send_continue(MidiDevice * device); +void midi_send_stop(MidiDevice * device); +void midi_send_activesense(MidiDevice * device); +void midi_send_reset(MidiDevice * device); + +//more obscure +void midi_send_tcquaterframe(MidiDevice * device, uint8_t time); //range 0..16383 +void midi_send_songposition(MidiDevice * device, uint16_t pos); +void midi_send_songselect(MidiDevice * device, uint8_t song); +void midi_send_tunerequest(MidiDevice * device); +void midi_send_byte(MidiDevice * device, uint8_t b); +void midi_send_data(MidiDevice * device, uint8_t count, uint8_t byte0, uint8_t byte1, uint8_t byte2); + + +//input callback registration *********************** + +//three byte funcs +void midi_register_cc_callback(MidiDevice * device, midi_three_byte_func_t func); +void midi_register_noteon_callback(MidiDevice * device, midi_three_byte_func_t func); +void midi_register_noteoff_callback(MidiDevice * device, midi_three_byte_func_t func); +void midi_register_aftertouch_callback(MidiDevice * device, midi_three_byte_func_t func); +void midi_register_pitchbend_callback(MidiDevice * device, midi_three_byte_func_t func); +void midi_register_songposition_callback(MidiDevice * device, midi_three_byte_func_t func); + +//two byte funcs +void midi_register_progchange_callback(MidiDevice * device, midi_two_byte_func_t func); +void midi_register_chanpressure_callback(MidiDevice * device, midi_two_byte_func_t func); +void midi_register_songselect_callback(MidiDevice * device, midi_two_byte_func_t func); +void midi_register_tc_quarterframe_callback(MidiDevice * device, midi_two_byte_func_t func); + +//one byte funcs +void midi_register_realtime_callback(MidiDevice * device, midi_one_byte_func_t func); +void midi_register_tunerequest_callback(MidiDevice * device, midi_one_byte_func_t func); + +//fall through, only called if a more specific callback isn't matched and called +void midi_register_fallthrough_callback(MidiDevice * device, midi_var_byte_func_t func); +//catch all, always called if registered, independent of a more specific or fallthrough call +void midi_register_catchall_callback(MidiDevice * device, midi_var_byte_func_t func); + +#define SYSEX_BEGIN 0xF0 +#define SYSEX_END 0xF7 +//if you and this with a byte and you get anything non-zero +//it is a status message +#define MIDI_STATUSMASK 0x80 +//if you and this with a status message that contains channel info, +//you'll get the channel +#define MIDI_CHANMASK 0x0F + +#define MIDI_CC 0xB0 +#define MIDI_NOTEON 0x90 +#define MIDI_NOTEOFF 0x80 +#define MIDI_AFTERTOUCH 0xA0 +#define MIDI_PITCHBEND 0xE0 +#define MIDI_PROGCHANGE 0xC0 +#define MIDI_CHANPRESSURE 0xD0 + +//midi realtime +#define MIDI_CLOCK 0xF8 +#define MIDI_TICK 0xF9 +#define MIDI_START 0xFA +#define MIDI_CONTINUE 0xFB +#define MIDI_STOP 0xFC +#define MIDI_ACTIVESENSE 0xFE +#define MIDI_RESET 0xFF + +#define MIDI_TC_QUATERFRAME 0xF1 +#define MIDI_SONGPOSITION 0xF2 +#define MIDI_SONGSELECT 0xF3 +#define MIDI_TUNEREQUEST 0xF6 + +//This ID is for educational or development use only +#define SYSEX_EDUMANUFID 0x7D + +#endif + diff --git a/Libraries/avrmidi/midi_device.c b/Libraries/avrmidi/midi_device.c new file mode 100644 index 0000000..ec49eb3 --- /dev/null +++ b/Libraries/avrmidi/midi_device.c @@ -0,0 +1,299 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#include "midi_device.h" +#include "midi.h" + +#ifndef NULL +#define NULL 0 +#endif + +#define DEBUG +#ifdef DEBUG +#include +#endif + +//forward declarations, internally used to call the callbacks +void midi_input_callbacks(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2); +void midi_process_byte(MidiDevice * device, uint8_t input); + +void midi_device_init(MidiDevice * device){ + device->input_state = IDLE; + device->input_count = 0; + bytequeue_init(&device->input_queue, device->input_queue_data, MIDI_INPUT_QUEUE_LENGTH); + + //three byte funcs + device->input_cc_callback = NULL; + device->input_noteon_callback = NULL; + device->input_noteoff_callback = NULL; + device->input_aftertouch_callback = NULL; + device->input_pitchbend_callback = NULL; + device->input_songposition_callback = NULL; + + //two byte funcs + device->input_progchange_callback = NULL; + device->input_chanpressure_callback = NULL; + device->input_songselect_callback = NULL; + device->input_tc_quaterframe_callback = NULL; + + //one byte funcs + device->input_realtime_callback = NULL; + device->input_tunerequest_callback = NULL; + + device->input_fallthrough_callback = NULL; + device->input_catchall_callback = NULL; + + device->pre_input_process_callback = NULL; +} + +void midi_device_input(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) { + //temp storage so we can loop over the bytes + uint8_t input[3]; + input[0] = byte0; + input[1] = byte1; + input[2] = byte2; + + //clamp range + if (cnt > 3) + cnt = 3; + + uint8_t i; + for (i = 0; i < cnt; i++) { +#ifdef DEBUG + printf("queueing %x\n", input[i]); +#endif + bytequeue_enqueue(&device->input_queue, input[i]); + } +} + +void midi_device_set_send_func(MidiDevice * device, midi_var_byte_func_t send_func){ + device->send_func = send_func; +} + +void midi_device_set_pre_input_process_func(MidiDevice * device, midi_no_byte_func_t pre_process_func){ + device->pre_input_process_callback = pre_process_func; +} + +void midi_device_process(MidiDevice * device) { + //call the pre_input_process_callback if there is one + if(device->pre_input_process_callback) + device->pre_input_process_callback(device); + + //pull stuff off the queue and process + byteQueueIndex_t len = bytequeue_length(&device->input_queue); + uint16_t i; + //TODO limit number of bytes processed? + for(i = 0; i < len; i++) { + uint8_t val = bytequeue_get(&device->input_queue, 0); +#ifdef DEBUG + printf("processing %x\n", val); +#endif + midi_process_byte(device, val); + bytequeue_remove(&device->input_queue, 1); + } +} + +void midi_process_byte(MidiDevice * device, uint8_t input) { + if (midi_is_realtime(input)) { + //call callback, don't change any state + midi_input_callbacks(device, 1, input, 0, 0); + } else if (midi_is_statusbyte(input)) { + //store the byte + if (device->input_state != SYSEX_MESSAGE) { + device->input_buffer[0] = input; + device->input_count = 1; + } + switch (midi_packet_length(input)) { + case ONE: + device->input_state = IDLE; + midi_input_callbacks(device, 1, input, 0, 0); + break; + case TWO: + device->input_state = TWO_BYTE_MESSAGE; + break; + case THREE: + device->input_state = THREE_BYTE_MESSAGE; + break; + case UNDEFINED: + switch(input) { + case SYSEX_BEGIN: + device->input_state = SYSEX_MESSAGE; + device->input_buffer[0] = input; + device->input_count = 1; + break; + case SYSEX_END: + //failsafe, should never happen + if(device->input_count > 2) { + device->input_state = IDLE; + device->input_count = 2; + } + //send what is left in the input buffer, set idle + device->input_buffer[device->input_count] = input; + device->input_state = IDLE; + device->input_count += 1; + //call the callback + midi_input_callbacks(device, device->input_count, + device->input_buffer[0], device->input_buffer[1], device->input_buffer[2]); + break; + default: + device->input_state = IDLE; + device->input_count = 0; + } + + break; + default: + device->input_state = IDLE; + device->input_count = 0; + break; + } + } else { + //failsafe, should never happen +// if(device->input_count > 2) +// { +// device->input_state = IDLE; +// } + if (device->input_state != IDLE) { + //store the byte + device->input_buffer[device->input_count] = input; + //increment count + device->input_count += 1; + switch(device->input_count%4) { + case 3: +// if (device->input_state != SYSEX_MESSAGE) +// device->input_state = IDLE; + device->input_count = 1; + //call callback + midi_input_callbacks(device, 3, + device->input_buffer[0], device->input_buffer[1], device->input_buffer[2]); + break; + case 2: + if (device->input_state == TWO_BYTE_MESSAGE) { + device->input_count = 1; + //device->input_state = IDLE; + //call callback + midi_input_callbacks(device, 2, device->input_buffer[0], device->input_buffer[1], 0); + } + break; + case 1: + default: + if (device->input_state == SYSEX_MESSAGE) + { + //call callback + midi_input_callbacks(device, 1, device->input_buffer[0], 0, 0); + device->input_count = 1; + } else { + //shouldn't happen + //device->input_state = IDLE; + } + break; + } + } + } +} + +void midi_input_callbacks(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) { +#ifdef DEBUG + printf("callback func %d %x %x %x\n", cnt, byte0, byte1, byte2); +#endif + //did we end up calling a callback? + bool called = false; + switch (cnt) { + case 3: + { + midi_three_byte_func_t func = NULL; + switch (byte0 & 0xF0) { + case MIDI_CC: + func = device->input_cc_callback; + break; + case MIDI_NOTEON: + func = device->input_noteon_callback; + break; + case MIDI_NOTEOFF: + func = device->input_noteoff_callback; + break; + case MIDI_AFTERTOUCH: + func = device->input_aftertouch_callback; + break; + case MIDI_PITCHBEND: + func = device->input_pitchbend_callback; + break; + case MIDI_SONGPOSITION: + func = device->input_songposition_callback; + break; + default: + break; + } + if(func) { + func(device, byte0, byte1, byte2); + called = true; + } + } + break; + case 2: + { + midi_two_byte_func_t func = NULL; + switch (byte0 & 0xF0) { + case MIDI_PROGCHANGE: + func = device->input_progchange_callback; + break; + case MIDI_CHANPRESSURE: + func = device->input_chanpressure_callback; + break; + case MIDI_SONGSELECT: + func = device->input_songselect_callback; + break; + case MIDI_TC_QUATERFRAME: + func = device->input_tc_quaterframe_callback; + break; + default: + break; + } + if(func) { + func(device, byte0, byte1); + called = true; + } + } + break; + case 1: + { + midi_one_byte_func_t func = NULL; + if (midi_is_realtime(byte0)) + func = device->input_realtime_callback; + else if (byte0 == MIDI_TUNEREQUEST) + func = device->input_tunerequest_callback; + if (func) { + func(device, byte0); + called = true; + } + } + break; + default: + //just in case + if (cnt > 3) + cnt = 0; + break; + } + + //if there is fallthrough default callback and we haven't called a more specific one, + //call the fallthrough + if (!called && device->input_fallthrough_callback) + device->input_fallthrough_callback(device, cnt, byte0, byte1, byte2); + //always call the catch all if it exists + if (device->input_catchall_callback) + device->input_catchall_callback(device, cnt, byte0, byte1, byte2); +} diff --git a/Libraries/avrmidi/midi_device.h b/Libraries/avrmidi/midi_device.h new file mode 100644 index 0000000..d34e7b1 --- /dev/null +++ b/Libraries/avrmidi/midi_device.h @@ -0,0 +1,90 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#ifndef MIDI_DEVICE_H +#define MIDI_DEVICE_H + +#include "midi_function_types.h" +#include "bytequeue.h" + +#define MIDI_INPUT_QUEUE_LENGTH 16 + +typedef enum { + IDLE, + TWO_BYTE_MESSAGE = 2, + THREE_BYTE_MESSAGE = 3, + SYSEX_MESSAGE} input_state_t; + +typedef void (* midi_no_byte_func_t)(MidiDevice * device); + +//this structure represents the input and output functions and processing data +//for a midi device. +//A device can represent an actual physical device [serial port, usb port] or +//something virtual. +//You should not need to modify this structure directly. +struct _midi_device { + //output send function + midi_var_byte_func_t send_func; + + //********input callbacks + //three byte funcs + midi_three_byte_func_t input_cc_callback; + midi_three_byte_func_t input_noteon_callback; + midi_three_byte_func_t input_noteoff_callback; + midi_three_byte_func_t input_aftertouch_callback; + midi_three_byte_func_t input_pitchbend_callback; + midi_three_byte_func_t input_songposition_callback; + //two byte funcs + midi_two_byte_func_t input_progchange_callback; + midi_two_byte_func_t input_chanpressure_callback; + midi_two_byte_func_t input_songselect_callback; + midi_two_byte_func_t input_tc_quaterframe_callback; + //one byte funcs + midi_one_byte_func_t input_realtime_callback; + midi_one_byte_func_t input_tunerequest_callback; + + //only called if more specific callback is not matched + midi_var_byte_func_t input_fallthrough_callback; + //called if registered, independent of other callbacks + midi_var_byte_func_t input_catchall_callback; + + //pre input processing function + midi_no_byte_func_t pre_input_process_callback; + + //for internal input processing + uint8_t input_buffer[3]; + input_state_t input_state; + uint8_t input_count; + + //for queueing data between the input and the processing functions + uint8_t input_queue_data[MIDI_INPUT_QUEUE_LENGTH]; + byteQueue_t input_queue; +}; + +//input processing, only used if you're creating a custom device +void midi_device_input(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2); +//set send function, only used if you're creating a custom device +//you'll most likely want the function that this calls to disable interrupts so +//that you can call the various midi send functions without worrying about +//locking. +void midi_device_set_send_func(MidiDevice * device, midi_var_byte_func_t send_func); + +//if you need to run a function to grab input before you pass it to midi_device_input, set it here. +void midi_device_set_pre_input_process_func(MidiDevice * device, midi_no_byte_func_t pre_process_func); + +#endif diff --git a/Libraries/avrmidi/midi_function_types.h b/Libraries/avrmidi/midi_function_types.h new file mode 100644 index 0000000..4645239 --- /dev/null +++ b/Libraries/avrmidi/midi_function_types.h @@ -0,0 +1,34 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#ifndef MIDI_FUNCTION_TYPES_H +#define MIDI_FUNCTION_TYPES_H + +#include +#include + +//forward declaration +typedef struct _midi_device MidiDevice; + +typedef void (* midi_one_byte_func_t)(MidiDevice * device, uint8_t byte); +typedef void (* midi_two_byte_func_t)(MidiDevice * device, uint8_t byte0, uint8_t byte1); +typedef void (* midi_three_byte_func_t)(MidiDevice * device, uint8_t byte0, uint8_t byte1, uint8_t byte2); +//all bytes after count bytes should be ignored +typedef void (* midi_var_byte_func_t)(MidiDevice * device, uint8_t count, uint8_t byte0, uint8_t byte1, uint8_t byte2); + +#endif diff --git a/Libraries/avrmidi/sysex_tools.c b/Libraries/avrmidi/sysex_tools.c new file mode 100644 index 0000000..2ff8052 --- /dev/null +++ b/Libraries/avrmidi/sysex_tools.c @@ -0,0 +1,99 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#include "sysex_tools.h" + +uint16_t sysex_bit_packed_length(uint16_t unpacked_length){ + uint8_t remainder = unpacked_length % 7; + if (remainder) + return (unpacked_length / 7) * 8 + remainder + 1; + else + return (unpacked_length / 7) * 8; +} + +uint16_t sysex_bit_unpacked_length(uint16_t packed_length){ + uint8_t remainder = packed_length % 8; + if (remainder) + return (packed_length / 8) * 7 + remainder - 1; + else + return (packed_length / 8) * 7; +} + +uint16_t sysex_bit_pack(uint8_t *packed, const uint8_t *source, const uint16_t length){ + uint16_t packed_full = length / 7; //number of full 8 byte sections from 7 bytes of input + uint16_t i,j; + + //fill out the fully packed sections + for(i = 0; i < packed_full; i++) { + uint16_t packed_msb_idx = i * 8; + uint16_t input_start_idx = i * 7; + packed[packed_msb_idx] = 0; + for(j = 0; j < 7; j++){ + uint8_t current = source[input_start_idx + j]; + packed[packed_msb_idx] |= (0x80 & current) >> (1 + j); + packed[packed_msb_idx + 1 + j] = 0x7F & current; + } + } + + //fill out the rest if there is any more + uint8_t remainder = length % 7; + if (remainder) { + uint16_t packed_msb_idx = packed_full * 8; + uint16_t input_start_idx = packed_full * 7; + packed[packed_msb_idx] = 0; + for(j = 0; j < remainder; j++){ + uint8_t current = source[input_start_idx + j]; + packed[packed_msb_idx] |= (0x80 & current) >> (1 + j); + packed[packed_msb_idx + 1 + j] = 0x7F & current; + } + return packed_msb_idx + remainder + 1; + } else { + return packed_full * 8; + } +} + +uint16_t sysex_bit_unpack(uint8_t *unpacked, const uint8_t *source, const uint16_t length){ + uint16_t unpacked_full = length / 8; + uint16_t i,j; + + if (length < 2) + return 0; + + //fill out the fully packed sections + for(i = 0; i < unpacked_full; i++) { + uint16_t packed_msb_idx = i * 8; + uint16_t output_start_index = i * 7; + for(j = 0; j < 7; j++){ + unpacked[output_start_index + j] = 0x7F & source[packed_msb_idx + j + 1]; + unpacked[output_start_index + j] |= (0x80 & (source[packed_msb_idx] << (1 + j))); + } + } + uint8_t remainder = length % 8; + if (remainder) { + uint16_t packed_msb_idx = unpacked_full * 8; + uint16_t output_start_index = unpacked_full * 7; + for(j = 0; j < (remainder - 1); j++) { + unpacked[output_start_index + j] = 0x7F & source[packed_msb_idx + j + 1]; + unpacked[output_start_index + j] |= (0x80 & (source[packed_msb_idx] << (1 + j))); + } + return unpacked_full * 7 + remainder - 1; + } else { + return unpacked_full * 7; + } +} + diff --git a/Libraries/avrmidi/sysex_tools.h b/Libraries/avrmidi/sysex_tools.h new file mode 100644 index 0000000..df86974 --- /dev/null +++ b/Libraries/avrmidi/sysex_tools.h @@ -0,0 +1,78 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#ifndef SYSEX_TOOLS_H +#define SYSEX_TOOLS_H + +#include + +/** + * These functions are for converting data to and from a "midi-safe" format, + * which can be use to send data with sysex messages. Sysex messages may only + * contain data where the to bit is not set. + * + * A bit "packed" midi message is one that contains all of the data from its + * original state, but does not have any of the top bits set. + * + * Every 7 bytes of unpacked data is converted into 8 bytes of packed data and + * visa-versa. If you'd like to operate on small segments, make sure that you + * pack in 7 byte increments and unpack in 8 byte increments. + * + */ + +/** + * Compute the length of a message after it is packed. + * + * @param unpacked_length The length, in bytes, of the message to pack. + * + * @return The length, in bytes, of the message after packing. + */ +uint16_t sysex_bit_packed_length(uint16_t unpacked_length); + +/** + * Compute the length of a message after it is unpacked. + * + * @param packed_length The length, in bytes, of the packed message. + * + * @return The length, in bytes, of the message after it is unpacked. + */ +uint16_t sysex_bit_unpacked_length(uint16_t packed_length); + +/** + * Pack data so that it can be transmitted safely in a sysex message. + * + * @param packed The output data buffer, must be at least sysex_bit_packed_length(length) bytes long. + * @param source The input buffer of data to be packed. + * @param length The number of bytes from the input buffer to pack. + * + * @return number of bytes packed. + */ +uint16_t sysex_bit_pack(uint8_t *packed, const uint8_t *source, uint16_t length); + +/** + * Unpack packed data. + * + * @param unpacked The output data buffer, must be at least sysex_bit_unpacked_length(length) bytes long. + * @param source The input buffer of data to be unpacked. + * @param length The number of bytes from the input buffer to unpack. + * + * @return number of bytes unpacked. + */ +uint16_t sysex_bit_unpack(uint8_t *unpacked, const uint8_t *source, uint16_t length); + +#endif diff --git a/Libraries/avrmidi/test/.gitignore b/Libraries/avrmidi/test/.gitignore new file mode 100644 index 0000000..9d58ef3 --- /dev/null +++ b/Libraries/avrmidi/test/.gitignore @@ -0,0 +1,3 @@ +test +sysex_test +dummy_test diff --git a/Libraries/avrmidi/test/Makefile b/Libraries/avrmidi/test/Makefile new file mode 100644 index 0000000..d0bcd48 --- /dev/null +++ b/Libraries/avrmidi/test/Makefile @@ -0,0 +1,28 @@ +CFLAGS += -I. -I../ -g -Wall -DDEBUG +DUMMY_SRC = dummy_device.c ../midi.c ../midi_device.c ../bytequeue.c ../interrupt_setting.c +DUMMY_OBJ = ${DUMMY_SRC:.c=.o} + +SYSEX_SRC = sysex_test.c ../sysex_tools.c +SYSEX_OBJ = ${SYSEX_SRC:.c=.o} + +.c.o: + @echo CC $< + @$(CC) -c $(CFLAGS) -o $*.o $< + +dummy_test: clean $(DUMMY_OBJ) + @$(CC) -o dummy_test $(DUMMY_OBJ) + +sysex_test: clean $(SYSEX_OBJ) + @$(CC) -o sysex_test $(SYSEX_OBJ) + +run_tests: sysex_test dummy_test + ./dummy_test + ./sysex_test + +all: run_tests + +#------------------- +clean: + rm -f *.o *.map *.out *.hex *.tar.gz ../*.o ../bytequeue/*.o dummy_test sysex_test +#------------------- + diff --git a/Libraries/avrmidi/test/avr/interrupt.h b/Libraries/avrmidi/test/avr/interrupt.h new file mode 100644 index 0000000..8770647 --- /dev/null +++ b/Libraries/avrmidi/test/avr/interrupt.h @@ -0,0 +1,27 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#ifndef FAKE_AVR_INTERRUPTS_H +#define FAKE_AVR_INTERRUPTS_H + +static uint8_t SREG = 0; + +void cli(void) { +} + +#endif diff --git a/Libraries/avrmidi/test/dummy_device.c b/Libraries/avrmidi/test/dummy_device.c new file mode 100644 index 0000000..b76439b --- /dev/null +++ b/Libraries/avrmidi/test/dummy_device.c @@ -0,0 +1,283 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#include "midi_device.h" +#include "midi.h" +#include +#include +#include "bytequeue.h" + +#define Q_BUFLEN 8 +uint8_t buf[Q_BUFLEN]; +byteQueue_t queue; + +MidiDevice test_device; + +uint8_t sent[3]; +uint8_t got[16]; + +bool cc_called; +bool noteon_called; +bool noteoff_called; +bool aftertouch_called; +bool pitchbend_called; +bool songposition_called; +bool progchange_called; +bool chanpressure_called; +bool songselect_called; +bool tc_quarterframe_called; +bool realtime_called; +bool tunerequest_called; +bool fallthrough_called; + + +void send_func(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) { + sent[0] = byte0; + sent[1] = byte1; + sent[2] = byte0; + printf("sent: "); + uint8_t i; + for (i = 0; i < cnt; i++) { + printf("%02x ", sent[i]); + } + printf("\n"); +} + +void cc_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + cc_called = true; + got[0] = byte0; + got[1] = byte1; + got[2] = byte2; +} +void noteon_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + noteon_called = true; + got[0] = byte0; + got[1] = byte1; + got[2] = byte2; +} +void noteoff_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + noteoff_called = true; + got[0] = byte0; + got[1] = byte1; + got[2] = byte2; +} +void aftertouch_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + aftertouch_called = true; + got[0] = byte0; + got[1] = byte1; + got[2] = byte2; +} +void pitchbend_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + pitchbend_called = true; + got[0] = byte0; + got[1] = byte1; + got[2] = byte2; +} +void songposition_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + songposition_called = true; + got[0] = byte0; + got[1] = byte1; + got[2] = byte2; +} + +void progchange_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1){ + progchange_called = true; + got[0] = byte0; + got[1] = byte1; +} +void chanpressure_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1){ + chanpressure_called = true; + got[0] = byte0; + got[1] = byte1; +} +void songselect_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1){ + songselect_called = true; + got[0] = byte0; + got[1] = byte1; +} +void tc_quarterframe_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1){ + tc_quarterframe_called = true; + got[0] = byte0; + got[1] = byte1; +} + +void realtime_callback(MidiDevice * device, uint8_t byte){ + realtime_called = true; + got[0] = byte; +} +void tunerequest_callback(MidiDevice * device, uint8_t byte){ + tunerequest_called = true; + got[0] = byte; +} + +void fallthrough_callback(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + fallthrough_called = true; + got[0] = byte0; + got[1] = byte1; + got[2] = byte2; +} + +void sysex_callback(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + fallthrough_called = true; + static int index = 0; + fallthrough_called = true; + switch (cnt) + { + case 3 : + got[index+2] = byte2; + case 2: + got[index+1] = byte1; + case 1: + got[index+0] = byte0; + } + index += cnt; +} + +void reset() { + uint8_t i; + for(i = 0; i < 3; i++) + got[i] = sent[i] = 0; + cc_called = false; + noteon_called = false; + noteoff_called = false; + aftertouch_called = false; + pitchbend_called = false; + songposition_called = false; + progchange_called = false; + chanpressure_called = false; + songselect_called = false; + tc_quarterframe_called = false; + realtime_called = false; + tunerequest_called = false; + fallthrough_called = false; +} + +bool anything_called() { + return cc_called || + noteon_called || + noteoff_called || + aftertouch_called || + pitchbend_called || + songposition_called || + progchange_called || + chanpressure_called || + songselect_called || + tc_quarterframe_called || + realtime_called || + tunerequest_called || + fallthrough_called; +} + +int main(void) { + bytequeue_init(&queue, buf, Q_BUFLEN); + uint8_t i; + for (i = 0; i < Q_BUFLEN - 1; i++) + { + assert(bytequeue_enqueue(&queue, i)); + assert(bytequeue_length(&queue) == i+1); + } + assert(!bytequeue_enqueue(&queue, 0)); + bytequeue_remove(&queue, bytequeue_length(&queue)); + assert(bytequeue_length(&queue) == 0); + for (i = 0; i < Q_BUFLEN - 1; i++) + { + assert(bytequeue_enqueue(&queue, i)); + assert(bytequeue_length(&queue) == i+1); + } + for (i = 0; i < Q_BUFLEN - 1; i++) + { + bytequeue_remove(&queue, 1); + } + assert(bytequeue_length(&queue) == 0); + + midi_device_init(&test_device); + midi_device_set_send_func(&test_device, send_func); + + midi_send_cc(&test_device, 0, 0, 1); + midi_send_cc(&test_device, 15, 1, 1); + + midi_register_fallthrough_callback(&test_device, fallthrough_callback); + midi_register_realtime_callback(&test_device, realtime_callback); + + assert(!fallthrough_called); + assert(!realtime_called); + midi_device_input(&test_device, 3, 0xB0, 0, 1); + midi_device_input(&test_device, 1, MIDI_CLOCK, 0, 0); + midi_device_process(&test_device); + assert(fallthrough_called); + assert(realtime_called); + + reset(); + assert(!fallthrough_called); + assert(!realtime_called); + //interspersed + midi_device_input(&test_device, 1, 0xB0, 0, 0); + midi_device_input(&test_device, 1, MIDI_CLOCK, 0, 0); + midi_device_input(&test_device, 1, 0, 0, 0); + midi_device_input(&test_device, 1, MIDI_START, 0, 0); + midi_device_input(&test_device, 1, 1, 0, 0); + midi_device_process(&test_device); + assert(fallthrough_called); + assert(realtime_called); + + midi_register_cc_callback(&test_device, cc_callback); + assert(!cc_called); + midi_device_input(&test_device, 3, 0xB0, 0, 1); + midi_device_process(&test_device); + assert(cc_called); + + reset(); + assert(!cc_called); + assert(!realtime_called); + midi_device_input(&test_device, 1, 0xB0, 0, 0); + midi_device_input(&test_device, 1, MIDI_CLOCK, 0, 0); + midi_device_input(&test_device, 1, 0, 0, 0); + midi_device_input(&test_device, 1, MIDI_START, 0, 0); + midi_device_input(&test_device, 1, 1, 0, 0); + midi_device_process(&test_device); + assert(cc_called); + assert(realtime_called); + + reset(); + assert(!anything_called()); + midi_device_input(&test_device, 1, 0xB0, 0, 0); + midi_device_input(&test_device, 1, 0, 0, 0); + midi_device_process(&test_device); + assert(!anything_called()); + + midi_register_fallthrough_callback(&test_device, sysex_callback); + midi_device_input(&test_device, 3, SYSEX_BEGIN, 0, 1); + midi_device_input(&test_device, 3, 2, 3, 4); + midi_device_input(&test_device, 2, 5, 6, 0); + midi_device_input(&test_device, 1, 7, 0, 0); + midi_device_input(&test_device, 1, SYSEX_END, 0, 0); + midi_device_process(&test_device); + + assert(fallthrough_called); + assert(got[0] == SYSEX_BEGIN); +// uint8_t i; + for (i = 0; i < 8; i++) + assert(got[i+1] == i); + assert(got[9] == SYSEX_END); + + assert(midi_packet_length(MIDI_NOTEON) == 3); + assert(midi_packet_length(MIDI_CLOCK) == 1); + + printf("\n\nTEST PASSED!\n\n"); + return 0; +} diff --git a/Libraries/avrmidi/test/dummy_device.h b/Libraries/avrmidi/test/dummy_device.h new file mode 100644 index 0000000..e69de29 diff --git a/Libraries/avrmidi/test/sysex_test.c b/Libraries/avrmidi/test/sysex_test.c new file mode 100644 index 0000000..73a1915 --- /dev/null +++ b/Libraries/avrmidi/test/sysex_test.c @@ -0,0 +1,79 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#include "sysex_tools.h" +#include +#include +#include +#include +#include + +#define SIZE 1028 + +int main(int argc, char * argv[]) { + unsigned int i, j; + uint8_t orig[SIZE]; + uint8_t unpacked[SIZE]; + uint8_t * packed = malloc(sizeof(uint8_t) * sysex_bit_packed_length(SIZE)); + uint8_t * packed2 = malloc(sizeof(uint8_t) * sysex_bit_packed_length(SIZE)); + + for(i = 0; i < SIZE; i++) + orig[i] = rand() & 0xFF; + + for (i = 1; i < 512; i++) { + assert(i == sysex_bit_unpacked_length(sysex_bit_packed_length(i))); + } + + //test byte packing + for (i = 1; i < SIZE; i++) { + uint16_t res_size0 = sysex_bit_pack(packed, orig, i); + uint16_t res_size1 = sysex_bit_packed_length(i); + //printf("packed %d == %d\n", res_size0, res_size1); + assert(res_size0 == res_size1); + //make sure that the top bit isn't set + for (j = 0; j < res_size0; j++) + assert( (packed[i] & 0x80) == 0); + //just in case, zero out unpacked.. + memset(unpacked, SIZE, 0); + res_size1 = sysex_bit_unpack(unpacked, packed, res_size0); + assert(i == sysex_bit_unpacked_length(res_size0)); + //printf("unpacked %d == %d\n", res_size1, i); + assert(res_size1 == i); + res_size0 = memcmp(orig, unpacked, i); + assert(0 == res_size0); + } + + for (i = 0, j = 0; i < (SIZE - 7); i += 7, j +=8) { + //pack in segments + assert(8 == sysex_bit_pack(packed2 + j, orig + i, 7)); + } + + for (i = 0, j = 0; i < (SIZE - 7); i += 7, j +=8) { + //pack in segments + assert(7 == sysex_bit_unpack(unpacked + i, packed2 + j, 8)); + } + //make sure the unpacked contents are the same length + assert(0 == memcmp(unpacked, orig, SIZE - 7)); + //make sure that packing in 7 byte segments is the same as packing all at once + assert(0 == memcmp(packed2, packed, sysex_bit_packed_length(SIZE - 7))); + + free(packed); + + printf("\n%s passed!\n\n", argv[0]); + return 0; +} diff --git a/Libraries/twi/twi.c b/Libraries/twi/twi.c new file mode 100644 index 0000000..73c4d54 --- /dev/null +++ b/Libraries/twi/twi.c @@ -0,0 +1,274 @@ +/* + twi.c - TWI/I2C library for Wiring & Arduino + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include + +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif + +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + +#include "twi.h" + +static volatile uint8_t twi_state; + +static void (*twi_onSlaveTransmit)(void); +static uint8_t (*twi_onSlaveReceive)(uint8_t); + +uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_txBufferIndex; +static volatile uint8_t twi_txBufferLength; + +static volatile uint8_t twi_error; + +/* + * Function twi_init + * Desc readys twi pins and sets twi bitrate + * Input none + * Output none + */ +void twi_init(void) +{ + // initialize state + twi_state = TWI_READY; + + #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__) + // activate internal pull-ups for twi + // as per note from atmega8 manual pg167 + sbi(PORTC, 4); + sbi(PORTC, 5); + #else + // activate internal pull-ups for twi + // as per note from atmega128 manual pg204 + sbi(PORTD, 0); + sbi(PORTD, 1); + #endif + + // initialize twi prescaler and bit rate + cbi(TWSR, TWPS0); + cbi(TWSR, TWPS1); + TWBR = ((CPU_FREQ / TWI_FREQ) - 16) / 2; + + /* twi bit rate formula from atmega128 manual pg 204 + SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR)) + note: TWBR should be 10 or higher for master mode + It is 72 for a 16mhz Wiring board with 100kHz TWI */ + + // enable twi module, acks, and twi interrupt + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA); +} + +/* + * Function twi_slaveInit + * Desc sets slave address and enables interrupt + * Input none + * Output none + */ +void twi_setAddress(uint8_t address) +{ + // set twi slave address (skip over TWGCE bit) + TWAR = address << 1; +} + +/* + * Function twi_transmit + * Desc fills slave tx buffer with data + * must be called in slave tx event callback + * Input data: pointer to byte array + * length: number of bytes in array + * Output 1 length too long for buffer + * 2 not slave transmitter + * 0 ok + */ +uint8_t twi_transmit(uint8_t* data, uint8_t length) +{ + uint8_t i; + + // ensure data will fit into buffer + if(TWI_BUFFER_LENGTH < length){ + return 1; + } + + // ensure we are currently a slave transmitter + if(TWI_STX != twi_state){ + return 2; + } + + // set length and copy data into tx buffer + twi_txBufferLength = length; + for(i = 0; i < length; ++i){ + twi_txBuffer[i] = data[i]; + } + + return 0; +} + +/* + * Function twi_attachSlaveRxEvent + * Desc sets function called before a slave read operation + * Input function: callback function to use + * Output none + */ +void twi_attachSlaveRxEvent( uint8_t (*function)(uint8_t) ) +{ + twi_onSlaveReceive = function; +} + +/* + * Function twi_attachSlaveTxEvent + * Desc sets function called before a slave write operation + * Input function: callback function to use + * Output none + */ +void twi_attachSlaveTxEvent( void (*function)(void) ) +{ + twi_onSlaveTransmit = function; +} + +/* + * Function twi_reply + * Desc sends byte or readys receive line + * Input ack: byte indicating to ack or to nack + * Output none + */ +void twi_reply(uint8_t ack) +{ + // transmit master read ready signal, with or without ack + if(ack){ + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); + }else{ + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); + } +} + +/* + * Function twi_stop + * Desc relinquishes bus master status + * Input none + * Output none + */ +void twi_stop(void) +{ + // send stop condition + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); + + // wait for stop condition to be exectued on bus + // TWINT is not set after a stop condition! + while(TWCR & _BV(TWSTO)){ + continue; + } + + // update twi state + twi_state = TWI_READY; +} + +/* + * Function twi_releaseBus + * Desc releases bus control + * Input none + * Output none + */ +void twi_releaseBus(void) +{ + // release bus + TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); + + // update twi state + twi_state = TWI_READY; +} + +SIGNAL(TWI_vect) +{ + switch(TW_STATUS){ + // Slave Receiver + case TW_SR_SLA_ACK: // addressed, returned ack + case TW_SR_GCALL_ACK: // addressed generally, returned ack + case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack + case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack + // enter slave receiver mode + twi_state = TWI_SRX; + // indicate that rx buffer can be overwritten and ack + twi_reply(1); + break; + case TW_SR_DATA_ACK: // data received, returned ack + case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack + // if there is still room in the rx buffer + twi_reply(twi_onSlaveReceive(TWDR)); + break; + case TW_SR_STOP: // stop or repeated start condition received + // sends ack and stops interface for clock stretching + twi_stop(); + // ack future responses and leave slave receiver state + //twi_releaseBus(); + break; + case TW_SR_DATA_NACK: // data received, returned nack + case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack + // nack back at master + twi_reply(1); + break; + + // Slave Transmitter + case TW_ST_SLA_ACK: // addressed, returned ack + case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack + // enter slave transmitter mode + twi_state = TWI_STX; + // ready the tx buffer index for iteration + twi_txBufferIndex = 0; + // set tx buffer length to be zero, to verify if user changes it + twi_txBufferLength = 0; + // request for txBuffer to be filled and length to be set + // note: user must call twi_transmit(bytes, length) to do this + twi_onSlaveTransmit(); + // transmit first byte from buffer, fall + case TW_ST_DATA_ACK: // byte sent, ack returned + // copy data to output register + TWDR = twi_txBuffer[twi_txBufferIndex++]; + // if there is more to send, ack, otherwise nack + if(twi_txBufferIndex < twi_txBufferLength){ + twi_reply(1); + }else{ + twi_reply(0); + } + break; + case TW_ST_DATA_NACK: // received nack, we are done + case TW_ST_LAST_DATA: // received ack, but we are done already! + // ack future responses + twi_reply(1); + // leave slave receiver state + twi_state = TWI_READY; + break; + + // All + case TW_NO_INFO: // no state information + break; + case TW_BUS_ERROR: // bus error, illegal stop/start + twi_error = TW_BUS_ERROR; + twi_stop(); + break; + } +} + diff --git a/Libraries/twi/twi.h b/Libraries/twi/twi.h new file mode 100644 index 0000000..ad5746a --- /dev/null +++ b/Libraries/twi/twi.h @@ -0,0 +1,59 @@ +/* + twi.h - TWI/I2C library for Wiring & Arduino + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef twi_h +#define twi_h + + #include + + //#define ATMEGA8 + + #ifndef CPU_FREQ + #define CPU_FREQ 16000000L + #endif + + #ifndef TWI_FREQ + #define TWI_FREQ 100000L + #endif + + #ifndef TWI_BUFFER_LENGTH + #define TWI_BUFFER_LENGTH 96 + #endif + + #define TWI_READY 0 + #define TWI_MRX 1 + #define TWI_MTX 2 + #define TWI_SRX 3 + #define TWI_STX 4 + + void twi_init(void); + void twi_setAddress(uint8_t); + uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t); + uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t); + uint8_t twi_transmit(uint8_t*, uint8_t); + void twi_attachSlaveRxEvent( uint8_t (*)(uint8_t) ); + void twi_attachSlaveTxEvent( void (*)(void) ); + void twi_reply(uint8_t); + void twi_stop(void); + void twi_releaseBus(void); + +extern uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; + +#endif + diff --git a/MissingLink/HandleMidi.cpp b/MissingLink/HandleMidi.cpp new file mode 100644 index 0000000..1615e84 --- /dev/null +++ b/MissingLink/HandleMidi.cpp @@ -0,0 +1,543 @@ +/* + * MissingLink Firmware + * Copyright 2011 Jabrudian Industries LLC + * + * MissingLink Firmware 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. + * + * MissingLink Firmware 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 MissingLink Firmware. If not, see . + * + */ +#include +#include +#include +#include +#include "led.h" +#include "HandleMidi.h" +#include "MLSerial.h" +#include "WiShield.h" +#include "Parse.h" +#include "Output.h" +#include "wiring.h" +#include "udpapp.h" +#include "udpapp-ml.h" +extern "C" { +#include "midi.h" +#include "ML_Config.h" +#include "twi.h" +#include "bytequeue.h" +#include "uip.h" +} + +// +// Device stuff +// +static MidiDevice md_serial; +static MidiDevice md_usbToOSC; +static MidiDevice md_serialToOSC; + +// sysex +static uint8_t serial_sysex_index = 0; +static uint8_t serial_sysex_command = 0xFF; +static uint8_t usb_sysex_index = 0; +static uint8_t usb_sysex_command = 0xFF; + +// USB out (via I2C) +#define USB_OUT_BUFFER_SIZE 64 +static uint8_t usb_buff[USB_OUT_BUFFER_SIZE]; +static byteQueue_t usb_queue; + +uint8_t onReceiveService(uint8_t inByte); +void onRequestService(); +bool sendByteUSB(unsigned char b); + +void sendByte(unsigned char b) +{ + if ((fromOSC & TO_MIDI) == TO_MIDI) + { + Serial.write(b); + } + if ((fromOSC & TO_USBMIDI) == TO_USBMIDI) + { + sendByteUSB(b); + } +} + +void midi_send_serial(MidiDevice * device, uint8_t count, uint8_t byte0, uint8_t byte1, uint8_t byte2) { + uint8_t out[3]; + out[0] = byte0; + out[1] = byte1; + out[2] = byte2; + if (count > 3) + count = 3; + + uint8_t i; + for(i = 0; i < count; i++) { + Serial.write(out[i]); + } +} + +void midi_check_sysex(MidiDevice * device, uint8_t count, uint8_t byte0, uint8_t byte1, uint8_t byte2) +{ + // This below is a little hacky, but I think it's good for a couple of reasons. + if (device == &md_serial) + { + if ((fromMIDI & TO_MIDI) == TO_MIDI) + { + // Here we send a full packet in one blast, which will minimize chances of + // merge issues. (Still have long sysex to worry about) + midi_send_serial(&md_serial, count, byte0, byte1, byte2); + } + if ((fromMIDI & TO_USBMIDI) == TO_USBMIDI) + { + // Here we have a full packet for the host to grab. Less time of + // the host asking for packets repeatedly and we not being able to provide them. + uint8_t out[3]; + out[0] = byte0; + out[1] = byte1; + out[2] = byte2; + if (count > 3) + count = 3; + + uint8_t i; + for(i = 0; i < count; i++) { + sendByteUSB(out[i]); + } + } + } + + // Header contents: start, dev id, "M", "L", "N", "K", Command, Data, F7 + // TODO: PROGMEM this shit + // 240, 125, 77, 76, 78, 75, + static const uint8_t ML_HEADER[] = {0xF0, 0x7D, 0x4D, 0x4C, 0x4E, 0x4B}; + static const uint8_t ML_HEADER_LEN = 6; + + uint8_t in[3]; + in[0] = byte0; + in[1] = byte1; + in[2] = byte2; + if (count > 3) + count = 3; + + uint8_t& sysex_index = (device == &md_serial) ? serial_sysex_index : usb_sysex_index; + uint8_t& sysex_command = (device == &md_serial) ? serial_sysex_command : usb_sysex_command; + for (uint8_t i = 0; i < count; i++) + { + if (sysex_index < ML_HEADER_LEN) + { + if (in[i] == ML_HEADER[sysex_index]) + { + sysex_index++; + } else { + DEBUG_PRINTF("index: %d, mismatch: %d %d\n", sysex_index, in[i], ML_HEADER[sysex_index]); + sysex_index = 0; + } + DEBUG_PRINTF("csysindex: %d\n", sysex_index); + } else { + if (sysex_index == ML_HEADER_LEN) + { + if (in[i] != SYSEX_END) + { + sysex_command = in[i]; + DEBUG_PRINTF("ML SYSEX: %d\n", sysex_command); + sysex_index++; + } else { + sysex_index = 0; // reset + } + } else { + // dispatch + switch (sysex_command) + { + + case 0: // Reset configuration to defaut, (if we need to get aggressive about code size, kill this and use eeprom write, 0, 255, device reset to get back to defaults. + { + if (in[i] == SYSEX_END) + { + DEBUG_PRINTF("Resetting to default.\n"); + setDefaultConfig(); + sysex_index = 0xFF; + } + } + break; + case 2 : // write to eeprom location + { + static uint16_t eeprom_offset = 0; + static uint8_t currdata = 0; + uint16_t offset = sysex_index - ML_HEADER_LEN - 1; // for command + // Accumlate offset + if (offset < 4) + { + if (offset == 0) + eeprom_offset = 0; + DEBUG_PRINTF("\noffset: %d, %d\n", offset, in[i]); + eeprom_offset |= in[i] << ((3-offset)*4); + } else { + // Actually write data, we split 4 bits between two bytes (super inefficient, but simple) + offset -= 4; // 1 byte for command, 4 bytes for length + if (offset++%2 == 0) + { + currdata = in[i] << 4; + DEBUG_PRINTF("storing high byte: %d, offset: %d\n", currdata, offset); + } else { + currdata |= in[i]; + offset /= 2; // Since we use two bytes to store one byte of data + offset--; // -1 to account for the initial two bytes + eeprom_write_byte((uint8_t*) (eeprom_offset + offset), currdata); + DEBUG_PRINTF("writing %x @ offset %d\n", currdata, eeprom_offset + offset); + } + } + } + break; + case 1 : // Reset (handled by PIC) + break; + case 3 : // Enter AVR bootloader, handled on PIC + default: + sysex_index = 0xFF; // reset (the increment that happens will overflow to 0) + break; + } + + if (in[i] != SYSEX_END) + { + sysex_index++; + } else { + sysex_index = 0; // reset + } + } + } + } +} + +void sendMidiOSC(MidiDevice * device, uint8_t count, uint8_t byte0, uint8_t byte1, uint8_t byte2) +{ + uip_udp_prep_buffer(); + char* buf = (char*) uip_appdata; + // TODO: Progmem me + const char* msg = "/midi/0x"; + const uint8_t msglen = 8; + strcpy(buf, msg); + buf += msglen; + // Status byte + itoa(byte0, buf, 16); + buf += strlen(buf); + // First byte + if (count > 1) + { + *buf++ = ' '; + itoa(byte1, buf, 10); + buf += strlen(buf); + } + // Second byte + if (count > 2) + { + *buf++ = ' '; + *buf++ = 'x'; + } + // pad, add comma, typetag, data + uint8_t pad = buf - (char*)uip_appdata; // current size + pad = ((pad+4)&0xFC) - pad; + // Clear this gap. + for (uint8_t i = 0; i < pad; i++) + { + *buf++ = 0; + } + // comma + *buf++ = ','; + if (count > 2) + { + // typetag + *buf++ = 'f'; + *buf++ = 0; + *buf++ = 0; + // data + float data = ((float) byte2) / 127.0f; + uint8_t* tmpptr = (uint8_t*) &data; + *buf++ = *(tmpptr+3); + *buf++ = *(tmpptr+2); + *buf++ = *(tmpptr+1); + *buf++ = *(tmpptr+0); + } + sendAppBuffer(buf - (char*)uip_appdata, oscTargetIp[0], oscTargetIp[1], oscTargetIp[2], oscTargetIp[3], oscTargetPort); + WiFi.sendUdp(); +} + +void missinglink_init_midi() +{ + midi_device_init(&md_serial); + midi_device_set_send_func(&md_serial, midi_send_serial); + midi_register_fallthrough_callback(&md_serial, midi_check_sysex); + + midi_device_init(&md_usbToOSC); + midi_register_fallthrough_callback(&md_usbToOSC, sendMidiOSC); + midi_device_init(&md_serialToOSC); + midi_register_fallthrough_callback(&md_serialToOSC, sendMidiOSC); + + bytequeue_init(&usb_queue, usb_buff, USB_OUT_BUFFER_SIZE); + + twi_setAddress(4); + twi_attachSlaveTxEvent(onRequestService); + twi_attachSlaveRxEvent(onReceiveService); + twi_init(); +} + +void missinglink_midi_process() +{ + // Serial + uint8_t amt = Serial.available(); + if (amt > 3) + amt = 3; + uint8_t buf[3]; + for (uint8_t i = 0; i < amt; i++) + buf[i] = Serial.read(); + midi_device_input(&md_serial, amt, buf[0], buf[1], buf[2]); + midi_device_process(&md_serial); + + // Blink LED, main loop will reset back + if (amt > 0 && canBlink()) + { + LED_RED; + } + + // Serial to OSC + if ((fromMIDI & TO_OSC) == TO_OSC) + { + midi_device_input(&md_serialToOSC, amt, buf[0], buf[1], buf[2]); + midi_device_process(&md_serialToOSC); + } + + // Process this too! + if ((fromUSBMIDI & TO_OSC) == TO_OSC) + { + midi_device_process(&md_usbToOSC); + } +} + +// +// Message stuff +// +void handleSimpleMess(OSCMessage& oscMess, int msgOffset) +{ + const char* addr = oscMess.getOSCAddress(); + int addrLen = oscMess.getOSCAddressLen() - msgOffset; + const char* currOffset = addr + msgOffset; + + sendChunk(currOffset, addrLen, oscMess); +} + +// Handles a "touchosc midi" address which requires different parsing. +void handleTouchOSCMidi(OSCMessage& oscMess, void* userArg) +{ + MessageInfo mi; + if (!getMessageInfo(oscMess, mi)) + return; + if (mi.isZ) + return; + // For any message without variable, send only when x > 0 + if (!mi.hasX && !mi.hasY && oscMess.getArgsNum() > 0) + { + if (!(getTouchArg(oscMess, 0, 1.0f, 0.0f) > 0.0f)) + return; + } + handleSimpleMess(oscMess, 6); // /midi/ +} + +// Handles a "touchosc midi" address which requires different parsing. +void handleTouchOSCMidiZ(OSCMessage& oscMess, void* userArg) +{ + const char* addr = oscMess.getOSCAddress(); + int addrLen = oscMess.getOSCAddressLen() - 6; + + // Find the z on, x or x/y slide, and z off chunks + uint8_t chunks[4]; + const int startPos = 8; // len(/midi/z/) + chunks[0] = startPos; + uint8_t currChunk = 1; + for (uint8_t i = startPos; i < addrLen + 7 && currChunk < 4; i++) + { + if (addr[i] == '/') + { + chunks[currChunk++] = i; + } + } + if (currChunk < 3) + return; // bad message + + // Ok, if currChunk == 3 then it's an x or x/y message (since the /z will be missing from the address) + if (currChunk == 3) + { + sendChunk(addr + (chunks[1]), chunks[2] - chunks[1], oscMess); + } else { + if (oscMess.getFloat(0) > 0.0f) + { + // push down + sendChunk(addr + (chunks[0]), chunks[1] - chunks[0], oscMess); + } else { + // push up + sendChunk(addr + (chunks[2]), chunks[3] - chunks[2], oscMess); + } + } +} + +// Handles a "touchosc midi" address which requires different parsing. +void handleMidiButton(OSCMessage& oscMess, void* userArg) +{ + const char* addr = oscMess.getOSCAddress(); + int addrLen = oscMess.getOSCAddressLen(); + + MessageInfo mi; + if (!getMessageInfo(oscMess, mi)) + return; + if (mi.isZ) + return; + + // Find the z on, x or x/y slide, and z off chunks + const int startPos = 13; // len(/midi/button/) + uint8_t chunks[2] = {startPos, startPos}; + uint8_t currChunk = 1; + for (uint8_t i = startPos; addr[i] != 0 && currChunk < 2; i++) + { + if (addr[i] == '/') + { + chunks[currChunk++] = i; + } + } + if (currChunk < 2) + return; // bad message + + // Ok, if currChunk == 3 then it's an x or x/y message (since the /z will be missing from the address) + if (oscMess.getFloat(0) > 0.0f) + { + // push down + sendChunk(addr + chunks[0], chunks[1] - chunks[0], oscMess); + } else { + // push up + sendChunk(addr + chunks[1], addrLen - chunks[1], oscMess); + } +} + +// USB IN -> MIDI OUT +void setDataReadyFlag() +{ + if (bytequeue_length(&usb_queue) > 0) + { + PORTC |= _BV(1); // on! + } else { + PORTC &= ~(_BV(1)); // off! + } +} + +bool sendByteUSB(unsigned char b) +{ + bool ret = bytequeue_enqueue(&usb_queue, b); + setDataReadyFlag(); + return ret; +} + +uint8_t onReceiveService(uint8_t inByte) +{ + if ((fromUSBMIDI & TO_USBMIDI) == TO_USBMIDI) + { + if (!sendByteUSB(inByte) || + (bytequeue_length((byteQueue_t*) &usb_queue) >= USB_OUT_BUFFER_SIZE - 1)) + { + return 0; + } + } + midi_check_sysex(NULL, 1, inByte, 0, 0); + if ((fromUSBMIDI & TO_MIDI) == TO_MIDI) + { + Serial.write(inByte); + } + if ((fromUSBMIDI & TO_OSC) == TO_OSC) + { + midi_device_input(&md_usbToOSC, 1, inByte, 0, 0); + } + return 1; +} + +void onRequestService() +{ + unsigned char out[5]; + // SYSEX message can span multiple packets, so we need to store that state. + static uint8_t usb_in_sysex_mode = 0; + + // Figure out lengths, we never send more than 3 bytes at a time + uint8_t qlen = bytequeue_length(&usb_queue); + if (qlen > 3) + qlen = 3; + uint8_t midi_packet_len = 0; + + // Figure out how much data to send + if (qlen > 0) + { + uint8_t status_byte = bytequeue_get(&usb_queue, 0); + if (status_byte == SYSEX_BEGIN) + { + usb_in_sysex_mode = 1; + } else { + midi_packet_len = midi_packet_length(status_byte); + } + } + + if (usb_in_sysex_mode == 0) + { + // Not a sysex message, just wait until we have all the data we need and + // send it off. + if (qlen >= midi_packet_len) + { + if (midi_packet_len > 0) + { + out[0] = 4; + out[1] = bytequeue_get(&usb_queue, 0) >> 4; + for (uint8_t i = 0; i < midi_packet_len; i++) + { + out[i+2] = bytequeue_get(&usb_queue, i); + } + bytequeue_remove(&usb_queue, midi_packet_len); + } else { + // Hrm, we're not in sysex mode and there's no status byte. Just consume + // the byte + bytequeue_remove(&usb_queue, 1); + } + } + } else { + // Search ahead for sysex_end + uint8_t end = 0xFF; + for (uint8_t i = 0; i < qlen; i++) + { + if (bytequeue_get(&usb_queue, i) == SYSEX_END) + { + end = i+1; + usb_in_sysex_mode = 0; + break; + } + } + // If this is the end of a message, or we have a full packet, send it. + if ((end != 0xFF) || (qlen >= 3)) + { + out[0] = 4; + // Figure out sysex flag byte + out[1] = 0x4 + (end != 0xFF ? end : 0); + // Loop until sysex_end or buffer end + uint8_t consume = end != 0xFF ? end : 3; + for (uint8_t i = 0; i < consume; i++) + { + out[i+2] = bytequeue_get(&usb_queue, i); + } + bytequeue_remove(&usb_queue, consume); + } + } + // Finally, let's send this data! + twi_transmit(out, out[0]+1); + if (bytequeue_length(&usb_queue) == 0) + { + PORTC &= ~(_BV(1)); + } +} diff --git a/MissingLink/HandleMidi.h b/MissingLink/HandleMidi.h new file mode 100644 index 0000000..80928fc --- /dev/null +++ b/MissingLink/HandleMidi.h @@ -0,0 +1,59 @@ +/* + * MissingLink Firmware + * Copyright 2011 Jabrudian Industries LLC + * + * MissingLink Firmware 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. + * + * MissingLink Firmware 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 MissingLink Firmware. If not, see . + * + */ +#ifndef _HANDLEMIDI_H_ +#define _HANDLEMIDI_H_ + +#include "OSCMessage.h" + +// Setup/process +void missinglink_init_midi(); +void missinglink_midi_process(); + +// Message handlers +void handleTouchOSCMidi(OSCMessage& oscMess, void* userArg); +void handleTouchOSCMidiZ(OSCMessage& oscMess, void* userArg); +void handleMidiButton(OSCMessage& oscmess, void* userArg); + +void handleMidiStart(OSCMessage& ocsMess, void* userArg); +void handleMidiContinue(OSCMessage& ocsMess, void* userArg); +void handleMidiStop(OSCMessage& ocsMess, void* userArg); +void handleMidiReset(OSCMessage& ocsMess, void* userArg); +void handleMidiTune(OSCMessage& ocsMess, void* userArg); +void handleMidiSong(OSCMessage& oscMess, void* userArg); +void handleMidiSysex(OSCMessage& oscMess, void* userArg); + +void handleChannelNoteOn(OSCMessage& oscMess, void* userArg); +void handleChannelNoteOff(OSCMessage& oscMess, void* userArg); +void handleChannelCC(OSCMessage& oscMess, void* userArg); +void handleChannelAftertouch(OSCMessage& oscMess, void* userArg); +void handleChannelPitch(OSCMessage& oscMess, void* userArg); +void handleChannelPatch(OSCMessage& oscMess, void* userArg); +void handleChannelPressure(OSCMessage& oscMess, void* userArg); + +// I2C/USB midi +void receiveEvent(int howMany); +void requestEvent(); + +struct ChannelMsgInfo +{ + char* messageOffset; + int channel; +}; + +#endif diff --git a/MissingLink/MLSerial.cpp b/MissingLink/MLSerial.cpp new file mode 100644 index 0000000..681a367 --- /dev/null +++ b/MissingLink/MLSerial.cpp @@ -0,0 +1,255 @@ +/* + * MissingLink Firmware + * Copyright 2011 Jabrudian Industries LLC + * + * MissingLink Firmware 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. + * + * MissingLink Firmware 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 MissingLink Firmware. If not, see . + * + */ + +/* + HardwareSerial.cpp - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis +*/ + +#include +#include +#include +#include +#include "wiring.h" +#include "wiring_private.h" + +#include "MLSerial.h" + +// Define constants and variables for buffering incoming serial data. We're +// using a ring buffer (I think), in which rx_buffer_head is the index of the +// location to which to write the next incoming character and rx_buffer_tail +// is the index of the location from which to read. +#define RX_BUFFER_SIZE 32 + +struct ring_buffer { + unsigned char buffer[RX_BUFFER_SIZE]; + int head; + int tail; +}; + +ring_buffer rx_buffer = { { 0 }, 0, 0 }; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +ring_buffer rx_buffer1 = { { 0 }, 0, 0 }; +ring_buffer rx_buffer2 = { { 0 }, 0, 0 }; +ring_buffer rx_buffer3 = { { 0 }, 0, 0 }; +#endif + +inline void store_char(unsigned char c, ring_buffer *rx_buffer) +{ + int i = (rx_buffer->head + 1) % RX_BUFFER_SIZE; + + // if we should be storing the received character into the location + // just before the tail (meaning that the head would advance to the + // current location of the tail), we're about to overflow the buffer + // and so we don't write the character or advance the head. + if (i != rx_buffer->tail) { + rx_buffer->buffer[rx_buffer->head] = c; + rx_buffer->head = i; + } +} + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + +SIGNAL(SIG_USART0_RECV) +{ + unsigned char c = UDR0; + store_char(c, &rx_buffer); +} + +SIGNAL(SIG_USART1_RECV) +{ + unsigned char c = UDR1; + store_char(c, &rx_buffer1); +} + +SIGNAL(SIG_USART2_RECV) +{ + unsigned char c = UDR2; + store_char(c, &rx_buffer2); +} + +SIGNAL(SIG_USART3_RECV) +{ + unsigned char c = UDR3; + store_char(c, &rx_buffer3); +} + +#else + +#if defined(__AVR_ATmega8__) +SIGNAL(SIG_UART_RECV) +#else +SIGNAL(USART_RX_vect) +#endif +{ +#if defined(__AVR_ATmega8__) + unsigned char c = UDR; +#else + unsigned char c = UDR0; +#endif + store_char(c, &rx_buffer); +} + +#endif + +// Constructors //////////////////////////////////////////////////////////////// + +HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, + volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *udr, + uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x) +{ + _rx_buffer = rx_buffer; + _ubrrh = ubrrh; + _ubrrl = ubrrl; + _ucsra = ucsra; + _ucsrb = ucsrb; + _udr = udr; + _rxen = rxen; + _txen = txen; + _rxcie = rxcie; + _udre = udre; + _u2x = u2x; +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void HardwareSerial::begin(long baud) +{ + uint16_t baud_setting; + bool use_u2x; + + // U2X mode is needed for baud rates higher than (CPU Hz / 16) + if (baud > F_CPU / 16) { + use_u2x = true; + } else { + // figure out if U2X mode would allow for a better connection + + // calculate the percent difference between the baud-rate specified and + // the real baud rate for both U2X and non-U2X mode (0-255 error percent) + uint8_t nonu2x_baud_error = abs((int)(255-((F_CPU/(16*(((F_CPU/8/baud-1)/2)+1))*255)/baud))); + uint8_t u2x_baud_error = abs((int)(255-((F_CPU/(8*(((F_CPU/4/baud-1)/2)+1))*255)/baud))); + + // prefer non-U2X mode because it handles clock skew better + use_u2x = (nonu2x_baud_error > u2x_baud_error); + } + + if (use_u2x) { + *_ucsra = 1 << _u2x; + baud_setting = (F_CPU / 4 / baud - 1) / 2; + } else { + *_ucsra = 0; + baud_setting = (F_CPU / 8 / baud - 1) / 2; + } + + // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) + *_ubrrh = baud_setting >> 8; + *_ubrrl = baud_setting; + + sbi(*_ucsrb, _rxen); + sbi(*_ucsrb, _txen); + sbi(*_ucsrb, _rxcie); +} + +void HardwareSerial::end() +{ + cbi(*_ucsrb, _rxen); + cbi(*_ucsrb, _txen); + cbi(*_ucsrb, _rxcie); +} + +int HardwareSerial::available(void) +{ + return (RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RX_BUFFER_SIZE; +} + +int HardwareSerial::peek(void) +{ + if (_rx_buffer->head == _rx_buffer->tail) { + return -1; + } else { + return _rx_buffer->buffer[_rx_buffer->tail]; + } +} + +int HardwareSerial::read(void) +{ + // if the head isn't ahead of the tail, we don't have any characters + if (_rx_buffer->head == _rx_buffer->tail) { + return -1; + } else { + unsigned char c = _rx_buffer->buffer[_rx_buffer->tail]; + _rx_buffer->tail = (_rx_buffer->tail + 1) % RX_BUFFER_SIZE; + return c; + } +} + +void HardwareSerial::flush() +{ + // don't reverse this or there may be problems if the RX interrupt + // occurs after reading the value of rx_buffer_head but before writing + // the value to rx_buffer_tail; the previous value of rx_buffer_head + // may be written to rx_buffer_tail, making it appear as if the buffer + // don't reverse this or there may be problems if the RX interrupt + // occurs after reading the value of rx_buffer_head but before writing + // the value to rx_buffer_tail; the previous value of rx_buffer_head + // may be written to rx_buffer_tail, making it appear as if the buffer + // were full, not empty. + _rx_buffer->head = _rx_buffer->tail; +} + +void HardwareSerial::write(uint8_t c) +{ + while (!((*_ucsra) & (1 << _udre))) + ; + + *_udr = c; +} + +// Preinstantiate Objects ////////////////////////////////////////////////////// + +#if defined(__AVR_ATmega8__) +HardwareSerial Serial(&rx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRE, U2X); +#else +HardwareSerial Serial(&rx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0, U2X0); +#endif + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +HardwareSerial Serial1(&rx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRE1, U2X1); +HardwareSerial Serial2(&rx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UDR2, RXEN2, TXEN2, RXCIE2, UDRE2, U2X2); +HardwareSerial Serial3(&rx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRE3, U2X3); +#endif diff --git a/MissingLink/MLSerial.h b/MissingLink/MLSerial.h new file mode 100644 index 0000000..cf0fa58 --- /dev/null +++ b/MissingLink/MLSerial.h @@ -0,0 +1,86 @@ +/* + * MissingLink Firmware + * Copyright 2011 Jabrudian Industries LLC + * + * MissingLink Firmware 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. + * + * MissingLink Firmware 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 MissingLink Firmware. If not, see . + * + */ + +/* + HardwareSerial.h - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef HardwareSerial_h +#define HardwareSerial_h + +#include + +#include "Stream.h" + +struct ring_buffer; + +class HardwareSerial // : public Stream +{ + private: + ring_buffer *_rx_buffer; + volatile uint8_t *_ubrrh; + volatile uint8_t *_ubrrl; + volatile uint8_t *_ucsra; + volatile uint8_t *_ucsrb; + volatile uint8_t *_udr; + uint8_t _rxen; + uint8_t _txen; + uint8_t _rxcie; + uint8_t _udre; + uint8_t _u2x; + public: + HardwareSerial(ring_buffer *rx_buffer, + volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, + volatile uint8_t *ucsra, volatile uint8_t *ucsrb, + volatile uint8_t *udr, + uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x); + void begin(long); + void end(); + virtual int available(void); + virtual int peek(void); + virtual int read(void); + virtual void flush(void); + virtual void write(uint8_t); + //using Print::write; // pull in write(str) and write(buf, size) from Print +}; + +extern HardwareSerial Serial; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +extern HardwareSerial Serial1; +extern HardwareSerial Serial2; +extern HardwareSerial Serial3; +#endif + +#endif diff --git a/MissingLink/ML_Config.c b/MissingLink/ML_Config.c new file mode 100644 index 0000000..22bde18 --- /dev/null +++ b/MissingLink/ML_Config.c @@ -0,0 +1,130 @@ +/* + * MissingLink Firmware + * Copyright 2011 Jabrudian Industries LLC + * + * MissingLink Firmware 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. + * + * MissingLink Firmware 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 MissingLink Firmware. If not, see . + * + */ +#include "ML_Config.h" +#include +#include +#include +#include "config.h" +#include "Output.h" + +// Wireless params +unsigned char wireless_mode = WIRELESS_MODE_ADHOC; +unsigned char security_type = 0; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2 + +// TCP/IP params +unsigned char local_ip[] = {192,168,1,100}; // IP address of WiShield +unsigned char gateway_ip[] = {192,168,1,1}; // router or gateway IP address +unsigned char subnet_mask[] = {255,255,255,0}; // subnet mask for the local network + +// MIDI routing params +unsigned char fromMIDI; +unsigned char fromUSBMIDI; +unsigned char fromOSC; + +// For MIDI->OSC routing +unsigned char oscTargetSet = 0; +unsigned char oscTargetIp[] = {0, 0, 0, 0}; +uint16_t oscTargetPort = 12345; + +void setDefaultConfig() +{ + MissingLinkConfig mlconfig; + memset(&mlconfig, 0, sizeof(mlconfig)); + mlconfig.version = CURR_CONFIG_VERSION; + mlconfig.wireless_mode = WIRELESS_MODE_ADHOC; // adhoc + strcpy_P(mlconfig.ssid, PSTR("MissingLink")); + mlconfig.security_type = 0; + mlconfig.local_ip[0] = 192; + mlconfig.local_ip[1] = 168; + mlconfig.local_ip[2] = 1; + mlconfig.local_ip[3] = 100; + mlconfig.subnet_mask[0] = 255; + mlconfig.subnet_mask[1] = 255; + mlconfig.subnet_mask[2] = 255; + mlconfig.subnet_mask[3] = 0; + + mlconfig.fromMIDI = TO_MIDI; + mlconfig.fromUSBMIDI = 0; + mlconfig.fromOSC = TO_MIDI; + + mlconfig.oscTargetPort = 12345; + + eeprom_write_block(&mlconfig, 0, sizeof(MissingLinkConfig)); +} + +void dumpConfig() +{ +#if 0 +#ifdef DEBUG_OUT + MissingLinkConfig m; + eeprom_read_block(&m, 0, sizeof(MissingLinkConfig)); + DEBUG_PRINTF("%d: version: %d\n", CONFIG_OFFSET(version), m.version); + DEBUG_PRINTF("%d: wireless_mode: %d\n", CONFIG_OFFSET(wireless_mode), m.wireless_mode); + DEBUG_PRINTF("%d: ssid: %s\n", CONFIG_OFFSET(ssid), m.ssid); + DEBUG_PRINTF("%d: security_type: %d\n", CONFIG_OFFSET(security_type), m.security_type); + DEBUG_PRINTF("%d: wep_keys\n", CONFIG_OFFSET(wep_keys)); + DEBUG_PRINTF("%d: passphrase: %s\n", CONFIG_OFFSET(security_passphrase), m.security_passphrase); + DEBUG_PRINTF("%d: ip: %d.%d.%d.%d\n", CONFIG_OFFSET(local_ip), m.local_ip[0], m.local_ip[1], m.local_ip[2], m.local_ip[3]); + DEBUG_PRINTF("%d: gateway_ip: %d.%d.%d.%d\n", CONFIG_OFFSET(gateway_ip), m.gateway_ip[0], m.gateway_ip[1], m.gateway_ip[2], m.gateway_ip[3]); + DEBUG_PRINTF("%d: subnet_mask: %d.%d.%d.%d\n", CONFIG_OFFSET(subnet_mask), m.subnet_mask[0], m.subnet_mask[1], m.subnet_mask[2], m.subnet_mask[3]); +#endif +#endif +} + +void initConfig() +{ + uint8_t version = eeprom_read_byte(CONFIG_OFFSET(version)); + if (version != CURR_CONFIG_VERSION) + { + setDefaultConfig(); + } + + dumpConfig(); + + // Read in our config. + wireless_mode = eeprom_read_byte(CONFIG_OFFSET(wireless_mode)); + security_type = eeprom_read_byte(CONFIG_OFFSET(security_type)); + eeprom_read_block(local_ip, CONFIG_OFFSET(local_ip), 4); + eeprom_read_block(subnet_mask, CONFIG_OFFSET(subnet_mask), 4); + eeprom_read_block(gateway_ip, CONFIG_OFFSET(gateway_ip), 4); + + fromMIDI = eeprom_read_byte(CONFIG_OFFSET(fromMIDI)); + fromUSBMIDI = eeprom_read_byte(CONFIG_OFFSET(fromUSBMIDI)); + fromOSC = eeprom_read_byte(CONFIG_OFFSET(fromOSC)); + eeprom_read_block(oscTargetIp, CONFIG_OFFSET(oscTargetIp), 4); + oscTargetSet = (oscTargetIp[0] != 0 || oscTargetIp[1] != 0 || oscTargetIp[2] != 0 || oscTargetIp[3] != 0); + oscTargetPort = eeprom_read_word(CONFIG_OFFSET16(oscTargetPort)); +} + +void return_ssid(uint8_t* ssid, uint8_t* ssid_len) +{ + eeprom_read_block(ssid, CONFIG_OFFSET(ssid), ZG_MAX_SSID_LENGTH); + *ssid_len = strnlen(ssid, ZG_MAX_SSID_LENGTH); +} + +void return_passphrase(uint8_t* passphrase, uint8_t* passphrase_len) +{ + eeprom_read_block(passphrase, CONFIG_OFFSET(security_passphrase), ZG_MAX_WPA_PASSPHRASE_LEN); + *passphrase_len = strnlen(passphrase, ZG_MAX_WPA_PASSPHRASE_LEN); +} + +void return_wepkeys(uint8_t* keys) +{ + eeprom_read_block(keys, CONFIG_OFFSET(wep_keys), ZG_MAX_ENCRYPTION_KEYS * ZG_MAX_ENCRYPTION_KEY_SIZE); +} diff --git a/MissingLink/ML_Config.h b/MissingLink/ML_Config.h new file mode 100644 index 0000000..59d7df6 --- /dev/null +++ b/MissingLink/ML_Config.h @@ -0,0 +1,88 @@ +/* + * MissingLink Firmware + * Copyright 2011 Jabrudian Industries LLC + * + * MissingLink Firmware 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. + * + * MissingLink Firmware 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 MissingLink Firmware. If not, see . + * + */ +#ifndef _ML_CONFIG_H_ +#define _ML_CONFIG_H_ + +#include "witypes.h" +#include "g2100.h" + +#define CURR_CONFIG_VERSION 3 + +typedef struct MissingLinkConfig +{ + // 0xFF = unprogrammed/invalid, 0x00 = valid data + unsigned char version; // Offset: 0 + + // + // Wireless config + // + // 1 = infrastructure, 2 = adhoc + unsigned char wireless_mode; // Offset 1 + + char ssid[ZG_MAX_SSID_LENGTH]; // Offset: 2 + + // Wireless security config: open; 1 - WEP; 2 - WPA; 3 - WPA2 + unsigned char security_type; // Offset: 34 + + // WEP keys (4, 13) + unsigned char wep_keys[ZG_MAX_ENCRYPTION_KEYS][ZG_MAX_ENCRYPTION_KEY_SIZE]; // Offset: 35 + + // WPA/WPA2 passpharse + const prog_char security_passphrase[ZG_MAX_WPA_PASSPHRASE_LEN]; // Offset: 87 + + // + // TCP/IP + // + unsigned char local_ip[4]; // Offset: 151 + unsigned char gateway_ip[4]; // Offset: 155 + unsigned char subnet_mask[4]; // Offset: 159 + + // + // MIDI signal routing + // bit 0 = toMIDI + // bit 1 = toUSBMidi + // bit 2 = toOSC + // + unsigned char fromMIDI; // Offst: 163 + unsigned char fromUSBMIDI; // Offset: 164 + unsigned char fromOSC; // Offst: 165 + + // Where to send OSC messages + unsigned char oscTargetIp[4]; // 166 + uint16_t oscTargetPort; // 167 +} MissingLinkConfig; + +#define TO_MIDI 0x1 +#define TO_USBMIDI 0x2 +#define TO_OSC 0x4 + +extern unsigned char fromMIDI; +extern unsigned char fromUSBMIDI; +extern unsigned char fromOSC; +extern unsigned char oscTargetSet; // 1 = don't override +extern unsigned char oscTargetIp[]; +extern uint16_t oscTargetPort; + +#define CONFIG_OFFSET(x) ((uint8_t*) offsetof(MissingLinkConfig, x)) +#define CONFIG_OFFSET16(x) ((uint16_t*) offsetof(MissingLinkConfig, x)) + +void initConfig(); +void setDefaultConfig(); + +#endif diff --git a/MissingLink/Makefile b/MissingLink/Makefile new file mode 100644 index 0000000..6a2b2a3 --- /dev/null +++ b/MissingLink/Makefile @@ -0,0 +1,97 @@ +#/* +# * MissingLink Firmware +# * Copyright 2011 Jabrudian Industries LLC +# * +# * MissingLink Firmware 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. +# * +# * MissingLink Firmware 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 MissingLink Firmware. If not, see . +# * +# */ +MCU=atmega328p +CC=avr-gcc +CPP=avr-g++ +OBJCOPY=avr-objcopy +# optimize for size: +INCLUDES=-I../Libraries/WiShield -I../Libraries/OSC -I../Libraries/avrmidi -I../Libraries/arduino -I../Libraries/twi +CPPFLAGS=-c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -fpack-struct -fshort-enums -funsigned-bitfields -mmcu=$(MCU) -DF_CPU=16000000UL -DARDUINO=21 $(INCLUDES) +CFLAGS=-c -g -Os -Wall -ffunction-sections -fdata-sections -fpack-struct -fshort-enums -funsigned-bitfields -mmcu=$(MCU) -DF_CPU=16000000UL -DARDUINO=21 $(INCLUDES) +LDFLAGS=-Os -Wl,--gc-sections -Wl,-Map,main.map -lm -mmcu=$(MCU) +PORT=/dev/ttyUSB0 + +SRC = \ + MissingLink.cpp \ + HandleMidi.cpp \ + MLSerial.cpp \ + ML_Config.c \ + Output.cpp \ + Parse.cpp \ + udpapp.cpp \ + ../Libraries/OSC/OSCMessage.cpp \ + ../Libraries/OSC/OSCEncoder.cpp \ + ../Libraries/OSC/OSCDecoder.cpp \ + ../Libraries/WiShield/WiShield.cpp \ + ../Libraries/WiShield/clock-arch.c \ + ../Libraries/WiShield/g2100.c \ + ../Libraries/WiShield/memb.c \ + ../Libraries/WiShield/network.c \ + ../Libraries/WiShield/stack.c \ + ../Libraries/WiShield/timer.c \ + ../Libraries/WiShield/uip-fw.c \ + ../Libraries/WiShield/uip-split.c \ + ../Libraries/WiShield/uip.c \ + ../Libraries/WiShield/uip_arp.c \ + ../Libraries/WiShield/uiplib.c \ + ../Libraries/arduino/WInterrupts.c \ + ../Libraries/arduino/wiring.c \ + ../Libraries/twi/twi.c \ + ../Libraries/avrmidi/bytequeue.c \ + ../Libraries/avrmidi/interrupt_setting.c \ + ../Libraries/avrmidi/midi.c \ + ../Libraries/avrmidi/midi_device.c + +OBJC = ${SRC:.c=.o} +OBJ = ${OBJC:.cpp=.o} + +.cpp.o: + $(CPP) -c $(CPPFLAGS) -o $*.o $< + +.c.o: + echo CC $< + $(CC) -c $(CFLAGS) -o $*.o $< + +MissingLink.out : $(OBJ) + $(CC) $(LDFLAGS) -o MissingLink.out $(OBJ) + +MissingLink.bin : MissingLink.out + $(OBJCOPY) -R .eeprom -O binary MissingLink.out MissingLink.bin + +program: MissingLink.bin + ../bootloader/uploader/sysexupload MissingLink.bin + +MissingLink.hex : MissingLink.out + $(OBJCOPY) -R .eeprom -O ihex MissingLink.out MissingLink.hex + +programmkII : MissingLink.hex + avrdude -pm328p -cavrispmkII -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0x00:m -Uhfuse:w:0xda:m -Ulfuse:w:0xff:m + avrdude -pm328p -cavrispmkII -Pusb -Uflash:w:MissingLink.hex:i -Ulock:w:0x0F:m + +programmkIIFull : MissingLink.hex + avrdude -pm328p -cavrispmkII -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0x00:m -Uhfuse:w:0xda:m -Ulfuse:w:0xff:m + avrdude -pm328p -cavrispmkII -Pusb -Uflash:w:MissingLinkFull.hex:i -Ulock:w:0x0F:m + +programmtinyFull : MissingLinkFull.hex + avrdude -pm328p -cusbtiny -e -Ulock:w:0x3F:m -Uefuse:w:0x00:m -Uhfuse:w:0xda:m -Ulfuse:w:0xff:m + avrdude -pm328p -cusbtiny -Uflash:w:MissingLinkFull.hex:i -Ulock:w:0x0F:m + +clean: + rm -f *.o *.map *.out *.hex */*.o *.bin + rm -rf ../Libraries/*/*.o diff --git a/MissingLink/MissingLink.cpp b/MissingLink/MissingLink.cpp new file mode 100644 index 0000000..3f8c541 --- /dev/null +++ b/MissingLink/MissingLink.cpp @@ -0,0 +1,326 @@ +/* + * Missing Link Firmware + */ +#include + +#include +#include + +#include +#include +#include + +#include "led.h" +#include "HandleMidi.h" +#include "Parse.h" +#include "Output.h" +#include "udpapp-ml.h" +extern "C" +{ +#include "ML_Config.h" +} + +int wifiInit = 0; + +#define BLINK_LENGTH 20 +unsigned long POVBlink = 0; + +void dumpMessage(OSCMessage& oscMess) +{ +#ifdef DEBUG_OUT + unsigned char *ip=oscMess.getIpAddress(); + + DEBUG_PRINTF("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + DEBUG_PRINTF(":%d %s %s --", oscMess.getPortNumber(), oscMess.getOSCAddress(), oscMess.getTypeTags()); + + for(uint8_t i=0 ; i BLINK_LENGTH) + { + LED_GREEN; + } + } else { + wifiInit = WiFi.continueInit(); + if (wifiInit) + { + LED_GREEN; + } + } + + missinglink_midi_process(); +} + +void handlePingMessage(OSCMessage& oscMess, void* userArg) +{ + if ((fromOSC & TO_OSC) == TO_OSC) + return; // Ping response will be handled by OSC->OSC + + const uint8_t* ip = oscMess.getIpAddress(); + bounceMessage(ip[0], ip[1], ip[2], ip[3], 12345); +} + +// +// Message dispatching stuff below. +// + +// Function pointer and a struct to hold message/handler combo. +typedef void (*MessageProcessor)(OSCMessage& oscMess, void* userData); +struct MessageHandler +{ + char* PROGMEM address; + MessageProcessor processor; +}; + +uint8_t dispatch(OSCMessage& oscMess, unsigned char offset, const MessageHandler* messages, void* userArg) +{ + const char* OSCaddress=(oscMess.getOSCAddress()+offset); // 5 = /midi + for (unsigned char i = 0; messages[i].address != NULL; i++) + { + if (strstr_P(OSCaddress, messages[i].address) == OSCaddress) + { + messages[i].processor(oscMess, userArg); + return 1; + } + } + return 0; +} + +void midiDispatch(OSCMessage& oscMess, void* userArg) +{ + /*static */const MessageHandler messages[] = { + { PSTR("/z"), &handleTouchOSCMidiZ}, + { PSTR("/button"), &handleMidiButton}, +// { PSTR("/clock"), &unimplemented }, + { PSTR("/"), &handleTouchOSCMidi}, + { NULL, NULL } + }; + // 5 = /midi + dispatch(oscMess, 5, messages, NULL); +} + +typedef void (*ConfigMessageProcessor)(OSCMessage& oscMess, uint8_t messageLength, uint8_t* eepromOffset); +struct ConfigMessageHandler +{ + char* PROGMEM address; + ConfigMessageProcessor processor; + uint8_t messageLength; + uint8_t* eepromOffset; +}; + +void handleSetDefaults(OSCMessage& oscMess, uint8_t messageLength, uint8_t* eepromOffset) +{ + setDefaultConfig(); +} + +void handleReboot(OSCMessage& oscMess, uint8_t messageLength, uint8_t* eepromOffset) +{ + void(* resetFunc) (void) = 0; //declare reset function @ address 0 + resetFunc(); +} + +void handleWriteEeprom(OSCMessage& oscMess, uint8_t messageOffset, uint8_t* eepromOffset) +{ + const char quoteChar = '\''; + enum ConfigParseState { + cpsNumeric, + cpsString + }; + uint8_t* eOffset = eepromOffset; + const char* addr = oscMess.getOSCAddress(); + int addrLen = oscMess.getOSCAddressLen(); + char* currOffset = (char*) (addr + messageOffset); // /config/set/ + ConfigParseState parseState = cpsNumeric; + while (currOffset < addr + addrLen) + { + if (parseState == cpsNumeric) + { + // Check to see if we should switch to string mode + if (*currOffset == quoteChar) + { + parseState = cpsString; + currOffset++; + } else { + // If not, try and parse numbers (including variables) + char* oldOffset = currOffset; + uint8_t val = (uint8_t) getValue(currOffset, &currOffset, oscMess); + if (oldOffset != currOffset) + { + eeprom_write_byte((uint8_t*) eOffset, val); + eOffset++; + } + currOffset++; + } + } else { + // Check to see if we should switch to number mode + if (*currOffset == quoteChar) + { + parseState = cpsNumeric; + currOffset++; + } else { + // Nope, just take the value and write it + uint8_t val = *currOffset; + eeprom_write_byte(eOffset, val); + eOffset++; + currOffset++; + } + } + } +} + +void handleConfigSet(OSCMessage& oscMess, uint8_t messageLength, uint8_t* ignoredEepromOffset) +{ + char* addr = (char*) oscMess.getOSCAddress(); + char* currOffset = (char*) (addr + messageLength); // /config/set/ + char* oldOffset = currOffset; + uint16_t eepromOffset = getValue(currOffset, &currOffset, oscMess); + if (currOffset != oldOffset) + handleWriteEeprom(oscMess, currOffset - addr, (uint8_t*) eepromOffset); +} + +uint8_t configDispatcher(OSCMessage& oscMess, unsigned char offset, const ConfigMessageHandler* messages) +{ + const char* OSCaddress=(oscMess.getOSCAddress()+offset); // 5 = /midi + for (unsigned char i = 0; messages[i].address != NULL; i++) + { + if (strstr_P(OSCaddress, messages[i].address) == OSCaddress) + { + messages[i].processor(oscMess, messages[i].messageLength, messages[i].eepromOffset); + return 1; + } + } + return 0; +} + +void configDispatch(OSCMessage& oscMess, void* userArg) +{ + // A little silly, but I want to prevent strlen calls and ram + // usage. + const uint8_t twoCharLen = 11; + const uint8_t threeCharLen = twoCharLen + 1; + const uint8_t fourCharLen = threeCharLen + 1; + const uint8_t sixCharLen = fourCharLen + 2; + const uint8_t sevenCharLen = sixCharLen + 1; + const uint8_t eightCharLen = sevenCharLen + 1; + const uint8_t tenCharLen = eightCharLen + 2; + const uint8_t elevenCharLen = tenCharLen + 1; + + const ConfigMessageHandler messages[] = { + { PSTR("defaults"), &handleSetDefaults, 0xFF, (uint8_t*) NULL }, + { PSTR("reboot"), &handleReboot, 0xFF, (uint8_t*) NULL }, + { PSTR("set"), &handleConfigSet, threeCharLen, (uint8_t*) NULL }, + { PSTR("mode"), &handleWriteEeprom, fourCharLen, CONFIG_OFFSET(wireless_mode) }, + { PSTR("ssid"), &handleWriteEeprom, fourCharLen, CONFIG_OFFSET(ssid) }, + { PSTR("security"), &handleWriteEeprom, eightCharLen, CONFIG_OFFSET(security_type) }, + { PSTR("wep1"), &handleWriteEeprom, fourCharLen, CONFIG_OFFSET(wep_keys)+ZG_MAX_ENCRYPTION_KEY_SIZE*0 }, + { PSTR("wep2"), &handleWriteEeprom, fourCharLen, CONFIG_OFFSET(wep_keys)+ZG_MAX_ENCRYPTION_KEY_SIZE*1 }, + { PSTR("wep3"), &handleWriteEeprom, fourCharLen, CONFIG_OFFSET(wep_keys)+ZG_MAX_ENCRYPTION_KEY_SIZE*2 }, + { PSTR("wep4"), &handleWriteEeprom, fourCharLen, CONFIG_OFFSET(wep_keys)+ZG_MAX_ENCRYPTION_KEY_SIZE*3 }, + { PSTR("wpa"), &handleWriteEeprom, threeCharLen, CONFIG_OFFSET(security_passphrase) }, + { PSTR("ip"), &handleWriteEeprom, twoCharLen, CONFIG_OFFSET(local_ip) }, + { PSTR("gateway"), &handleWriteEeprom, sevenCharLen, CONFIG_OFFSET(gateway_ip) }, + { PSTR("subnet"), &handleWriteEeprom, sixCharLen, CONFIG_OFFSET(subnet_mask) }, + { PSTR("fromMIDI"), &handleWriteEeprom, eightCharLen, CONFIG_OFFSET(fromMIDI) }, + { PSTR("fromUSBMIDI"), &handleWriteEeprom, elevenCharLen, CONFIG_OFFSET(fromUSBMIDI) }, + { PSTR("fromOSC"), &handleWriteEeprom, sevenCharLen, CONFIG_OFFSET(fromOSC) }, + { PSTR("targetIp"), &handleWriteEeprom, eightCharLen, CONFIG_OFFSET(oscTargetIp) }, + { PSTR("targetPort"), &handleWriteEeprom, tenCharLen, CONFIG_OFFSET(oscTargetPort) }, + { NULL, NULL, NULL, (uint8_t*) NULL } + }; + uint8_t messageLength = 8; // /config/ + configDispatcher(oscMess, messageLength, messages); +} + +bool canBlink() +{ + unsigned long now = millis(); + if (now - POVBlink > BLINK_LENGTH) + { + POVBlink = now; + return true; + } else { + return false; + } +} + +// Main dispatcher +void handleOSCMessage(OSCMessage& oscMess) +{ + // For future MIDI->OSC messages + if (!oscTargetSet) + { + memcpy(oscTargetIp, oscMess.getIpAddress(), 4); + } + + // Blink the LED! + if (canBlink()) + { + LED_OFF; + } + + DEBUG_PRINTF("\nhandleOSCMessage: "); + dumpMessage(oscMess); + DEBUG_PRINTF("\n"); + + // List of messages and handlers, make sure it ends with NULL address + /*static */const MessageHandler messages[] = { + { PSTR("/midi"), &midiDispatch}, + { PSTR("/ping"), &handlePingMessage }, + { PSTR("/config/"), &configDispatch }, + { NULL, NULL } + }; + + dispatch(oscMess, 0, messages, NULL); + + if ((fromOSC & TO_OSC) == TO_OSC) + { + const uint8_t* ip = oscMess.getIpAddress(); + bounceMessage(ip[0], ip[1], ip[2], ip[3], 12345); + } +} + +int main(void) +{ + init(); + + setup(); + + for (;;) + loop(); + + return 0; +} diff --git a/MissingLink/Output.cpp b/MissingLink/Output.cpp new file mode 100644 index 0000000..e034dbc --- /dev/null +++ b/MissingLink/Output.cpp @@ -0,0 +1,54 @@ +/* + * MissingLink Firmware + * Copyright 2011 Jabrudian Industries LLC + * + * MissingLink Firmware 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. + * + * MissingLink Firmware 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 MissingLink Firmware. If not, see . + * + */ +#include "Output.h" +#include "MLSerial.h" + +#ifdef DEBUG_OUT + +// we need fundamental FILE definitions and printf declarations +#include + +// create a FILE structure to reference our UART output function + +static FILE uartout = {0} ; + +// create a output function +// This works because Serial.write, although of +// type virtual, already exists. +static int uart_putchar (char c, FILE *stream) +{ + Serial.write(c); + return 0 ; +} + +#endif + +void initOutput() +{ +#ifndef DEBUG_OUT + Serial.begin(31250); +#else + Serial.begin(9600); + // fill in the UART file descriptor with pointer to writer. + fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE); + + // The uart is the standard output device STDOUT. + stdout = &uartout ; +#endif +} diff --git a/MissingLink/Output.h b/MissingLink/Output.h new file mode 100644 index 0000000..ba14d1c --- /dev/null +++ b/MissingLink/Output.h @@ -0,0 +1,34 @@ +/* + * MissingLink Firmware + * Copyright 2011 Jabrudian Industries LLC + * + * MissingLink Firmware 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. + * + * MissingLink Firmware 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 MissingLink Firmware. If not, see . + * + */ +#ifndef _OUTPUT_H_ +#define _OUTPUT_H_ + +//#define DEBUG_OUT + +#ifdef DEBUG_OUT +#include +#define DEBUG_PRINTF(...) printf(__VA_ARGS__) +#else +#define DEBUG_PRINTF(...) +#endif + +void initOutput(); +void sendByte(unsigned char b); + +#endif diff --git a/MissingLink/Parse.cpp b/MissingLink/Parse.cpp new file mode 100644 index 0000000..c5aacda --- /dev/null +++ b/MissingLink/Parse.cpp @@ -0,0 +1,178 @@ +/* + * MissingLink Firmware + * Copyright 2011 Jabrudian Industries LLC + * + * MissingLink Firmware 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. + * + * MissingLink Firmware 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 MissingLink Firmware. If not, see . + * + */ +#include +#include +#include +#include +#include "Parse.h" +#include "Output.h" + +bool getMessageInfo(OSCMessage& oscMess, MessageInfo& mi) +{ + const char* addr = oscMess.getOSCAddress(); + int addrLen = oscMess.getOSCAddressLen(); + if (addrLen <= 0) + return false; + + mi.isZ = (addrLen > 2) && (addr[addrLen - 2] == '/') && (addr[addrLen - 1] == 'z'); + mi.hasX = ((addr[0] == 'x') || addr[0] == 'X'); + mi.hasY = ((addr[0] == 'y') || addr[0] == 'Y'); + for (int i = 1; i < addrLen; i++) + { + mi.hasX |= ((addr[i] == 'x' || addr[i] == 'X') && (addr[i-1] != '0')); + mi.hasY |= (addr[i] == 'y' || addr[i] == 'Y'); + } + + // Make sure this message passes basic checks + // Make sure we've got at least one argument if we're reference it in the message + if ((mi.hasX || mi.isZ) && oscMess.getArgsNum() < 1) + return false; + // Make sure there's a y argument if we're referencing y + if (mi.hasY && oscMess.getArgsNum() < 2) + return false; + + return true; +} + +uint8_t getTouchArg(OSCMessage& oscMess, uint8_t arg, float fScale, float fOffset) +{ + switch( oscMess.getTypeTag(arg) ) + { + case 'i': + return oscMess.getInteger32(arg); + break; + + case 'f': + { + const float HAXVALUE = 0.9f; // Make sliders in TouchOSC happier + return trunc(oscMess.getFloat(arg) * (fScale+HAXVALUE)) + fOffset; + } + break; + + case 's': + default : + return 0xFF; + break; + } +} + +int getValue(const char* str, char** numstr, OSCMessage& oscMess) +{ + char* currOffset = (char*) str; + float offset = 0.0f; + float scale = 127.0f; + int argIndex = -1; + int whichBits = 0; // 0 = all, 1 = lsb7, 2 = msb7 + + // Eat whitespace + while ((*currOffset == ' ') || (*currOffset == '_')) + currOffset++; + // Handle constants + if (*currOffset >= '0' && *currOffset <= '9') + { + return strtol(currOffset, numstr, 0); + } + // Handle variables + if (*currOffset == 'x' || *currOffset == 'y' || *currOffset == 'z' || + *currOffset == 'X' || *currOffset == 'Y' || *currOffset == 'Z') + { + switch (*currOffset) + { + case 'X' : + case 'x' : // first var + argIndex = 0; + break; + case 'Y': + case 'y': // second var + argIndex = 1; + break; + case 'Z' : + case 'z' : // first var for /z messages + argIndex = 0; + break; + } + currOffset++; + if (*currOffset == 'L') + { + whichBits = 1; + currOffset++; + } else { + if (*currOffset == 'M') + { + whichBits = 2; + currOffset++; + } + } + // Check for offset/scale + if (*currOffset == '(') + { + currOffset++; // ( + const char* oldOffset = currOffset; + float lowEnd = (float) strtol(currOffset, &currOffset, 0); + // Check for parse issues + if (oldOffset == currOffset) + return 0; + // Skip ".." + currOffset += 2; + // Parse the next param + oldOffset = currOffset; + float highEnd = (float) strtol(currOffset, &currOffset, 0); + if (oldOffset == currOffset) + return 0; + currOffset++; // ) + offset = lowEnd; + scale = highEnd - lowEnd; + } + *numstr = currOffset; + int ret = getTouchArg(oscMess, argIndex, scale, offset); + switch (whichBits) + { + case 1 : + return ret & 0x7F; + break; + case 2 : + return (ret >> 7) & 0x7F; + break; + default : + return ret; + break; + } + } + return 0; +} + +void sendChunk(const char* inbuffer, const uint8_t inlen, OSCMessage& oscMess) +{ + char* currOffset = (char*) inbuffer; + + while (currOffset < inbuffer + inlen) + { + cli(); + const char* oldOffset = currOffset; + uint8_t val = (uint8_t) getValue(currOffset, &currOffset, oscMess); + if (oldOffset != currOffset) + { + sendByte(val); + } else { + currOffset++; + } + sei(); + } + DEBUG_PRINTF("\n"); +} diff --git a/MissingLink/Parse.h b/MissingLink/Parse.h new file mode 100644 index 0000000..c3b2790 --- /dev/null +++ b/MissingLink/Parse.h @@ -0,0 +1,36 @@ +/* + * MissingLink Firmware + * Copyright 2011 Jabrudian Industries LLC + * + * MissingLink Firmware 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. + * + * MissingLink Firmware 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 MissingLink Firmware. If not, see . + * + */ +#ifndef _PARSE_H_ +#define _PARSE_H_ + +#include "OSCMessage.h" + +struct MessageInfo +{ + bool isZ; // does this message end in /z? + bool hasX; // does this message reference an X variable? + bool hasY; // does this message reference a Y variable? +}; + +uint8_t getTouchArg(OSCMessage& oscMess, uint8_t arg, float fScale = 127.0, float fOffset = 0.0f); +int getValue(const char* str, char** numstr, OSCMessage& msg); +void sendChunk(const char* inbuffer, const uint8_t inlen, OSCMessage& oscMess); +bool getMessageInfo(OSCMessage& oscMess, MessageInfo& mi); + +#endif diff --git a/MissingLink/led.h b/MissingLink/led.h new file mode 100644 index 0000000..471adc7 --- /dev/null +++ b/MissingLink/led.h @@ -0,0 +1,29 @@ +/* + * MissingLink Firmware + * Copyright 2011 Jabrudian Industries LLC + * + * MissingLink Firmware 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. + * + * MissingLink Firmware 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 MissingLink Firmware. If not, see . + * + */ +#ifndef _LED_H +#define _LED_H + +#define LED_OFF { PORTC &= ~(_BV(2) | _BV(3)); } +#define LED_GREEN { LED_OFF; PORTC |= _BV(2); } +#define LED_RED { LED_OFF; PORTC |= _BV(3); } +#define LED_YELLOW { LED_OFF; PORTC |= _BV(2) | _BV(3); } + +bool canBlink(); + +#endif diff --git a/MissingLink/udpapp-ml.h b/MissingLink/udpapp-ml.h new file mode 100644 index 0000000..74a81cd --- /dev/null +++ b/MissingLink/udpapp-ml.h @@ -0,0 +1,25 @@ +/* + * MissingLink Firmware + * Copyright 2011 Jabrudian Industries LLC + * + * MissingLink Firmware 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. + * + * MissingLink Firmware 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 MissingLink Firmware. If not, see . + * + */ +#ifndef _UDPAPP_ML_H_ +#define _UDPAPP_ML_H_ + +void sendAppBuffer(uint8_t len, uint16_t addr1, uint16_t addr2, uint16_t addr3, uint16_t addr4, uint16_t port); +void bounceMessage(uint16_t addr1, uint16_t addr2, uint16_t addr3, uint16_t addr4, uint16_t port); + +#endif diff --git a/MissingLink/udpapp.cpp b/MissingLink/udpapp.cpp new file mode 100644 index 0000000..8954d8b --- /dev/null +++ b/MissingLink/udpapp.cpp @@ -0,0 +1,158 @@ +/* + * MissingLink Firmware + * Copyright 2011 Jabrudian Industries LLC + * + * MissingLink Firmware 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. + * + * MissingLink Firmware 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 MissingLink Firmware. If not, see . + * + */ + +/****************************************************************************** + + Filename: udpapp.h + Description: UDP app for the WiShield 1.0 + + ****************************************************************************** + + TCP/IP stack and driver for the WiShield 1.0 wireless devices + + Copyright(c) 2009 Async Labs Inc. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + 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, write to the Free Software Foundation, Inc., 59 + Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Contact Information: + + + Author Date Comment + --------------------------------------------------------------- + AsyncLabs 07/11/2009 Initial version + +*****************************************************************************/ +#include "config.h" +#include "udpapp.h" +#include "uip-conf.h" +extern "C" { +#include "uip.h" +} +#include + +#include "MLSerial.h" +#include "OSCMessage.h" +#include "OSCDecoder.h" +#include "OSCEncoder.h" + +static struct udpapp_state s; +static OSCDecoder decoder; +static struct uip_udp_conn* connOutgoing; + +// This exists within the sketch for the user to modify. +extern void handleOSCMessage(OSCMessage& oscMess); + +void dummy_app_appcall(void) +{ +} + +void udpapp_init(void) +{ + // Allocate our outgoing udp connection, we'll reuse this. + connOutgoing = uip_udp_new(NULL, 0); + + // Allocate our incoming udp connection, we'll reuse this as well! + struct uip_udp_conn *c = uip_udp_new(NULL, HTONS(0)); + if(c != NULL) { + uip_udp_bind(c, HTONS(12344)); + } + PT_INIT(&s.pt); +} + +static unsigned char parse_msg(void) +{ +#if 0 + for (int i = 0; i < uip_datalen(); i++) + Serial.write(((char*)(uip_appdata))[i]); + Serial.write("\n"); +#endif + + OSCMessage m; + decoder.decode(&m, (uint8_t*)(uip_appdata)); + u16_t* ip = uip_udp_conn->ripaddr; + m.setIpAddress(ip[0] & 0xFF, ip[0] >> 8, ip[1] & 0xFF, ip[1] >> 8); + m.setPortNumber(htons(uip_udp_conn->rport)); + + // Here, we mark the connection as available for new remote ip/port combo notice that + // we leave the local port alone so that uIP knows to keep listening. + uip_udp_conn->ripaddr[0] = uip_udp_conn->ripaddr[1] = 0; + uip_udp_conn->rport = 0; + + handleOSCMessage(m); + + return 1; +} + +void sendAppBuffer(uint8_t len, uint16_t addr1, uint16_t addr2, uint16_t addr3, uint16_t addr4, uint16_t port) +{ + uip_ipaddr_t addr; + uip_ipaddr(&addr, addr1, addr2, addr3, addr4); + + uip_ipaddr_copy(&connOutgoing->ripaddr, addr); + connOutgoing->rport = HTONS(port); + connOutgoing->ttl = UIP_TTL; + + uip_send(uip_appdata, len); + uip_udp_conn = connOutgoing; +} + +void bounceMessage(uint16_t addr1, uint16_t addr2, uint16_t addr3, uint16_t addr4, uint16_t port) +{ + uip_ipaddr_t addr; + uip_ipaddr(&addr, addr1, addr2, addr3, addr4); + + uip_ipaddr_copy(&connOutgoing->ripaddr, addr); + connOutgoing->rport = HTONS(port); + connOutgoing->ttl = UIP_TTL; + + uip_send(uip_appdata, uip_len); + uip_udp_conn = connOutgoing; +} + +static PT_THREAD(handle_connection(void)) +{ + PT_BEGIN(&s.pt); + + // No state machine here now, we just stay in "Parse OSC Message" state. + while (true) { + PT_WAIT_UNTIL(&s.pt, uip_newdata()); + if(uip_newdata() && parse_msg()) { + uip_flags &= (~UIP_NEWDATA); + } + } + + PT_END(&s.pt); +} + +void udpapp_appcall(void) +{ + handle_connection(); +} + diff --git a/OSCSendTest/OSCSendTest.pde b/OSCSendTest/OSCSendTest.pde deleted file mode 100644 index 67cdcd0..0000000 --- a/OSCSendTest/OSCSendTest.pde +++ /dev/null @@ -1,63 +0,0 @@ - -/* - * UDP endpoint - * - * A simple UDP endpoint example using the WiShield 1.0 - */ - -#include -#include - -#define WIRELESS_MODE_INFRA 1 -#define WIRELESS_MODE_ADHOC 2 - -extern void sendOSCMessage(OSCMessage& m, uint8 addr1, uint8 addr2, uint8 addr3, uint8 addr4, uint8 port); - -// Wireless configuration parameters ---------------------------------------- -unsigned char local_ip[] = {192,168,1,23}; // IP address of WiShield -unsigned char gateway_ip[] = {192,168,1,1}; // router or gateway IP address -unsigned char subnet_mask[] = {255,255,255,0}; // subnet mask for the local network -const prog_char ssid[] PROGMEM = {"craque"}; // max 32 bytes - -unsigned char security_type = 3; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2 - -// WPA/WPA2 passphrase -const prog_char security_passphrase[] PROGMEM = {"DEADBEEF23"}; // max 64 characters - -// WEP 128-bit keys -// sample HEX keys -prog_uchar wep_keys[] PROGMEM = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, // Key 0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 1 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 2 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Key 3 - }; - -// setup the wireless mode -// infrastructure - connect to AP -// adhoc - connect to another WiFi device -unsigned char wireless_mode = WIRELESS_MODE_INFRA; - -unsigned char ssid_len; -unsigned char security_passphrase_len; - -long startTime = 0; -//--------------------------------------------------------------------------- - -void setup() -{ - Serial.begin(9600); - Serial.println("init"); - WiFi.init(); -} - -void loop() -{ - WiFi.run(); - - if (millis() - startTime > 5000) - { - startTime = millis(); - OSCMessage oscMess("/TestMessage"); - sendOSCMessage(oscMess, 192, 168, 1, 100, 12345); - } -} diff --git a/OSCSendTest/udpapp.cpp b/OSCSendTest/udpapp.cpp deleted file mode 100644 index a773df9..0000000 --- a/OSCSendTest/udpapp.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - -Modified for OSC by Brian Richardson (skinny@knowhere.net) - -*/ - -/****************************************************************************** - - Filename: udpapp.h - Description: UDP app for the WiShield 1.0 - - ****************************************************************************** - - TCP/IP stack and driver for the WiShield 1.0 wireless devices - - Copyright(c) 2009 Async Labs Inc. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - 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, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - Contact Information: - - - Author Date Comment - --------------------------------------------------------------- - AsyncLabs 07/11/2009 Initial version - - *****************************************************************************/ -extern "C" { -#include "uip.h" -} -#include -#include "udpapp.h" -#include "config.h" -#include "HardwareSerial.h" -#include "OSCMessage.h" -#include "OSCEncoder.h" - -static OSCEncoder encoder; - -void dummy_app_appcall(void) -{ -} - -void udpapp_init(void) -{ -} - -void udpapp_appcall(void) -{ -} - -void sendOSCMessage(OSCMessage& m, uint8 addr1, uint8 addr2, uint8 addr3, uint8 addr4, uint8 port) -{ - uip_ipaddr_t addr; - struct uip_udp_conn *c; - - uip_ipaddr(&addr, addr1, addr2, addr3, addr4); - c = uip_udp_new(&addr, HTONS(port)); - uint16_t len = encoder.encode(&m, (uint8_t*) uip_appdata); - uip_send(uip_appdata, len); - uip_close(); // Is this needed? UDP is connectionless, or we might be closing the connection before the data gets sent out.. -} diff --git a/OSCTest/OSCTest.pde b/OSCTest/OSCTest.pde deleted file mode 100644 index 8c7e37f..0000000 --- a/OSCTest/OSCTest.pde +++ /dev/null @@ -1,109 +0,0 @@ - -/* - * UDP endpoint - * - * A simple UDP endpoint example using the WiShield 1.0 - */ - -#include -#include - -#define WIRELESS_MODE_INFRA 1 -#define WIRELESS_MODE_ADHOC 2 - -// Wireless configuration parameters ---------------------------------------- -unsigned char local_ip[] = {192,168,1,23}; // IP address of WiShield -unsigned char gateway_ip[] = {192,168,1,1}; // router or gateway IP address -unsigned char subnet_mask[] = {255,255,255,0}; // subnet mask for the local network -const prog_char ssid[] PROGMEM = {"craque"}; // max 32 bytes - -unsigned char security_type = 3; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2 - -// WPA/WPA2 passphrase -const prog_char security_passphrase[] PROGMEM = {"DEADBEEF23"}; // max 64 characters - -// WEP 128-bit keys -// sample HEX keys -prog_uchar wep_keys[] PROGMEM = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, // Key 0 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 1 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 2 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Key 3 - }; - -// setup the wireless mode -// infrastructure - connect to AP -// adhoc - connect to another WiFi device -unsigned char wireless_mode = WIRELESS_MODE_INFRA; - -unsigned char ssid_len; -unsigned char security_passphrase_len; -//--------------------------------------------------------------------------- - -void setup() -{ - Serial.begin(9600); - Serial.println("init"); - WiFi.init(); -} - -void loop() -{ - WiFi.run(); -} - -void handleOSCMessage(OSCMessage& oscMess) -{ - uint16_t i; - unsigned char *ip=oscMess.getIpAddress(); - - long int intValue; - float floatValue; - char *stringValue; - - Serial.print(ip[0],DEC); - Serial.print("."); - Serial.print(ip[1],DEC); - Serial.print("."); - Serial.print(ip[2],DEC); - Serial.print("."); - Serial.print(ip[3],DEC); - Serial.print(":"); - - Serial.print(oscMess.getPortNumber()); - Serial.print(" "); - Serial.print(oscMess.getOSCAddress()); - Serial.print(" "); - Serial.print(oscMess.getTypeTags()); - Serial.print("--"); - - for(i=0 ; i - - Author Date Comment - --------------------------------------------------------------- - AsyncLabs 07/11/2009 Initial version - - *****************************************************************************/ -extern "C" { -#include "uip.h" -} -#include -#include "udpapp.h" -#include "config.h" -#include "HardwareSerial.h" -#include "OSCMessage.h" -#include "OSCDecoder.h" - -static struct udpapp_state s; -static OSCDecoder decoder; - -// This exists within the sketch for the user to modify. -extern void handleOSCMessage(OSCMessage& oscMess); - -void dummy_app_appcall(void) -{ -} - -void udpapp_init(void) -{ - struct uip_udp_conn *c; - - c = uip_udp_new(NULL, HTONS(0)); - if(c != NULL) { - uip_udp_bind(c, HTONS(12344)); - } - PT_INIT(&s.pt); -} - -static unsigned char parse_msg(void) -{ -#if 0 - for (int i = 0; i < uip_datalen(); i++) - Serial.print(((char*)(uip_appdata))[i]); - Serial.println(""); -#endif - - OSCMessage m; - decoder.decode(&m, (uint8_t*)(uip_appdata)); - handleOSCMessage(m); - - return 1; -} - -static PT_THREAD(handle_connection(void)) -{ - PT_BEGIN(&s.pt); - - // No state machine here now, we just stay in "Parse OSC Message" state. - while (true) { - PT_WAIT_UNTIL(&s.pt, uip_newdata()); - if(uip_newdata() && parse_msg()) { - uip_flags &= (~UIP_NEWDATA); - } - } - - PT_END(&s.pt); -} - -void udpapp_appcall(void) -{ - handle_connection(); -} diff --git a/bootloader/COPYING b/bootloader/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/bootloader/COPYING @@ -0,0 +1,674 @@ + 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 +. diff --git a/bootloader/README b/bootloader/README new file mode 100644 index 0000000..d7c6ec2 --- /dev/null +++ b/bootloader/README @@ -0,0 +1,32 @@ +This is sysex_boot by Alex Norman [http://www.x37v.info] + +REQUIREMENTS: + avr-gcc + portmidi + g++ + +OVERVIEW: + +there are 2 components to this project, the avr_code and the uploader + +the avr_code needs to be loaded onto your microcontroller.. edit +avr_code/bootloadercfg.h as appropriate [setting the bootloader entry condition, etc]. + +the uploader takes binary files [see the example for main.bin] and uploads them to the +microcontroller. + +make sure that your microcontroller is in bootloader mode and has both the midi +ins and outs conected to your computer. + + +EXAMPLE: + +once you've programmed your microcontroller and you've built your uploader do this: +cd example/ +make +cd ../uploader/ +./sysexupload ../example/main.bin + +this will prompt you for some information and then upload the example program +to your microcontroller + diff --git a/bootloader/avr_code/Makefile b/bootloader/avr_code/Makefile new file mode 100644 index 0000000..dbc0699 --- /dev/null +++ b/bootloader/avr_code/Makefile @@ -0,0 +1,40 @@ +MCU=atmega328p +BOOTLOADER_ADDRESS=0x7800 + +CC=avr-gcc +OBJCOPY=avr-objcopy +# optimize for size: +CFLAGS= -mmcu=$(MCU) -I. -I../ -I../midi/ -I../../Libraries/twi/ -Wall -Wstrict-prototypes -Os -fpack-struct -fshort-enums -funsigned-bitfields +LDFLAGS += -Wl,-Ttext=$(BOOTLOADER_ADDRESS) + +SRC = main.c \ + bootloadercfg.h \ + ../../Libraries/twi/twi.c \ + ../midi/bytequeue/interrupt_setting.c \ + ../midi/bytequeue/bytequeue.c \ + +OBJ = ${SRC:.c=.o} + +#------------------- +all: main.hex +#------------------- + +.c.o: + @echo CC $< + @$(CC) -c $(CFLAGS) -Os -o $*.o $< + +main.hex : main.out + $(OBJCOPY) -R .eeprom -O ihex main.out main.hex + +main.out : $(OBJ) + $(CC) $(CFLAGS) $(LDFLAGS) -o main.out -Wl,-Map,main.map $(OBJ) + +program: main.hex + avrdude -pm328p -cavrispmkII -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0x00:m -Uhfuse:w:0xda:m -Ulfuse:w:0xff:m + avrdude -pm328p -cavrispmkII -Pusb -Uflash:w:main.hex:i -Ulock:w:0x0F:m + +#------------------- +clean: + rm -f *.o *.map *.out *.hex + rm -rf ../../Libraries/*/*.o +#------------------- diff --git a/bootloader/avr_code/bootloadercfg.h b/bootloader/avr_code/bootloadercfg.h new file mode 100644 index 0000000..c756366 --- /dev/null +++ b/bootloader/avr_code/bootloadercfg.h @@ -0,0 +1,59 @@ +/* + * A sysex bootloader for avr chips. + * Copyright 2010 Alex Norman + * + * This file is part of SysexBoot. + * + * SysexBoot 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. + * + * SysexBoot 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 SysexBoot. If not, see . + * + */ + +#ifndef BOOTLOADERCFG_H +#define BOOTLOADERCFG_H + +/* + +//turn on port b bit zero as input +//turn on pullups +#define BOOTLOADER_INIT \ + DDRB = 0xFE; \ + PORTB = 0x01; + +//a zero tells us that the button is down +#define BOOTLOADER_CONDITION (!(PINB & _BV(PINB0))) +*/ + +//turn on port b bit zero as input +//turn on pullups +#ifndef BOOTLOADER_INIT +#define BOOTLOADER_INIT +#endif + +//a zero tells us that the button is down +#ifndef BOOTLOADER_CONDITION +#define BOOTLOADER_CONDITION (!(PIND & _BV(PIND4))) +#endif + +#ifndef INDICATE_BOOTLOADER_MODE +#define INDICATE_BOOTLOADER_MODE \ + PORTB = 170; +#endif + +//could be reduced [probably] to decrease ram size, but needs to be at least 43 +//long in current implementation +#ifndef MIDIIN_BUF_SIZE +#define MIDIIN_BUF_SIZE 128 +#endif + +#endif diff --git a/bootloader/avr_code/main.c b/bootloader/avr_code/main.c new file mode 100644 index 0000000..c7c09c8 --- /dev/null +++ b/bootloader/avr_code/main.c @@ -0,0 +1,306 @@ +/* + * A sysex bootloader for avr chips. + * Copyright 2010 Alex Norman + * + * This file is part of SysexBoot. + * + * SysexBoot 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. + * + * SysexBoot 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 SysexBoot. If not, see . + * + */ +#define F_CPU 16000000UL +#define IN_BUFSIZE 260 +#include +#include +#include +#include +#include +#include +#include +#include "twi.h" +#include "bytequeue/bytequeue.h" +#include "bootloadercfg.h" +#include "midibootcommon.h" + +#define SYSEX_BEGIN 0xF0 +#define SYSEX_END 0xF7 + +#define MIDI_CIN_SYSEX_START 0x4 +#define MIDI_CIN_SYSEX_ENDS_1 0x5 +#define MIDI_CIN_SYSEX_ENDS_2 0x6 +#define MIDI_CIN_SYSEX_ENDS_3 0x7 + +// From I2C master +uint8_t midiInBuf[MIDIIN_BUF_SIZE]; +volatile byteQueue_t midiByteQueue; + +// To I2C master +#define MIDIOUT_BUF_SIZE 64 +uint8_t midiOutBuf[MIDIOUT_BUF_SIZE]; +volatile byteQueue_t midiOutQueue; + +uint8_t onReceiveService(uint8_t inByte) +{ + if (bytequeue_enqueue((byteQueue_t*) &midiByteQueue, inByte)) + { + if (bytequeue_length((byteQueue_t*) &midiByteQueue) < MIDIIN_BUF_SIZE - 1) + return 1; + } + return 0; +} + +void onRequestService(void) +{ + uint8_t data[5]; + uint8_t i; + + // Packet length + data[0] = bytequeue_length((byteQueue_t*) &midiOutQueue); + if (data[0] > 3) + data[0] = 3; + // USB midi status byte + data[1] = MIDI_CIN_SYSEX_START; + for (i = 0; i < data[0]; i++) + { + data[i+2] = bytequeue_get((byteQueue_t*) &midiOutQueue, i); + // Search for SYSEX_END and set USB status byte if needed. + if (data[i+2] == SYSEX_END) + { + data[1] += (i+1); + } + } + // If we're not sending a full packet, it better have a sysex_end in it + if ((data[1] == MIDI_CIN_SYSEX_START) && (data[0] < 3)) + { + data[0] = 0; + } else { + bytequeue_remove((byteQueue_t*) &midiOutQueue, data[0]); + data[0] = 4; + } + + twi_transmit(data, data[0]+1); + if (bytequeue_length((byteQueue_t*) &midiOutQueue) == 0) + PORTC &= ~(_BV(1)); +} + +void (*jump_to_app)(void) = 0x0; + +void exit_bootloader(void){ + cli(); + boot_rww_enable(); + MCUCR = _BV(IVCE); + MCUCR = 0; + jump_to_app(); +} + +void midi_send_byte(uint8_t b) +{ + bytequeue_enqueue((byteQueue_t*) &midiOutQueue, b); + PORTC |= _BV(1); // notify PIC we've got data +} + +void midi_send_encoded_byte(uint8_t b) +{ + midi_send_byte(b >> 4); + midi_send_byte(b & 0xF); +} + +void send_sysex_start(void) { + uint8_t i = 0; + midi_send_byte(SYSEX_BEGIN); + for(i = 0; i < MIDIBOOT_SYSEX_ID_LEN; i++) + midi_send_byte(midiboot_sysex_id[i]); +} + +void send_sysex_end(void) { + midi_send_byte(SYSEX_END); +} + +//The ack is just our sysex id in a sysex message, that is all +void send_ack(void){ + send_sysex_start(); + send_sysex_end(); +} + +int main(void) { + uint8_t i, size, curByte; + bool cancelTimeout = false; + bool inSysexMode = false; + uint16_t inByteIndex = 0; + uint16_t pageAddress = 0; + uint16_t counterLow = 0; + + //page size is 128, need 2 more bytes for page address + //128 + 2 == 130.. + //we actually don't need so much space but, whatever + uint8_t tmpUnpackedData[IN_BUFSIZE / 2]; + //once we pack it, it is 149 bytes + uint8_t tmpPackedData[IN_BUFSIZE]; + midiboot_sysex_t sysexMode = MIDIBOOT_INVALID; + + //set up the bootloader conditions + MCUCR = _BV(IVCE); + MCUCR = _BV(IVSEL); + + // Everything INPUT except LED pins + DDRC = _BV(1) | _BV(2) | _BV(3); + // Enable pullups, set LED red + PORTC = 0xFB; + + bytequeue_init((byteQueue_t *)&midiByteQueue, midiInBuf, MIDIIN_BUF_SIZE); + bytequeue_init((byteQueue_t*) &midiOutQueue, midiOutBuf, MIDIOUT_BUF_SIZE); + + // Init I2C + twi_setAddress(4); + twi_attachSlaveTxEvent(onRequestService); + twi_attachSlaveRxEvent(onReceiveService); + twi_init(); + + sei(); + + //do main loop + while(true){ + // Cheesy timeout method, but frugal on bytes + if ((++counterLow == 0) && (!cancelTimeout)) + { + exit_bootloader(); + } + + //read data from the queue and deal with it + size = bytequeue_length((byteQueue_t *)&midiByteQueue); + //deal with input data + for(i = 0; i < size; i++){ + curByte = bytequeue_get((byteQueue_t *)&midiByteQueue, i); + + if(curByte == SYSEX_BEGIN){ + inSysexMode = true; + inByteIndex = 0; + sysexMode = MIDIBOOT_INVALID; + } else if(curByte == SYSEX_END){ + if(inSysexMode){ + //see what mode we're in + switch(sysexMode){ + case MIDIBOOT_LEAVE_BOOT: + exit_bootloader(); + break; + case MIDIBOOT_GETPAGESIZE: + //if we've been sent the correct size packet then send back our data + if(inByteIndex == (1 + MIDIBOOT_SYSEX_ID_LEN)){ + cancelTimeout = true; + //pack the contents of SPM_PAGESIZE into tmpPackedData + //SPM_PAGESIZE is 2 bytes wide + send_sysex_start(); + midi_send_byte(MIDIBOOT_GETPAGESIZE); + midi_send_encoded_byte(SPM_PAGESIZE >> 8); + midi_send_encoded_byte(SPM_PAGESIZE & 0xFF); + send_sysex_end(); + } + break; + //actually write the page that has been filled up through MIDIBOOT_FILLPAGE + case MIDIBOOT_WRITEPAGE: + + cli(); + + //erase the page + eeprom_busy_wait (); + boot_page_erase (pageAddress); + boot_spm_busy_wait (); + //write the page + boot_page_write (pageAddress); // Store buffer in flash page. + boot_spm_busy_wait(); // Wait until the memory is written. + + sei(); + + send_ack(); + break; + //write data into the temporary page buffer [boot_page_fill] + case MIDIBOOT_FILLPAGE: + if(inByteIndex > (MIDIBOOT_SYSEX_ID_LEN + 1)) { + const uint16_t packedSize = inByteIndex - MIDIBOOT_SYSEX_ID_LEN - 1; + const uint16_t unpackedSize = packedSize / 2; + if(unpackedSize <= 64){ + //the first two bytes are the address + uint16_t bytesToWrite = unpackedSize - 2; + uint16_t writeStartAddr; + + //unpack our addr+data + uint16_t n; + for (n = 0; n < packedSize; n+=2) + { + tmpUnpackedData[n >> 1] = (tmpPackedData[n] << 4) | tmpPackedData[n+1]; + } + + //grab the start address + writeStartAddr = (tmpUnpackedData[0] << 8) | tmpUnpackedData[1]; + //page address, just zero out the lower bits, used for WRITEPAGE + pageAddress = writeStartAddr & ~(SPM_PAGESIZE - 1); + + cli(); + + //fill the temp page buffer + uint8_t * pageData = tmpUnpackedData + 2; + uint16_t j; + for(j = 0; j < bytesToWrite; j+=2){ + uint16_t w = (((uint16_t)pageData[j + 1]) << 8) + pageData[j]; + boot_page_fill (writeStartAddr + j, w); + } + + sei(); + //ack that we've done this so that we can get some more data + send_ack(); + } + } + break; + default: + break; + } + } + inSysexMode = false; + } else if(inSysexMode){ + //make sure the sysex prefix matches ours + if((inByteIndex < MIDIBOOT_SYSEX_ID_LEN) && (curByte != midiboot_sysex_id[inByteIndex])){ + inSysexMode = false; + } else { + //we're in sysex mode and we've matched the midiboot_sysex_id + //the next byte tells us what to do + if(inByteIndex == MIDIBOOT_SYSEX_ID_LEN){ + if(curByte >= MIDIBOOT_LEAVE_BOOT && curByte <= MIDIBOOT_WRITEPAGE) + { + sysexMode = curByte; + } + else + inSysexMode = false; + //if we're filling a page, write it to the tmpPackedData, we'll unpack later + } else if (sysexMode == MIDIBOOT_FILLPAGE){ + //the first MIDIBOOT_SYSEX_ID_LEN + 1 bytes have already been dealt with + uint16_t index = inByteIndex - MIDIBOOT_SYSEX_ID_LEN - 1; + if(index < IN_BUFSIZE) { + tmpPackedData[index] = curByte; + } else { + //XXX ERROR!!! + sysexMode = MIDIBOOT_INVALID; + inSysexMode = false; + } + } + //increment the index + inByteIndex++; + } + } + } + + //advance the pointer + bytequeue_remove((byteQueue_t *)&midiByteQueue, size); + } + + return 0; +} diff --git a/bootloader/example/Makefile b/bootloader/example/Makefile new file mode 100755 index 0000000..886c11f --- /dev/null +++ b/bootloader/example/Makefile @@ -0,0 +1,45 @@ +MCU=atmega328p +CC=avr-gcc +OBJCOPY=avr-objcopy +# optimize for size: +CFLAGS=-g -mmcu=$(MCU) -Wall -Wstrict-prototypes -Os -mcall-prologues +PORT=/dev/ttyUSB0 +PART=ATmega16 +UISP = uisp -dprog=stk500 -dserial=/dev/ttyUSB0 -dpart=$(PART) +#------------------- +all: main.bin +#------------------- + +SRC = main.c + +OBJ = ${SRC:.c=.o} + +main.bin : main.out + $(OBJCOPY) -R .eeprom -O binary main.out main.bin + +main.hex : main.out + $(OBJCOPY) -R .eeprom -O ihex main.out main.hex + +main.out : $(OBJ) + $(CC) $(CFLAGS) -o main.out -Wl,-Map,main.map $(OBJ) + +.c.o: + @echo CC $< + @$(CC) -c $(CFLAGS) -Os -o $*.o $< + +# you need to erase first before loading the program. +# load (program) the software into the eeprom: +load: main.hex + $(UISP) --erase + $(UISP) --upload --verify if=main.hex -v=3 --hash=32 + +fuse_mega16: + $(UISP) --wr_fuse_l=0x9f --wr_fuse_h=0xd0 + +check_fuse: + $(UISP) --rd_fuses + +#------------------- +clean: + rm -f *.o *.map *.out *.hex *.bin +#------------------- diff --git a/bootloader/example/main.c b/bootloader/example/main.c new file mode 100644 index 0000000..a873da0 --- /dev/null +++ b/bootloader/example/main.c @@ -0,0 +1,46 @@ +/* + * A sysex bootloader for avr chips. + * Copyright 2010 Alex Norman + * + * This file is part of SysexBoot. + * + * SysexBoot 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. + * + * SysexBoot 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 SysexBoot. If not, see . + * + */ + +#include + +int main(void) { + uint8_t i, j, k, cnt = 0; + DDRB = 0xFF; + PORTB = 0xF0; + + DDRC = 0xFF; + PORTC = 0xFF; + + while(1){ + for(i = 0; i < 255; i++) + for(j = 0; j < 128; j++) + for(k = 0; k < 128; k++); + cnt++; + PORTB = ~cnt; + if (PORTC == 0) + PORTC = 0xFF; + else + PORTC = 0x00; + } + + return 0; +} + diff --git a/bootloader/midi/.gitignore b/bootloader/midi/.gitignore new file mode 100644 index 0000000..e53a2a5 --- /dev/null +++ b/bootloader/midi/.gitignore @@ -0,0 +1,6 @@ +*.o +*.hex +*.out +*.map +*.swp +*.gz diff --git a/bootloader/midi/COPYING b/bootloader/midi/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/bootloader/midi/COPYING @@ -0,0 +1,674 @@ + 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 +. diff --git a/bootloader/midi/Makefile b/bootloader/midi/Makefile new file mode 100644 index 0000000..e292826 --- /dev/null +++ b/bootloader/midi/Makefile @@ -0,0 +1,41 @@ +MCU=atmega8 +CC=avr-gcc +OBJCOPY=avr-objcopy +# optimize for size: +CFLAGS=-g -mmcu=$(MCU) -Wall -Wstrict-prototypes -Os -mcall-prologues +PORT=/dev/ttyUSB0 +PART=ATmega8 +UISP = uisp -dprog=stk500 -dserial=/dev/ttyUSB0 -dpart=$(PART) + +VERSION = 0.2.develop +DISTDIR = avr-midi.${VERSION} + +#------------------- +current: examples +#------------------- + +examples: + cd examples && make + +.c.o: + @echo CC $< + @$(CC) -c $(CFLAGS) -Os -o $*.o $< + +dist: clean + mkdir -p ${DISTDIR} + cp -R COPYING Makefile *.c *.h README examples/ test/ bytequeue/ ${DISTDIR} + tar -czf ${DISTDIR}.tar.gz ${DISTDIR} + rm -rf ${DISTDIR} + +post: dist + scp ${DISTDIR}.tar.gz x37v.info:x37v.info/projects/microcontroller/avr-midi/files/ + scp basic.c x37v.info:x37v.info/projects/microcontroller/avr-midi/ + +clean: + rm -f *.o *.map *.out *.hex *.tar.gz */*.o + cd examples/ && make clean + cd test/ && make clean + +.PHONY: examples + +all: examples diff --git a/bootloader/midi/README b/bootloader/midi/README new file mode 100644 index 0000000..d253a94 --- /dev/null +++ b/bootloader/midi/README @@ -0,0 +1,15 @@ +embedded midi is a library written by Alex Norman. + +This project used to be called avr-midi but it should be useful for other C +projects, thought it is intended for embedded work, so that is why it has been +renamed. + +It is licenced with the GPL v3 licence, see the file "COPYING" for more info. + +Please send me bug info, bug fixes, general improvements, etc. alex@x37v.info + +This is the development version which has only been tested on a atmega32u2. + +my website is here: +http://www.x37v.info + diff --git a/bootloader/midi/bytequeue/COPYING b/bootloader/midi/bytequeue/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/bootloader/midi/bytequeue/COPYING @@ -0,0 +1,674 @@ + 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 +. diff --git a/bootloader/midi/bytequeue/bytequeue.c b/bootloader/midi/bytequeue/bytequeue.c new file mode 100644 index 0000000..e434956 --- /dev/null +++ b/bootloader/midi/bytequeue/bytequeue.c @@ -0,0 +1,65 @@ +//this is a single reader [maybe multiple writer?] byte queue +//Copyright 2008 Alex Norman +//writen by Alex Norman +// +//This file is part of avr-bytequeue. +// +//avr-bytequeue 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. +// +//avr-bytequeue 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 avr-bytequeue. If not, see . + +#include "bytequeue.h" +#include "interrupt_setting.h" + +void bytequeue_init(byteQueue_t * queue, uint8_t * dataArray, byteQueueIndex_t arrayLen){ + queue->length = arrayLen; + queue->data = dataArray; + queue->start = queue->end = 0; +} + +bool bytequeue_enqueue(byteQueue_t * queue, uint8_t item){ + interrupt_setting_t setting = store_and_clear_interrupt(); + //full + if(((queue->end + 1) % queue->length) == queue->start){ + restore_interrupt_setting(setting); + return false; + } else { + queue->data[queue->end] = item; + queue->end = (queue->end + 1) % queue->length; + restore_interrupt_setting(setting); + return true; + } +} + +byteQueueIndex_t bytequeue_length(byteQueue_t * queue){ + byteQueueIndex_t len; + interrupt_setting_t setting = store_and_clear_interrupt(); + if(queue->end >= queue->start) + len = queue->end - queue->start; + else + len = (queue->length - queue->start) + queue->end; + restore_interrupt_setting(setting); + return len; +} + +//we don't need to avoid interrupts if there is only one reader +uint8_t bytequeue_get(byteQueue_t * queue, byteQueueIndex_t index){ + return queue->data[(queue->start + index) % queue->length]; +} + +//we just update the start index to remove elements +void bytequeue_remove(byteQueue_t * queue, byteQueueIndex_t numToRemove){ + interrupt_setting_t setting = store_and_clear_interrupt(); + queue->start = (queue->start + numToRemove) % queue->length; + restore_interrupt_setting(setting); +} + diff --git a/bootloader/midi/bytequeue/bytequeue.h b/bootloader/midi/bytequeue/bytequeue.h new file mode 100644 index 0000000..d12df50 --- /dev/null +++ b/bootloader/midi/bytequeue/bytequeue.h @@ -0,0 +1,49 @@ +//this is a single reader [maybe multiple writer?] byte queue +//Copyright 2008 Alex Norman +//writen by Alex Norman +// +//This file is part of avr-bytequeue. +// +//avr-bytequeue 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. +// +//avr-bytequeue 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 avr-bytequeue. If not, see . +#ifndef BYTEQUEUE_H +#define BYTEQUEUE_H +#include +#include + +typedef uint8_t byteQueueIndex_t; + +typedef struct { + byteQueueIndex_t start; + byteQueueIndex_t end; + byteQueueIndex_t length; + uint8_t * data; +} byteQueue_t; + +//you must have a queue, an array of data which the queue will use, and the length of that array +void bytequeue_init(byteQueue_t * queue, uint8_t * dataArray, byteQueueIndex_t arrayLen); + +//add an item to the queue, returns false if the queue is full +bool bytequeue_enqueue(byteQueue_t * queue, uint8_t item); + +//get the length of the queue +byteQueueIndex_t bytequeue_length(byteQueue_t * queue); + +//this grabs data at the index given [starting at queue->start] +uint8_t bytequeue_get(byteQueue_t * queue, byteQueueIndex_t index); + +//update the index in the queue to reflect data that has been dealt with +void bytequeue_remove(byteQueue_t * queue, byteQueueIndex_t numToRemove); + +#endif + diff --git a/bootloader/midi/bytequeue/interrupt_setting.c b/bootloader/midi/bytequeue/interrupt_setting.c new file mode 100644 index 0000000..eafef52 --- /dev/null +++ b/bootloader/midi/bytequeue/interrupt_setting.c @@ -0,0 +1,36 @@ +//Copyright 20010 Alex Norman +//writen by Alex Norman +// +//This file is part of avr-bytequeue. +// +//avr-bytequeue 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. +// +//avr-bytequeue 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 avr-bytequeue. If not, see . + + +//AVR specific code +//should be able to port to other systems by simply providing chip specific +//implementations of the typedef and these functions + +#include "interrupt_setting.h" +#include + +interrupt_setting_t store_and_clear_interrupt(void) { + uint8_t sreg = SREG; + cli(); + return sreg; +} + +void restore_interrupt_setting(interrupt_setting_t setting) { + SREG = setting; +} + diff --git a/bootloader/midi/bytequeue/interrupt_setting.h b/bootloader/midi/bytequeue/interrupt_setting.h new file mode 100644 index 0000000..3d2a163 --- /dev/null +++ b/bootloader/midi/bytequeue/interrupt_setting.h @@ -0,0 +1,31 @@ +//Copyright 20010 Alex Norman +//writen by Alex Norman +// +//This file is part of avr-bytequeue. +// +//avr-bytequeue 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. +// +//avr-bytequeue 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 avr-bytequeue. If not, see . + +#ifndef INTERRUPT_SETTING_H +#define INTERRUPT_SETTING_H + +#include + +//AVR specific typedef +typedef uint8_t interrupt_setting_t; + +interrupt_setting_t store_and_clear_interrupt(void); +void restore_interrupt_setting(interrupt_setting_t setting); + +#endif + diff --git a/bootloader/midi/examples/Makefile b/bootloader/midi/examples/Makefile new file mode 100644 index 0000000..ba6f1cd --- /dev/null +++ b/bootloader/midi/examples/Makefile @@ -0,0 +1,68 @@ +MCU=atmega8 +CC=avr-gcc +OBJCOPY=avr-objcopy +# optimize for size: +CFLAGS=-g -mmcu=$(MCU) -Wall -Wstrict-prototypes -Os -mcall-prologues -I../ +PORT=/dev/ttyUSB0 +PART=ATmega8 +UISP = uisp -dprog=stk500 -dserial=/dev/ttyUSB0 -dpart=$(PART) + +#------------------- +current: basic.hex +#------------------- + +BASICSRC = basic.c ../midi.c ../midi_device.c ../bytequeue/bytequeue.c ../bytequeue/interrupt_setting.c serial_midi.c +SPITSRC = spit.c ../midi.c serial_midi.c + +BASICOBJ = ${BASICSRC:.c=.o} +SPITOBJ = ${SPITSRC:.c=.o} + +.c.o: + @echo CC $< + @$(CC) -c $(CFLAGS) -Os -o $*.o $< + + +basic.bin : basic.out + $(OBJCOPY) -R .eeprom -O binary basic.out basic.bin + +basic.hex : basic.out + $(OBJCOPY) -R .eeprom -O ihex basic.out basic.hex + +basic.out : $(BASICOBJ) + $(CC) $(CFLAGS) -o basic.out -Wl,-Map,basic.map $(BASICOBJ) + +# load (program) the software +load_basic: basic.hex + $(UISP) --erase + $(UISP) --upload --verify if=basic.hex -v=3 --hash=32 + + +spit.bin : spit.out + $(OBJCOPY) -R .eeprom -O binary spit.out spit.bin + +spit.hex : spit.out + $(OBJCOPY) -R .eeprom -O ihex spit.out spit.hex + +spit.out : $(SPITOBJ) + $(CC) $(CFLAGS) -o spit.out -Wl,-Map,spit.map $(SPITOBJ) + +load_spit: spit.hex + $(UISP) --erase + $(UISP) --upload --verify if=spit.hex -v=3 --hash=32 + + +fuse_mega16: + $(UISP) --wr_fuse_l=0x9f --wr_fuse_h=0xd0 + +fuse_mega8: + $(UISP) --wr_fuse_l=0xef --wr_fuse_h=0xc9 + +check_fuse: + $(UISP) --rd_fuses + +#------------------- +clean: + rm -f *.o *.map *.out *.hex *.tar.gz +#------------------- + +all: spit.hex basic.hex diff --git a/bootloader/midi/examples/basic.c b/bootloader/midi/examples/basic.c new file mode 100644 index 0000000..a4a844c --- /dev/null +++ b/bootloader/midi/examples/basic.c @@ -0,0 +1,127 @@ +/* + + Here is an example of how to use avr-midi + this was written for an atmega16 using a 12Mhz clock in an stk500 + the switch inputs of the STK500 are connected to PORTC + + switch 0 and 1 increment and decrement [respectively] a midi program and + send the appropriate midi program change + + switch 2 sends a note on message when the button is pushed and a note off + when the button is released + + the rest of the switches send CC messages, a 1 when the button is down and a + 0 when the button is released + +*/ + +#include +#include +#include +#include "serial_midi.h" + +#define MIDI_CLOCK_12MHZ_OSC 23 +#define MIDI_CLOCK_RATE MIDI_CLOCK_12MHZ_OSC + +//how many times to we read the buttons before we say they're valid +#define INPUT_HISTORY 4 + +//this is the midi channel we'll be sending on.. 0 is midi channel 1 +#define MIDI_CHAN 0 + +int main(void) { + //index for looping + uint8_t i, j; + bool consistent; + //is the button up + bool up; + //midi program + uint8_t program = 0; + //button inputs, for debouncing + uint8_t inputs[INPUT_HISTORY]; + uint8_t curInput = 0; + uint8_t lastInput = 0; + uint8_t historyIndex = 0; + + //PORTC is in input with internal pullups + DDRC = 0x00; + PORTC = 0xFF; + + //init the button history + for(i = 0; i < INPUT_HISTORY; i++) + inputs[i] = 0; + + //init midi, give the clock rate setting, indicate that we want only output + MidiDevice * midi_device = serial_midi_init(MIDI_CLOCK_RATE, true, false); + + while(1){ + + //grab the inputs + inputs[historyIndex] = PINC; + curInput = lastInput; + + //debounce inputs + //for each input + for(i = 0; i < 8; i++){ + consistent = true; + //the STK500 has 1 for up and 0 for down if you're using the on board buttons + up = (bool)(0x1 & (inputs[0] >> i)); + //check the history to make sure we have the same value for this input + //for the whole history + for(j = 1; j < INPUT_HISTORY; j++){ + if(up != (bool)(0x1 & (inputs[j] >> i))){ + consistent = false; + break; + } + } + //if we have the same value for the whole history then store it in + //curInput + if(consistent){ + if(up) { + //store the current input state + curInput |= (1 << i); + //if the last input was a 0 and the current is a 1 + if(((lastInput >> i) & 0x1) == 0){ + //we don't do anything on up for the first two buttons + //send the appropriate midi data + if(i == 2){ + midi_send_noteoff(midi_device, MIDI_CHAN, 64, 30); + } else if(i > 1) + midi_send_cc(midi_device, MIDI_CHAN, i - 3, 0); + } + } else { + //store the current input state + curInput &= ~(1 << i); + //if the last input was a 1 and the current is a 0 + if(((lastInput >> i) & 0x1) == 1){ + //send the appropriate midi data + switch(i){ + case 0: + program = (program + 1) % 128; + midi_send_programchange(midi_device, MIDI_CHAN, program); + break; + case 1: + program = (program - 1) % 128; + midi_send_programchange(midi_device, MIDI_CHAN, program); + break; + case 2: + midi_send_noteon(midi_device, MIDI_CHAN, 64, 127); + break; + default: + midi_send_cc(midi_device, MIDI_CHAN, i - 3, 1); + break; + } + } + } + } + } + + //update the history index + historyIndex = (historyIndex + 1) % INPUT_HISTORY; + //store the curInput as lastInput for the next loop + lastInput = curInput; + } + + return 0; +} + diff --git a/bootloader/midi/examples/lufa_midi/Descriptors.c b/bootloader/midi/examples/lufa_midi/Descriptors.c new file mode 100644 index 0000000..8405b55 --- /dev/null +++ b/bootloader/midi/examples/lufa_midi/Descriptors.c @@ -0,0 +1,329 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * USB Device Descriptors, for library use when in USB device mode. Descriptors are special + * computer-readable structures which the host requests upon device enumeration, to determine + * the device's capabilities and functions. + */ + +#include "Descriptors.h" + +/** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall + * device characteristics, including the supported USB version, control endpoint size and the + * number of device configurations. The descriptor is read out by the USB host when the enumeration + * process begins. + */ +USB_Descriptor_Device_t PROGMEM DeviceDescriptor = +{ + .Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device}, + + .USBSpecification = VERSION_BCD(01.10), + .Class = USB_CSCP_NoDeviceClass, + .SubClass = USB_CSCP_NoDeviceSubclass, + .Protocol = USB_CSCP_NoDeviceProtocol, + + .Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE, + + .VendorID = 0x03EB, + .ProductID = 0x2048, + .ReleaseNumber = VERSION_BCD(00.01), + + .ManufacturerStrIndex = 0x01, + .ProductStrIndex = 0x02, + .SerialNumStrIndex = NO_DESCRIPTOR, + + .NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS +}; + +/** Configuration descriptor structure. This descriptor, located in FLASH memory, describes the usage + * of the device in one of its supported configurations, including information about any device interfaces + * and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting + * a configuration so that the host may correctly communicate with the USB device. + */ +USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = +{ + .Config = + { + .Header = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration}, + + .TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t), + .TotalInterfaces = 2, + + .ConfigurationNumber = 1, + .ConfigurationStrIndex = NO_DESCRIPTOR, + + .ConfigAttributes = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELFPOWERED), + + .MaxPowerConsumption = USB_CONFIG_POWER_MA(100) + }, + + .Audio_ControlInterface = + { + .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, + + .InterfaceNumber = 0, + .AlternateSetting = 0, + + .TotalEndpoints = 0, + + .Class = AUDIO_CSCP_AudioClass, + .SubClass = AUDIO_CSCP_ControlSubclass, + .Protocol = AUDIO_CSCP_ControlProtocol, + + .InterfaceStrIndex = NO_DESCRIPTOR + }, + + .Audio_ControlInterface_SPC = + { + .Header = {.Size = sizeof(USB_Audio_Descriptor_Interface_AC_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_Header, + + .ACSpecification = VERSION_BCD(01.00), + .TotalLength = sizeof(USB_Audio_Descriptor_Interface_AC_t), + + .InCollection = 1, + .InterfaceNumber = 1, + }, + + .Audio_StreamInterface = + { + .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, + + .InterfaceNumber = 1, + .AlternateSetting = 0, + + .TotalEndpoints = 2, + + .Class = AUDIO_CSCP_AudioClass, + .SubClass = AUDIO_CSCP_MIDIStreamingSubclass, + .Protocol = AUDIO_CSCP_StreamingProtocol, + + .InterfaceStrIndex = NO_DESCRIPTOR + }, + + .Audio_StreamInterface_SPC = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_AudioInterface_AS_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_General, + + .AudioSpecification = VERSION_BCD(01.00), + + .TotalLength = (sizeof(USB_Descriptor_Configuration_t) - + offsetof(USB_Descriptor_Configuration_t, Audio_StreamInterface_SPC)) + }, + + .MIDI_In_Jack_Emb = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_InputJack_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_InputTerminal, + + .JackType = MIDI_JACKTYPE_Embedded, + .JackID = 0x01, + + .JackStrIndex = NO_DESCRIPTOR + }, + + .MIDI_In_Jack_Ext = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_InputJack_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_InputTerminal, + + .JackType = MIDI_JACKTYPE_External, + .JackID = 0x02, + + .JackStrIndex = NO_DESCRIPTOR + }, + + .MIDI_Out_Jack_Emb = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_OutputJack_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_OutputTerminal, + + .JackType = MIDI_JACKTYPE_Embedded, + .JackID = 0x03, + + .NumberOfPins = 1, + .SourceJackID = {0x02}, + .SourcePinID = {0x01}, + + .JackStrIndex = NO_DESCRIPTOR + }, + + .MIDI_Out_Jack_Ext = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_OutputJack_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_OutputTerminal, + + .JackType = MIDI_JACKTYPE_External, + .JackID = 0x04, + + .NumberOfPins = 1, + .SourceJackID = {0x01}, + .SourcePinID = {0x01}, + + .JackStrIndex = NO_DESCRIPTOR + }, + + .MIDI_In_Jack_Endpoint = + { + .Endpoint = + { + .Header = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_OUT | MIDI_STREAM_OUT_EPNUM), + .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = MIDI_STREAM_EPSIZE, + .PollingIntervalMS = 0 + }, + + .Refresh = 0, + .SyncEndpointNumber = 0 + }, + + .MIDI_In_Jack_Endpoint_SPC = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t), .Type = DTYPE_CSEndpoint}, + .Subtype = AUDIO_DSUBTYPE_CSEndpoint_General, + + .TotalEmbeddedJacks = 0x01, + .AssociatedJackID = {0x01} + }, + + .MIDI_Out_Jack_Endpoint = + { + .Endpoint = + { + .Header = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_IN | MIDI_STREAM_IN_EPNUM), + .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = MIDI_STREAM_EPSIZE, + .PollingIntervalMS = 0 + }, + + .Refresh = 0, + .SyncEndpointNumber = 0 + }, + + .MIDI_Out_Jack_Endpoint_SPC = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t), .Type = DTYPE_CSEndpoint}, + .Subtype = AUDIO_DSUBTYPE_CSEndpoint_General, + + .TotalEmbeddedJacks = 0x01, + .AssociatedJackID = {0x03} + } +}; + +/** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests + * the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate + * via the language ID table available at USB.org what languages the device supports for its string descriptors. + */ +USB_Descriptor_String_t PROGMEM LanguageString = +{ + .Header = {.Size = USB_STRING_LEN(1), .Type = DTYPE_String}, + + .UnicodeString = {LANGUAGE_ID_ENG} +}; + +/** Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable + * form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device + * Descriptor. + */ +USB_Descriptor_String_t PROGMEM ManufacturerString = +{ + .Header = {.Size = USB_STRING_LEN(11), .Type = DTYPE_String}, + + .UnicodeString = L"Dean Camera" +}; + +/** Product descriptor string. This is a Unicode string containing the product's details in human readable form, + * and is read out upon request by the host when the appropriate string ID is requested, listed in the Device + * Descriptor. + */ +USB_Descriptor_String_t PROGMEM ProductString = +{ + .Header = {.Size = USB_STRING_LEN(17), .Type = DTYPE_String}, + + .UnicodeString = L"embedded usb midi" +}; + +/** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" + * documentation) by the application code so that the address and size of a requested descriptor can be given + * to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function + * is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the + * USB host. + */ +uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, + const uint8_t wIndex, + const void** const DescriptorAddress) +{ + const uint8_t DescriptorType = (wValue >> 8); + const uint8_t DescriptorNumber = (wValue & 0xFF); + + const void* Address = NULL; + uint16_t Size = NO_DESCRIPTOR; + + switch (DescriptorType) + { + case DTYPE_Device: + Address = &DeviceDescriptor; + Size = sizeof(USB_Descriptor_Device_t); + break; + case DTYPE_Configuration: + Address = &ConfigurationDescriptor; + Size = sizeof(USB_Descriptor_Configuration_t); + break; + case DTYPE_String: + switch (DescriptorNumber) + { + case 0x00: + Address = &LanguageString; + Size = pgm_read_byte(&LanguageString.Header.Size); + break; + case 0x01: + Address = &ManufacturerString; + Size = pgm_read_byte(&ManufacturerString.Header.Size); + break; + case 0x02: + Address = &ProductString; + Size = pgm_read_byte(&ProductString.Header.Size); + break; + } + + break; + } + + *DescriptorAddress = Address; + return Size; +} + diff --git a/bootloader/midi/examples/lufa_midi/Descriptors.h b/bootloader/midi/examples/lufa_midi/Descriptors.h new file mode 100644 index 0000000..b56fb6f --- /dev/null +++ b/bootloader/midi/examples/lufa_midi/Descriptors.h @@ -0,0 +1,83 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for Descriptors.c. + */ + +#ifndef _DESCRIPTORS_H_ +#define _DESCRIPTORS_H_ + + /* Includes: */ + #include + + #include + + /* Macros: */ + /** Endpoint number of the MIDI streaming data IN endpoint, for device-to-host data transfers. */ + #define MIDI_STREAM_IN_EPNUM 2 + + /** Endpoint number of the MIDI streaming data OUT endpoint, for host-to-device data transfers. */ + #define MIDI_STREAM_OUT_EPNUM 1 + + /** Endpoint size in bytes of the Audio isochronous streaming data IN and OUT endpoints. */ + #define MIDI_STREAM_EPSIZE 64 + + /* Type Defines: */ + /** Type define for the device configuration descriptor structure. This must be defined in the + * application code, as the configuration descriptor contains several sub-descriptors which + * vary between devices, and which describe the device's usage to the host. + */ + typedef struct + { + USB_Descriptor_Configuration_Header_t Config; + USB_Descriptor_Interface_t Audio_ControlInterface; + USB_Audio_Descriptor_Interface_AC_t Audio_ControlInterface_SPC; + USB_Descriptor_Interface_t Audio_StreamInterface; + USB_MIDI_Descriptor_AudioInterface_AS_t Audio_StreamInterface_SPC; + USB_MIDI_Descriptor_InputJack_t MIDI_In_Jack_Emb; + USB_MIDI_Descriptor_InputJack_t MIDI_In_Jack_Ext; + USB_MIDI_Descriptor_OutputJack_t MIDI_Out_Jack_Emb; + USB_MIDI_Descriptor_OutputJack_t MIDI_Out_Jack_Ext; + USB_Audio_Descriptor_StreamEndpoint_Std_t MIDI_In_Jack_Endpoint; + USB_MIDI_Descriptor_Jack_Endpoint_t MIDI_In_Jack_Endpoint_SPC; + USB_Audio_Descriptor_StreamEndpoint_Std_t MIDI_Out_Jack_Endpoint; + USB_MIDI_Descriptor_Jack_Endpoint_t MIDI_Out_Jack_Endpoint_SPC; + } USB_Descriptor_Configuration_t; + + /* Function Prototypes: */ + uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, + const uint8_t wIndex, + const void** const DescriptorAddress) + ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); + +#endif + diff --git a/bootloader/midi/examples/lufa_midi/main.c b/bootloader/midi/examples/lufa_midi/main.c new file mode 100644 index 0000000..09732e6 --- /dev/null +++ b/bootloader/midi/examples/lufa_midi/main.c @@ -0,0 +1,20 @@ +#include "midi_usb.h" + +//this example simply echos midi back, for now + +void fallthrough_callback(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + midi_send_data(device, cnt, byte0, byte1, byte2); +} + +int main(void) { + MidiDevice usb_midi; + + midi_usb_init(&usb_midi); + midi_register_fallthrough_callback(&usb_midi, fallthrough_callback); + + while(1){ + midi_device_process(&usb_midi); + } + + return 0; +} diff --git a/bootloader/midi/examples/lufa_midi/makefile b/bootloader/midi/examples/lufa_midi/makefile new file mode 100644 index 0000000..954c8fd --- /dev/null +++ b/bootloader/midi/examples/lufa_midi/makefile @@ -0,0 +1,719 @@ +# Hey Emacs, this is a -*- makefile -*- +#---------------------------------------------------------------------------- +# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al. +# >> Modified for use with the LUFA project. << +# +# Released to the Public Domain +# +# Additional material for this makefile was written by: +# Peter Fleury +# Tim Henigan +# Colin O'Flynn +# Reiner Patommel +# Markus Pfaff +# Sander Pool +# Frederik Rouleau +# Carlos Lamas +# Dean Camera +# Opendous Inc. +# Denver Gingerich +# +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device, using avrdude. +# Please customize the avrdude settings below first! +# +# make dfu = Download the hex file to the device, using dfu-programmer (must +# have dfu-programmer installed). +# +# make flip = Download the hex file to the device, using Atmel FLIP (must +# have Atmel FLIP installed). +# +# make dfu-ee = Download the eeprom file to the device, using dfu-programmer +# (must have dfu-programmer installed). +# +# make flip-ee = Download the eeprom file to the device, using Atmel FLIP +# (must have Atmel FLIP installed). +# +# make doxygen = Generate DoxyGen documentation for the project (must have +# DoxyGen installed) +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + + +# MCU name +MCU = atmega32u2 + + +# Target board (see library "Board Types" documentation, NONE for projects not requiring +# LUFA board drivers). If USER is selected, put custom board drivers in a directory called +# "Board" inside the application directory. +BOARD = NONE + + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_CLOCK below, as it is sourced by +# F_CLOCK after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + + +# Input clock frequency. +# This will define a symbol, F_CLOCK, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_CLOCK = $(F_CPU) + + +# Output format. (can be srec, ihex, binary) +FORMAT = ihex + + +# Target file name (without extension). +TARGET = MIDI + + +# Object files directory +# To put object files in current directory, use a dot (.), do NOT make +# this an empty or blank macro! +OBJDIR = . + + +# Path to the LUFA library +LUFA_PATH = ../../../lufa_101122_beta3/ + + +# LUFA library compile-time options and predefined tokens +LUFA_OPTS = -D USB_DEVICE_ONLY +LUFA_OPTS += -D FIXED_CONTROL_ENDPOINT_SIZE=8 +LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1 +LUFA_OPTS += -D USE_FLASH_DESCRIPTORS +LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" + + +# Create the LUFA source path variables by including the LUFA root makefile +include $(LUFA_PATH)/LUFA/makefile + + +# List C source files here. (C dependencies are automatically generated.) +SRC = midi_usb.c \ + Descriptors.c \ + main.c \ + ../../midi.c \ + ../../midi_device.c \ + ../../bytequeue/bytequeue.c \ + ../../bytequeue/interrupt_setting.c \ + $(LUFA_SRC_USB) \ + $(LUFA_SRC_USBCLASS) + + +# List C++ source files here. (C dependencies are automatically generated.) +CPPSRC = + + +# List Assembler source files here. +# Make them always end in a capital .S. Files ending in a lowercase .s +# will not be considered source files but generated files (assembler +# output from the compiler), and will be deleted upon "make clean"! +# Even though the DOS/Win* filesystem matches both .s and .S the same, +# it will preserve the spelling of the filenames, and gcc itself does +# care about how the name is spelled on its command-line. +ASRC = + + +# Optimization level, can be [0, 1, 2, 3, s]. +# 0 = turn off optimization. s = optimize for size. +# (Note: 3 is not always the best optimization level. See avr-libc FAQ.) +OPT = s + + +# Debugging format. +# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs. +# AVR Studio 4.10 requires dwarf-2. +# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run. +DEBUG = dwarf-2 + + +# List any extra directories to look for include files here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRAINCDIRS = $(LUFA_PATH)/ ../../ + + +# Compiler flag to set the C Standard level. +# c89 = "ANSI" C +# gnu89 = c89 plus GCC extensions +# c99 = ISO C99 standard (not yet fully implemented) +# gnu99 = c99 plus GCC extensions +CSTANDARD = -std=c99 + + +# Place -D or -U options here for C sources +CDEFS = -DF_CPU=$(F_CPU)UL +CDEFS += -DF_CLOCK=$(F_CLOCK)UL +CDEFS += -DBOARD=BOARD_$(BOARD) +CDEFS += $(LUFA_OPTS) + + +# Place -D or -U options here for ASM sources +ADEFS = -DF_CPU=$(F_CPU) +ADEFS += -DF_CLOCK=$(F_CLOCK)UL +ADEFS += -DBOARD=BOARD_$(BOARD) +ADEFS += $(LUFA_OPTS) + +# Place -D or -U options here for C++ sources +CPPDEFS = -DF_CPU=$(F_CPU)UL +CPPDEFS += -DF_CLOCK=$(F_CLOCK)UL +CPPDEFS += -DBOARD=BOARD_$(BOARD) +CPPDEFS += $(LUFA_OPTS) +#CPPDEFS += -D__STDC_LIMIT_MACROS +#CPPDEFS += -D__STDC_CONSTANT_MACROS + + + +#---------------- Compiler Options C ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CFLAGS = -g$(DEBUG) +CFLAGS += $(CDEFS) +CFLAGS += -O$(OPT) +CFLAGS += -funsigned-char +CFLAGS += -funsigned-bitfields +CFLAGS += -ffunction-sections +CFLAGS += -fno-inline-small-functions +CFLAGS += -fpack-struct +CFLAGS += -fshort-enums +CFLAGS += -fno-strict-aliasing +CFLAGS += -Wall +CFLAGS += -Wstrict-prototypes +#CFLAGS += -mshort-calls +#CFLAGS += -fno-unit-at-a-time +#CFLAGS += -Wundef +#CFLAGS += -Wunreachable-code +#CFLAGS += -Wsign-compare +CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst) +CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +CFLAGS += $(CSTANDARD) + + +#---------------- Compiler Options C++ ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CPPFLAGS = -g$(DEBUG) +CPPFLAGS += $(CPPDEFS) +CPPFLAGS += -O$(OPT) +CPPFLAGS += -funsigned-char +CPPFLAGS += -funsigned-bitfields +CPPFLAGS += -fpack-struct +CPPFLAGS += -fshort-enums +CPPFLAGS += -fno-exceptions +CPPFLAGS += -Wall +CPPFLAGS += -Wundef +#CPPFLAGS += -mshort-calls +#CPPFLAGS += -fno-unit-at-a-time +#CPPFLAGS += -Wstrict-prototypes +#CPPFLAGS += -Wunreachable-code +#CPPFLAGS += -Wsign-compare +CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst) +CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +#CPPFLAGS += $(CSTANDARD) + + +#---------------- Assembler Options ---------------- +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns: create listing +# -gstabs: have the assembler create line number information; note that +# for use in COFF files, additional information about filenames +# and function names needs to be present in the assembler source +# files -- see avr-libc docs [FIXME: not yet described there] +# -listing-cont-lines: Sets the maximum number of continuation lines of hex +# dump that will be displayed for a given single line of source input. +ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100 + + +#---------------- Library Options ---------------- +# Minimalistic printf version +PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min + +# Floating point printf version (requires MATH_LIB = -lm below) +PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt + +# If this is left blank, then it will use the Standard printf version. +PRINTF_LIB = +#PRINTF_LIB = $(PRINTF_LIB_MIN) +#PRINTF_LIB = $(PRINTF_LIB_FLOAT) + + +# Minimalistic scanf version +SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min + +# Floating point + %[ scanf version (requires MATH_LIB = -lm below) +SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt + +# If this is left blank, then it will use the Standard scanf version. +SCANF_LIB = +#SCANF_LIB = $(SCANF_LIB_MIN) +#SCANF_LIB = $(SCANF_LIB_FLOAT) + + +MATH_LIB = -lm + + +# List any extra directories to look for libraries here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRALIBDIRS = + + + +#---------------- External Memory Options ---------------- + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# used for variables (.data/.bss) and heap (malloc()). +#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# only used for heap (malloc()). +#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff + +EXTMEMOPTS = + + + +#---------------- Linker Options ---------------- +# -Wl,...: tell GCC to pass this to linker. +# -Map: create map file +# --cref: add cross reference to map file +LDFLAGS = -Wl,-Map=$(TARGET).map,--cref +LDFLAGS += -Wl,--relax +LDFLAGS += -Wl,--gc-sections +LDFLAGS += $(EXTMEMOPTS) +LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS)) +LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) +#LDFLAGS += -T linker_script.x + + + +#---------------- Programming Options (avrdude) ---------------- + +# Programming hardware +# Type: avrdude -c ? +# to get a full listing. +# +AVRDUDE_PROGRAMMER = jtagmkII + +# com1 = serial port. Use lpt1 to connect to parallel port. +AVRDUDE_PORT = usb + +AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex +#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep + + +# Uncomment the following if you want avrdude's erase cycle counter. +# Note that this counter needs to be initialized first using -Yn, +# see avrdude manual. +#AVRDUDE_ERASE_COUNTER = -y + +# Uncomment the following if you do /not/ wish a verification to be +# performed after programming the device. +#AVRDUDE_NO_VERIFY = -V + +# Increase verbosity level. Please use this when submitting bug +# reports about avrdude. See +# to submit bug reports. +#AVRDUDE_VERBOSE = -v -v + +AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) +AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) +AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) +AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) + + + +#---------------- Debugging Options ---------------- + +# For simulavr only - target MCU frequency. +DEBUG_MFREQ = $(F_CPU) + +# Set the DEBUG_UI to either gdb or insight. +# DEBUG_UI = gdb +DEBUG_UI = insight + +# Set the debugging back-end to either avarice, simulavr. +DEBUG_BACKEND = avarice +#DEBUG_BACKEND = simulavr + +# GDB Init Filename. +GDBINIT_FILE = __avr_gdbinit + +# When using avarice settings for the JTAG +JTAG_DEV = /dev/com1 + +# Debugging port used to communicate between GDB / avarice / simulavr. +DEBUG_PORT = 4242 + +# Debugging host used to communicate between GDB / avarice / simulavr, normally +# just set to localhost unless doing some sort of crazy debugging when +# avarice is running on a different computer. +DEBUG_HOST = localhost + + + +#============================================================================ + + +# Define programs and commands. +SHELL = sh +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +AR = avr-ar rcs +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +REMOVEDIR = rm -rf +COPY = cp +WINSHELL = cmd + + +# Define Messages +# English +MSG_ERRORS_NONE = Errors: none +MSG_BEGIN = -------- begin -------- +MSG_END = -------- end -------- +MSG_SIZE_BEFORE = Size before: +MSG_SIZE_AFTER = Size after: +MSG_COFF = Converting to AVR COFF: +MSG_EXTENDED_COFF = Converting to AVR Extended COFF: +MSG_FLASH = Creating load file for Flash: +MSG_EEPROM = Creating load file for EEPROM: +MSG_EXTENDED_LISTING = Creating Extended Listing: +MSG_SYMBOL_TABLE = Creating Symbol Table: +MSG_LINKING = Linking: +MSG_COMPILING = Compiling C: +MSG_COMPILING_CPP = Compiling C++: +MSG_ASSEMBLING = Assembling: +MSG_CLEANING = Cleaning project: +MSG_CREATING_LIBRARY = Creating library: + + + + +# Define all object files. +OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o) + +# Define all listing files. +LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst) + + +# Compiler flags to generate dependency files. +GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d + + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS) +ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + + + + +# Default target. +all: begin gccversion sizebefore build sizeafter end + +# Change the build target to build a HEX file or a library. +build: elf hex eep lss sym +#build: lib + + +elf: $(TARGET).elf +hex: $(TARGET).hex +eep: $(TARGET).eep +lss: $(TARGET).lss +sym: $(TARGET).sym +LIBNAME=lib$(TARGET).a +lib: $(LIBNAME) + + + +# Eye candy. +# AVR Studio 3.x does not check make's exit code but relies on +# the following magic strings to be generated by the compile job. +begin: + @echo + @echo $(MSG_BEGIN) + +end: + @echo $(MSG_END) + @echo + + +# Display size of file. +HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex +ELFSIZE = $(SIZE) $(MCU_FLAG) $(FORMAT_FLAG) $(TARGET).elf +MCU_FLAG = $(shell $(SIZE) --help | grep -- --mcu > /dev/null && echo --mcu=$(MCU) ) +FORMAT_FLAG = $(shell $(SIZE) --help | grep -- --format=.*avr > /dev/null && echo --format=avr ) + + +sizebefore: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \ + 2>/dev/null; echo; fi + +sizeafter: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \ + 2>/dev/null; echo; fi + + + +# Display compiler version information. +gccversion : + @$(CC) --version + + +# Program the device. +program: $(TARGET).hex $(TARGET).eep + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) + +flip: $(TARGET).hex + batchisp -hardware usb -device $(MCU) -operation erase f + batchisp -hardware usb -device $(MCU) -operation loadbuffer $(TARGET).hex program + batchisp -hardware usb -device $(MCU) -operation start reset 0 + +dfu: $(TARGET).hex + dfu-programmer $(MCU) erase + dfu-programmer $(MCU) flash $(TARGET).hex + dfu-programmer $(MCU) reset + +flip-ee: $(TARGET).hex $(TARGET).eep + $(COPY) $(TARGET).eep $(TARGET)eep.hex + batchisp -hardware usb -device $(MCU) -operation memory EEPROM erase + batchisp -hardware usb -device $(MCU) -operation memory EEPROM loadbuffer $(TARGET)eep.hex program + batchisp -hardware usb -device $(MCU) -operation start reset 0 + $(REMOVE) $(TARGET)eep.hex + +dfu-ee: $(TARGET).hex $(TARGET).eep + dfu-programmer $(MCU) eeprom-flash $(TARGET).eep + dfu-programmer $(MCU) reset + + +# Generate avr-gdb config/init file which does the following: +# define the reset signal, load the target file, connect to target, and set +# a breakpoint at main(). +gdb-config: + @$(REMOVE) $(GDBINIT_FILE) + @echo define reset >> $(GDBINIT_FILE) + @echo SIGNAL SIGHUP >> $(GDBINIT_FILE) + @echo end >> $(GDBINIT_FILE) + @echo file $(TARGET).elf >> $(GDBINIT_FILE) + @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE) +ifeq ($(DEBUG_BACKEND),simulavr) + @echo load >> $(GDBINIT_FILE) +endif + @echo break main >> $(GDBINIT_FILE) + +debug: gdb-config $(TARGET).elf +ifeq ($(DEBUG_BACKEND), avarice) + @echo Starting AVaRICE - Press enter when "waiting to connect" message displays. + @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \ + $(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT) + @$(WINSHELL) /c pause + +else + @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \ + $(DEBUG_MFREQ) --port $(DEBUG_PORT) +endif + @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE) + + + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT = $(OBJCOPY) --debugging +COFFCONVERT += --change-section-address .data-0x800000 +COFFCONVERT += --change-section-address .bss-0x800000 +COFFCONVERT += --change-section-address .noinit-0x800000 +COFFCONVERT += --change-section-address .eeprom-0x810000 + + + +coff: $(TARGET).elf + @echo + @echo $(MSG_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-avr $< $(TARGET).cof + + +extcoff: $(TARGET).elf + @echo + @echo $(MSG_EXTENDED_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof + + + +# Create final output files (.hex, .eep) from ELF output file. +%.hex: %.elf + @echo + @echo $(MSG_FLASH) $@ + $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock $< $@ + +%.eep: %.elf + @echo + @echo $(MSG_EEPROM) $@ + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0 + +# Create extended listing file from ELF output file. +%.lss: %.elf + @echo + @echo $(MSG_EXTENDED_LISTING) $@ + $(OBJDUMP) -h -S -z $< > $@ + +# Create a symbol table from ELF output file. +%.sym: %.elf + @echo + @echo $(MSG_SYMBOL_TABLE) $@ + $(NM) -n $< > $@ + + + +# Create library from object files. +.SECONDARY : $(TARGET).a +.PRECIOUS : $(OBJ) +%.a: $(OBJ) + @echo + @echo $(MSG_CREATING_LIBRARY) $@ + $(AR) $@ $(OBJ) + + +# Link: create ELF output file from object files. +.SECONDARY : $(TARGET).elf +.PRECIOUS : $(OBJ) +%.elf: $(OBJ) + @echo + @echo $(MSG_LINKING) $@ + $(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS) + + +# Compile: create object files from C source files. +$(OBJDIR)/%.o : %.c + @echo + @echo $(MSG_COMPILING) $< + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create object files from C++ source files. +$(OBJDIR)/%.o : %.cpp + @echo + @echo $(MSG_COMPILING_CPP) $< + $(CC) -c $(ALL_CPPFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +%.s : %.c + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C++ source files. +%.s : %.cpp + $(CC) -S $(ALL_CPPFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +$(OBJDIR)/%.o : %.S + @echo + @echo $(MSG_ASSEMBLING) $< + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + +# Create preprocessed source for use in sending a bug report. +%.i : %.c + $(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@ + + +# Target: clean project. +clean: begin clean_list end + +clean_list : + @echo + @echo $(MSG_CLEANING) + $(REMOVE) $(TARGET).hex + $(REMOVE) $(TARGET).eep + $(REMOVE) $(TARGET).cof + $(REMOVE) $(TARGET).elf + $(REMOVE) $(TARGET).map + $(REMOVE) $(TARGET).sym + $(REMOVE) $(TARGET).lss + $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o) + $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst) + $(REMOVE) $(SRC:.c=.s) + $(REMOVE) $(SRC:.c=.d) + $(REMOVE) $(SRC:.c=.i) + $(REMOVEDIR) .dep + $(REMOVE) main + +doxygen: + @echo Generating Project Documentation... + @doxygen Doxygen.conf + @echo Documentation Generation Complete. + +clean_doxygen: + rm -rf Documentation + +# Create object files directory +$(shell mkdir $(OBJDIR) 2>/dev/null) + + +# Include the dependency files. +-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) + + +# Listing of phony targets. +.PHONY : all begin finish end sizebefore sizeafter gccversion \ +build elf hex eep lss sym coff extcoff doxygen clean \ +clean_list clean_doxygen program dfu flip flip-ee dfu-ee \ +debug gdb-config + diff --git a/bootloader/midi/examples/lufa_midi/midi_usb.c b/bootloader/midi/examples/lufa_midi/midi_usb.c new file mode 100644 index 0000000..4a045c8 --- /dev/null +++ b/bootloader/midi/examples/lufa_midi/midi_usb.c @@ -0,0 +1,161 @@ +/* + * Modified by Alex Norman (x37v.info) from Dean Camera's MIDI LUFA demo + * Original Copyright below + */ + +/* + LUFA Library + Copyright (C) Dean Camera, 2010. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org + */ + +/* + Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. + */ + +#include "midi_usb.h" + +#include +#include +#include +#include +#include + +#include "Descriptors.h" + +#include +#include + +/* Function Prototypes: */ +void SetupHardware(void); + +void EVENT_USB_Device_Connect(void); +void EVENT_USB_Device_Disconnect(void); +void EVENT_USB_Device_ConfigurationChanged(void); +void EVENT_USB_Device_ControlRequest(void); + +/** LUFA MIDI Class driver interface configuration and state information. This structure is + * passed to all MIDI Class driver functions, so that multiple instances of the same class + * within a device can be differentiated from one another. + */ + +USB_ClassInfo_MIDI_Device_t USB_MIDI_Interface = +{ + .Config = + { + .StreamingInterfaceNumber = 1, + + .DataINEndpointNumber = MIDI_STREAM_IN_EPNUM, + .DataINEndpointSize = MIDI_STREAM_EPSIZE, + .DataINEndpointDoubleBank = false, + + .DataOUTEndpointNumber = MIDI_STREAM_OUT_EPNUM, + .DataOUTEndpointSize = MIDI_STREAM_EPSIZE, + .DataOUTEndpointDoubleBank = false, + }, + }; + +//we disregard cnt because we assume all other bytes are zero and we always send 4 bytes +void usb_send_func(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) { + MIDI_EventPacket_t event; + event.CableNumber = 0; + event.Command = byte0 >> 4; + event.Data1 = byte0; + event.Data2 = byte1; + event.Data3 = byte2; + + MIDI_Device_SendEventPacket(&USB_MIDI_Interface, &event); + MIDI_Device_Flush(&USB_MIDI_Interface); + MIDI_Device_USBTask(&USB_MIDI_Interface); + USB_USBTask(); +} + +void usb_get_midi(MidiDevice * device) { + /* Select the MIDI OUT stream */ + Endpoint_SelectEndpoint(MIDI_STREAM_OUT_EPNUM); + + MIDI_EventPacket_t event; + while (MIDI_Device_ReceiveEventPacket(&USB_MIDI_Interface, &event)) { + + midi_packet_length_t length = midi_packet_length(event.Data1); + + //pass the data to the device input function + //not dealing with sysex yet + if (length != UNDEFINED) + midi_device_input(device, length, event.Data1, event.Data2, event.Data3); + + } + MIDI_Device_USBTask(&USB_MIDI_Interface); + USB_USBTask(); +} + +void midi_usb_init(MidiDevice * device){ + midi_device_init(device); + midi_device_set_send_func(device, usb_send_func); + midi_device_set_pre_input_process_func(device, usb_get_midi); + + SetupHardware(); + sei(); +} + +/** Configures the board hardware and chip peripherals for the demo's functionality. */ +void SetupHardware(void) +{ + /* Disable watchdog if enabled by bootloader/fuses */ + MCUSR &= ~(1 << WDRF); + wdt_disable(); + + /* Disable clock division */ + clock_prescale_set(clock_div_1); + + /* Hardware Initialization */ + USB_Init(); +} + +/** Event handler for the library USB Connection event. */ +void EVENT_USB_Device_Connect(void) +{ + //set some LED? +} + +/** Event handler for the library USB Disconnection event. */ +void EVENT_USB_Device_Disconnect(void) +{ + //set some LED? +} + +/** Event handler for the library USB Configuration Changed event. */ +void EVENT_USB_Device_ConfigurationChanged(void) +{ + bool ConfigSuccess = true; + + ConfigSuccess &= MIDI_Device_ConfigureEndpoints(&USB_MIDI_Interface); + //set some LED? +} + +/** Event handler for the library USB Control Request reception event. */ +void EVENT_USB_Device_ControlRequest(void) +{ + MIDI_Device_ProcessControlRequest(&USB_MIDI_Interface); +} + diff --git a/bootloader/midi/examples/lufa_midi/midi_usb.h b/bootloader/midi/examples/lufa_midi/midi_usb.h new file mode 100644 index 0000000..551c8e0 --- /dev/null +++ b/bootloader/midi/examples/lufa_midi/midi_usb.h @@ -0,0 +1,8 @@ +#ifndef MIDI_USB_H +#define MIDI_USB_H + +#include "midi.h" + +void midi_usb_init(MidiDevice * device); + +#endif diff --git a/bootloader/midi/examples/serial_midi.c b/bootloader/midi/examples/serial_midi.c new file mode 100644 index 0000000..49c57a6 --- /dev/null +++ b/bootloader/midi/examples/serial_midi.c @@ -0,0 +1,49 @@ +#include "serial_midi.h" +#include +#include "stdlib.h" + +static MidiDevice midi_device; + +void serial_midi_send(MidiDevice * device, uint8_t cnt, uint8_t inByte0, uint8_t inByte1, uint8_t inByte2){ + //we always send the first byte + while ( !(UCSRA & _BV(UDRE)) ); // Wait for empty transmit buffer + UDR = inByte0; + //if cnt == 2 or 3 we send the send byte + if(cnt > 1) { + while ( !(UCSRA & _BV(UDRE)) ); // Wait for empty transmit buffer + UDR = inByte1; + } + //if cnt == 3 we send the third byte + if(cnt == 3) { + while ( !(UCSRA & _BV(UDRE)) ); // Wait for empty transmit buffer + UDR = inByte2; + } +} + +MidiDevice * serial_midi_device(void) { + return &midi_device; +} + +MidiDevice* serial_midi_init(uint16_t clockScale, bool out, bool in){ + //send up the device + midi_device_init(&midi_device); + midi_device_set_send_func(&midi_device, serial_midi_send); + + // Set baud rate + UBRRH = (uint8_t)(clockScale >> 8); + UBRRL = (uint8_t)(clockScale & 0xFF); + // Enable transmitter + if(out) + UCSRB |= _BV(TXEN); + if(in) { + //Enable receiver + //RX Complete Interrupt Enable (user must provide routine) + UCSRB |= _BV(RXEN) | _BV(RXCIE); + } + //Set frame format: Async, 8data, 1 stop bit, 1 start bit, no parity + //needs to have URSEL set in order to write into this reg + UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0); + + return serial_midi_device(); +} + diff --git a/bootloader/midi/examples/serial_midi.h b/bootloader/midi/examples/serial_midi.h new file mode 100644 index 0000000..38abd4e --- /dev/null +++ b/bootloader/midi/examples/serial_midi.h @@ -0,0 +1,10 @@ +#ifndef SERIAL_MIDI_H +#define SERIAL_MIDI_H + +#include +#include "midi.h" + +//initialize serial midi and return the device pointer +MidiDevice* serial_midi_init(uint16_t clockScale, bool out, bool in); + +#endif diff --git a/bootloader/midi/examples/spit.c b/bootloader/midi/examples/spit.c new file mode 100644 index 0000000..d8c989b --- /dev/null +++ b/bootloader/midi/examples/spit.c @@ -0,0 +1,18 @@ +#include +#include "serial_midi.h" + +#define MIDI_CLOCK_12MHZ_OSC 23 +#define MIDI_CLOCK_RATE MIDI_CLOCK_12MHZ_OSC + +int main(void){ + //init midi, give the clock rate setting, indicate that we want only output + MidiDevice * midi_device = serial_midi_init(MIDI_CLOCK_RATE, true, false); + + uint8_t cnt = 0; + + while (1) { + midi_send_cc(midi_device, 0, 0, cnt); + cnt = (cnt + 1) & 0x7F; + } + return 0; +} diff --git a/bootloader/midi/midi.c b/bootloader/midi/midi.c new file mode 100644 index 0000000..0437391 --- /dev/null +++ b/bootloader/midi/midi.c @@ -0,0 +1,250 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#include "midi.h" +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) + +#ifndef NULL +#define NULL 0 +#endif + +bool midi_is_statusbyte(uint8_t theByte){ + return (bool)(theByte & MIDI_STATUSMASK); +} + +bool midi_is_realtime(uint8_t theByte){ + return (theByte >= MIDI_CLOCK); +} + +midi_packet_length_t midi_packet_length(uint8_t status){ + switch(status & MIDI_STATUSMASK){ + case MIDI_CC: + case MIDI_NOTEON: + case MIDI_NOTEOFF: + case MIDI_AFTERTOUCH: + case MIDI_PITCHBEND: + case MIDI_SONGPOSITION: + return THREE; + case MIDI_PROGCHANGE: + case MIDI_CHANPRESSURE: + case MIDI_SONGSELECT: + case MIDI_TC_QUATERFRAME: + return TWO; + case MIDI_CLOCK: + case MIDI_TICK: + case MIDI_START: + case MIDI_CONTINUE: + case MIDI_STOP: + case MIDI_ACTIVESENSE: + case MIDI_RESET: + case MIDI_TUNEREQUEST: + return ONE; + case SYSEX_END: + case SYSEX_BEGIN: + default: + return UNDEFINED; + } +} + +void midi_send_cc(MidiDevice * device, uint8_t chan, uint8_t num, uint8_t val){ + //CC Status: 0xB0 to 0xBF where the low nibble is the MIDI channel. + //CC Data: Controller Num, Controller Val + device->send_func(device, 3, + MIDI_CC | (chan & MIDI_CHANMASK), + num & 0x7F, + val & 0x7F); +} + +void midi_send_noteon(MidiDevice * device, uint8_t chan, uint8_t num, uint8_t vel){ + //Note Data: Note Num, Note Velocity + device->send_func(device, 3, + MIDI_NOTEON | (chan & MIDI_CHANMASK), + num & 0x7F, + vel & 0x7F); +} + +void midi_send_noteoff(MidiDevice * device, uint8_t chan, uint8_t num, uint8_t vel){ + //Note Data: Note Num, Note Velocity + device->send_func(device, 3, + MIDI_NOTEOFF | (chan & MIDI_CHANMASK), + num & 0x7F, + vel & 0x7F); +} + +void midi_send_aftertouch(MidiDevice * device, uint8_t chan, uint8_t note_num, uint8_t amt){ + device->send_func(device, 3, + MIDI_AFTERTOUCH | (chan & MIDI_CHANMASK), + note_num & 0x7F, + amt & 0x7F); +} + +//XXX does this work right? +//amt in range -0x2000, 0x1fff +//uAmt should be in range.. +//0x0000 to 0x3FFF +void midi_send_pitchbend(MidiDevice * device, uint8_t chan, int16_t amt){ + uint16_t uAmt; + //check range + if(amt > 0x1fff){ + uAmt = 0x3FFF; + } else if(amt < -0x2000){ + uAmt = 0; + } else { + uAmt = amt + 0x2000; + } + device->send_func(device, 3, + MIDI_PITCHBEND | (chan & MIDI_CHANMASK), + uAmt & 0x7F, + (uAmt >> 7) & 0x7F); +} + +void midi_send_programchange(MidiDevice * device, uint8_t chan, uint8_t num){ + device->send_func(device, 2, + MIDI_PROGCHANGE | (chan & MIDI_CHANMASK), + num & 0x7F, + 0); +} + +void midi_send_channelpressure(MidiDevice * device, uint8_t chan, uint8_t amt){ + device->send_func(device, 2, + MIDI_CHANPRESSURE | (chan & MIDI_CHANMASK), + amt & 0x7F, + 0); +} + +void midi_send_clock(MidiDevice * device){ + device->send_func(device, 1, MIDI_CLOCK, 0, 0); +} + +void midi_send_tick(MidiDevice * device){ + device->send_func(device, 1, MIDI_TICK, 0, 0); +} + +void midi_send_start(MidiDevice * device){ + device->send_func(device, 1, MIDI_START, 0, 0); +} + +void midi_send_continue(MidiDevice * device){ + device->send_func(device, 1, MIDI_CONTINUE, 0, 0); +} + +void midi_send_stop(MidiDevice * device){ + device->send_func(device, 1, MIDI_STOP, 0, 0); +} + +void midi_send_activesense(MidiDevice * device){ + device->send_func(device, 1, MIDI_ACTIVESENSE, 0, 0); +} + +void midi_send_reset(MidiDevice * device){ + device->send_func(device, 1, MIDI_RESET, 0, 0); +} + +void midi_send_tcquaterframe(MidiDevice * device, uint8_t time){ + device->send_func(device, 2, + MIDI_TC_QUATERFRAME, + time & 0x7F, + 0); +} + +//XXX is this right? +void midi_send_songposition(MidiDevice * device, uint16_t pos){ + device->send_func(device, 3, + MIDI_SONGPOSITION, + pos & 0x7F, + (pos >> 7) & 0x7F); +} + +void midi_send_songselect(MidiDevice * device, uint8_t song){ + device->send_func(device, 2, + MIDI_SONGSELECT, + song & 0x7F, + 0); +} + +void midi_send_tunerequest(MidiDevice * device){ + device->send_func(device, 1, MIDI_TUNEREQUEST, 0, 0); +} + +void midi_send_byte(MidiDevice * device, uint8_t b){ + device->send_func(device, 1, b, 0, 0); +} + + void midi_send_data(MidiDevice * device, uint8_t count, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + if (count > 3) + count = 3; + device->send_func(device, count, byte0, byte1, byte2); + } + + +void midi_register_cc_callback(MidiDevice * device, midi_three_byte_func_t func){ + device->input_cc_callback = func; +} + +void midi_register_noteon_callback(MidiDevice * device, midi_three_byte_func_t func){ + device->input_noteon_callback = func; +} + +void midi_register_noteoff_callback(MidiDevice * device, midi_three_byte_func_t func){ + device->input_noteoff_callback = func; +} + +void midi_register_aftertouch_callback(MidiDevice * device, midi_three_byte_func_t func){ + device->input_aftertouch_callback = func; +} + +void midi_register_pitchbend_callback(MidiDevice * device, midi_three_byte_func_t func){ + device->input_pitchbend_callback = func; +} + +void midi_register_songposition_callback(MidiDevice * device, midi_three_byte_func_t func){ + device->input_songposition_callback = func; +} + +void midi_register_progchange_callback(MidiDevice * device, midi_two_byte_func_t func) { + device->input_progchange_callback = func; +} + +void midi_register_chanpressure_callback(MidiDevice * device, midi_two_byte_func_t func) { + device->input_chanpressure_callback = func; +} + +void midi_register_songselect_callback(MidiDevice * device, midi_two_byte_func_t func) { + device->input_songselect_callback = func; +} + +void midi_register_tc_quarterframe_callback(MidiDevice * device, midi_two_byte_func_t func) { + device->input_tc_quaterframe_callback = func; +} + +void midi_register_realtime_callback(MidiDevice * device, midi_one_byte_func_t func){ + device->input_realtime_callback = func; +} + +void midi_register_tunerequest_callback(MidiDevice * device, midi_one_byte_func_t func){ + device->input_tunerequest_callback = func; +} + +void midi_register_fallthrough_callback(MidiDevice * device, midi_var_byte_func_t func){ + device->input_fallthrough_callback = func; +} + +void midi_register_catchall_callback(MidiDevice * device, midi_var_byte_func_t func){ + device->input_catchall_callback = func; +} + diff --git a/bootloader/midi/midi.h b/bootloader/midi/midi.h new file mode 100644 index 0000000..292cf68 --- /dev/null +++ b/bootloader/midi/midi.h @@ -0,0 +1,135 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#ifndef AVR_MIDI_H +#define AVR_MIDI_H + +#include "midi_device.h" +#include "midi_function_types.h" + +typedef enum { + UNDEFINED = 0, + ONE = 1, + TWO = 2, + THREE = 3} midi_packet_length_t; + +//general information [device independent] **************** +//returns true if the byte given is a midi status byte +bool midi_is_statusbyte(uint8_t theByte); +//returns true if the byte given is a realtime status byte +bool midi_is_realtime(uint8_t theByte); +//returns the length of the packet associated with the status byte given +midi_packet_length_t midi_packet_length(uint8_t status); + + +//initialize midi device +void midi_device_init(MidiDevice * device); // [implementation in midi_device.c] + +//process input data +//you need to call this if you expect your input callbacks to be called +void midi_device_process(MidiDevice * device); // [implementation in midi_device.c] + + +//send functions ********************** +void midi_send_cc(MidiDevice * device, uint8_t chan, uint8_t num, uint8_t val); +void midi_send_noteon(MidiDevice * device, uint8_t chan, uint8_t num, uint8_t vel); +void midi_send_noteoff(MidiDevice * device, uint8_t chan, uint8_t num, uint8_t vel); +void midi_send_aftertouch(MidiDevice * device, uint8_t chan, uint8_t note_num, uint8_t amt); +void midi_send_pitchbend(MidiDevice * device, uint8_t chan, int16_t amt); //range -8192, 8191 +void midi_send_programchange(MidiDevice * device, uint8_t chan, uint8_t num); +void midi_send_channelpressure(MidiDevice * device, uint8_t chan, uint8_t amt); + +//realtime +void midi_send_clock(MidiDevice * device); +void midi_send_tick(MidiDevice * device); +void midi_send_start(MidiDevice * device); +void midi_send_continue(MidiDevice * device); +void midi_send_stop(MidiDevice * device); +void midi_send_activesense(MidiDevice * device); +void midi_send_reset(MidiDevice * device); + +//more obscure +void midi_send_tcquaterframe(MidiDevice * device, uint8_t time); //range 0..16383 +void midi_send_songposition(MidiDevice * device, uint16_t pos); +void midi_send_songselect(MidiDevice * device, uint8_t song); +void midi_send_tunerequest(MidiDevice * device); +void midi_send_byte(MidiDevice * device, uint8_t b); +void midi_send_data(MidiDevice * device, uint8_t count, uint8_t byte0, uint8_t byte1, uint8_t byte2); + + +//input callback registration *********************** + +//three byte funcs +void midi_register_cc_callback(MidiDevice * device, midi_three_byte_func_t func); +void midi_register_noteon_callback(MidiDevice * device, midi_three_byte_func_t func); +void midi_register_noteoff_callback(MidiDevice * device, midi_three_byte_func_t func); +void midi_register_aftertouch_callback(MidiDevice * device, midi_three_byte_func_t func); +void midi_register_pitchbend_callback(MidiDevice * device, midi_three_byte_func_t func); +void midi_register_songposition_callback(MidiDevice * device, midi_three_byte_func_t func); + +//two byte funcs +void midi_register_progchange_callback(MidiDevice * device, midi_two_byte_func_t func); +void midi_register_chanpressure_callback(MidiDevice * device, midi_two_byte_func_t func); +void midi_register_songselect_callback(MidiDevice * device, midi_two_byte_func_t func); +void midi_register_tc_quarterframe_callback(MidiDevice * device, midi_two_byte_func_t func); + +//one byte funcs +void midi_register_realtime_callback(MidiDevice * device, midi_one_byte_func_t func); +void midi_register_tunerequest_callback(MidiDevice * device, midi_one_byte_func_t func); + +//fall through, only called if a more specific callback isn't matched and called +void midi_register_fallthrough_callback(MidiDevice * device, midi_var_byte_func_t func); +//catch all, always called if registered, independent of a more specific or fallthrough call +void midi_register_catchall_callback(MidiDevice * device, midi_var_byte_func_t func); + +#define SYSEX_BEGIN 0xF0 +#define SYSEX_END 0xF7 +//if you and this with a byte and you get anything non-zero +//it is a status message +#define MIDI_STATUSMASK 0x80 +//if you and this with a status message that contains channel info, +//you'll get the channel +#define MIDI_CHANMASK 0x0F + +#define MIDI_CC 0xB0 +#define MIDI_NOTEON 0x90 +#define MIDI_NOTEOFF 0x80 +#define MIDI_AFTERTOUCH 0xA0 +#define MIDI_PITCHBEND 0xE0 +#define MIDI_PROGCHANGE 0xC0 +#define MIDI_CHANPRESSURE 0xD0 + +//midi realtime +#define MIDI_CLOCK 0xF8 +#define MIDI_TICK 0xF9 +#define MIDI_START 0xFA +#define MIDI_CONTINUE 0xFB +#define MIDI_STOP 0xFC +#define MIDI_ACTIVESENSE 0xFE +#define MIDI_RESET 0xFF + +#define MIDI_TC_QUATERFRAME 0xF1 +#define MIDI_SONGPOSITION 0xF2 +#define MIDI_SONGSELECT 0xF3 +#define MIDI_TUNEREQUEST 0xF6 + +//This ID is for educational or development use only +#define SYSEX_EDUMANUFID 0x7D + +#endif + diff --git a/bootloader/midi/midi_device.c b/bootloader/midi/midi_device.c new file mode 100644 index 0000000..fe7323f --- /dev/null +++ b/bootloader/midi/midi_device.c @@ -0,0 +1,290 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#include "midi_device.h" +#include "midi.h" + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef DEBUG +#include +#endif + +//forward declarations, internally used to call the callbacks +void midi_input_callbacks(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2); +void midi_process_byte(MidiDevice * device, uint8_t input); + +void midi_device_init(MidiDevice * device){ + device->input_state = IDLE; + device->input_count = 0; + bytequeue_init(&device->input_queue, device->input_queue_data, MIDI_INPUT_QUEUE_LENGTH); + + //three byte funcs + device->input_cc_callback = NULL; + device->input_noteon_callback = NULL; + device->input_noteoff_callback = NULL; + device->input_aftertouch_callback = NULL; + device->input_pitchbend_callback = NULL; + device->input_songposition_callback = NULL; + + //two byte funcs + device->input_progchange_callback = NULL; + device->input_chanpressure_callback = NULL; + device->input_songselect_callback = NULL; + device->input_tc_quaterframe_callback = NULL; + + //one byte funcs + device->input_realtime_callback = NULL; + device->input_tunerequest_callback = NULL; + + device->input_fallthrough_callback = NULL; + device->input_catchall_callback = NULL; + + device->pre_input_process_callback = NULL; +} + +void midi_device_input(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) { + //temp storage so we can loop over the bytes + uint8_t input[3]; + input[0] = byte0; + input[1] = byte1; + input[2] = byte2; + + //clamp range + if (cnt > 3) + cnt = 3; + + uint8_t i; + for (i = 0; i < cnt; i++) { +#ifdef DEBUG + printf("queueing %x\n", input[i]); +#endif + bytequeue_enqueue(&device->input_queue, input[i]); + } +} + +void midi_device_set_send_func(MidiDevice * device, midi_var_byte_func_t send_func){ + device->send_func = send_func; +} + +void midi_device_set_pre_input_process_func(MidiDevice * device, midi_no_byte_func_t pre_process_func){ + device->pre_input_process_callback = pre_process_func; +} + +void midi_device_process(MidiDevice * device) { + //call the pre_input_process_callback if there is one + if(device->pre_input_process_callback) + device->pre_input_process_callback(device); + + //pull stuff off the queue and process + byteQueueIndex_t len = bytequeue_length(&device->input_queue); + uint16_t i; + //TODO limit number of bytes processed? + for(i = 0; i < len; i++) { + uint8_t val = bytequeue_get(&device->input_queue, 0); +#ifdef DEBUG + printf("processing %x\n", val); +#endif + midi_process_byte(device, val); + bytequeue_remove(&device->input_queue, 1); + } +} + +void midi_process_byte(MidiDevice * device, uint8_t input) { + if (midi_is_realtime(input)) { + //call callback, don't change any state + midi_input_callbacks(device, 1, input, 0, 0); + } else if (midi_is_statusbyte(input)) { + //store the byte + if (device->input_state != SYSEX_MESSAGE) { + device->input_buffer[0] = input; + device->input_count = 1; + } + switch (midi_packet_length(input)) { + case ONE: + device->input_state = IDLE; + midi_input_callbacks(device, 1, input, 0, 0); + break; + case TWO: + device->input_state = TWO_BYTE_MESSAGE; + break; + case THREE: + device->input_state = THREE_BYTE_MESSAGE; + break; + case UNDEFINED: + switch(input) { + case SYSEX_BEGIN: + device->input_state = SYSEX_MESSAGE; + device->input_buffer[0] = input; + device->input_count = 1; + break; + case SYSEX_END: + //failsafe, should never happen + if(device->input_count > 2) { + device->input_state = IDLE; + device->input_count = 2; + } + //send what is left in the input buffer, set idle + device->input_buffer[device->input_count] = input; + device->input_state = IDLE; + device->input_count += 1; + //call the callback + midi_input_callbacks(device, device->input_count, + device->input_buffer[0], device->input_buffer[1], device->input_buffer[2]); + break; + default: + device->input_state = IDLE; + device->input_count = 0; + } + + break; + default: + device->input_state = IDLE; + device->input_count = 0; + break; + } + } else { + //failsafe, should never happen + if(device->input_count > 2) + device->input_state = IDLE; + + if (device->input_state != IDLE) { + //store the byte + device->input_buffer[device->input_count] = input; + //increment count + device->input_count += 1; + switch(device->input_count) { + case 3: + if (device->input_state != SYSEX_MESSAGE) + device->input_state = IDLE; + device->input_count = 0; + //call callback + midi_input_callbacks(device, 3, + device->input_buffer[0], device->input_buffer[1], device->input_buffer[2]); + break; + case 2: + if (device->input_state == TWO_BYTE_MESSAGE) { + device->input_state = IDLE; + //call callback + midi_input_callbacks(device, 2, device->input_buffer[0], device->input_buffer[1], 0); + } + break; + case 1: + default: + //shouldn't happen + device->input_state = IDLE; + break; + } + } + } +} + +void midi_input_callbacks(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) { +#ifdef DEBUG + printf("callback func %d %x %x %x\n", cnt, byte0, byte1, byte2); +#endif + //did we end up calling a callback? + bool called = false; + switch (cnt) { + case 3: + { + midi_three_byte_func_t func = NULL; + switch (byte0 & 0xF0) { + case MIDI_CC: + func = device->input_cc_callback; + break; + case MIDI_NOTEON: + func = device->input_noteon_callback; + break; + case MIDI_NOTEOFF: + func = device->input_noteoff_callback; + break; + case MIDI_AFTERTOUCH: + func = device->input_aftertouch_callback; + break; + case MIDI_PITCHBEND: + func = device->input_pitchbend_callback; + break; + case MIDI_SONGPOSITION: + func = device->input_songposition_callback; + break; + default: + break; + } + if(func) { + func(device, byte0, byte1, byte2); + called = true; + } + } + break; + case 2: + { + midi_two_byte_func_t func = NULL; + switch (byte0 & 0xF0) { + case MIDI_PROGCHANGE: + func = device->input_progchange_callback; + break; + case MIDI_CHANPRESSURE: + func = device->input_chanpressure_callback; + break; + case MIDI_SONGSELECT: + func = device->input_songselect_callback; + break; + case MIDI_TC_QUATERFRAME: + func = device->input_tc_quaterframe_callback; + break; + default: + break; + } + if(func) { + func(device, byte0, byte1); + called = true; + } + } + break; + case 1: + { + midi_one_byte_func_t func = NULL; + if (midi_is_realtime(byte0)) + func = device->input_realtime_callback; + else if (byte0 == MIDI_TUNEREQUEST) + func = device->input_tunerequest_callback; + if (func) { + func(device, byte0); + called = true; + } + } + break; + default: + //just in case + if (cnt > 3) + cnt = 0; + break; + } + + //if there is fallthrough default callback and we haven't called a more specific one, + //call the fallthrough + if (!called && device->input_fallthrough_callback) + device->input_fallthrough_callback(device, cnt, byte0, byte1, byte2); + //always call the catch all if it exists + if (device->input_catchall_callback) + device->input_catchall_callback(device, cnt, byte0, byte1, byte2); +} + diff --git a/bootloader/midi/midi_device.h b/bootloader/midi/midi_device.h new file mode 100644 index 0000000..9a69917 --- /dev/null +++ b/bootloader/midi/midi_device.h @@ -0,0 +1,89 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#ifndef MIDI_DEVICE_H +#define MIDI_DEVICE_H + +#include "midi_function_types.h" +#include "bytequeue/bytequeue.h" +#define MIDI_INPUT_QUEUE_LENGTH 192 + +typedef enum { + IDLE, + TWO_BYTE_MESSAGE = 2, + THREE_BYTE_MESSAGE = 3, + SYSEX_MESSAGE} input_state_t; + +typedef void (* midi_no_byte_func_t)(MidiDevice * device); + +//this structure represents the input and output functions and processing data +//for a midi device. +//A device can represent an actual physical device [serial port, usb port] or +//something virtual. +//You should not need to modify this structure directly. +struct _midi_device { + //output send function + midi_var_byte_func_t send_func; + + //********input callbacks + //three byte funcs + midi_three_byte_func_t input_cc_callback; + midi_three_byte_func_t input_noteon_callback; + midi_three_byte_func_t input_noteoff_callback; + midi_three_byte_func_t input_aftertouch_callback; + midi_three_byte_func_t input_pitchbend_callback; + midi_three_byte_func_t input_songposition_callback; + //two byte funcs + midi_two_byte_func_t input_progchange_callback; + midi_two_byte_func_t input_chanpressure_callback; + midi_two_byte_func_t input_songselect_callback; + midi_two_byte_func_t input_tc_quaterframe_callback; + //one byte funcs + midi_one_byte_func_t input_realtime_callback; + midi_one_byte_func_t input_tunerequest_callback; + + //only called if more specific callback is not matched + midi_var_byte_func_t input_fallthrough_callback; + //called if registered, independent of other callbacks + midi_var_byte_func_t input_catchall_callback; + + //pre input processing function + midi_no_byte_func_t pre_input_process_callback; + + //for internal input processing + uint8_t input_buffer[3]; + input_state_t input_state; + uint8_t input_count; + + //for queueing data between the input and the processing functions + uint8_t input_queue_data[MIDI_INPUT_QUEUE_LENGTH]; + byteQueue_t input_queue; +}; + +//input processing, only used if you're creating a custom device +void midi_device_input(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2); +//set send function, only used if you're creating a custom device +//you'll most likely want the function that this calls to disable interrupts so +//that you can call the various midi send functions without worrying about +//locking. +void midi_device_set_send_func(MidiDevice * device, midi_var_byte_func_t send_func); + +//if you need to run a function to grab input before you pass it to midi_device_input, set it here. +void midi_device_set_pre_input_process_func(MidiDevice * device, midi_no_byte_func_t pre_process_func); + +#endif diff --git a/bootloader/midi/midi_function_types.h b/bootloader/midi/midi_function_types.h new file mode 100644 index 0000000..4645239 --- /dev/null +++ b/bootloader/midi/midi_function_types.h @@ -0,0 +1,34 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#ifndef MIDI_FUNCTION_TYPES_H +#define MIDI_FUNCTION_TYPES_H + +#include +#include + +//forward declaration +typedef struct _midi_device MidiDevice; + +typedef void (* midi_one_byte_func_t)(MidiDevice * device, uint8_t byte); +typedef void (* midi_two_byte_func_t)(MidiDevice * device, uint8_t byte0, uint8_t byte1); +typedef void (* midi_three_byte_func_t)(MidiDevice * device, uint8_t byte0, uint8_t byte1, uint8_t byte2); +//all bytes after count bytes should be ignored +typedef void (* midi_var_byte_func_t)(MidiDevice * device, uint8_t count, uint8_t byte0, uint8_t byte1, uint8_t byte2); + +#endif diff --git a/bootloader/midi/sysex_tools.c b/bootloader/midi/sysex_tools.c new file mode 100644 index 0000000..2ff8052 --- /dev/null +++ b/bootloader/midi/sysex_tools.c @@ -0,0 +1,99 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#include "sysex_tools.h" + +uint16_t sysex_bit_packed_length(uint16_t unpacked_length){ + uint8_t remainder = unpacked_length % 7; + if (remainder) + return (unpacked_length / 7) * 8 + remainder + 1; + else + return (unpacked_length / 7) * 8; +} + +uint16_t sysex_bit_unpacked_length(uint16_t packed_length){ + uint8_t remainder = packed_length % 8; + if (remainder) + return (packed_length / 8) * 7 + remainder - 1; + else + return (packed_length / 8) * 7; +} + +uint16_t sysex_bit_pack(uint8_t *packed, const uint8_t *source, const uint16_t length){ + uint16_t packed_full = length / 7; //number of full 8 byte sections from 7 bytes of input + uint16_t i,j; + + //fill out the fully packed sections + for(i = 0; i < packed_full; i++) { + uint16_t packed_msb_idx = i * 8; + uint16_t input_start_idx = i * 7; + packed[packed_msb_idx] = 0; + for(j = 0; j < 7; j++){ + uint8_t current = source[input_start_idx + j]; + packed[packed_msb_idx] |= (0x80 & current) >> (1 + j); + packed[packed_msb_idx + 1 + j] = 0x7F & current; + } + } + + //fill out the rest if there is any more + uint8_t remainder = length % 7; + if (remainder) { + uint16_t packed_msb_idx = packed_full * 8; + uint16_t input_start_idx = packed_full * 7; + packed[packed_msb_idx] = 0; + for(j = 0; j < remainder; j++){ + uint8_t current = source[input_start_idx + j]; + packed[packed_msb_idx] |= (0x80 & current) >> (1 + j); + packed[packed_msb_idx + 1 + j] = 0x7F & current; + } + return packed_msb_idx + remainder + 1; + } else { + return packed_full * 8; + } +} + +uint16_t sysex_bit_unpack(uint8_t *unpacked, const uint8_t *source, const uint16_t length){ + uint16_t unpacked_full = length / 8; + uint16_t i,j; + + if (length < 2) + return 0; + + //fill out the fully packed sections + for(i = 0; i < unpacked_full; i++) { + uint16_t packed_msb_idx = i * 8; + uint16_t output_start_index = i * 7; + for(j = 0; j < 7; j++){ + unpacked[output_start_index + j] = 0x7F & source[packed_msb_idx + j + 1]; + unpacked[output_start_index + j] |= (0x80 & (source[packed_msb_idx] << (1 + j))); + } + } + uint8_t remainder = length % 8; + if (remainder) { + uint16_t packed_msb_idx = unpacked_full * 8; + uint16_t output_start_index = unpacked_full * 7; + for(j = 0; j < (remainder - 1); j++) { + unpacked[output_start_index + j] = 0x7F & source[packed_msb_idx + j + 1]; + unpacked[output_start_index + j] |= (0x80 & (source[packed_msb_idx] << (1 + j))); + } + return unpacked_full * 7 + remainder - 1; + } else { + return unpacked_full * 7; + } +} + diff --git a/bootloader/midi/sysex_tools.h b/bootloader/midi/sysex_tools.h new file mode 100644 index 0000000..df86974 --- /dev/null +++ b/bootloader/midi/sysex_tools.h @@ -0,0 +1,78 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#ifndef SYSEX_TOOLS_H +#define SYSEX_TOOLS_H + +#include + +/** + * These functions are for converting data to and from a "midi-safe" format, + * which can be use to send data with sysex messages. Sysex messages may only + * contain data where the to bit is not set. + * + * A bit "packed" midi message is one that contains all of the data from its + * original state, but does not have any of the top bits set. + * + * Every 7 bytes of unpacked data is converted into 8 bytes of packed data and + * visa-versa. If you'd like to operate on small segments, make sure that you + * pack in 7 byte increments and unpack in 8 byte increments. + * + */ + +/** + * Compute the length of a message after it is packed. + * + * @param unpacked_length The length, in bytes, of the message to pack. + * + * @return The length, in bytes, of the message after packing. + */ +uint16_t sysex_bit_packed_length(uint16_t unpacked_length); + +/** + * Compute the length of a message after it is unpacked. + * + * @param packed_length The length, in bytes, of the packed message. + * + * @return The length, in bytes, of the message after it is unpacked. + */ +uint16_t sysex_bit_unpacked_length(uint16_t packed_length); + +/** + * Pack data so that it can be transmitted safely in a sysex message. + * + * @param packed The output data buffer, must be at least sysex_bit_packed_length(length) bytes long. + * @param source The input buffer of data to be packed. + * @param length The number of bytes from the input buffer to pack. + * + * @return number of bytes packed. + */ +uint16_t sysex_bit_pack(uint8_t *packed, const uint8_t *source, uint16_t length); + +/** + * Unpack packed data. + * + * @param unpacked The output data buffer, must be at least sysex_bit_unpacked_length(length) bytes long. + * @param source The input buffer of data to be unpacked. + * @param length The number of bytes from the input buffer to unpack. + * + * @return number of bytes unpacked. + */ +uint16_t sysex_bit_unpack(uint8_t *unpacked, const uint8_t *source, uint16_t length); + +#endif diff --git a/bootloader/midi/test/.gitignore b/bootloader/midi/test/.gitignore new file mode 100644 index 0000000..9d58ef3 --- /dev/null +++ b/bootloader/midi/test/.gitignore @@ -0,0 +1,3 @@ +test +sysex_test +dummy_test diff --git a/bootloader/midi/test/Makefile b/bootloader/midi/test/Makefile new file mode 100644 index 0000000..03547b6 --- /dev/null +++ b/bootloader/midi/test/Makefile @@ -0,0 +1,28 @@ +CFLAGS += -I. -I../ -g -Wall -DDEBUG +DUMMY_SRC = dummy_device.c ../midi.c ../midi_device.c ../bytequeue/bytequeue.c ../bytequeue/interrupt_setting.c +DUMMY_OBJ = ${DUMMY_SRC:.c=.o} + +SYSEX_SRC = sysex_test.c ../sysex_tools.c +SYSEX_OBJ = ${SYSEX_SRC:.c=.o} + +.c.o: + @echo CC $< + @$(CC) -c $(CFLAGS) -o $*.o $< + +dummy_test: clean $(DUMMY_OBJ) + @$(CC) -o dummy_test $(DUMMY_OBJ) + +sysex_test: clean $(SYSEX_OBJ) + @$(CC) -o sysex_test $(SYSEX_OBJ) + +run_tests: sysex_test dummy_test + ./dummy_test + ./sysex_test + +all: run_tests + +#------------------- +clean: + rm -f *.o *.map *.out *.hex *.tar.gz ../*.o ../bytequeue/*.o dummy_test sysex_test +#------------------- + diff --git a/bootloader/midi/test/avr/interrupt.h b/bootloader/midi/test/avr/interrupt.h new file mode 100644 index 0000000..8770647 --- /dev/null +++ b/bootloader/midi/test/avr/interrupt.h @@ -0,0 +1,27 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#ifndef FAKE_AVR_INTERRUPTS_H +#define FAKE_AVR_INTERRUPTS_H + +static uint8_t SREG = 0; + +void cli(void) { +} + +#endif diff --git a/bootloader/midi/test/dummy_device.c b/bootloader/midi/test/dummy_device.c new file mode 100644 index 0000000..268b5ca --- /dev/null +++ b/bootloader/midi/test/dummy_device.c @@ -0,0 +1,222 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#include "midi_device.h" +#include "midi.h" +#include +#include + +MidiDevice test_device; + +uint8_t sent[3]; +uint8_t got[3]; + +bool cc_called; +bool noteon_called; +bool noteoff_called; +bool aftertouch_called; +bool pitchbend_called; +bool songposition_called; +bool progchange_called; +bool chanpressure_called; +bool songselect_called; +bool tc_quarterframe_called; +bool realtime_called; +bool tunerequest_called; +bool fallthrough_called; + +void send_func(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) { + sent[0] = byte0; + sent[1] = byte1; + sent[2] = byte0; + printf("sent: "); + uint8_t i; + for (i = 0; i < cnt; i++) { + printf("%02x ", sent[i]); + } + printf("\n"); +} + +void cc_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + cc_called = true; + got[0] = byte0; + got[1] = byte1; + got[2] = byte2; +} +void noteon_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + noteon_called = true; + got[0] = byte0; + got[1] = byte1; + got[2] = byte2; +} +void noteoff_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + noteoff_called = true; + got[0] = byte0; + got[1] = byte1; + got[2] = byte2; +} +void aftertouch_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + aftertouch_called = true; + got[0] = byte0; + got[1] = byte1; + got[2] = byte2; +} +void pitchbend_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + pitchbend_called = true; + got[0] = byte0; + got[1] = byte1; + got[2] = byte2; +} +void songposition_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + songposition_called = true; + got[0] = byte0; + got[1] = byte1; + got[2] = byte2; +} + +void progchange_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1){ + progchange_called = true; + got[0] = byte0; + got[1] = byte1; +} +void chanpressure_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1){ + chanpressure_called = true; + got[0] = byte0; + got[1] = byte1; +} +void songselect_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1){ + songselect_called = true; + got[0] = byte0; + got[1] = byte1; +} +void tc_quarterframe_callback(MidiDevice * device, uint8_t byte0, uint8_t byte1){ + tc_quarterframe_called = true; + got[0] = byte0; + got[1] = byte1; +} + +void realtime_callback(MidiDevice * device, uint8_t byte){ + realtime_called = true; + got[0] = byte; +} +void tunerequest_callback(MidiDevice * device, uint8_t byte){ + tunerequest_called = true; + got[0] = byte; +} + +void fallthrough_callback(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + fallthrough_called = true; + got[0] = byte0; + got[1] = byte1; + got[2] = byte2; +} + +void reset() { + uint8_t i; + for(i = 0; i < 3; i++) + got[i] = sent[i] = 0; + cc_called = false; + noteon_called = false; + noteoff_called = false; + aftertouch_called = false; + pitchbend_called = false; + songposition_called = false; + progchange_called = false; + chanpressure_called = false; + songselect_called = false; + tc_quarterframe_called = false; + realtime_called = false; + tunerequest_called = false; + fallthrough_called = false; +} + +bool anything_called() { + return cc_called || + noteon_called || + noteoff_called || + aftertouch_called || + pitchbend_called || + songposition_called || + progchange_called || + chanpressure_called || + songselect_called || + tc_quarterframe_called || + realtime_called || + tunerequest_called || + fallthrough_called; +} + +int main(void) { + midi_device_init(&test_device); + midi_device_set_send_func(&test_device, send_func); + + midi_send_cc(&test_device, 0, 0, 1); + midi_send_cc(&test_device, 15, 1, 1); + + midi_register_fallthrough_callback(&test_device, fallthrough_callback); + midi_register_realtime_callback(&test_device, realtime_callback); + + assert(!fallthrough_called); + assert(!realtime_called); + midi_device_input(&test_device, 3, 0xB0, 0, 1); + midi_device_input(&test_device, 1, MIDI_CLOCK, 0, 0); + midi_device_process(&test_device); + assert(fallthrough_called); + assert(realtime_called); + + reset(); + assert(!fallthrough_called); + assert(!realtime_called); + //interspersed + midi_device_input(&test_device, 1, 0xB0, 0, 0); + midi_device_input(&test_device, 1, MIDI_CLOCK, 0, 0); + midi_device_input(&test_device, 1, 0, 0, 0); + midi_device_input(&test_device, 1, MIDI_START, 0, 0); + midi_device_input(&test_device, 1, 1, 0, 0); + midi_device_process(&test_device); + assert(fallthrough_called); + assert(realtime_called); + + midi_register_cc_callback(&test_device, cc_callback); + assert(!cc_called); + midi_device_input(&test_device, 3, 0xB0, 0, 1); + midi_device_process(&test_device); + assert(cc_called); + + reset(); + assert(!cc_called); + assert(!realtime_called); + midi_device_input(&test_device, 1, 0xB0, 0, 0); + midi_device_input(&test_device, 1, MIDI_CLOCK, 0, 0); + midi_device_input(&test_device, 1, 0, 0, 0); + midi_device_input(&test_device, 1, MIDI_START, 0, 0); + midi_device_input(&test_device, 1, 1, 0, 0); + midi_device_process(&test_device); + assert(cc_called); + assert(realtime_called); + + reset(); + assert(!anything_called()); + midi_device_input(&test_device, 1, 0xB0, 0, 0); + midi_device_input(&test_device, 1, 0, 0, 0); + midi_device_process(&test_device); + assert(!anything_called()); + + printf("\n\nTEST PASSED!\n\n"); + return 0; +} diff --git a/bootloader/midi/test/dummy_device.h b/bootloader/midi/test/dummy_device.h new file mode 100644 index 0000000..e69de29 diff --git a/bootloader/midi/test/sysex_test.c b/bootloader/midi/test/sysex_test.c new file mode 100644 index 0000000..73a1915 --- /dev/null +++ b/bootloader/midi/test/sysex_test.c @@ -0,0 +1,79 @@ +//midi for embedded chips, +//Copyright 2010 Alex Norman +// +//This file is part of avr-midi. +// +//avr-midi 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. +// +//avr-midi 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 avr-midi. If not, see . + +#include "sysex_tools.h" +#include +#include +#include +#include +#include + +#define SIZE 1028 + +int main(int argc, char * argv[]) { + unsigned int i, j; + uint8_t orig[SIZE]; + uint8_t unpacked[SIZE]; + uint8_t * packed = malloc(sizeof(uint8_t) * sysex_bit_packed_length(SIZE)); + uint8_t * packed2 = malloc(sizeof(uint8_t) * sysex_bit_packed_length(SIZE)); + + for(i = 0; i < SIZE; i++) + orig[i] = rand() & 0xFF; + + for (i = 1; i < 512; i++) { + assert(i == sysex_bit_unpacked_length(sysex_bit_packed_length(i))); + } + + //test byte packing + for (i = 1; i < SIZE; i++) { + uint16_t res_size0 = sysex_bit_pack(packed, orig, i); + uint16_t res_size1 = sysex_bit_packed_length(i); + //printf("packed %d == %d\n", res_size0, res_size1); + assert(res_size0 == res_size1); + //make sure that the top bit isn't set + for (j = 0; j < res_size0; j++) + assert( (packed[i] & 0x80) == 0); + //just in case, zero out unpacked.. + memset(unpacked, SIZE, 0); + res_size1 = sysex_bit_unpack(unpacked, packed, res_size0); + assert(i == sysex_bit_unpacked_length(res_size0)); + //printf("unpacked %d == %d\n", res_size1, i); + assert(res_size1 == i); + res_size0 = memcmp(orig, unpacked, i); + assert(0 == res_size0); + } + + for (i = 0, j = 0; i < (SIZE - 7); i += 7, j +=8) { + //pack in segments + assert(8 == sysex_bit_pack(packed2 + j, orig + i, 7)); + } + + for (i = 0, j = 0; i < (SIZE - 7); i += 7, j +=8) { + //pack in segments + assert(7 == sysex_bit_unpack(unpacked + i, packed2 + j, 8)); + } + //make sure the unpacked contents are the same length + assert(0 == memcmp(unpacked, orig, SIZE - 7)); + //make sure that packing in 7 byte segments is the same as packing all at once + assert(0 == memcmp(packed2, packed, sysex_bit_packed_length(SIZE - 7))); + + free(packed); + + printf("\n%s passed!\n\n", argv[0]); + return 0; +} diff --git a/bootloader/midibootcommon.h b/bootloader/midibootcommon.h new file mode 100644 index 0000000..6877cf8 --- /dev/null +++ b/bootloader/midibootcommon.h @@ -0,0 +1,49 @@ +/* + * A sysex bootloader for avr chips. + * Copyright 2010 Alex Norman + * + * This file is part of SysexBoot. + * + * SysexBoot 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. + * + * SysexBoot 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 SysexBoot. If not, see . + * + */ + +//this is a file that both the uploader and the atmega code uses +#ifndef MIDIBOOT_COMMON_H +#define MIDIBOOT_COMMON_H + +#ifndef SYSEX_EDUMANUFID +#define SYSEX_EDUMANUFID 0x7D +#endif + +#define MIDI_SYSEX_START 0xF0 +#define MIDI_SYSEX_STOP 0xF7 + +//the edu manufacture id + 'x37vboot' +const unsigned char midiboot_sysex_id[] = { + SYSEX_EDUMANUFID, + 120, 51, 55, 118, 98, 111, 111, 116 +}; + +#define MIDIBOOT_SYSEX_ID_LEN 9 + +typedef enum { + MIDIBOOT_INVALID = 0, + MIDIBOOT_LEAVE_BOOT = 1, + MIDIBOOT_GETPAGESIZE = 2, + MIDIBOOT_FILLPAGE = 3, + MIDIBOOT_WRITEPAGE = 4 +} midiboot_sysex_t; + +#endif diff --git a/bootloader/uploader/Makefile b/bootloader/uploader/Makefile new file mode 100644 index 0000000..5e8b763 --- /dev/null +++ b/bootloader/uploader/Makefile @@ -0,0 +1,22 @@ +CFLAGS = -Wall -g -I. -I../ -I../midi +LDFLAGS = -lportmidi +CC = g++ +SRC = main.cpp \ + ../midi/sysex_tools.c + +OBJ = ${SRC:.cpp=.o} + +current: sysexupload + +.cpp.o: + @echo CC $< + @${CC} -c ${CFLAGS} -o $*.o $< + +sysexupload: ${OBJ} + @echo CC $@ + @${CC} ${CFLAGS} -o $@ ${OBJ} ${LDFLAGS} + +clean: + rm -f *.o sysexupload + +all: sysexupload diff --git a/bootloader/uploader/main.cpp b/bootloader/uploader/main.cpp new file mode 100644 index 0000000..f18c81b --- /dev/null +++ b/bootloader/uploader/main.cpp @@ -0,0 +1,492 @@ +/* + * This is a derivative of SysExBoot + * + * Modified by Brian Richardson for Jabrudian Industries + * + * >>>>>>>>>>>>>> origional header >>>>>> + * + * "A sysex bootloader for avr chips." + * Copyright 2010 Alex Norman + * + * This file is part of SysexBoot. + * + * + * SysexBoot 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. + * + * SysexBoot 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 SysexBoot. If not, see . + * + * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ +#include +#include +#include +#include +#include "portmidi.h" +#include "porttime.h" +#include +#include +#include + +#include "sysex_tools.h" + +#include "midibootcommon.h" + +#define TIMEOUT_MS 3000 + +#define CHUNK_SIZE 48 + +/* + * a sysex packet for a page_fill looks like: + * MIDI_SYSEX_START + * midiboot_sysex_id[] + * MIDIBOOT_FILLPAGE + * packed_addr+data[<=35] (unpacks to 2 addr bytes + 28 or fewer data bytes) + * MIDI_SYSEX_STOP + */ + +using std::cout; +using std::cerr; +using std::endl; +using std::hex; +using std::dec; + +void simple_bit_unpack(uint8_t * unpacked, const uint8_t * source, + uint16_t length) +{ + for (int i = 0; i < length; i += 2) { + unpacked[i / 2] = (source[i] << 4) | source[i + 1]; + } +} + +uint16_t simple_bit_packed_length(uint16_t unpacked_length) +{ + return unpacked_length * 2; +} + +uint16_t simple_bit_pack(uint8_t * packed, const uint8_t * source, + uint16_t length) +{ + for (int i = 0; i < length; i++) { + packed[i * 2] = source[i] >> 4; + packed[i * 2 + 1] = source[i] & 0xF; + } + return length * 2; +} + +int getMissingLink(bool input) +{ + for (int i = 0; i < Pm_CountDevices(); i++) { + const PmDeviceInfo *info = Pm_GetDeviceInfo(i); + if ((info->input && input) || (info->output && !input)) { + if (strncmp(info->name, "Missing Link", 12) == 0) { + return i; + } + } + } + return -1; +} + +void printMidiDevices(bool input) +{ + for (int i = 0; i < Pm_CountDevices(); i++) { + const PmDeviceInfo *info = Pm_GetDeviceInfo(i); + if (info->input && input) + cout << i << ", " << info->interf << ", " << info-> + name << endl; + if (info->output && !input) + cout << i << ", " << info->interf << ", " << info-> + name << endl; + //printf("%d: %s, %s\n", i, info->interf, info->name); + } +} + +void MLCommand(PmStream * midi_in, PmStream * midi_out, long timeout, + unsigned char command) +{ + // SYSEX BEGIN, EDU, MLNK, 3=enter bootloader, SYSEX END + unsigned char requestMsg[] = + { 0xF0, 0x7D, 0x4D, 0x4C, 0x4E, 0x4B, command, 0xF7 }; + //send the message + PmError error = Pm_WriteSysEx(midi_out, 0, requestMsg); + if (error) { + cerr << "error writing ENTER BOOTLOADER msg: " << + Pm_GetErrorText(error) << endl; + exit(-1); + } + long startTime = Pt_Time(); + while (Pt_Time() - startTime < timeout) ; +} + +int getPageSize(PmStream * midi_in, PmStream * midi_out, long timeout) +{ + PmEvent msg; + bool inSysexMessage; + unsigned int sysexByteCount; + long startTime = Pt_Time(); + int pageSize = 0; + uint8_t buf[3]; + uint8_t bufout[3]; + + //write get page size message + unsigned char requestMsg[64]; + memset(&requestMsg, 0, 64); + requestMsg[0] = MIDI_SYSEX_START; + for (unsigned int i = 0; i < MIDIBOOT_SYSEX_ID_LEN; i++) + requestMsg[i + 1] = midiboot_sysex_id[i]; + requestMsg[MIDIBOOT_SYSEX_ID_LEN + 1] = MIDIBOOT_GETPAGESIZE; + requestMsg[MIDIBOOT_SYSEX_ID_LEN + 2] = MIDI_SYSEX_STOP; + //send the message + PmError error = Pm_WriteSysEx(midi_out, 0, requestMsg); + if (error) { + cerr << "error writing GET PAGE SIZE msg: " << + Pm_GetErrorText(error) << endl; + exit(-1); + } + //allow for a second timeout + while (startTime + timeout > Pt_Time()) { + unsigned int count = Pm_Read(midi_in, &msg, 1); + if (count != 0) { + for (unsigned int i = 0; i < 4; i++) { + unsigned char inByte = + (msg.message >> (i * 8)) & 0xFF; + if (inByte == MIDI_SYSEX_START) { + sysexByteCount = 0; + inSysexMessage = true; + } else if (inSysexMessage) { + if (inByte == MIDI_SYSEX_STOP) { + simple_bit_unpack(bufout, buf, + 4); + pageSize = + (bufout[0] << 8) | + bufout[1]; + return pageSize; + } else + if ((sysexByteCount < + MIDIBOOT_SYSEX_ID_LEN)) { + //make sure that our id matches + if (inByte == + midiboot_sysex_id + [sysexByteCount]) + sysexByteCount++; + else + inSysexMessage = false; + } else if (sysexByteCount == + MIDIBOOT_SYSEX_ID_LEN) { + if (inByte != + MIDIBOOT_GETPAGESIZE) + inSysexMessage = false; + else + sysexByteCount++; + } else if (sysexByteCount < + (MIDIBOOT_SYSEX_ID_LEN + + 5)) { + unsigned int index = + (sysexByteCount - + MIDIBOOT_SYSEX_ID_LEN - 1); + buf[index] = inByte; + sysexByteCount++; + } else + inSysexMessage = false; + } + } + } + } + cout << endl; + return 0; +} + +bool waitForAck(PmStream * midi_in, long timeout) +{ + PmEvent msg; + bool inSysexMessage; + unsigned int sysexByteCount; + long startTime = Pt_Time(); + //allow for a second timeout + while (startTime + timeout > Pt_Time()) { + unsigned int count = Pm_Read(midi_in, &msg, 1); + if (count != 0) { + for (unsigned int i = 0; i < 4; i++) { + unsigned char inByte = + (msg.message >> (i * 8)) & 0xFF; + if (inByte == MIDI_SYSEX_START) { + sysexByteCount = 0; + inSysexMessage = true; + } else if (inSysexMessage) { + if (sysexByteCount == + MIDIBOOT_SYSEX_ID_LEN) { + if (inByte == MIDI_SYSEX_STOP) { + return true; + } else + inSysexMessage = false; + } else + if ((sysexByteCount < + MIDIBOOT_SYSEX_ID_LEN) + && inByte == + midiboot_sysex_id + [sysexByteCount]) + sysexByteCount++; + else + inSysexMessage = false; + } + } + } + } + return false; +} + +void writeSysexPrefix(std::vector < unsigned char >*sysexMesg) +{ + sysexMesg->push_back(MIDI_SYSEX_START); + for (unsigned int i = 0; i < MIDIBOOT_SYSEX_ID_LEN; i++) + sysexMesg->push_back(midiboot_sysex_id[i]); +} + +int main(int argc, char *argv[]) +{ + std::vector < unsigned char >inputData; + std::vector < std::vector < unsigned char >*>pages; + std::vector < std::vector < unsigned char >*>sysexMessages; + std::vector < unsigned char >packedPage; + unsigned char tmp; + int id; + std::ifstream inFile; + struct stat stFileInfo; + PmStream *midi_in; + PmStream *midi_out; + unsigned int pageSize = 0; + unsigned short numPages = 0; + const PmDeviceInfo *info; + + //start our time + Pt_Start(1, 0, 0); + + //test args + if (argc != 2) { + cout << "usage:" << endl; + cout << argv[0] << " binfiletoupload" << endl; + exit(-1); + } + if (stat(argv[1], &stFileInfo) != 0 || !S_ISREG(stFileInfo.st_mode)) { + cerr << "file does not exist or is not a regular file" << endl; + exit(-1); + } + + printMidiDevices(true); + printMidiDevices(false); + + id = getMissingLink(true); + if (id == -1) { + cerr << "I Did Not Find a Missing Link!" << endl; + exit(-1); + } +//error checking here VVVV + info = Pm_GetDeviceInfo(id); + cout << endl << "**opening input : " << info->name << endl << endl; +//error checking here VVVV + Pm_OpenInput(&midi_in, id, NULL, 512, NULL, NULL); + + id = getMissingLink(false); + if (id == -1) { + cerr << "Could Not Find Missing Links Ouput" << endl; + exit(-1); + } +//error checking here VVVV + info = Pm_GetDeviceInfo(id); + cout << endl << "**opening output : " << info->name << endl << endl; +//error checking here VVVV + Pm_OpenOutput(&midi_out, id, NULL, 0, NULL, NULL, 0); + + cout << "uploading file " << argv[1] << endl; + //cout << "* make sure that you have put the microcontroller in boot loader mode" << endl; + //cout << "hit enter to continue, or control-c to quit" << endl; + //std::cin.get(); + + //grab the page size! + MLCommand(midi_in, midi_out, 1500, 3); + pageSize = getPageSize(midi_in, midi_out, 3000); + if (pageSize == 0) { + cerr << + "*** failed to get the page size from the microcontroller" + << endl; + cerr << "*** are you in boot loader mode?" << endl; + cerr << + "*** do you have both the midi input and output to/from your microcontroller connected to your computer" + << endl; + cerr << "*** did you select the correct input and output?" << + endl; + cerr << "*** aborting" << endl; + exit(-1); + } else if (pageSize != 128) { + cerr << "*** something is amok !!! " << endl + << " " << pageSize << " isnt the page size we are expecting (128)" << endl + << " Bailing ***" << endl; + exit(-1); + } + + + //open the file + inFile.open(argv[1], std::ios::in | std::ios::binary); + if (!inFile.is_open()) { + cerr << "cannot open file: " << argv[1] << endl; + //Pm_Close(midi_out); + Pm_Close(midi_in); + exit(-1); + } + //read in the file data + tmp = inFile.get(); + while (!inFile.eof()) { + inputData.push_back(tmp); + tmp = inFile.get(); + } + //see if there is data + if (inputData.size() < 1) { + cerr << "datafile is empty" << endl; + //Pm_Close(midi_out); + Pm_Close(midi_in); + exit(-1); + } + //compute the number of pages we'll need + numPages = (unsigned short)ceil((float)inputData.size() / pageSize); + if (numPages == 0) + numPages = 1; + //make sure there are enough positions in the pages + pages.reserve(numPages); + sysexMessages.reserve(numPages); + + //cut the data into pages + for (unsigned short i = 0; i < inputData.size(); i++) { + unsigned int pageIndex = i / pageSize; + //if we're at a new page then push the page index, two bytes + if (i % pageSize == 0) { + pages.push_back(new std::vector < unsigned char >); + } + pages[pageIndex]->push_back(inputData[i]); + } + + //pack and build the sysex messages + cout << "byte packing the file contents" << endl; + + for (unsigned int i = 0; i < numPages; i++) { + //create a new sysex message for each chunk + for (unsigned int j = 0; j < pages[i]->size(); j += CHUNK_SIZE) { + std::vector < unsigned char >tmp; + unsigned int start_index = j; + unsigned int end_index = j + CHUNK_SIZE; + + //make sure our index is in range + if (end_index > pages[i]->size()) + end_index = pages[i]->size(); + std::vector < unsigned char >*newMsg = + new std::vector < unsigned char >; + + //write the header + writeSysexPrefix(newMsg); + newMsg->push_back(MIDIBOOT_FILLPAGE); + + //write address to tmp + unsigned int pageAddress = i * pageSize + start_index; + tmp.clear(); + tmp.push_back((unsigned char)(pageAddress >> 8) & 0xFF); + tmp.push_back((unsigned char)pageAddress & 0xFF); + + //write the data to tmp + for (unsigned int k = start_index; k < end_index; k++) + tmp.push_back(pages[i]->at(k)); + + //pack the address+data + packedPage.clear(); + packedPage.resize(simple_bit_packed_length(tmp.size())); + + simple_bit_pack(&packedPage[0], &tmp[0], tmp.size()); + + //write the packed address+data to the sysexMessage + for (std::vector < unsigned char >::iterator it = + packedPage.begin(); it != packedPage.end(); it++) + newMsg->push_back(*it); + + //write the sysex end message + newMsg->push_back(MIDI_SYSEX_STOP); + //push this sysex message onto our list of sysex messages + sysexMessages.push_back(newMsg); + } + //create the 'write page' sysex message + std::vector < unsigned char >*newMsg = + new std::vector < unsigned char >; + writeSysexPrefix(newMsg); + newMsg->push_back(MIDIBOOT_WRITEPAGE); + newMsg->push_back(MIDI_SYSEX_STOP); + //push this sysex message onto our list of sysex messages + sysexMessages.push_back(newMsg); + } + + cout << "page size: " << pageSize << endl; + cout << "this many pages will be written: " << pages.size() << endl; + cout << "this many bytes will be written: " << inputData.size() << endl; + cout << "using this many sysex messages: " << sysexMessages. + size() << endl; + + //upload + cout << "uploading now" << endl; + + //send each sysex message + for (std::vector < std::vector < unsigned char >*>::iterator it = + sysexMessages.begin(); it != sysexMessages.end(); it++) { + PmError error; + unsigned char msg[64]; + + //make sure we've only got zeros + memset(&msg, 0, 64); + + //fill in sysex buffer + for (unsigned int i = 0; i < (*it)->size(); i++) { + msg[i] = (*it)->at(i); + } + + //send the message + error = Pm_WriteSysEx(midi_out, 0, msg); + if (error) { + cerr << "error: " << Pm_GetErrorText(error) << endl; + exit(-1); + } + //get ack + if (!waitForAck(midi_in, TIMEOUT_MS)) { + cerr << + "FAILED: sysex message failed to acknowledge within the timeout" + << endl; + cerr << "was the microcontroller in boot loader mode?" + << endl; + exit(-1); + } + } + + cout << "success" << endl; + + //leave boot + unsigned char msg[64]; + memset(&msg, 0, 64); + msg[0] = MIDI_SYSEX_START; + for (unsigned int i = 0; i < MIDIBOOT_SYSEX_ID_LEN; i++) + msg[i + 1] = midiboot_sysex_id[i]; + msg[MIDIBOOT_SYSEX_ID_LEN + 1] = MIDIBOOT_LEAVE_BOOT; + msg[MIDIBOOT_SYSEX_ID_LEN + 2] = MIDI_SYSEX_STOP; + //send the message + PmError error = Pm_WriteSysEx(midi_out, 0, msg); + if (error) { + cerr << "error writing LEAVE BOOT msg: " << + Pm_GetErrorText(error) << endl; + exit(-1); + } + MLCommand(midi_in, midi_out, 1500, 1); + + Pm_Close(midi_out); + Pm_Close(midi_in); + return 0; +} diff --git a/readme.markdown b/readme.markdown index 5eea2ca..e9f10f1 100644 --- a/readme.markdown +++ b/readme.markdown @@ -1,7 +1,17 @@ -# Intro - -This branch of the WiSheildOSC code is focused on support The Missing Link. http://www.youtube.com/watch?v=YarIPK-gwbw&feature=player_embedded this branch will focus on ease of use for that device and will likely strip away all unneeded code/examples (and change the uIP stack) - -# Todo - -* Add /midi extended message support. \ No newline at end of file +# Intro + +This is the bootloader and firmware for the AVR chip used with The Missing Link (http://wifimidi.com/). It is Copyright 2011 Jabrudian Industries LLC. + +# License + +This code is licensed under GPL 3, see COPYING for more information. + +# Getting the code onto the device + +See bootloader/README for more details on compiling and using the bootloader. There is a Makefile setup for use with avrdude and a AVRMKII ISP programmer in bootloader/avr_code. The target is program. + +To compile/burn the main firmware, first make sure that the uploader program under bootloader/uploader has been compiled. Then go to the MissingLink directory and type make program. + +# General overview + +The AVR chip communicates to two other modules. One is a WIFI module and the other is an USB MIDI module. The WIFI module is controlled via SPI. The USB MIDI module is controlled via I2C. OSC packets are received via UDP and processed by the uIP/WiShield TCP/IP stack and code in udpapp.cpp. This is then fed to the OSC library (http://recotana.com). From here the message is dispatched to the code that responds to it (MissingLink.cpp). For a normal OSC->MIDI message, handleTouchOSCMidi (HandleMidi.cpp) is called and uses code from Parse.cpp to parse the OSC address and send data to MIDI. For MIDI input, the avrmidi library (http://www.x37v.info) is used to parse incoming midi and routed out to the appropiate destination. Finally, I2C support is provided by the twi/arduino library and user code is at the bottom of HandleMidi.cpp. (More to come here..) \ No newline at end of file -- cgit v1.2.3