From 92eed41b794619aaeb2947f6b9ff22a9e7eef08c Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Thu, 31 Dec 2015 00:54:23 -0800 Subject: [PATCH 001/110] initial pass at BLE firmata for Arduino 101 --- examples/StandardFirmataBLE/LICENSE.txt | 458 ++++++++++ .../StandardFirmataBLE/StandardFirmataBLE.ino | 780 ++++++++++++++++++ utility/BLEStream.cpp | 132 +++ utility/BLEStream.h | 54 ++ 4 files changed, 1424 insertions(+) create mode 100755 examples/StandardFirmataBLE/LICENSE.txt create mode 100755 examples/StandardFirmataBLE/StandardFirmataBLE.ino create mode 100644 utility/BLEStream.cpp create mode 100644 utility/BLEStream.h diff --git a/examples/StandardFirmataBLE/LICENSE.txt b/examples/StandardFirmataBLE/LICENSE.txt new file mode 100755 index 00000000..77cec6dd --- /dev/null +++ b/examples/StandardFirmataBLE/LICENSE.txt @@ -0,0 +1,458 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino new file mode 100755 index 00000000..bb44af60 --- /dev/null +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -0,0 +1,780 @@ +/* + Firmata is a generic protocol for communicating with microcontrollers + from software on a host computer. It is intended to work with + any host computer software package. + + To download a host software package, please clink on the following link + to open the list of Firmata client libraries your default browser. + + https://github.com/firmata/arduino#firmata-client-libraries + + Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved. + Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. + Copyright (C) 2009-2015 Jeff Hoefs. 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. + + See file LICENSE.txt for further informations on licensing terms. + + Last updated by Jeff Hoefs: December 26th, 2015 +*/ + +#include +#include +#include + +#include +#include "utility/BLEStream.h" + +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 +#define I2C_END_TX_MASK B01000000 +#define I2C_STOP_TX 1 +#define I2C_RESTART_TX 0 +#define I2C_MAX_QUERIES 8 +#define I2C_REGISTER_NOT_SPECIFIED -1 + +// the minimum interval for sampling analog input +#define MINIMUM_SAMPLING_INTERVAL 1 + + +/*============================================================================== + * GLOBAL VARIABLES + *============================================================================*/ + +/* analog inputs */ +int analogInputsToReport = 0; // bitwise array to store pin reporting + +/* digital input ports */ +byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence +byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent + +/* pins configuration */ +byte pinConfig[TOTAL_PINS]; // configuration of every pin +byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else +int pinState[TOTAL_PINS]; // any value that has been written + +/* timer variables */ +unsigned long currentMillis; // store the current value from millis() +unsigned long previousMillis; // for comparison with currentMillis +unsigned int samplingInterval = 19; // how often to run the main loop (in ms) + +/* i2c data */ +struct i2c_device_info { + byte addr; + int reg; + byte bytes; + byte stopTX; +}; + +/* for i2c read continuous more */ +i2c_device_info query[I2C_MAX_QUERIES]; + +byte i2cRxData[32]; +boolean isI2CEnabled = false; +signed char queryIndex = -1; +// default delay time between i2c read request and Wire.requestFrom() +unsigned int i2cReadDelayTime = 0; + +Servo servos[MAX_SERVOS]; +byte servoPinMap[TOTAL_PINS]; +byte detachedServos[MAX_SERVOS]; +byte detachedServoCount = 0; +byte servoCount = 0; + +boolean isResetting = false; + +BLEStream stream(0); + +/* utility functions */ +void wireWrite(byte data) +{ +#if ARDUINO >= 100 + Wire.write((byte)data); +#else + Wire.send(data); +#endif +} + +byte wireRead(void) +{ +#if ARDUINO >= 100 + return Wire.read(); +#else + return Wire.receive(); +#endif +} + +/*============================================================================== + * FUNCTIONS + *============================================================================*/ + +void attachServo(byte pin, int minPulse, int maxPulse) +{ + if (servoCount < MAX_SERVOS) { + // reuse indexes of detached servos until all have been reallocated + if (detachedServoCount > 0) { + servoPinMap[pin] = detachedServos[detachedServoCount - 1]; + if (detachedServoCount > 0) detachedServoCount--; + } else { + servoPinMap[pin] = servoCount; + servoCount++; + } + if (minPulse > 0 && maxPulse > 0) { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); + } else { + servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); + } + } else { + Firmata.sendString("Max servos attached"); + } +} + +void detachServo(byte pin) +{ + servos[servoPinMap[pin]].detach(); + // if we're detaching the last servo, decrement the count + // otherwise store the index of the detached servo + if (servoPinMap[pin] == servoCount && servoCount > 0) { + servoCount--; + } else if (servoCount > 0) { + // keep track of detached servos because we want to reuse their indexes + // before incrementing the count of attached servos + detachedServoCount++; + detachedServos[detachedServoCount - 1] = servoPinMap[pin]; + } + + servoPinMap[pin] = 255; +} + +void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { + // allow I2C requests that don't require a register read + // for example, some devices using an interrupt pin to signify new data available + // do not always require the register read so upon interrupt you call Wire.requestFrom() + if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { + Wire.beginTransmission(address); + wireWrite((byte)theRegister); + Wire.endTransmission(stopTX); // default = true + // do not set a value of 0 + if (i2cReadDelayTime > 0) { + // delay is necessary for some devices such as WiiNunchuck + delayMicroseconds(i2cReadDelayTime); + } + } else { + theRegister = 0; // fill the register with a dummy value + } + + Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom + + // check to be sure correct number of bytes were returned by slave + if (numBytes < Wire.available()) { + Firmata.sendString("I2C: Too many bytes received"); + } else if (numBytes > Wire.available()) { + Firmata.sendString("I2C: Too few bytes received"); + } + + i2cRxData[0] = address; + i2cRxData[1] = theRegister; + + for (int i = 0; i < numBytes && Wire.available(); i++) { + i2cRxData[2 + i] = wireRead(); + } + + // send slave address, register and received bytes + Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); +} + +void outputPort(byte portNumber, byte portValue, byte forceSend) +{ + // pins not configured as INPUT are cleared to zeros + portValue = portValue & portConfigInputs[portNumber]; + // only send if the value is different than previously sent + if (forceSend || previousPINs[portNumber] != portValue) { + Firmata.sendDigitalPort(portNumber, portValue); + previousPINs[portNumber] = portValue; + } +} + +/* ----------------------------------------------------------------------------- + * check all the active digital inputs for change of state, then add any events + * to the Serial output queue using Serial.print() */ +void checkDigitalInputs(void) +{ + /* Using non-looping code allows constants to be given to readPort(). + * The compiler will apply substantial optimizations if the inputs + * to readPort() are compile-time constants. */ + if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); + if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); + if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); + if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); + if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); + if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); + if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); + if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); + if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); + if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); + if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); + if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); + if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); + if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); + if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); + if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); +} + +// ----------------------------------------------------------------------------- +/* sets the pin mode to the correct state and sets the relevant bits in the + * two bit-arrays that track Digital I/O and PWM status + */ +void setPinModeCallback(byte pin, int mode) +{ + if (pinConfig[pin] == PIN_MODE_IGNORE) + return; + + if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { + // disable i2c so pins can be used for other functions + // the following if statements should reconfigure the pins properly + disableI2CPins(); + } + if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + } + if (IS_PIN_ANALOG(pin)) { + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting + } + if (IS_PIN_DIGITAL(pin)) { + if (mode == INPUT || mode == PIN_MODE_PULLUP) { + portConfigInputs[pin / 8] |= (1 << (pin & 7)); + } else { + portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); + } + } + pinState[pin] = 0; + switch (mode) { + case PIN_MODE_ANALOG: + if (IS_PIN_ANALOG(pin)) { + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif + } + pinConfig[pin] = PIN_MODE_ANALOG; + } + break; + case INPUT: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +#if ARDUINO <= 100 + // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +#endif + pinConfig[pin] = INPUT; + } + break; + case PIN_MODE_PULLUP: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); + pinConfig[pin] = PIN_MODE_PULLUP; + pinState[pin] = 1; + } + break; + case OUTPUT: + if (IS_PIN_DIGITAL(pin)) { + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + pinMode(PIN_TO_DIGITAL(pin), OUTPUT); + pinConfig[pin] = OUTPUT; + } + break; + case PIN_MODE_PWM: + if (IS_PIN_PWM(pin)) { + pinMode(PIN_TO_PWM(pin), OUTPUT); + analogWrite(PIN_TO_PWM(pin), 0); + pinConfig[pin] = PIN_MODE_PWM; + } + break; + case PIN_MODE_SERVO: + if (IS_PIN_DIGITAL(pin)) { + pinConfig[pin] = PIN_MODE_SERVO; + if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { + // pass -1 for min and max pulse values to use default values set + // by Servo library + attachServo(pin, -1, -1); + } + } + break; + case PIN_MODE_I2C: + if (IS_PIN_I2C(pin)) { + // mark the pin as i2c + // the user must call I2C_CONFIG to enable I2C for a device + pinConfig[pin] = PIN_MODE_I2C; + } + break; + default: + Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM + } + // TODO: save status to EEPROM here, if changed +} + +/* + * Sets the value of an individual pin. Useful if you want to set a pin value but + * are not tracking the digital port state. + * Can only be used on pins configured as OUTPUT. + * Cannot be used to enable pull-ups on Digital INPUT pins. + */ +void setPinValueCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { + if (pinConfig[pin] == OUTPUT) { + pinState[pin] = value; + digitalWrite(PIN_TO_DIGITAL(pin), value); + } + } +} + +void analogWriteCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS) { + switch (pinConfig[pin]) { + case PIN_MODE_SERVO: + if (IS_PIN_DIGITAL(pin)) + servos[servoPinMap[pin]].write(value); + pinState[pin] = value; + break; + case PIN_MODE_PWM: + if (IS_PIN_PWM(pin)) + analogWrite(PIN_TO_PWM(pin), value); + pinState[pin] = value; + break; + } + } +} + +void digitalWriteCallback(byte port, int value) +{ + byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; + + if (port < TOTAL_PORTS) { + // create a mask of the pins on this port that are writable. + lastPin = port * 8 + 8; + if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; + for (pin = port * 8; pin < lastPin; pin++) { + // do not disturb non-digital pins (eg, Rx & Tx) + if (IS_PIN_DIGITAL(pin)) { + // do not touch pins in PWM, ANALOG, SERVO or other modes + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinValue = ((byte)value & mask) ? 1 : 0; + if (pinConfig[pin] == OUTPUT) { + pinWriteMask |= mask; + } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + // only handle INPUT here for backwards compatibility +#if ARDUINO > 100 + pinMode(pin, INPUT_PULLUP); +#else + // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier + pinWriteMask |= mask; +#endif + } + pinState[pin] = pinValue; + } + } + mask = mask << 1; + } + writePort(port, (byte)value, pinWriteMask); + } +} + + +// ----------------------------------------------------------------------------- +/* sets bits in a bit array (int) to toggle the reporting of the analogIns + */ +//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { +//} +void reportAnalogCallback(byte analogPin, int value) +{ + if (analogPin < TOTAL_ANALOG_PINS) { + if (value == 0) { + analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); + } else { + analogInputsToReport = analogInputsToReport | (1 << analogPin); + // prevent during system reset or all analog pin values will be reported + // which may report noise for unconnected analog pins + if (!isResetting) { + // Send pin value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // TODO: save status to EEPROM here, if changed +} + +void reportDigitalCallback(byte port, int value) +{ + if (port < TOTAL_PORTS) { + reportPINs[port] = (byte)value; + // Send port value immediately. This is helpful when connected via + // ethernet, wi-fi or bluetooth so pin states can be known upon + // reconnecting. + if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); + } + // do not disable analog reporting on these 8 pins, to allow some + // pins used for digital, others analog. Instead, allow both types + // of reporting to be enabled, but check if the pin is configured + // as analog when sampling the analog inputs. Likewise, while + // scanning digital pins, portConfigInputs will mask off values from any + // pins configured as analog +} + +/*============================================================================== + * SYSEX-BASED commands + *============================================================================*/ + +void sysexCallback(byte command, byte argc, byte *argv) +{ + byte mode; + byte stopTX; + byte slaveAddress; + byte data; + int slaveRegister; + unsigned int delayTime; + + switch (command) { + case I2C_REQUEST: + mode = argv[1] & I2C_READ_WRITE_MODE_MASK; + if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { + Firmata.sendString("10-bit addressing not supported"); + return; + } + else { + slaveAddress = argv[0]; + } + + // need to invert the logic here since 0 will be default for client + // libraries that have not updated to add support for restart tx + if (argv[1] & I2C_END_TX_MASK) { + stopTX = I2C_RESTART_TX; + } + else { + stopTX = I2C_STOP_TX; // default + } + + switch (mode) { + case I2C_WRITE: + Wire.beginTransmission(slaveAddress); + for (byte i = 2; i < argc; i += 2) { + data = argv[i] + (argv[i + 1] << 7); + wireWrite(data); + } + Wire.endTransmission(); + delayMicroseconds(70); + break; + case I2C_READ: + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = I2C_REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX); + break; + case I2C_READ_CONTINUOUSLY: + if ((queryIndex + 1) >= I2C_MAX_QUERIES) { + // too many queries, just ignore + Firmata.sendString("too many queries"); + break; + } + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + } + else { + // a slave register is NOT specified + slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; + data = argv[2] + (argv[3] << 7); // bytes to read + } + queryIndex++; + query[queryIndex].addr = slaveAddress; + query[queryIndex].reg = slaveRegister; + query[queryIndex].bytes = data; + query[queryIndex].stopTX = stopTX; + break; + case I2C_STOP_READING: + byte queryIndexToSkip; + // if read continuous mode is enabled for only 1 i2c device, disable + // read continuous reporting for that device + if (queryIndex <= 0) { + queryIndex = -1; + } else { + queryIndexToSkip = 0; + // if read continuous mode is enabled for multiple devices, + // determine which device to stop reading and remove it's data from + // the array, shifiting other array data to fill the space + for (byte i = 0; i < queryIndex + 1; i++) { + if (query[i].addr == slaveAddress) { + queryIndexToSkip = i; + break; + } + } + + for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { + if (i < I2C_MAX_QUERIES) { + query[i].addr = query[i + 1].addr; + query[i].reg = query[i + 1].reg; + query[i].bytes = query[i + 1].bytes; + query[i].stopTX = query[i + 1].stopTX; + } + } + queryIndex--; + } + break; + default: + break; + } + break; + case I2C_CONFIG: + delayTime = (argv[0] + (argv[1] << 7)); + + if (delayTime > 0) { + i2cReadDelayTime = delayTime; + } + + if (!isI2CEnabled) { + enableI2CPins(); + } + + break; + case SERVO_CONFIG: + if (argc > 4) { + // these vars are here for clarity, they'll optimized away by the compiler + byte pin = argv[0]; + int minPulse = argv[1] + (argv[2] << 7); + int maxPulse = argv[3] + (argv[4] << 7); + + if (IS_PIN_DIGITAL(pin)) { + if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { + detachServo(pin); + } + attachServo(pin, minPulse, maxPulse); + setPinModeCallback(pin, PIN_MODE_SERVO); + } + } + break; + case SAMPLING_INTERVAL: + if (argc > 1) { + samplingInterval = argv[0] + (argv[1] << 7); + if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { + samplingInterval = MINIMUM_SAMPLING_INTERVAL; + } + } else { + //Firmata.sendString("Not enough data"); + } + break; + case EXTENDED_ANALOG: + if (argc > 1) { + int val = argv[1]; + if (argc > 2) val |= (argv[2] << 7); + if (argc > 3) val |= (argv[3] << 14); + analogWriteCallback(argv[0], val); + } + break; + case CAPABILITY_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(CAPABILITY_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_DIGITAL(pin)) { + Firmata.write((byte)INPUT); + Firmata.write(1); + Firmata.write((byte)PIN_MODE_PULLUP); + Firmata.write(1); + Firmata.write((byte)OUTPUT); + Firmata.write(1); + } + if (IS_PIN_ANALOG(pin)) { + Firmata.write(PIN_MODE_ANALOG); + Firmata.write(10); // 10 = 10-bit resolution + } + if (IS_PIN_PWM(pin)) { + Firmata.write(PIN_MODE_PWM); + Firmata.write(8); // 8 = 8-bit resolution + } + if (IS_PIN_DIGITAL(pin)) { + Firmata.write(PIN_MODE_SERVO); + Firmata.write(14); + } + if (IS_PIN_I2C(pin)) { + Firmata.write(PIN_MODE_I2C); + Firmata.write(1); // TODO: could assign a number to map to SCL or SDA + } + Firmata.write(127); + } + Firmata.write(END_SYSEX); + break; + case PIN_STATE_QUERY: + if (argc > 0) { + byte pin = argv[0]; + Firmata.write(START_SYSEX); + Firmata.write(PIN_STATE_RESPONSE); + Firmata.write(pin); + if (pin < TOTAL_PINS) { + Firmata.write((byte)pinConfig[pin]); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + } + Firmata.write(END_SYSEX); + } + break; + case ANALOG_MAPPING_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(ANALOG_MAPPING_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); + } + Firmata.write(END_SYSEX); + break; + } +} + +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + +/*============================================================================== + * SETUP() + *============================================================================*/ + +void systemResetCallback() +{ + isResetting = true; + + if (isI2CEnabled) { + disableI2CPins(); + } + + for (byte i = 0; i < TOTAL_PORTS; i++) { + reportPINs[i] = false; // by default, reporting off + portConfigInputs[i] = 0; // until activated + previousPINs[i] = 0; + } + + for (byte i = 0; i < TOTAL_PINS; i++) { + // pins with analog capability default to analog input + // otherwise, pins default to digital output + if (IS_PIN_ANALOG(i)) { + // turns off pullup, configures everything + setPinModeCallback(i, PIN_MODE_ANALOG); + } else if (IS_PIN_DIGITAL(i)) { + // sets the output to 0, configures portConfigInputs + setPinModeCallback(i, OUTPUT); + } + + servoPinMap[i] = 255; + } + // by default, do not report any analog inputs + analogInputsToReport = 0; + + detachedServoCount = 0; + servoCount = 0; + + isResetting = false; +} + +void setup() +{ + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); + + Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); + Firmata.attach(REPORT_ANALOG, reportAnalogCallback); + Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); + Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); + Firmata.attach(START_SYSEX, sysexCallback); + Firmata.attach(SYSTEM_RESET, systemResetCallback); + + stream.setLocalName("FIRMATA"); + + stream.begin(); + Firmata.begin(stream); + + systemResetCallback(); // reset to default config +} + +/*============================================================================== + * LOOP() + *============================================================================*/ +void loop() +{ + byte pin, analogPin; + + // do not process data if no BLE connection is established + if (!stream.poll()) return; + + /* DIGITALREAD - as fast as possible, check for changes and output them to the + * Stream buffer using Stream.write() */ + checkDigitalInputs(); + //stream.flush(); // send digital input values immediately + + /* STREAMREAD - processing incoming messagse as soon as possible, while still + * checking digital inputs. */ + while (Firmata.available()) + Firmata.processInput(); + + currentMillis = millis(); + if (currentMillis - previousMillis > samplingInterval) { + previousMillis += samplingInterval; + /* ANALOGREAD - do all analogReads() at the configured sampling interval */ + for (pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { + analogPin = PIN_TO_ANALOG(pin); + if (analogInputsToReport & (1 << analogPin)) { + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // report i2c data for all device with read continuous mode enabled + if (queryIndex > -1) { + for (byte i = 0; i < queryIndex + 1; i++) { + readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); + } + } + //stream.flush(); + } +} diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp new file mode 100644 index 00000000..624c0c4d --- /dev/null +++ b/utility/BLEStream.cpp @@ -0,0 +1,132 @@ +/* + BLEStream.cpp + + Based on BLESerial.cpp by Voita Molda + https://github.com/vojtamolda/BLEPeripheral/blob/master/examples/uart/BLESerial.cpp + */ + +#include "BLEStream.h" + +// #define BLE_SERIAL_DEBUG + +BLEStream* BLEStream::_instance = NULL; + +BLEStream::BLEStream(unsigned char) : + BLEPeripheral() +{ + this->_txCount = 0; + this->_rxHead = this->_rxTail = 0; + this->_flushed = 0; + BLEStream::_instance = this; + + addAttribute(this->_uartService); + addAttribute(this->_uartNameDescriptor); + setAdvertisedServiceUuid(this->_uartService.uuid()); + addAttribute(this->_rxCharacteristic); + addAttribute(this->_rxNameDescriptor); + this->_rxCharacteristic.setEventHandler(BLEWritten, BLEStream::_received); + addAttribute(this->_txCharacteristic); + addAttribute(this->_txNameDescriptor); +} + +void BLEStream::begin(...) { + BLEPeripheral::begin(); + #ifdef BLE_SERIAL_DEBUG + Serial.println(F("BLEStream::begin()")); + #endif +} + +bool BLEStream::poll() { + this->_connected = BLEPeripheral::connected(); + if (millis() > this->_flushed + 100) flush(); + return this->_connected; +} + +void BLEStream::end() { + this->_rxCharacteristic.setEventHandler(BLEWritten, NULL); + this->_rxHead = this->_rxTail = 0; + flush(); + BLEPeripheral::disconnect(); +} + +int BLEStream::available(void) { + int retval = (this->_rxHead - this->_rxTail + sizeof(this->_rxBuffer)) % sizeof(this->_rxBuffer); + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::available() = ")); + Serial.println(retval); + #endif + return retval; +} + +int BLEStream::peek(void) { + if (this->_rxTail == this->_rxHead) return -1; + unsigned char byte = this->_rxBuffer[this->_rxTail]; + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::peek() = ")); + Serial.print((char) byte); + Serial.print(F(" 0x")); + Serial.println(byte, HEX); + #endif + return byte; +} + +int BLEStream::read(void) { + if (this->_rxTail == this->_rxHead) return -1; + this->_rxTail = (this->_rxTail + 1) % sizeof(this->_rxBuffer); + unsigned char byte = this->_rxBuffer[this->_rxTail]; + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::read() = ")); + Serial.print((char) byte); + Serial.print(F(" 0x")); + Serial.println(byte, HEX); + #endif + return byte; +} + +void BLEStream::flush(void) { + if (this->_txCount == 0) return; + if (this->_connected) this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount); + this->_flushed = millis(); + this->_txCount = 0; + #ifdef BLE_SERIAL_DEBUG + Serial.println(F("BLEStream::flush()")); + #endif +} + +size_t BLEStream::write(uint8_t byte) { + this->_txBuffer[this->_txCount++] = byte; + if (this->_txCount == sizeof(this->_txBuffer)) flush(); + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::write(")); + Serial.print((char) byte); + Serial.print(F(" 0x")); + Serial.print(byte, HEX); + Serial.println(F(") = 1")); + #endif + return 1; +} + +BLEStream::operator bool() { + bool retval = this->_connected = BLEPeripheral::connected(); + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::operator bool() = ")); + Serial.println(retval); + #endif + return retval; +} + +void BLEStream::_received(const unsigned char* data, size_t size) { + for (int i = 0; i < size; i++) { + this->_rxHead = (this->_rxHead + 1) % sizeof(this->_rxBuffer); + this->_rxBuffer[this->_rxHead] = data[i]; + } + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::received(")); + for (int i = 0; i < size; i++) Serial.print((char)data[i]); + Serial.println(F(")")); + #endif +} + +void BLEStream::_received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic) { + BLEStream::_instance->_received(rxCharacteristic.value(), rxCharacteristic.valueLength()); +} diff --git a/utility/BLEStream.h b/utility/BLEStream.h new file mode 100644 index 00000000..49821aae --- /dev/null +++ b/utility/BLEStream.h @@ -0,0 +1,54 @@ +/* + BLEStream.h + + Based on BLESerial.cpp by Voita Molda + https://github.com/vojtamolda/BLEPeripheral/blob/master/examples/uart/BLESerial.h + */ + +#ifndef _BLE_STREAM_H_ +#define _BLE_STREAM_H_ + +#include +#include + +class BLEStream : public BLEPeripheral, public Stream +{ + public: + BLEStream(unsigned char); + + void begin(...); + bool poll(); + void end(); + + virtual int available(void); + virtual int peek(void); + virtual int read(void); + virtual void flush(void); + virtual size_t write(uint8_t byte); + using Print::write; + virtual operator bool(); + + private: + bool _connected; + unsigned long _flushed; + static BLEStream* _instance; + + size_t _rxHead; + size_t _rxTail; + size_t _rxCount() const; + unsigned char _rxBuffer[256]; + size_t _txCount; + unsigned char _txBuffer[BLE_MAX_ATTR_DATA_LEN]; + + BLEService _uartService = BLEService("6E400001-B5A3-F393-E0A9-E50E24DCCA9E"); + BLEDescriptor _uartNameDescriptor = BLEDescriptor("2901", "UART"); + BLECharacteristic _rxCharacteristic = BLECharacteristic("6E400002-B5A3-F393-E0A9-E50E24DCCA9E", BLEWriteWithoutResponse, BLE_MAX_ATTR_DATA_LEN); + BLEDescriptor _rxNameDescriptor = BLEDescriptor("2901", "RX - Receive Data (Write)"); + BLECharacteristic _txCharacteristic = BLECharacteristic("6E400003-B5A3-F393-E0A9-E50E24DCCA9E", BLENotify, BLE_MAX_ATTR_DATA_LEN); + BLEDescriptor _txNameDescriptor = BLEDescriptor("2901", "TX - Transfer Data (Notify)"); + + void _received(const unsigned char* data, size_t size); + static void _received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic); +}; + +#endif From 6ce3fbe5b3471e972d9425dfeefe31f6492181fa Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 3 Jan 2016 16:56:27 -0800 Subject: [PATCH 002/110] fix previousMillis val. minor BLEStream improvements --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 14 +++++++---- utility/BLEStream.cpp | 24 ++++++++----------- utility/BLEStream.h | 2 ++ 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index bb44af60..a5bdbcb7 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -11,7 +11,7 @@ Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved. Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. - Copyright (C) 2009-2015 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2016 Jeff Hoefs. 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 @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: December 26th, 2015 + Last updated by Jeff Hoefs: January 3rd, 2015 */ #include @@ -30,6 +30,9 @@ #include #include "utility/BLEStream.h" +//#define SERIAL_DEBUG +#include "utility/firmataDebug.h" + #define I2C_WRITE B00000000 #define I2C_READ B00001000 #define I2C_READ_CONTINUOUSLY B00010000 @@ -718,6 +721,8 @@ void systemResetCallback() void setup() { + DEBUG_BEGIN(9600); + Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); @@ -745,12 +750,12 @@ void loop() byte pin, analogPin; // do not process data if no BLE connection is established + // poll will send the TX buffer every 30ms while it contains data if (!stream.poll()) return; /* DIGITALREAD - as fast as possible, check for changes and output them to the * Stream buffer using Stream.write() */ checkDigitalInputs(); - //stream.flush(); // send digital input values immediately /* STREAMREAD - processing incoming messagse as soon as possible, while still * checking digital inputs. */ @@ -759,7 +764,7 @@ void loop() currentMillis = millis(); if (currentMillis - previousMillis > samplingInterval) { - previousMillis += samplingInterval; + previousMillis = currentMillis; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { @@ -775,6 +780,5 @@ void loop() readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); } } - //stream.flush(); } } diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp index 624c0c4d..d3f61d9b 100644 --- a/utility/BLEStream.cpp +++ b/utility/BLEStream.cpp @@ -7,7 +7,7 @@ #include "BLEStream.h" -// #define BLE_SERIAL_DEBUG +//#define BLE_SERIAL_DEBUG BLEStream* BLEStream::_instance = NULL; @@ -38,7 +38,7 @@ void BLEStream::begin(...) { bool BLEStream::poll() { this->_connected = BLEPeripheral::connected(); - if (millis() > this->_flushed + 100) flush(); + if (millis() > this->_flushed + BLESTREAM_TXBUFFER_FLUSH_INTERVAL) flush(); return this->_connected; } @@ -52,8 +52,10 @@ void BLEStream::end() { int BLEStream::available(void) { int retval = (this->_rxHead - this->_rxTail + sizeof(this->_rxBuffer)) % sizeof(this->_rxBuffer); #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::available() = ")); - Serial.println(retval); + if (retval > 0) { + Serial.print(F("BLEStream::available() = ")); + Serial.println(retval); + } #endif return retval; } @@ -62,9 +64,7 @@ int BLEStream::peek(void) { if (this->_rxTail == this->_rxHead) return -1; unsigned char byte = this->_rxBuffer[this->_rxTail]; #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::peek() = ")); - Serial.print((char) byte); - Serial.print(F(" 0x")); + Serial.print(F("BLEStream::peek() = 0x")); Serial.println(byte, HEX); #endif return byte; @@ -75,9 +75,7 @@ int BLEStream::read(void) { this->_rxTail = (this->_rxTail + 1) % sizeof(this->_rxBuffer); unsigned char byte = this->_rxBuffer[this->_rxTail]; #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::read() = ")); - Serial.print((char) byte); - Serial.print(F(" 0x")); + Serial.print(F("BLEStream::read() = 0x")); Serial.println(byte, HEX); #endif return byte; @@ -97,9 +95,7 @@ size_t BLEStream::write(uint8_t byte) { this->_txBuffer[this->_txCount++] = byte; if (this->_txCount == sizeof(this->_txBuffer)) flush(); #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::write(")); - Serial.print((char) byte); - Serial.print(F(" 0x")); + Serial.print(F("BLEStream::write( 0x")); Serial.print(byte, HEX); Serial.println(F(") = 1")); #endif @@ -122,7 +118,7 @@ void BLEStream::_received(const unsigned char* data, size_t size) { } #ifdef BLE_SERIAL_DEBUG Serial.print(F("BLEStream::received(")); - for (int i = 0; i < size; i++) Serial.print((char)data[i]); + for (int i = 0; i < size; i++) Serial.print(data[i], HEX); Serial.println(F(")")); #endif } diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 49821aae..4e92cf65 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -11,6 +11,8 @@ #include #include +#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 30 + class BLEStream : public BLEPeripheral, public Stream { public: From e7a2c30b497a5b764bcfaa93a8355418d13177d6 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 21 Feb 2016 13:20:47 -0800 Subject: [PATCH 003/110] add support for BLEPeripheral library --- Boards.h | 16 ++ Firmata.cpp | 4 +- .../StandardFirmataBLE/StandardFirmataBLE.ino | 29 ++-- examples/StandardFirmataBLE/bleConfig.h | 95 ++++++++++++ utility/BLEStream.cpp | 140 +++++++++++------- utility/BLEStream.h | 21 ++- 6 files changed, 233 insertions(+), 72 deletions(-) create mode 100644 examples/StandardFirmataBLE/bleConfig.h diff --git a/Boards.h b/Boards.h index e084f9cf..15ffa32f 100644 --- a/Boards.h +++ b/Boards.h @@ -449,6 +449,22 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) ((p) - 2) +// RedBearLab BLE Nano with factory switch settings (S1 - S10) +#elif defined(BLE_NANO) +#define TOTAL_ANALOG_PINS 6 +#define TOTAL_PINS 15 // 9 digital + 3 analog +#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 14) +#define IS_PIN_ANALOG(p) ((p) == 8 || (p) == 9 || (p) == 10 || (p) == 11 || (p) == 12 || (p) == 14) //A0~A5 +#define IS_PIN_PWM(p) ((p) == 3 || (p) == 5 || (p) == 6) +#define IS_PIN_SERVO(p) ((p) >= 2 && (p) <= 7) +#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) +#define IS_PIN_SPI(p) ((p) == CS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 8) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) + + // Sanguino #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) #define TOTAL_ANALOG_PINS 8 diff --git a/Firmata.cpp b/Firmata.cpp index 5e5d4b79..1047a6ce 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -33,8 +33,8 @@ extern "C" { */ void FirmataClass::sendValueAsTwo7bitBytes(int value) { - FirmataStream->write(value & B01111111); // LSB - FirmataStream->write(value >> 7 & B01111111); // MSB + FirmataStream->write(value & 0x7F); // LSB + FirmataStream->write(value >> 7 & 0x7F); // MSB } /** diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index a5bdbcb7..7c9eb1e5 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,26 +20,25 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: January 3rd, 2015 + Last updated by Jeff Hoefs: February 20th, 2016 */ #include #include #include -#include -#include "utility/BLEStream.h" +#include "bleConfig.h" //#define SERIAL_DEBUG #include "utility/firmataDebug.h" -#define I2C_WRITE B00000000 -#define I2C_READ B00001000 -#define I2C_READ_CONTINUOUSLY B00010000 -#define I2C_STOP_READING B00011000 -#define I2C_READ_WRITE_MODE_MASK B00011000 -#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 -#define I2C_END_TX_MASK B01000000 +#define I2C_WRITE 0x00 //B00000000 +#define I2C_READ 0x08 //B00001000 +#define I2C_READ_CONTINUOUSLY 0x10 //B00010000 +#define I2C_STOP_READING 0x18 //B00011000 +#define I2C_READ_WRITE_MODE_MASK 0x18 //B00011000 +#define I2C_10BIT_ADDRESS_MODE_MASK 0x20 //B00100000 +#define I2C_END_TX_MASK 0x40 //B01000000 #define I2C_STOP_TX 1 #define I2C_RESTART_TX 0 #define I2C_MAX_QUERIES 8 @@ -95,8 +94,6 @@ byte servoCount = 0; boolean isResetting = false; -BLEStream stream(0); - /* utility functions */ void wireWrite(byte data) { @@ -736,6 +733,14 @@ void setup() stream.setLocalName("FIRMATA"); +#ifdef BLE_REQ + for (byte i = 0; i < TOTAL_PINS; i++) { + if (IS_IGNORE_BLE_PINS(i)) { + Firmata.setPinMode(i, PIN_MODE_IGNORE); + } + } +#endif + stream.begin(); Firmata.begin(stream); diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h new file mode 100644 index 00000000..6006fc11 --- /dev/null +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -0,0 +1,95 @@ +/*=================================================================================== + * BLE CONFIGURATION + * + * If you are using an Arduino 101, you do not need to make any changes to this + * file. If you are using another supported BLE board or shield, follow the + * instructions for the specific board or shield below. + * + * Supported boards and shields: + * - Arduino 101 (recommended) + * - RedBearLab BLE Shield (v2) ** to be verified ** + * + *==================================================================================*/ + +/* + * RedBearLab BLE Shield + * + * If you are using a RedBearLab BLE shield, uncomment the define below. + * Also, change the define for BLE_RST if you have the jumper set to pin 7 rather than pin 4. + * + * You will need to use the shield with an Arduino Mega, Due or other board with sufficient + * Flash and RAM. Arduino Uno, Leonardo and other ATmega328p and Atmega32u4 boards to not have + * enough memory to run StandardFirmataBLE. + * + * TODO: verify if this works and with which boards it works. + * + * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 + * (may need to skip capabilities - see https://gist.github.com/soundanalogous/d39bb3eb36333a0906df) + */ +//#define REDBEAR_BLE_SHIELD + +#ifdef REDBEAR_BLE_SHIELD +#include +#include +#include "utility/BLEStream.h" + +#define BLE_REQ 9 +#define BLE_RDY 8 +#define BLE_RST 4 // 4 or 7 via jumper on shield + +BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); +#endif + + +/*=================================================================================== + * END BLE CONFIGURATION - you should not need to change anything below this line + *==================================================================================*/ + +/* + * Arduino 101 + * + * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 + */ +#ifdef _VARIANT_ARDUINO_101_X_ +#include +//#include // switch to this once new Arduino 101 board package is available +#include "utility/BLEStream.h" +BLEStream stream; +#endif + + +/* + * RedBearLab BLE Nano + * Blocked on this issue: https://github.com/RedBearLab/nRF51822-Arduino/issues/46 + * Also, need to skip Capability Query (see example in test script) + * + * Test script: https://gist.github.com/soundanalogous/d39bb3eb36333a0906df + */ +// #ifdef BLE_NANO +// #include +// #include "utility/BLEStream.h" +// BLEStream stream; +// #endif + + +/* + * RedBearLab Blend and Blend Micro + * StandardFirmataBLE is requires too much Flash and RAM to run on Blend Micro + * may work with ConfigurableFirmata selecting only analog and digital I/O + */ +// #if defined(BLEND_MICRO) || defined(BLEND) +// #include +// #include +// #include "utility/BLEStream.h" + +// #define BLE_REQ 6 +// #define BLE_RDY 7 +// #define BLE_RST 4 + +// BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); +// #endif + + +#if defined(BLE_REQ) && defined(BLE_RDY) && defined(BLE_RST) +#define IS_IGNORE_BLE_PINS(p) ((p) == BLE_REQ || (p) == BLE_RDY || (p) == BLE_RST) +#endif diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp index d3f61d9b..8a12491d 100644 --- a/utility/BLEStream.cpp +++ b/utility/BLEStream.cpp @@ -2,17 +2,21 @@ BLEStream.cpp Based on BLESerial.cpp by Voita Molda - https://github.com/vojtamolda/BLEPeripheral/blob/master/examples/uart/BLESerial.cpp + https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.cpp */ #include "BLEStream.h" -//#define BLE_SERIAL_DEBUG +// #define BLE_SERIAL_DEBUG BLEStream* BLEStream::_instance = NULL; -BLEStream::BLEStream(unsigned char) : +BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : +#if defined(_VARIANT_ARDUINO_101_X_) BLEPeripheral() +#else + BLEPeripheral(req, rdy, rst) +#endif { this->_txCount = 0; this->_rxHead = this->_rxTail = 0; @@ -29,100 +33,130 @@ BLEStream::BLEStream(unsigned char) : addAttribute(this->_txNameDescriptor); } -void BLEStream::begin(...) { +void BLEStream::begin(...) +{ BLEPeripheral::begin(); - #ifdef BLE_SERIAL_DEBUG - Serial.println(F("BLEStream::begin()")); - #endif +#ifdef BLE_SERIAL_DEBUG + Serial.println(F("BLEStream::begin()")); +#endif } -bool BLEStream::poll() { +bool BLEStream::poll() +{ + // BLEPeripheral::poll is called each time connected() is called this->_connected = BLEPeripheral::connected(); - if (millis() > this->_flushed + BLESTREAM_TXBUFFER_FLUSH_INTERVAL) flush(); + if (millis() > this->_flushed + BLESTREAM_TXBUFFER_FLUSH_INTERVAL) { + flush(); + } return this->_connected; } -void BLEStream::end() { +void BLEStream::end() +{ this->_rxCharacteristic.setEventHandler(BLEWritten, NULL); this->_rxHead = this->_rxTail = 0; flush(); BLEPeripheral::disconnect(); } -int BLEStream::available(void) { +int BLEStream::available(void) +{ +// BLEPeripheral::poll only calls delay(1) in CurieBLE so skipping it here to avoid the delay +#ifndef _VARIANT_ARDUINO_101_X_ + // TODO Need to do more testing to determine if all of these calls to BLEPeripheral::poll are + // actually necessary. Seems to run fine without them, but only minimal testing so far. + BLEPeripheral::poll(); +#endif int retval = (this->_rxHead - this->_rxTail + sizeof(this->_rxBuffer)) % sizeof(this->_rxBuffer); - #ifdef BLE_SERIAL_DEBUG - if (retval > 0) { - Serial.print(F("BLEStream::available() = ")); - Serial.println(retval); - } - #endif +#ifdef BLE_SERIAL_DEBUG + if (retval > 0) { + Serial.print(F("BLEStream::available() = ")); + Serial.println(retval); + } +#endif return retval; } -int BLEStream::peek(void) { +int BLEStream::peek(void) +{ +#ifndef _VARIANT_ARDUINO_101_X_ + BLEPeripheral::poll(); +#endif if (this->_rxTail == this->_rxHead) return -1; - unsigned char byte = this->_rxBuffer[this->_rxTail]; - #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::peek() = 0x")); - Serial.println(byte, HEX); - #endif + uint8_t byte = this->_rxBuffer[this->_rxTail]; +#ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::peek() = 0x")); + Serial.println(byte, HEX); +#endif return byte; } -int BLEStream::read(void) { +int BLEStream::read(void) +{ +#ifndef _VARIANT_ARDUINO_101_X_ + BLEPeripheral::poll(); +#endif if (this->_rxTail == this->_rxHead) return -1; this->_rxTail = (this->_rxTail + 1) % sizeof(this->_rxBuffer); - unsigned char byte = this->_rxBuffer[this->_rxTail]; - #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::read() = 0x")); - Serial.println(byte, HEX); - #endif + uint8_t byte = this->_rxBuffer[this->_rxTail]; +#ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::read() = 0x")); + Serial.println(byte, HEX); +#endif return byte; } -void BLEStream::flush(void) { +void BLEStream::flush(void) +{ if (this->_txCount == 0) return; - if (this->_connected) this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount); + this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount); this->_flushed = millis(); this->_txCount = 0; - #ifdef BLE_SERIAL_DEBUG - Serial.println(F("BLEStream::flush()")); - #endif +#ifdef BLE_SERIAL_DEBUG + Serial.println(F("BLEStream::flush()")); +#endif } -size_t BLEStream::write(uint8_t byte) { +size_t BLEStream::write(uint8_t byte) +{ +#ifndef _VARIANT_ARDUINO_101_X_ + BLEPeripheral::poll(); +#endif + if (this->_txCharacteristic.subscribed() == false) return 0; this->_txBuffer[this->_txCount++] = byte; if (this->_txCount == sizeof(this->_txBuffer)) flush(); - #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::write( 0x")); - Serial.print(byte, HEX); - Serial.println(F(") = 1")); - #endif +#ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::write( 0x")); + Serial.print(byte, HEX); + Serial.println(F(") = 1")); +#endif return 1; } -BLEStream::operator bool() { +BLEStream::operator bool() +{ bool retval = this->_connected = BLEPeripheral::connected(); - #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::operator bool() = ")); - Serial.println(retval); - #endif +#ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::operator bool() = ")); + Serial.println(retval); +#endif return retval; } -void BLEStream::_received(const unsigned char* data, size_t size) { - for (int i = 0; i < size; i++) { +void BLEStream::_received(const unsigned char* data, size_t size) +{ + for (size_t i = 0; i < size; i++) { this->_rxHead = (this->_rxHead + 1) % sizeof(this->_rxBuffer); this->_rxBuffer[this->_rxHead] = data[i]; } - #ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::received(")); - for (int i = 0; i < size; i++) Serial.print(data[i], HEX); - Serial.println(F(")")); - #endif +#ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::received(")); + for (int i = 0; i < size; i++) Serial.print(data[i], HEX); + Serial.println(F(")")); +#endif } -void BLEStream::_received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic) { +void BLEStream::_received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic) +{ BLEStream::_instance->_received(rxCharacteristic.value(), rxCharacteristic.valueLength()); } diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 4e92cf65..390f0ea5 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -2,21 +2,32 @@ BLEStream.h Based on BLESerial.cpp by Voita Molda - https://github.com/vojtamolda/BLEPeripheral/blob/master/examples/uart/BLESerial.h + https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h */ #ifndef _BLE_STREAM_H_ #define _BLE_STREAM_H_ #include +#if defined(_VARIANT_ARDUINO_101_X_) #include +//#include // switch to this once new Arduino 101 board package is available +#define _MAX_ATTR_DATA_LEN_ BLE_MAX_ATTR_DATA_LEN +#else +#include +#define _MAX_ATTR_DATA_LEN_ BLE_ATTRIBUTE_MAX_VALUE_LENGTH +#endif +#if defined(_VARIANT_ARDUINO_101_X_) #define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 30 +#else +#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 50 +#endif class BLEStream : public BLEPeripheral, public Stream { public: - BLEStream(unsigned char); + BLEStream(unsigned char req = 0, unsigned char rdy = 0, unsigned char rst = 0); void begin(...); bool poll(); @@ -40,13 +51,13 @@ class BLEStream : public BLEPeripheral, public Stream size_t _rxCount() const; unsigned char _rxBuffer[256]; size_t _txCount; - unsigned char _txBuffer[BLE_MAX_ATTR_DATA_LEN]; + unsigned char _txBuffer[_MAX_ATTR_DATA_LEN_]; BLEService _uartService = BLEService("6E400001-B5A3-F393-E0A9-E50E24DCCA9E"); BLEDescriptor _uartNameDescriptor = BLEDescriptor("2901", "UART"); - BLECharacteristic _rxCharacteristic = BLECharacteristic("6E400002-B5A3-F393-E0A9-E50E24DCCA9E", BLEWriteWithoutResponse, BLE_MAX_ATTR_DATA_LEN); + BLECharacteristic _rxCharacteristic = BLECharacteristic("6E400002-B5A3-F393-E0A9-E50E24DCCA9E", BLEWriteWithoutResponse, _MAX_ATTR_DATA_LEN_); BLEDescriptor _rxNameDescriptor = BLEDescriptor("2901", "RX - Receive Data (Write)"); - BLECharacteristic _txCharacteristic = BLECharacteristic("6E400003-B5A3-F393-E0A9-E50E24DCCA9E", BLENotify, BLE_MAX_ATTR_DATA_LEN); + BLECharacteristic _txCharacteristic = BLECharacteristic("6E400003-B5A3-F393-E0A9-E50E24DCCA9E", BLENotify, _MAX_ATTR_DATA_LEN_); BLEDescriptor _txNameDescriptor = BLEDescriptor("2901", "TX - Transfer Data (Notify)"); void _received(const unsigned char* data, size_t size); From 1b61d8f27152f4bb40c1cb93820973fa76e23d6e Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 27 Feb 2016 11:04:32 -0800 Subject: [PATCH 004/110] use pin state and mode getters and setters --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 80 ++++++++++++------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 7c9eb1e5..7a930741 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: February 20th, 2016 + Last updated by Jeff Hoefs: February 27th, 2016 */ #include @@ -52,6 +52,10 @@ * GLOBAL VARIABLES *============================================================================*/ +#ifdef FIRMATA_SERIAL_FEATURE +SerialFirmata serialFeature; +#endif + /* analog inputs */ int analogInputsToReport = 0; // bitwise array to store pin reporting @@ -60,9 +64,7 @@ byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent /* pins configuration */ -byte pinConfig[TOTAL_PINS]; // configuration of every pin byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else -int pinState[TOTAL_PINS]; // any value that has been written /* timer variables */ unsigned long currentMillis; // store the current value from millis() @@ -235,10 +237,10 @@ void checkDigitalInputs(void) */ void setPinModeCallback(byte pin, int mode) { - if (pinConfig[pin] == PIN_MODE_IGNORE) + if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE) return; - if (pinConfig[pin] == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { + if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { // disable i2c so pins can be used for other functions // the following if statements should reconfigure the pins properly disableI2CPins(); @@ -258,7 +260,7 @@ void setPinModeCallback(byte pin, int mode) portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); } } - pinState[pin] = 0; + Firmata.setPinState(pin, 0); switch (mode) { case PIN_MODE_ANALOG: if (IS_PIN_ANALOG(pin)) { @@ -269,7 +271,7 @@ void setPinModeCallback(byte pin, int mode) digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif } - pinConfig[pin] = PIN_MODE_ANALOG; + Firmata.setPinMode(pin, PIN_MODE_ANALOG); } break; case INPUT: @@ -279,33 +281,33 @@ void setPinModeCallback(byte pin, int mode) // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups #endif - pinConfig[pin] = INPUT; + Firmata.setPinMode(pin, INPUT); } break; case PIN_MODE_PULLUP: if (IS_PIN_DIGITAL(pin)) { pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - pinConfig[pin] = PIN_MODE_PULLUP; - pinState[pin] = 1; + Firmata.setPinMode(pin, PIN_MODE_PULLUP); + Firmata.setPinState(pin, 1); } break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - pinConfig[pin] = OUTPUT; + Firmata.setPinMode(pin, OUTPUT); } break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) { pinMode(PIN_TO_PWM(pin), OUTPUT); analogWrite(PIN_TO_PWM(pin), 0); - pinConfig[pin] = PIN_MODE_PWM; + Firmata.setPinMode(pin, PIN_MODE_PWM); } break; case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) { - pinConfig[pin] = PIN_MODE_SERVO; + Firmata.setPinMode(pin, PIN_MODE_SERVO); if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { // pass -1 for min and max pulse values to use default values set // by Servo library @@ -317,9 +319,14 @@ void setPinModeCallback(byte pin, int mode) if (IS_PIN_I2C(pin)) { // mark the pin as i2c // the user must call I2C_CONFIG to enable I2C for a device - pinConfig[pin] = PIN_MODE_I2C; + Firmata.setPinMode(pin, PIN_MODE_I2C); } break; + case PIN_MODE_SERIAL: +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handlePinMode(pin, PIN_MODE_SERIAL); +#endif + break; default: Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM } @@ -335,8 +342,8 @@ void setPinModeCallback(byte pin, int mode) void setPinValueCallback(byte pin, int value) { if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (pinConfig[pin] == OUTPUT) { - pinState[pin] = value; + if (Firmata.getPinMode(pin) == OUTPUT) { + Firmata.setPinState(pin, value); digitalWrite(PIN_TO_DIGITAL(pin), value); } } @@ -345,16 +352,16 @@ void setPinValueCallback(byte pin, int value) void analogWriteCallback(byte pin, int value) { if (pin < TOTAL_PINS) { - switch (pinConfig[pin]) { + switch (Firmata.getPinMode(pin)) { case PIN_MODE_SERVO: if (IS_PIN_DIGITAL(pin)) servos[servoPinMap[pin]].write(value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; case PIN_MODE_PWM: if (IS_PIN_PWM(pin)) analogWrite(PIN_TO_PWM(pin), value); - pinState[pin] = value; + Firmata.setPinState(pin, value); break; } } @@ -372,11 +379,11 @@ void digitalWriteCallback(byte port, int value) // do not disturb non-digital pins (eg, Rx & Tx) if (IS_PIN_DIGITAL(pin)) { // do not touch pins in PWM, ANALOG, SERVO or other modes - if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) { pinValue = ((byte)value & mask) ? 1 : 0; - if (pinConfig[pin] == OUTPUT) { + if (Firmata.getPinMode(pin) == OUTPUT) { pinWriteMask |= mask; - } else if (pinConfig[pin] == INPUT && pinValue == 1 && pinState[pin] != 1) { + } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) { // only handle INPUT here for backwards compatibility #if ARDUINO > 100 pinMode(pin, INPUT_PULLUP); @@ -385,7 +392,7 @@ void digitalWriteCallback(byte port, int value) pinWriteMask |= mask; #endif } - pinState[pin] = pinValue; + Firmata.setPinState(pin, pinValue); } } mask = mask << 1; @@ -622,6 +629,9 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_MODE_I2C); Firmata.write(1); // TODO: could assign a number to map to SCL or SDA } +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handleCapability(pin); +#endif Firmata.write(127); } Firmata.write(END_SYSEX); @@ -633,10 +643,10 @@ void sysexCallback(byte command, byte argc, byte *argv) Firmata.write(PIN_STATE_RESPONSE); Firmata.write(pin); if (pin < TOTAL_PINS) { - Firmata.write((byte)pinConfig[pin]); - Firmata.write((byte)pinState[pin] & 0x7F); - if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); - if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + Firmata.write(Firmata.getPinMode(pin)); + Firmata.write((byte)Firmata.getPinState(pin) & 0x7F); + if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F); + if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F); } Firmata.write(END_SYSEX); } @@ -649,6 +659,12 @@ void sysexCallback(byte command, byte argc, byte *argv) } Firmata.write(END_SYSEX); break; + + case SERIAL_MESSAGE: +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.handleSysex(command, argc, argv); +#endif + break; } } @@ -684,6 +700,10 @@ void systemResetCallback() { isResetting = true; +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.reset(); +#endif + if (isI2CEnabled) { disableI2CPins(); } @@ -772,7 +792,7 @@ void loop() previousMillis = currentMillis; /* ANALOGREAD - do all analogReads() at the configured sampling interval */ for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && pinConfig[pin] == PIN_MODE_ANALOG) { + if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) { analogPin = PIN_TO_ANALOG(pin); if (analogInputsToReport & (1 << analogPin)) { Firmata.sendAnalog(analogPin, analogRead(analogPin)); @@ -786,4 +806,8 @@ void loop() } } } + +#ifdef FIRMATA_SERIAL_FEATURE + serialFeature.update(); +#endif } From c37292f2091da08c368b766c28ac2925164c4c32 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 27 Feb 2016 13:50:25 -0800 Subject: [PATCH 005/110] temp fix for config query issue --- utility/BLEStream.cpp | 19 +++++++++++++++++++ utility/BLEStream.h | 4 +++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp index 8a12491d..52da96f2 100644 --- a/utility/BLEStream.cpp +++ b/utility/BLEStream.cpp @@ -21,6 +21,7 @@ BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : this->_txCount = 0; this->_rxHead = this->_rxTail = 0; this->_flushed = 0; + this->_packetTxCount = 0; BLEStream::_instance = this; addAttribute(this->_uartService); @@ -109,6 +110,24 @@ int BLEStream::read(void) void BLEStream::flush(void) { if (this->_txCount == 0) return; +#ifndef _VARIANT_ARDUINO_101_X_ + long diff = millis() - this->_flushed; + // flush() is called approximately every 1ms or less when sending multiple packets and + // otherwise no more frequently than BLESTREAM_TXBUFFER_FLUSH_INTERVAL + // TODO - determine if 2 is the best value or if something higher is necessary + if (diff < 2) { + // 2 is the max number of packets that can be sent in short succession + // TODO - get the max packet value programatically + if (++this->_packetTxCount >= 2) { + // delay after 2 packets have been sent in short succession + // 100ms is the minimum necessary delay value + delay(100); + this->_packetTxCount = 0; + } + } else { + this->_packetTxCount = 0; + } +#endif this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount); this->_flushed = millis(); this->_txCount = 0; diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 390f0ea5..70939491 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -21,7 +21,7 @@ #if defined(_VARIANT_ARDUINO_101_X_) #define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 30 #else -#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 50 +#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 80 #endif class BLEStream : public BLEPeripheral, public Stream @@ -53,6 +53,8 @@ class BLEStream : public BLEPeripheral, public Stream size_t _txCount; unsigned char _txBuffer[_MAX_ATTR_DATA_LEN_]; + uint8_t _packetTxCount; + BLEService _uartService = BLEService("6E400001-B5A3-F393-E0A9-E50E24DCCA9E"); BLEDescriptor _uartNameDescriptor = BLEDescriptor("2901", "UART"); BLECharacteristic _rxCharacteristic = BLECharacteristic("6E400002-B5A3-F393-E0A9-E50E24DCCA9E", BLEWriteWithoutResponse, _MAX_ATTR_DATA_LEN_); From 009eff9282243d7d2bd20dc2bf8cc74209432e09 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 28 Feb 2016 10:49:22 -0800 Subject: [PATCH 006/110] proper check for available packets --- utility/BLEStream.cpp | 21 +++++---------------- utility/BLEStream.h | 4 ++-- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp index 52da96f2..652b1fcf 100644 --- a/utility/BLEStream.cpp +++ b/utility/BLEStream.cpp @@ -3,6 +3,8 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.cpp + + Last updated by Jeff Hoefs: February 28th, 2016 */ #include "BLEStream.h" @@ -21,7 +23,6 @@ BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : this->_txCount = 0; this->_rxHead = this->_rxTail = 0; this->_flushed = 0; - this->_packetTxCount = 0; BLEStream::_instance = this; addAttribute(this->_uartService); @@ -111,21 +112,9 @@ void BLEStream::flush(void) { if (this->_txCount == 0) return; #ifndef _VARIANT_ARDUINO_101_X_ - long diff = millis() - this->_flushed; - // flush() is called approximately every 1ms or less when sending multiple packets and - // otherwise no more frequently than BLESTREAM_TXBUFFER_FLUSH_INTERVAL - // TODO - determine if 2 is the best value or if something higher is necessary - if (diff < 2) { - // 2 is the max number of packets that can be sent in short succession - // TODO - get the max packet value programatically - if (++this->_packetTxCount >= 2) { - // delay after 2 packets have been sent in short succession - // 100ms is the minimum necessary delay value - delay(100); - this->_packetTxCount = 0; - } - } else { - this->_packetTxCount = 0; + // ensure there are available packets before sending + while(!this->_txCharacteristic.canNotify()) { + BLEPeripheral::poll(); } #endif this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount); diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 70939491..468646be 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -3,6 +3,8 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h + + Last updated by Jeff Hoefs: February 28th, 2016 */ #ifndef _BLE_STREAM_H_ @@ -53,8 +55,6 @@ class BLEStream : public BLEPeripheral, public Stream size_t _txCount; unsigned char _txBuffer[_MAX_ATTR_DATA_LEN_]; - uint8_t _packetTxCount; - BLEService _uartService = BLEService("6E400001-B5A3-F393-E0A9-E50E24DCCA9E"); BLEDescriptor _uartNameDescriptor = BLEDescriptor("2901", "UART"); BLECharacteristic _rxCharacteristic = BLECharacteristic("6E400002-B5A3-F393-E0A9-E50E24DCCA9E", BLEWriteWithoutResponse, _MAX_ATTR_DATA_LEN_); From 733746fb686f384e257e3a97f5655ecf13414875 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 5 Mar 2016 12:19:50 -0800 Subject: [PATCH 007/110] updated comments in bleConfig --- examples/StandardFirmataBLE/bleConfig.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index 6006fc11..ce19f3c7 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -8,6 +8,7 @@ * Supported boards and shields: * - Arduino 101 (recommended) * - RedBearLab BLE Shield (v2) ** to be verified ** + * - RedBearLab BLE Nano ** works with modifications ** * *==================================================================================*/ @@ -59,11 +60,17 @@ BLEStream stream; /* - * RedBearLab BLE Nano + * RedBearLab BLE Nano (with default switch settings) + * * Blocked on this issue: https://github.com/RedBearLab/nRF51822-Arduino/issues/46 - * Also, need to skip Capability Query (see example in test script) + * Works with modifications. See comments at top of the test script referenced below. + * When the RBL nRF51822-Arduino library issue is resolved, this should work witout + * any modifications. * * Test script: https://gist.github.com/soundanalogous/d39bb3eb36333a0906df + * + * Note: If you have changed the solder jumpers on the Nano you may encounter issues since + * the pins are currently mapped in Firmata only for the default (factory) jumper settings. */ // #ifdef BLE_NANO // #include @@ -74,8 +81,10 @@ BLEStream stream; /* * RedBearLab Blend and Blend Micro - * StandardFirmataBLE is requires too much Flash and RAM to run on Blend Micro - * may work with ConfigurableFirmata selecting only analog and digital I/O + * + * StandardFirmataBLE requires too much Flash and RAM to run on the ATmega32u4-based Blend + * and Blend Micro boards. It may work with ConfigurableFirmata selecting only analog and/or + * digital I/O. */ // #if defined(BLEND_MICRO) || defined(BLEND) // #include From 9788f7f3b9937ca2fd7e73dde6e60e62a562eef5 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 5 Mar 2016 16:27:57 -0800 Subject: [PATCH 008/110] add ble connection interval and ble TX flush interval --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 14 ++++++++++--- examples/StandardFirmataBLE/bleConfig.h | 21 +++++++++++-------- utility/BLEStream.cpp | 12 +++++++++-- utility/BLEStream.h | 8 ++++--- 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 7a930741..f234d71f 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: February 27th, 2016 + Last updated by Jeff Hoefs: March 5th, 2016 */ #include @@ -47,6 +47,9 @@ // the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 1 +// min cannot be < 0x0006. Adjust max if necessary +#define FIRMATA_BLE_MIN_INTERVAL 0x0006 // 7.5ms (7.5 / 1.25) +#define FIRMATA_BLE_MAX_INTERVAL 0x0018 // 30ms (30 / 1.25) /*============================================================================== * GLOBAL VARIABLES @@ -751,7 +754,12 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); - stream.setLocalName("FIRMATA"); + stream.setLocalName(FIRMATA_BLE_LOCAL_NAME); + + // set the BLE connection interval - this is the fastest interval you can read inputs + stream.setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); + // set how often the BLE TX buffer is flushed (if not full) + stream.setFlushInterval(FIRMATA_BLE_MAX_INTERVAL); #ifdef BLE_REQ for (byte i = 0; i < TOTAL_PINS; i++) { @@ -775,7 +783,7 @@ void loop() byte pin, analogPin; // do not process data if no BLE connection is established - // poll will send the TX buffer every 30ms while it contains data + // poll will send the TX buffer at the specified flush interval or when the buffer is full if (!stream.poll()) return; /* DIGITALREAD - as fast as possible, check for changes and output them to the diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index ce19f3c7..43700517 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -1,16 +1,20 @@ -/*=================================================================================== +/*================================================================================================== * BLE CONFIGURATION * - * If you are using an Arduino 101, you do not need to make any changes to this - * file. If you are using another supported BLE board or shield, follow the - * instructions for the specific board or shield below. + * If you are using an Arduino 101, you do not need to make any changes to this file (unless you + * need a unique ble local name (see below). If you are using another supported BLE board or shield, + * follow the instructions for the specific board or shield below. * * Supported boards and shields: * - Arduino 101 (recommended) * - RedBearLab BLE Shield (v2) ** to be verified ** * - RedBearLab BLE Nano ** works with modifications ** * - *==================================================================================*/ + *================================================================================================*/ + +// change this to a unique name per board if running StandardFirmataBLE on multiple boards +// within the same physical space +#define FIRMATA_BLE_LOCAL_NAME "FIRMATA" /* * RedBearLab BLE Shield @@ -42,9 +46,9 @@ BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); #endif -/*=================================================================================== +/*================================================================================================== * END BLE CONFIGURATION - you should not need to change anything below this line - *==================================================================================*/ + *================================================================================================*/ /* * Arduino 101 @@ -52,8 +56,7 @@ BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 */ #ifdef _VARIANT_ARDUINO_101_X_ -#include -//#include // switch to this once new Arduino 101 board package is available +#include #include "utility/BLEStream.h" BLEStream stream; #endif diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp index 652b1fcf..1ff6dcf0 100644 --- a/utility/BLEStream.cpp +++ b/utility/BLEStream.cpp @@ -4,7 +4,7 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.cpp - Last updated by Jeff Hoefs: February 28th, 2016 + Last updated by Jeff Hoefs: March 5th, 2016 */ #include "BLEStream.h" @@ -23,6 +23,7 @@ BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : this->_txCount = 0; this->_rxHead = this->_rxTail = 0; this->_flushed = 0; + this->_flushInterval = BLESTREAM_TXBUFFER_FLUSH_INTERVAL; BLEStream::_instance = this; addAttribute(this->_uartService); @@ -47,7 +48,7 @@ bool BLEStream::poll() { // BLEPeripheral::poll is called each time connected() is called this->_connected = BLEPeripheral::connected(); - if (millis() > this->_flushed + BLESTREAM_TXBUFFER_FLUSH_INTERVAL) { + if (millis() > this->_flushed + this->_flushInterval) { flush(); } return this->_connected; @@ -151,6 +152,13 @@ BLEStream::operator bool() return retval; } +void BLEStream::setFlushInterval(int interval) +{ + if (interval > BLESTREAM_MIN_FLUSH_INTERVAL) { + this->_flushInterval = interval; + } +} + void BLEStream::_received(const unsigned char* data, size_t size) { for (size_t i = 0; i < size; i++) { diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 468646be..43a4f8b7 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -4,7 +4,7 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h - Last updated by Jeff Hoefs: February 28th, 2016 + Last updated by Jeff Hoefs: March 5th, 2016 */ #ifndef _BLE_STREAM_H_ @@ -12,8 +12,7 @@ #include #if defined(_VARIANT_ARDUINO_101_X_) -#include -//#include // switch to this once new Arduino 101 board package is available +#include #define _MAX_ATTR_DATA_LEN_ BLE_MAX_ATTR_DATA_LEN #else #include @@ -25,6 +24,7 @@ #else #define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 80 #endif +#define BLESTREAM_MIN_FLUSH_INTERVAL 8 // minimum interval for flushing the TX buffer class BLEStream : public BLEPeripheral, public Stream { @@ -34,6 +34,7 @@ class BLEStream : public BLEPeripheral, public Stream void begin(...); bool poll(); void end(); + void setFlushInterval(int); virtual int available(void); virtual int peek(void); @@ -46,6 +47,7 @@ class BLEStream : public BLEPeripheral, public Stream private: bool _connected; unsigned long _flushed; + int _flushInterval; static BLEStream* _instance; size_t _rxHead; From 25e6615e48e0337cfd8031e05196f7048f15d0cc Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 13 Mar 2016 21:21:22 -0700 Subject: [PATCH 009/110] increase i2c RX data buffer to 64 bytes --- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index f234d71f..e36ea709 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: March 5th, 2016 + Last updated March 13th, 2016 */ #include @@ -85,7 +85,7 @@ struct i2c_device_info { /* for i2c read continuous more */ i2c_device_info query[I2C_MAX_QUERIES]; -byte i2cRxData[32]; +byte i2cRxData[64]; boolean isI2CEnabled = false; signed char queryIndex = -1; // default delay time between i2c read request and Wire.requestFrom() From ae85c8488b2dd17b3b39522699cb8b7a8417a8ad Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 13 Mar 2016 22:12:29 -0700 Subject: [PATCH 010/110] skip setConnectionInterval for Arduino 101 by default --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 17 +++++++++++++++++ examples/StandardFirmataBLE/bleConfig.h | 3 +-- utility/BLEStream.cpp | 2 +- utility/BLEStream.h | 6 +----- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index e36ea709..69d4e304 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -756,10 +756,27 @@ void setup() stream.setLocalName(FIRMATA_BLE_LOCAL_NAME); +// setConnectionInterval is not available in the CurieBLE library included in the +// Intel Curie Boards package v1.0.5 (latest version via the Boards Manager). Without +// setConnectionInterval, the BLE reporting rate for analog input and I2C read continuous mode +// will be very slow (150ms instead of 30ms). +// However, you can manually update CurieBLE to get the functionality now. Follow these steps: +// 1. Install Intel Curie Boards v1.0.5 via the Arduino Boards manager (use Arduino 1.6.7 or newer) +// 2. Download or clone corelibs-arduino101: https://github.com/01org/corelibs-arduino101 +// 3. Make a copy of the CurieBLE directory found in corelibs-arduino101/libraries/ +// 4. Find the Arduino15 directory on your computer: +// OS X: ~/Library/Arduino15 +// Windows: C:\Users\(username)\AppData\Local\Arduino15 +// Linux: ~/.arduino15 +// 5. From the Arduino15 directory, navigate to: /packages/Intel/hardware/arc32/1.0.5/libraries/ +// 6. Replace the CurieBLE library with the version you copied in step 3 +// 7. Comment out the #ifndef statement below and the following #endif statement +#ifndef _VARIANT_ARDUINO_101_X_ // set the BLE connection interval - this is the fastest interval you can read inputs stream.setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); // set how often the BLE TX buffer is flushed (if not full) stream.setFlushInterval(FIRMATA_BLE_MAX_INTERVAL); +#endif #ifdef BLE_REQ for (byte i = 0; i < TOTAL_PINS; i++) { diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index 43700517..c1bd1fe6 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -22,14 +22,13 @@ * If you are using a RedBearLab BLE shield, uncomment the define below. * Also, change the define for BLE_RST if you have the jumper set to pin 7 rather than pin 4. * - * You will need to use the shield with an Arduino Mega, Due or other board with sufficient + * You will need to use the shield with an Arduino Zero, Due, Mega, or other board with sufficient * Flash and RAM. Arduino Uno, Leonardo and other ATmega328p and Atmega32u4 boards to not have * enough memory to run StandardFirmataBLE. * * TODO: verify if this works and with which boards it works. * * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 - * (may need to skip capabilities - see https://gist.github.com/soundanalogous/d39bb3eb36333a0906df) */ //#define REDBEAR_BLE_SHIELD diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp index 1ff6dcf0..e08b52ec 100644 --- a/utility/BLEStream.cpp +++ b/utility/BLEStream.cpp @@ -4,7 +4,7 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.cpp - Last updated by Jeff Hoefs: March 5th, 2016 + Last updated March 5th, 2016 */ #include "BLEStream.h" diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 43a4f8b7..63b86d69 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -4,7 +4,7 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h - Last updated by Jeff Hoefs: March 5th, 2016 + Last updated March 13th, 2016 */ #ifndef _BLE_STREAM_H_ @@ -19,11 +19,7 @@ #define _MAX_ATTR_DATA_LEN_ BLE_ATTRIBUTE_MAX_VALUE_LENGTH #endif -#if defined(_VARIANT_ARDUINO_101_X_) -#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 30 -#else #define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 80 -#endif #define BLESTREAM_MIN_FLUSH_INTERVAL 8 // minimum interval for flushing the TX buffer class BLEStream : public BLEPeripheral, public Stream From 872e3cce124ec156c98cc1c7d82bca09f9012a9b Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 13 Mar 2016 22:55:16 -0700 Subject: [PATCH 011/110] add missing SerialFirmata.h optional include --- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 69d4e304..621e9840 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -27,11 +27,18 @@ #include #include -#include "bleConfig.h" - //#define SERIAL_DEBUG #include "utility/firmataDebug.h" +/* + * Uncomment the following include to enable interfacing + * with Serial devices via hardware or software serial. + */ +//#include "utility/SerialFirmata.h" + +// follow the instructions in bleConfig.h to configure your BLE hardware +#include "bleConfig.h" + #define I2C_WRITE 0x00 //B00000000 #define I2C_READ 0x08 //B00001000 #define I2C_READ_CONTINUOUSLY 0x10 //B00010000 From a3b3f65fa807ff49ccc5ff3bc0b0a48c8831a847 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 4 Apr 2016 21:36:11 -0700 Subject: [PATCH 012/110] fix issue where BLEPeripheral lib needed to be included even if not needed --- utility/BLEStream.cpp | 177 +---------------------------------------- utility/BLEStream.h | 178 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 178 insertions(+), 177 deletions(-) diff --git a/utility/BLEStream.cpp b/utility/BLEStream.cpp index e08b52ec..ea508408 100644 --- a/utility/BLEStream.cpp +++ b/utility/BLEStream.cpp @@ -1,178 +1,3 @@ /* - BLEStream.cpp - - Based on BLESerial.cpp by Voita Molda - https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.cpp - - Last updated March 5th, 2016 + * Implementation is in BLEStream.h to avoid linker issues. */ - -#include "BLEStream.h" - -// #define BLE_SERIAL_DEBUG - -BLEStream* BLEStream::_instance = NULL; - -BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : -#if defined(_VARIANT_ARDUINO_101_X_) - BLEPeripheral() -#else - BLEPeripheral(req, rdy, rst) -#endif -{ - this->_txCount = 0; - this->_rxHead = this->_rxTail = 0; - this->_flushed = 0; - this->_flushInterval = BLESTREAM_TXBUFFER_FLUSH_INTERVAL; - BLEStream::_instance = this; - - addAttribute(this->_uartService); - addAttribute(this->_uartNameDescriptor); - setAdvertisedServiceUuid(this->_uartService.uuid()); - addAttribute(this->_rxCharacteristic); - addAttribute(this->_rxNameDescriptor); - this->_rxCharacteristic.setEventHandler(BLEWritten, BLEStream::_received); - addAttribute(this->_txCharacteristic); - addAttribute(this->_txNameDescriptor); -} - -void BLEStream::begin(...) -{ - BLEPeripheral::begin(); -#ifdef BLE_SERIAL_DEBUG - Serial.println(F("BLEStream::begin()")); -#endif -} - -bool BLEStream::poll() -{ - // BLEPeripheral::poll is called each time connected() is called - this->_connected = BLEPeripheral::connected(); - if (millis() > this->_flushed + this->_flushInterval) { - flush(); - } - return this->_connected; -} - -void BLEStream::end() -{ - this->_rxCharacteristic.setEventHandler(BLEWritten, NULL); - this->_rxHead = this->_rxTail = 0; - flush(); - BLEPeripheral::disconnect(); -} - -int BLEStream::available(void) -{ -// BLEPeripheral::poll only calls delay(1) in CurieBLE so skipping it here to avoid the delay -#ifndef _VARIANT_ARDUINO_101_X_ - // TODO Need to do more testing to determine if all of these calls to BLEPeripheral::poll are - // actually necessary. Seems to run fine without them, but only minimal testing so far. - BLEPeripheral::poll(); -#endif - int retval = (this->_rxHead - this->_rxTail + sizeof(this->_rxBuffer)) % sizeof(this->_rxBuffer); -#ifdef BLE_SERIAL_DEBUG - if (retval > 0) { - Serial.print(F("BLEStream::available() = ")); - Serial.println(retval); - } -#endif - return retval; -} - -int BLEStream::peek(void) -{ -#ifndef _VARIANT_ARDUINO_101_X_ - BLEPeripheral::poll(); -#endif - if (this->_rxTail == this->_rxHead) return -1; - uint8_t byte = this->_rxBuffer[this->_rxTail]; -#ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::peek() = 0x")); - Serial.println(byte, HEX); -#endif - return byte; -} - -int BLEStream::read(void) -{ -#ifndef _VARIANT_ARDUINO_101_X_ - BLEPeripheral::poll(); -#endif - if (this->_rxTail == this->_rxHead) return -1; - this->_rxTail = (this->_rxTail + 1) % sizeof(this->_rxBuffer); - uint8_t byte = this->_rxBuffer[this->_rxTail]; -#ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::read() = 0x")); - Serial.println(byte, HEX); -#endif - return byte; -} - -void BLEStream::flush(void) -{ - if (this->_txCount == 0) return; -#ifndef _VARIANT_ARDUINO_101_X_ - // ensure there are available packets before sending - while(!this->_txCharacteristic.canNotify()) { - BLEPeripheral::poll(); - } -#endif - this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount); - this->_flushed = millis(); - this->_txCount = 0; -#ifdef BLE_SERIAL_DEBUG - Serial.println(F("BLEStream::flush()")); -#endif -} - -size_t BLEStream::write(uint8_t byte) -{ -#ifndef _VARIANT_ARDUINO_101_X_ - BLEPeripheral::poll(); -#endif - if (this->_txCharacteristic.subscribed() == false) return 0; - this->_txBuffer[this->_txCount++] = byte; - if (this->_txCount == sizeof(this->_txBuffer)) flush(); -#ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::write( 0x")); - Serial.print(byte, HEX); - Serial.println(F(") = 1")); -#endif - return 1; -} - -BLEStream::operator bool() -{ - bool retval = this->_connected = BLEPeripheral::connected(); -#ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::operator bool() = ")); - Serial.println(retval); -#endif - return retval; -} - -void BLEStream::setFlushInterval(int interval) -{ - if (interval > BLESTREAM_MIN_FLUSH_INTERVAL) { - this->_flushInterval = interval; - } -} - -void BLEStream::_received(const unsigned char* data, size_t size) -{ - for (size_t i = 0; i < size; i++) { - this->_rxHead = (this->_rxHead + 1) % sizeof(this->_rxBuffer); - this->_rxBuffer[this->_rxHead] = data[i]; - } -#ifdef BLE_SERIAL_DEBUG - Serial.print(F("BLEStream::received(")); - for (int i = 0; i < size; i++) Serial.print(data[i], HEX); - Serial.println(F(")")); -#endif -} - -void BLEStream::_received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic) -{ - BLEStream::_instance->_received(rxCharacteristic.value(), rxCharacteristic.valueLength()); -} diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 63b86d69..bcf3b93d 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -4,7 +4,7 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h - Last updated March 13th, 2016 + Last updated April 04th, 2016 */ #ifndef _BLE_STREAM_H_ @@ -22,6 +22,8 @@ #define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 80 #define BLESTREAM_MIN_FLUSH_INTERVAL 8 // minimum interval for flushing the TX buffer +// #define BLE_SERIAL_DEBUG + class BLEStream : public BLEPeripheral, public Stream { public: @@ -64,4 +66,178 @@ class BLEStream : public BLEPeripheral, public Stream static void _received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic); }; + +/* + * BLEStream.cpp + * Copied here as a hack to avoid having to install the BLEPeripheral libarary even if it's + * not needed. + */ + +BLEStream* BLEStream::_instance = NULL; + +BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : +#if defined(_VARIANT_ARDUINO_101_X_) + BLEPeripheral() +#else + BLEPeripheral(req, rdy, rst) +#endif +{ + this->_txCount = 0; + this->_rxHead = this->_rxTail = 0; + this->_flushed = 0; + this->_flushInterval = BLESTREAM_TXBUFFER_FLUSH_INTERVAL; + BLEStream::_instance = this; + + addAttribute(this->_uartService); + addAttribute(this->_uartNameDescriptor); + setAdvertisedServiceUuid(this->_uartService.uuid()); + addAttribute(this->_rxCharacteristic); + addAttribute(this->_rxNameDescriptor); + this->_rxCharacteristic.setEventHandler(BLEWritten, BLEStream::_received); + addAttribute(this->_txCharacteristic); + addAttribute(this->_txNameDescriptor); +} + +void BLEStream::begin(...) +{ + BLEPeripheral::begin(); +#ifdef BLE_SERIAL_DEBUG + Serial.println(F("BLEStream::begin()")); +#endif +} + +bool BLEStream::poll() +{ + // BLEPeripheral::poll is called each time connected() is called + this->_connected = BLEPeripheral::connected(); + if (millis() > this->_flushed + this->_flushInterval) { + flush(); + } + return this->_connected; +} + +void BLEStream::end() +{ + this->_rxCharacteristic.setEventHandler(BLEWritten, NULL); + this->_rxHead = this->_rxTail = 0; + flush(); + BLEPeripheral::disconnect(); +} + +int BLEStream::available(void) +{ +// BLEPeripheral::poll only calls delay(1) in CurieBLE so skipping it here to avoid the delay +#ifndef _VARIANT_ARDUINO_101_X_ + // TODO Need to do more testing to determine if all of these calls to BLEPeripheral::poll are + // actually necessary. Seems to run fine without them, but only minimal testing so far. + BLEPeripheral::poll(); +#endif + int retval = (this->_rxHead - this->_rxTail + sizeof(this->_rxBuffer)) % sizeof(this->_rxBuffer); +#ifdef BLE_SERIAL_DEBUG + if (retval > 0) { + Serial.print(F("BLEStream::available() = ")); + Serial.println(retval); + } +#endif + return retval; +} + +int BLEStream::peek(void) +{ +#ifndef _VARIANT_ARDUINO_101_X_ + BLEPeripheral::poll(); +#endif + if (this->_rxTail == this->_rxHead) return -1; + uint8_t byte = this->_rxBuffer[this->_rxTail]; +#ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::peek() = 0x")); + Serial.println(byte, HEX); #endif + return byte; +} + +int BLEStream::read(void) +{ +#ifndef _VARIANT_ARDUINO_101_X_ + BLEPeripheral::poll(); +#endif + if (this->_rxTail == this->_rxHead) return -1; + this->_rxTail = (this->_rxTail + 1) % sizeof(this->_rxBuffer); + uint8_t byte = this->_rxBuffer[this->_rxTail]; +#ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::read() = 0x")); + Serial.println(byte, HEX); +#endif + return byte; +} + +void BLEStream::flush(void) +{ + if (this->_txCount == 0) return; +#ifndef _VARIANT_ARDUINO_101_X_ + // ensure there are available packets before sending + while(!this->_txCharacteristic.canNotify()) { + BLEPeripheral::poll(); + } +#endif + this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount); + this->_flushed = millis(); + this->_txCount = 0; +#ifdef BLE_SERIAL_DEBUG + Serial.println(F("BLEStream::flush()")); +#endif +} + +size_t BLEStream::write(uint8_t byte) +{ +#ifndef _VARIANT_ARDUINO_101_X_ + BLEPeripheral::poll(); +#endif + if (this->_txCharacteristic.subscribed() == false) return 0; + this->_txBuffer[this->_txCount++] = byte; + if (this->_txCount == sizeof(this->_txBuffer)) flush(); +#ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::write( 0x")); + Serial.print(byte, HEX); + Serial.println(F(") = 1")); +#endif + return 1; +} + +BLEStream::operator bool() +{ + bool retval = this->_connected = BLEPeripheral::connected(); +#ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::operator bool() = ")); + Serial.println(retval); +#endif + return retval; +} + +void BLEStream::setFlushInterval(int interval) +{ + if (interval > BLESTREAM_MIN_FLUSH_INTERVAL) { + this->_flushInterval = interval; + } +} + +void BLEStream::_received(const unsigned char* data, size_t size) +{ + for (size_t i = 0; i < size; i++) { + this->_rxHead = (this->_rxHead + 1) % sizeof(this->_rxBuffer); + this->_rxBuffer[this->_rxHead] = data[i]; + } +#ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLEStream::received(")); + for (int i = 0; i < size; i++) Serial.print(data[i], HEX); + Serial.println(F(")")); +#endif +} + +void BLEStream::_received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic) +{ + BLEStream::_instance->_received(rxCharacteristic.value(), rxCharacteristic.valueLength()); +} + + +#endif // _BLE_STREAM_H_ From 9f476ad9370780b45395f2a2a4005afef4a8215b Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 9 Apr 2016 17:16:54 -0700 Subject: [PATCH 013/110] do not ignore MKR1000 pins --- examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 8091b3a9..b6b4b2db 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -947,7 +947,8 @@ void setup() || 28 == i #endif //defined(__AVR_ATmega32U4__) ) { -#elif defined (WIFI_101) +// don't ignore pins when using Wi-Fi 101 library with the MKR1000 +#elif defined (WIFI_101) && !defined(ARDUINO_SAMD_MKR1000) if (IS_IGNORE_WIFI101_SHIELD(i)) { #elif defined (HUZZAH_WIFI) // TODO From e5582d0469e382ad06f3543f1041bed253921f69 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 9 Apr 2016 17:46:40 -0700 Subject: [PATCH 014/110] default config to MKR1000 / Arduino WiFi Shield 101 --- examples/StandardFirmataWiFi/wifiConfig.h | 42 +++++++++++------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index 3cd4b5cd..e967a479 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -12,25 +12,7 @@ // Option A is enabled by default. /* - * OPTION A: Configure for Arduino WiFi shield - * - * This will configure StandardFirmataWiFi to use the original WiFi library (deprecated) provided - * with the Arduino IDE. It is supported by the Arduino WiFi shield (a discontinued product) and - * is compatible with 802.11 B/G networks. - * - * To configure StandardFirmataWiFi to use the Arduino WiFi shield - * leave the #define below uncommented. - */ -#define ARDUINO_WIFI_SHIELD - -//do not modify these next 4 lines -#ifdef ARDUINO_WIFI_SHIELD -#include "utility/WiFiStream.h" -WiFiStream stream; -#endif - -/* - * OPTION B: Configure for WiFi 101 + * OPTION A: Configure for Arduino MKR1000 or Arduino WiFi Shield 101 * * This will configure StandardFirmataWiFi to use the WiFi101 library, which works with the Arduino WiFi101 * shield and devices that have the WiFi101 chip built in (such as the MKR1000). It is compatible @@ -42,7 +24,7 @@ WiFiStream stream; * IMPORTANT: You must have the WiFI 101 library installed. To easily install this library, opent the library manager via: * Arduino IDE Menus: Sketch > Include Library > Manage Libraries > filter search for "WiFi101" > Select the result and click 'install' */ -//#define WIFI_101 +#define WIFI_101 //do not modify these next 4 lines #ifdef WIFI_101 @@ -50,6 +32,24 @@ WiFiStream stream; WiFi101Stream stream; #endif +/* + * OPTION B: Configure for Arduino WiFi shield + * + * This will configure StandardFirmataWiFi to use the original WiFi library (deprecated) provided + * with the Arduino IDE. It is supported by the Arduino WiFi shield (a discontinued product) and + * is compatible with 802.11 B/G networks. + * + * To configure StandardFirmataWiFi to use the Arduino WiFi shield + * leave the #define below uncommented. + */ +//#define ARDUINO_WIFI_SHIELD + +//do not modify these next 4 lines +#ifdef ARDUINO_WIFI_SHIELD +#include "utility/WiFiStream.h" +WiFiStream stream; +#endif + /* * OPTION C: Configure for HUZZAH * @@ -148,7 +148,7 @@ char wep_key[] = "your_wep_key"; // ignore SPI pins, pin 5 (reset WiFi101 shield), pin 7 (WiFi handshake) and pin 10 (WiFi SS) // also don't ignore SS pin if it's not pin 10 -// TODO - need to differentiate between Arduino WiFi1 101 Shield and Arduino MKR1000 +// Not needed for Arduino MKR1000. #define IS_IGNORE_WIFI101_SHIELD(p) ((p) == 10 || (IS_PIN_SPI(p) && (p) != SS) || (p) == 5 || (p) == 7) // ignore SPI pins, pin 4 (SS for SD-Card on WiFi-shield), pin 7 (WiFi handshake) and pin 10 (WiFi SS) From 51e3c7d3f24cf357aaf6358d2a112396242419f6 Mon Sep 17 00:00:00 2001 From: Jacob Rosenthal Date: Wed, 17 Feb 2016 20:11:20 -0700 Subject: [PATCH 015/110] Adds ESP8266 support c/o jacobrosental and jnsbyr bare minimum esp support missing paren pin functions based on board depended defaults to support different ESP8266 boad layouts, use board depended constants from "...\esp8266\hardware\esp8266\2.1.0\variants\...\pins_arduino.h" analog pin mapping fixed requires Arduino core for ESP8266 V2.2 VERSION_BLINK_PIN and PIN_SERIAL1_TX removed most remaining absolte pin numbers/counts replaced by defines/constants from pins_arduino.h config optimizations - Firmata 2.5.1 or higher required - esp8266/Adruino needs to fix macros digitalPinHasPWM and digitalPinToInterrupt - no wifio board support fixed macro IS_PIN_INTERRUPT new define DEFAULT_PWM_RESOLUTION - default to 8-bit for all architectures and board - ESP8266 default is 10-bit examples updated to use define DEFAULT_PWM_RESOLUTION WiFiStream variant integration wifi updates - Consolidate WiFi stream classes into single class - Remove unused WiFi stream classes - Fix ESP8266 serial output (needed flush) - Fix ESP8266 connection status issue - Automatically include WiFi lib for MKR1000 and ESP8266 - Simplify config error checking - Update instructions in wifiConfig.h - Do not ignore MKR1000 pins --- Boards.h | 25 ++ examples/StandardFirmata/StandardFirmata.ino | 2 +- .../StandardFirmataChipKIT.ino | 2 +- .../StandardFirmataEthernet.ino | 2 +- .../StandardFirmataEthernetPlus.ino | 2 +- .../StandardFirmataPlus.ino | 2 +- .../StandardFirmataWiFi.ino | 41 ++- examples/StandardFirmataWiFi/wifiConfig.h | 126 ++++++--- utility/WiFi101Stream.cpp | 4 - utility/WiFi101Stream.h | 259 ------------------ utility/WiFiStream.h | 77 +++++- utility/firmataDebug.h | 2 +- 12 files changed, 223 insertions(+), 321 deletions(-) delete mode 100644 utility/WiFi101Stream.cpp delete mode 100644 utility/WiFi101Stream.h diff --git a/Boards.h b/Boards.h index 15ffa32f..f46c4eb0 100644 --- a/Boards.h +++ b/Boards.h @@ -681,6 +681,28 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) ((p) - 2) +// ESP8266 +// note: boot mode GPIOs 0, 2 and 15 can be used as outputs, GPIOs 6-11 are in use for flash IO +#elif defined(ESP8266) +#define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS +#define TOTAL_PINS A0 + NUM_ANALOG_INPUTS +#define PIN_SERIAL_RX 3 +#define PIN_SERIAL_TX 1 +#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 5) || ((p) >= 12 && (p) < A0)) +#define IS_PIN_ANALOG(p) ((p) >= A0 && (p) < A0 + NUM_ANALOG_INPUTS) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_INTERRUPT(p) (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT) +#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL_RX || (p) == PIN_SERIAL_TX) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - A0) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) +#define DEFAULT_PWM_RESOLUTION 10 + + // anything else #else #error "Please edit Boards.h with a hardware abstraction for this board" @@ -695,6 +717,9 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_SERIAL(p) 0 #endif +#ifndef DEFAULT_PWM_RESOLUTION +#define DEFAULT_PWM_RESOLUTION 8 +#endif /*============================================================================== * readPort() - Read an 8 bit port diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 27673e3f..0539e6eb 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -615,7 +615,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_PWM(pin)) { Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution + Firmata.write(DEFAULT_PWM_RESOLUTION); } if (IS_PIN_DIGITAL(pin)) { Firmata.write(PIN_MODE_SERVO); diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index b946dff9..7f5baaae 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -616,7 +616,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_PWM(pin)) { Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution + Firmata.write(DEFAULT_PWM_RESOLUTION); } if (IS_PIN_DIGITAL(pin)) { Firmata.write(PIN_MODE_SERVO); diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index ae8cb7f5..55e60953 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -672,7 +672,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_PWM(pin)) { Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution + Firmata.write(DEFAULT_PWM_RESOLUTION); } if (IS_PIN_DIGITAL(pin)) { Firmata.write(PIN_MODE_SERVO); diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino index 2c92109f..bbba246e 100644 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino @@ -680,7 +680,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_PWM(pin)) { Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution + Firmata.write(DEFAULT_PWM_RESOLUTION); } if (IS_PIN_DIGITAL(pin)) { Firmata.write(PIN_MODE_SERVO); diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index f36b9355..d9b78296 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -635,7 +635,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_PWM(pin)) { Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution + Firmata.write(DEFAULT_PWM_RESOLUTION); } if (IS_PIN_DIGITAL(pin)) { Firmata.write(PIN_MODE_SERVO); diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index b6b4b2db..e3cb2379 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -13,6 +13,7 @@ Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. Copyright (C) 2015-2016 Jesse Frush. All rights reserved. + Copyright (C) 2016 Jens B. 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 @@ -21,7 +22,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: January 10th, 2016 + Last updated by Jeff Hoefs: April 10th, 2016 */ /* @@ -36,7 +37,7 @@ - Arduino WiFi Shield (or clone) - Arduino WiFi Shield 101 - Arduino MKR1000 board (built-in WiFi 101) - - Adafruit HUZZAH CC3000 WiFi Shield (support coming soon) + - ESP8266 WiFi board compatible with ESP8266 Arduino core Follow the instructions in the wifiConfig.h file (wifiConfig.h tab in Arduino IDE) to configure your particular hardware. @@ -45,6 +46,8 @@ - WiFi Shield 101 requires version 0.7.0 or higher of the WiFi101 library (available in Arduino 1.6.8 or higher, or update the library via the Arduino Library Manager or clone from source: https://github.com/arduino-libraries/WiFi101) + - ESP8266 requires the Arduino ESP8266 core which can be obtained here: + https://github.com/esp8266/Arduino In order to use the WiFi Shield 101 with Firmata you will need a board with at least 35k of Flash memory. This means you cannot use the WiFi Shield 101 with an Arduino Uno @@ -120,6 +123,12 @@ SerialFirmata serialFeature; #ifdef STATIC_IP_ADDRESS IPAddress local_ip(STATIC_IP_ADDRESS); #endif +#ifdef SUBNET_MASK +IPAddress subnet(SUBNET_MASK); +#endif +#ifdef GATEWAY_IP_ADDRESS +IPAddress gateway(GATEWAY_IP_ADDRESS); +#endif int wifiConnectionAttemptCounter = 0; int wifiStatus = WL_IDLE_STATUS; @@ -687,7 +696,7 @@ void sysexCallback(byte command, byte argc, byte *argv) } if (IS_PIN_PWM(pin)) { Firmata.write(PIN_MODE_PWM); - Firmata.write(8); // 8 = 8-bit resolution + Firmata.write(DEFAULT_PWM_RESOLUTION); } if (IS_PIN_DIGITAL(pin)) { Firmata.write(PIN_MODE_SERVO); @@ -817,37 +826,37 @@ void systemResetCallback() } void printWifiStatus() { -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) if ( WiFi.status() != WL_CONNECTED ) { DEBUG_PRINT( "WiFi connection failed. Status value: " ); DEBUG_PRINTLN( WiFi.status() ); } else -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) { // print the SSID of the network you're attached to: DEBUG_PRINT( "SSID: " ); -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) DEBUG_PRINTLN( WiFi.SSID() ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) // print your WiFi shield's IP address: DEBUG_PRINT( "IP Address: " ); -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) IPAddress ip = WiFi.localIP(); DEBUG_PRINTLN( ip ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) // print the received signal strength: DEBUG_PRINT( "signal strength (RSSI): " ); -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) long rssi = WiFi.RSSI(); DEBUG_PRINT( rssi ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) +#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) DEBUG_PRINTLN( " dBm" ); } @@ -868,6 +877,8 @@ void setup() DEBUG_PRINTLN( "using the WiFi 101 library." ); #elif defined(ARDUINO_WIFI_SHIELD) DEBUG_PRINTLN( "using the legacy WiFi library." ); +#elif defined(ESP8266_WIFI) + DEBUG_PRINTLN( "using the ESP8266 WiFi library." ); #elif defined(HUZZAH_WIFI) DEBUG_PRINTLN( "using the HUZZAH WiFi library." ); //else should never happen here as error-checking in wifiConfig.h will catch this @@ -879,9 +890,13 @@ void setup() #ifdef STATIC_IP_ADDRESS DEBUG_PRINT( "Using static IP: " ); DEBUG_PRINTLN( local_ip ); - //you can also provide a static IP in the begin() functions, but this simplifies - //ifdef logic in this sketch due to support for all different encryption types. +#ifdef ESP8266_WIFI + stream.config( local_ip , gateway, subnet ); +#else + // you can also provide a static IP in the begin() functions, but this simplifies + // ifdef logic in this sketch due to support for all different encryption types. stream.config( local_ip ); +#endif #else DEBUG_PRINTLN( "IP will be requested from DHCP ..." ); #endif diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index e967a479..84b3acd0 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -3,8 +3,8 @@ * * You must configure your particular hardware. Follow the steps below. * - * Currently StandardFirmataWiFi is configured as a server. An option to - * configure as a client may be added in the future. + * Currently StandardFirmataWiFi is configured as a Wi-Fi server. An option to + * configure as a Wi-Fi client will be added in the future. *============================================================================*/ // STEP 1 [REQUIRED] @@ -14,46 +14,92 @@ /* * OPTION A: Configure for Arduino MKR1000 or Arduino WiFi Shield 101 * - * This will configure StandardFirmataWiFi to use the WiFi101 library, which works with the Arduino WiFi101 - * shield and devices that have the WiFi101 chip built in (such as the MKR1000). It is compatible - * with 802.11 B/G/N networks. + * This will configure StandardFirmataWiFi to use the WiFi101 library, which works with the + * Arduino WiFi101 shield and devices that have the WiFi101 chip built in (such as the MKR1000). + * It is compatible with 802.11 B/G/N networks. * - * To enable, uncomment the #define WIFI_101 below and verify the #define values under - * options A and C are commented out. + * If you are using the MKR1000 board, continue on to STEP 2. If you are using the WiFi 101 shield, + * follow the instructions below. * - * IMPORTANT: You must have the WiFI 101 library installed. To easily install this library, opent the library manager via: - * Arduino IDE Menus: Sketch > Include Library > Manage Libraries > filter search for "WiFi101" > Select the result and click 'install' + * To enable for the WiFi 101 shield, uncomment the #define WIFI_101 below and verify the + * #define ARDUINO_WIFI_SHIELD is commented out for OPTION B. + * + * IMPORTANT: You must have the WiFI 101 library installed. To easily install this library, open + * the library manager via: Arduino IDE Menus: Sketch > Include Library > Manage Libraries > filter + * search for "WiFi101" > Select the result and click 'install' */ -#define WIFI_101 +//#define WIFI_101 -//do not modify these next 4 lines +//do not modify the following 10 lines +#if defined(ARDUINO_SAMD_MKR1000) && !defined(WIFI_101) +// automatically include if compiling for MRK1000 +#define WIFI_101 +#endif #ifdef WIFI_101 -#include "utility/WiFi101Stream.h" -WiFi101Stream stream; +#include +#include "utility/WiFiStream.h" +WiFiStream stream; +#define WIFI_LIB_INCLUDED #endif /* - * OPTION B: Configure for Arduino WiFi shield + * OPTION B: Configure for legacy Arduino WiFi shield * * This will configure StandardFirmataWiFi to use the original WiFi library (deprecated) provided * with the Arduino IDE. It is supported by the Arduino WiFi shield (a discontinued product) and * is compatible with 802.11 B/G networks. * - * To configure StandardFirmataWiFi to use the Arduino WiFi shield - * leave the #define below uncommented. + * To configure StandardFirmataWiFi to use the legacy Arduino WiFi shield + * leave the #define below uncommented and ensure #define WIFI_101 is commented out for OPTION A. */ //#define ARDUINO_WIFI_SHIELD -//do not modify these next 4 lines +//do not modify the following 10 lines #ifdef ARDUINO_WIFI_SHIELD +#include +#include "utility/WiFiStream.h" +WiFiStream stream; + #ifdef WIFI_LIB_INCLUDED + #define MULTIPLE_WIFI_LIB_INCLUDES + #else + #define WIFI_LIB_INCLUDED + #endif +#endif + +/* + * OPTION C: Configure for ESP8266 + * + * This will configure StandardFirmataWiFi to use the ESP8266WiFi library for boards + * with an ESP8266 chip. It is compatible with 802.11 B/G/N networks. + * + * The appropriate libraries are included automatically when compiling for the ESP8266 so + * continue on to STEP 2. + * + * IMPORTANT: You must have the esp8266 board support installed. To easily install this board, open + * see the instructions here: https://github.com/esp8266/Arduino#installing-with-boards-manager. + */ +//do not modify the following 14 lines +#ifdef ESP8266 +// automatically include if compiling for ESP8266 +#define ESP8266_WIFI +#endif +#ifdef ESP8266_WIFI +#include #include "utility/WiFiStream.h" WiFiStream stream; + #ifdef WIFI_LIB_INCLUDED + #define MULTIPLE_WIFI_LIB_INCLUDES + #else + #define WIFI_LIB_INCLUDED + #endif #endif /* - * OPTION C: Configure for HUZZAH + * OPTION D: Configure for HUZZAH * - * HUZZAH is not yet supported, this will be added in a later revision to StandardFirmataWiFi + * HUZZAH with CC3000 is not yet supported, this will be added in a later revision to + * StandardFirmataWiFi. + * For HUZZAH with ESP8266 use ESP8266_WIFI. */ //------------------------------ @@ -66,26 +112,32 @@ WiFiStream stream; // replace this with your wireless network SSID char ssid[] = "your_network_name"; + // STEP 3 [OPTIONAL for all boards and shields] -// if you want to use a static IP (v4) address, uncomment the line below. You can also change the IP. -// if this line is commented out, the WiFi shield will attempt to get an IP from the DHCP server -// #define STATIC_IP_ADDRESS 192,168,1,113 +// If you want to use a static IP (v4) address, uncomment the line below. You can also change the IP. +// If the first line is commented out, the WiFi shield will attempt to get an IP from the DHCP server. +// If you are using a static IP with the ESP8266 then you must also uncomment the SUBNET and GATEWAY. +//#define STATIC_IP_ADDRESS 192,168,1,113 +//#define SUBNET_MASK 255,255,255,0 // REQUIRED for ESP8266_WIFI, optional for others +//#define GATEWAY_IP_ADDRESS 0,0,0,0 // REQUIRED for ESP8266_WIFI, optional for others + // STEP 4 [REQUIRED for all boards and shields] // define your port number here, you will need this to open a TCP connection to your Arduino #define SERVER_PORT 3030 -// STEP 5 [REQUIRED for all boards and shields] -// determine your network security type (OPTION A, B, or C). Option A is the most common, and the default. +// STEP 5 [REQUIRED for all boards and shields] +// determine your network security type (OPTION A, B, or C). Option A is the most common, and the +// default. /* * OPTION A: WPA / WPA2 * * WPA is the most common network security type. A passphrase is required to connect to this type. * - * To enable, leave #define WIFI_WPA_SECURITY uncommented below, set your wpa_passphrase value appropriately, - * and do not uncomment the #define values under options B and C + * To enable, leave #define WIFI_WPA_SECURITY uncommented below, set your wpa_passphrase value + * appropriately, and do not uncomment the #define values under options B and C */ #define WIFI_WPA_SECURITY @@ -93,14 +145,15 @@ char ssid[] = "your_network_name"; char wpa_passphrase[] = "your_wpa_passphrase"; #endif //WIFI_WPA_SECURITY + /* * OPTION B: WEP * - * WEP is a less common (and regarded as less safe) security type. A WEP key and its associated index are required - * to connect to this type. + * WEP is a less common (and regarded as less safe) security type. A WEP key and its associated + * index are required to connect to this type. * - * To enable, Uncomment the #define below, set your wep_index and wep_key values appropriately, and verify - * the #define values under options A and C are commented out. + * To enable, Uncomment the #define below, set your wep_index and wep_key values appropriately, + * and verify the #define values under options A and C are commented out. */ //#define WIFI_WEP_SECURITY @@ -115,7 +168,8 @@ char wep_key[] = "your_wep_key"; /* * OPTION C: Open network (no security) * - * Open networks have no security, can be connected to by any device that knows the ssid, and are unsafe. + * Open networks have no security, can be connected to by any device that knows the ssid, and are + * unsafe. * * To enable, uncomment #define WIFI_NO_SECURITY below and verify the #define values * under options A and B are commented out. @@ -126,11 +180,11 @@ char wep_key[] = "your_wep_key"; * CONFIGURATION ERROR CHECK (don't change anything here) *============================================================================*/ -#if ((defined(ARDUINO_WIFI_SHIELD) && (defined(WIFI_101) || defined(HUZZAH_WIFI))) || (defined(WIFI_101) && defined(HUZZAH_WIFI))) +#ifdef MULTIPLE_WIFI_LIB_INCLUDES #error "you may not define more than one wifi device type in wifiConfig.h." -#endif //WIFI device type check +#endif -#if !(defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(HUZZAH_WIFI)) +#ifndef WIFI_LIB_INCLUDED #error "you must define a wifi device type in wifiConfig.h." #endif @@ -142,6 +196,10 @@ char wep_key[] = "your_wep_key"; #error "you must define a wifi security type in wifiConfig.h." #endif //WIFI_* security define check +#if (defined(ESP8266_WIFI) && !(defined(WIFI_NO_SECURITY) || (defined(WIFI_WPA_SECURITY)))) +#error "you must choose between WIFI_NO_SECURITY and WIFI_WPA_SECURITY" +#endif + /*============================================================================== * PIN IGNORE MACROS (don't change anything here) *============================================================================*/ diff --git a/utility/WiFi101Stream.cpp b/utility/WiFi101Stream.cpp deleted file mode 100644 index 3beaf40e..00000000 --- a/utility/WiFi101Stream.cpp +++ /dev/null @@ -1,4 +0,0 @@ -/* - * Implementation is in WiFi101Stream.h to avoid linker issues. Legacy WiFi and modern WiFi101 both define WiFiClass which - * will cause linker errors whenever Firmata.h is included. - */ diff --git a/utility/WiFi101Stream.h b/utility/WiFi101Stream.h deleted file mode 100644 index eb95cf51..00000000 --- a/utility/WiFi101Stream.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - WiFi101Stream.h - An Arduino Stream that wraps an instance of a WiFi101 server. For use - with Arduino WiFi 101 shield, Arduino MKR1000 and other boards and - shields that are compatible with the Arduino WiFi101 library. - - Copyright (C) 2015-2016 Jesse Frush. 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. - - See file LICENSE.txt for further informations on licensing terms. - */ - -#ifndef WIFI101_STREAM_H -#define WIFI101_STREAM_H - -#include -#include -#include - - -class WiFi101Stream : public Stream -{ -private: - WiFiServer _server = WiFiServer(23); - WiFiClient _client; - - //configuration members - IPAddress _local_ip; - uint16_t _port = 0; - uint8_t _key_idx = 0; //WEP - const char *_key = nullptr; //WEP - const char *_passphrase = nullptr; //WPA - char *_ssid = nullptr; - - inline int connect_client() - { - if( !( _client && _client.connected() ) ) - { - WiFiClient newClient = _server.available(); - if( !newClient ) - { - return 0; - } - - _client = newClient; - } - return 1; - } - - inline bool is_ready() - { - uint8_t status = WiFi.status(); - return !( status == WL_NO_SHIELD || status == WL_CONNECTED ); - } - -public: - WiFi101Stream() {}; - - // allows another way to configure a static IP before begin is called - inline void config(IPAddress local_ip) - { - _local_ip = local_ip; - WiFi.config( local_ip ); - } - - // get DCHP IP - inline IPAddress localIP() - { - return WiFi.localIP(); - } - - inline bool maintain() - { - if( connect_client() ) return true; - - stop(); - int result = 0; - if( WiFi.status() != WL_CONNECTED ) - { - if( _local_ip ) - { - WiFi.config( _local_ip ); - } - - if( _passphrase ) - { - result = WiFi.begin( _ssid, _passphrase); - } - else if( _key_idx && _key ) - { - result = WiFi.begin( _ssid, _key_idx, _key ); - } - else - { - result = WiFi.begin( _ssid ); - } - } - if( result == 0 ) return false; - - _server = WiFiServer( _port ); - _server.begin(); - return result; - } - -/****************************************************************************** - * Connection functions with DHCP - ******************************************************************************/ - - //OPEN networks - inline int begin(char *ssid, uint16_t port) - { - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - int result = WiFi.begin( ssid ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - - //WEP-encrypted networks - inline int begin(char *ssid, uint8_t key_idx, const char *key, uint16_t port) - { - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _key_idx = key_idx; - _key = key; - - int result = WiFi.begin( ssid, key_idx, key ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - - //WPA-encrypted networks - inline int begin(char *ssid, const char *passphrase, uint16_t port) - { - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _passphrase = passphrase; - - int result = WiFi.begin( ssid, passphrase); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - -/****************************************************************************** - * Connection functions without DHCP - ******************************************************************************/ - - //OPEN networks with static IP - inline int begin(char *ssid, IPAddress local_ip, uint16_t port) - { - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - - //WEP-encrypted networks with static IP - inline int begin(char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port) - { - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - _key_idx = key_idx; - _key = key; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid, key_idx, key ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - - //WPA-encrypted networks with static IP - inline int begin(char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port) - { - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - _passphrase = passphrase; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid, passphrase); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - -/****************************************************************************** - * Stream implementations - ******************************************************************************/ - - inline int available() - { - return connect_client() ? _client.available() : 0; - } - - inline void flush() - { - if( _client ) _client.flush(); - } - - inline int peek() - { - return connect_client() ? _client.peek(): 0; - } - - inline int read() - { - return connect_client() ? _client.read() : -1; - } - - inline void stop() - { - _client.stop(); - } - - inline size_t write(uint8_t byte) - { - if( connect_client() ) _client.write( byte ); - } -}; - -#endif //WIFI101_STREAM_H diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h index fdcb483a..4f21c109 100644 --- a/utility/WiFiStream.h +++ b/utility/WiFiStream.h @@ -1,7 +1,7 @@ /* WiFiStream.h An Arduino Stream that wraps an instance of a WiFi server. For use - with legacy Arduino WiFi shield and other boards and sheilds that + with legacy Arduino WiFi shield and other boards and shields that are compatible with the Arduino WiFi library. Copyright (C) 2015-2016 Jesse Frush. All rights reserved. @@ -12,6 +12,8 @@ version 2.1 of the License, or (at your option) any later version. See file LICENSE.txt for further informations on licensing terms. + + Last updated April 10th, 2016 */ #ifndef WIFI_STREAM_H @@ -19,7 +21,6 @@ #include #include -#include class WiFiStream : public Stream { @@ -29,11 +30,14 @@ class WiFiStream : public Stream //configuration members IPAddress _local_ip; + IPAddress _gateway; + IPAddress _subnet; uint16_t _port = 0; uint8_t _key_idx = 0; //WEP const char *_key = nullptr; //WEP const char *_passphrase = nullptr; //WPA char *_ssid = nullptr; + bool _new_connection = false; inline int connect_client() { @@ -50,6 +54,16 @@ class WiFiStream : public Stream return 1; } + inline bool is_new_connection() + { + if (_new_connection && WiFi.status() == WL_CONNECTED) { + _new_connection = false; + return true; + } + _new_connection = true; + return false; + } + inline bool is_ready() { uint8_t status = WiFi.status(); @@ -59,12 +73,27 @@ class WiFiStream : public Stream public: WiFiStream() {}; +#ifndef ESP8266 // allows another way to configure a static IP before begin is called inline void config(IPAddress local_ip) { _local_ip = local_ip; WiFi.config( local_ip ); } +#endif + + // allows another way to configure a static IP before begin is called + inline void config(IPAddress local_ip, IPAddress gateway, IPAddress subnet) + { + _local_ip = local_ip; + _gateway = gateway; + _subnet = subnet; +#ifndef ESP8266 + WiFi.config( local_ip, IPAddress(0, 0, 0, 0), gateway, subnet ); +#else + WiFi.config( local_ip, gateway, subnet ); +#endif + } // get DCHP IP inline IPAddress localIP() @@ -72,6 +101,9 @@ class WiFiStream : public Stream return WiFi.localIP(); } + /** + * @return true if connected + */ inline bool maintain() { if( connect_client() ) return true; @@ -82,20 +114,36 @@ class WiFiStream : public Stream { if( _local_ip ) { +#ifndef ESP8266 WiFi.config( _local_ip ); +#else + WiFi.config( _local_ip, _gateway, _subnet ); +#endif } if( _passphrase ) { +#ifndef ESP8266 result = WiFi.begin( _ssid, _passphrase); +#else + WiFi.begin( _ssid, _passphrase); + result = WiFi.status(); +#endif } +#ifndef ESP8266 else if( _key_idx && _key ) { result = WiFi.begin( _ssid, _key_idx, _key ); } +#endif else { - result = WiFi.begin( _ssid ); +#ifndef ESP8266 + result = WiFi.begin( _ssid); +#else + WiFi.begin( _ssid); + result = WiFi.status(); +#endif } } if( result == 0 ) return false; @@ -112,11 +160,14 @@ class WiFiStream : public Stream //OPEN networks inline int begin(char *ssid, uint16_t port) { + if( is_new_connection() ) return WL_CONNECTED; if( !is_ready() ) return 0; _ssid = ssid; _port = port; - int result = WiFi.begin( ssid ); + + int result = WiFi.begin(ssid); + // will always return 0 for ESP8266 if( result == 0 ) return 0; _server = WiFiServer( port ); @@ -124,9 +175,11 @@ class WiFiStream : public Stream return result; } +#ifndef ESP8266 //WEP-encrypted networks inline int begin(char *ssid, uint8_t key_idx, const char *key, uint16_t port) { + if( is_new_connection() ) return WL_CONNECTED; if( !is_ready() ) return 0; _ssid = ssid; @@ -141,17 +194,25 @@ class WiFiStream : public Stream _server.begin(); return result; } +#endif //WPA-encrypted networks inline int begin(char *ssid, const char *passphrase, uint16_t port) { + // TODO - figure out a cleaner way to handle this. The issue is that with the ESP8266 + // WiFi.begin does not wait so the connect state is is therefore not updated until the + // next time begin is called. The call to !is_ready() below however returns 0 if + // WL_CONNECTED is true. This is to allow a new connection with different parameters than + // the original connection. is_new_connection is a temporary solution. + if( is_new_connection() ) return WL_CONNECTED; if( !is_ready() ) return 0; _ssid = ssid; _port = port; _passphrase = passphrase; - int result = WiFi.begin( ssid, passphrase); + int result = WiFi.begin(ssid, passphrase); + // will always return 0 for ESP8266 if( result == 0 ) return 0; _server = WiFiServer( port ); @@ -163,9 +224,12 @@ class WiFiStream : public Stream * Connection functions without DHCP ******************************************************************************/ +// ESP8266 requires gateway and subnet so the following functions are not compatible +#ifndef ESP8266 //OPEN networks with static IP inline int begin(char *ssid, IPAddress local_ip, uint16_t port) { + if( is_new_connection() ) return WL_CONNECTED; if( !is_ready() ) return 0; _ssid = ssid; @@ -184,6 +248,7 @@ class WiFiStream : public Stream //WEP-encrypted networks with static IP inline int begin(char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port) { + if( is_new_connection() ) return WL_CONNECTED; if( !is_ready() ) return 0; _ssid = ssid; @@ -204,6 +269,7 @@ class WiFiStream : public Stream //WPA-encrypted networks with static IP inline int begin(char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port) { + if( is_new_connection() ) return WL_CONNECTED; if( !is_ready() ) return 0; _ssid = ssid; @@ -219,6 +285,7 @@ class WiFiStream : public Stream _server.begin(); return result; } +#endif /****************************************************************************** * Stream implementations diff --git a/utility/firmataDebug.h b/utility/firmataDebug.h index 6e364b0c..dce0f801 100644 --- a/utility/firmataDebug.h +++ b/utility/firmataDebug.h @@ -3,7 +3,7 @@ #ifdef SERIAL_DEBUG #define DEBUG_BEGIN(baud) Serial.begin(baud); while(!Serial) {;} - #define DEBUG_PRINTLN(x) Serial.println (x) + #define DEBUG_PRINTLN(x) Serial.println (x); Serial.flush() #define DEBUG_PRINT(x) Serial.print (x) #else #define DEBUG_BEGIN(baud) From 94021287e3de32e2133b7b88bf7c6effb1360dd3 Mon Sep 17 00:00:00 2001 From: Jens B Date: Fri, 15 Apr 2016 20:50:23 +0200 Subject: [PATCH 016/110] WiFiClientStream added - server related functions moved from WiFiStream into WiFiServerStream - unified class interface for sketch file (no client/server defines) - WiFi and TCP configuration and connect split into individual methods (constructor, config, begin, maintain) - WiFi only initialized once at startup --- .../StandardFirmataWiFi.ino | 62 ++-- examples/StandardFirmataWiFi/wifiConfig.h | 35 ++- utility/WiFiClientStream.h | 97 ++++++ utility/WiFiServerStream.h | 98 ++++++ utility/WiFiStream.h | 289 +++++------------- 5 files changed, 326 insertions(+), 255 deletions(-) create mode 100644 utility/WiFiClientStream.h create mode 100644 utility/WiFiServerStream.h diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index e3cb2379..b84b8428 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -110,7 +110,7 @@ // the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 1 -#define WIFI_MAX_CONN_ATTEMPTS 3 +#define MAX_CONN_ATTEMPTS 20 // [500 ms] -> 10 s /*============================================================================== * GLOBAL VARIABLES @@ -130,8 +130,8 @@ IPAddress subnet(SUBNET_MASK); IPAddress gateway(GATEWAY_IP_ADDRESS); #endif -int wifiConnectionAttemptCounter = 0; -int wifiStatus = WL_IDLE_STATUS; +int connectionAttempts = 0; +bool streamConnected = false; /* analog inputs */ int analogInputsToReport = 0; // bitwise array to store pin reporting @@ -308,6 +308,12 @@ void checkDigitalInputs(void) if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); } +// ----------------------------------------------------------------------------- +// function forward declarations +void enableI2CPins(); +void disableI2CPins(); +void reportAnalogCallback(byte analogPin, int value); + // ----------------------------------------------------------------------------- /* sets the pin mode to the correct state and sets the relevant bits in the * two bit-arrays that track Digital I/O and PWM status @@ -826,38 +832,26 @@ void systemResetCallback() } void printWifiStatus() { -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) if ( WiFi.status() != WL_CONNECTED ) { DEBUG_PRINT( "WiFi connection failed. Status value: " ); DEBUG_PRINTLN( WiFi.status() ); } else -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) { // print the SSID of the network you're attached to: DEBUG_PRINT( "SSID: " ); - -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) DEBUG_PRINTLN( WiFi.SSID() ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) // print your WiFi shield's IP address: DEBUG_PRINT( "IP Address: " ); - -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) IPAddress ip = WiFi.localIP(); DEBUG_PRINTLN( ip ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) // print the received signal strength: DEBUG_PRINT( "signal strength (RSSI): " ); - -#if defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) long rssi = WiFi.RSSI(); DEBUG_PRINT( rssi ); -#endif //defined(ARDUINO_WIFI_SHIELD) || defined(WIFI_101) || defined(ESP8266_WIFI) - DEBUG_PRINTLN( " dBm" ); } } @@ -890,7 +884,7 @@ void setup() #ifdef STATIC_IP_ADDRESS DEBUG_PRINT( "Using static IP: " ); DEBUG_PRINTLN( local_ip ); -#ifdef ESP8266_WIFI +#if defined(ESP8266_WIFI) || (defined(SUBNET_MASK) && defined(GATEWAY_IP_ADDRESS)) stream.config( local_ip , gateway, subnet ); #else // you can also provide a static IP in the begin() functions, but this simplifies @@ -902,37 +896,35 @@ void setup() #endif /* - * Configure WiFi security + * Configure WiFi security and initiate WiFi connection */ #if defined(WIFI_WEP_SECURITY) - while (wifiStatus != WL_CONNECTED) { DEBUG_PRINT( "Attempting to connect to WEP SSID: " ); DEBUG_PRINTLN(ssid); - wifiStatus = stream.begin( ssid, wep_index, wep_key, SERVER_PORT ); - delay(5000); // TODO - determine minimum delay - if (++wifiConnectionAttemptCounter > WIFI_MAX_CONN_ATTEMPTS) break; - } - + stream.begin(ssid, wep_index, wep_key); #elif defined(WIFI_WPA_SECURITY) - while (wifiStatus != WL_CONNECTED) { DEBUG_PRINT( "Attempting to connect to WPA SSID: " ); DEBUG_PRINTLN(ssid); - wifiStatus = stream.begin(ssid, wpa_passphrase, SERVER_PORT); - delay(5000); // TODO - determine minimum delay - if (++wifiConnectionAttemptCounter > WIFI_MAX_CONN_ATTEMPTS) break; - } - + stream.begin(ssid, wpa_passphrase); #else //OPEN network - while (wifiStatus != WL_CONNECTED) { DEBUG_PRINTLN( "Attempting to connect to open SSID: " ); DEBUG_PRINTLN(ssid); - wifiStatus = stream.begin(ssid, SERVER_PORT); - delay(5000); // TODO - determine minimum delay - if (++wifiConnectionAttemptCounter > WIFI_MAX_CONN_ATTEMPTS) break; - } + stream.begin(ssid); #endif //defined(WIFI_WEP_SECURITY) - DEBUG_PRINTLN( "WiFi setup done" ); + + /* + * Wait for TCP connection to be established + */ + while (!streamConnected && ++connectionAttempts <= MAX_CONN_ATTEMPTS) { + delay(500); + streamConnected = stream.maintain(); + } + if (streamConnected) { + DEBUG_PRINTLN( "TCP connection established" ); + } else { + DEBUG_PRINTLN( "failed to establish TCP connection" ); + } printWifiStatus(); /* diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index 84b3acd0..85042d4c 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -30,16 +30,16 @@ */ //#define WIFI_101 -//do not modify the following 10 lines +//do not modify the following 11 lines #if defined(ARDUINO_SAMD_MKR1000) && !defined(WIFI_101) // automatically include if compiling for MRK1000 #define WIFI_101 #endif #ifdef WIFI_101 #include -#include "utility/WiFiStream.h" -WiFiStream stream; -#define WIFI_LIB_INCLUDED +#include "utility/WiFiClientStream.h" +#include "utility/WiFiServerStream.h" + #define WIFI_LIB_INCLUDED #endif /* @@ -57,8 +57,8 @@ WiFiStream stream; //do not modify the following 10 lines #ifdef ARDUINO_WIFI_SHIELD #include -#include "utility/WiFiStream.h" -WiFiStream stream; +#include "utility/WiFiClientStream.h" +#include "utility/WiFiServerStream.h" #ifdef WIFI_LIB_INCLUDED #define MULTIPLE_WIFI_LIB_INCLUDES #else @@ -85,8 +85,8 @@ WiFiStream stream; #endif #ifdef ESP8266_WIFI #include -#include "utility/WiFiStream.h" -WiFiStream stream; +#include "utility/WiFiClientStream.h" +#include "utility/WiFiServerStream.h" #ifdef WIFI_LIB_INCLUDED #define MULTIPLE_WIFI_LIB_INCLUDES #else @@ -122,12 +122,17 @@ char ssid[] = "your_network_name"; //#define GATEWAY_IP_ADDRESS 0,0,0,0 // REQUIRED for ESP8266_WIFI, optional for others -// STEP 4 [REQUIRED for all boards and shields] +// STEP 4 [OPTIONAL for all boards and shields] +// uncomment and replace with the IP address of your server if the Arduino is the TCP client +//#define SERVER_IP 10, 0, 0, 15 + + +// STEP 5 [REQUIRED for all boards and shields] // define your port number here, you will need this to open a TCP connection to your Arduino #define SERVER_PORT 3030 -// STEP 5 [REQUIRED for all boards and shields] +// STEP 6 [REQUIRED for all boards and shields] // determine your network security type (OPTION A, B, or C). Option A is the most common, and the // default. @@ -200,6 +205,16 @@ char wep_key[] = "your_wep_key"; #error "you must choose between WIFI_NO_SECURITY and WIFI_WPA_SECURITY" #endif +/*============================================================================== + * WIFI STREAM (don't change anything here) + *============================================================================*/ + +#ifdef SERVER_IP + WiFiClientStream stream(IPAddress(SERVER_IP), SERVER_PORT); +#else + WiFiServerStream stream(SERVER_PORT); +#endif + /*============================================================================== * PIN IGNORE MACROS (don't change anything here) *============================================================================*/ diff --git a/utility/WiFiClientStream.h b/utility/WiFiClientStream.h new file mode 100644 index 00000000..0eacd1d2 --- /dev/null +++ b/utility/WiFiClientStream.h @@ -0,0 +1,97 @@ +/* + WiFiClientStream.h + + An Arduino Stream that wraps an instance of a WiFiClient. For use + with legacy Arduino WiFi shield and other boards and shields that + are compatible with the Arduino WiFi library. + + Copyright (C) 2016 Jens B. 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. + + See file LICENSE.txt for further informations on licensing terms. + + Parts of this class are based on + + - EthernetClientStream - Copyright (C) 2013 Norbert Truchsess. All rights reserved. + + published under the same license. + + Last updated April 15th, 2016 + */ + +#ifndef WIFI_CLIENT_STREAM_H +#define WIFI_CLIENT_STREAM_H + +#include "WiFiStream.h" + +#define MILLIS_RECONNECT 5000 + +class WiFiClientStream : public WiFiStream +{ +protected: + uint32_t _time_connect = 0; + + /** + * check if TCP client is connected + * @return true if connected + */ + virtual inline bool connect_client() + { + if( _client && _client.connected() ) return true; + + if( _connected ) + { + stop(); + } + + // active TCP connect + if( WiFi.status() == WL_CONNECTED ) + { + // if the client is disconnected, try to reconnect every 5 seconds + if( millis() - _time_connect >= MILLIS_RECONNECT ) + { + _connected = _client.connect( _remote_ip, _port ); + if( !_connected ) { + _time_connect = millis(); + } + } + } + + return _connected; + } + +public: + /** + * create a WiFi stream with a TCP client + */ + WiFiClientStream(IPAddress server_ip, uint16_t server_port) : WiFiStream(server_ip, server_port) {} + + /** + * maintain WiFi and TCP connection + * @return true if WiFi and TCP connection are established + */ + virtual inline bool maintain() + { + return connect_client(); + } + + /** + * stop client connection + */ + virtual inline void stop() + { + if( _client) + { + _client.stop(); + } + _connected = false; + _time_connect = millis(); + } + +}; + +#endif //WIFI_CLIENT_STREAM_H diff --git a/utility/WiFiServerStream.h b/utility/WiFiServerStream.h new file mode 100644 index 00000000..596d8788 --- /dev/null +++ b/utility/WiFiServerStream.h @@ -0,0 +1,98 @@ +/* + WiFiServerStream.h + + An Arduino Stream extension for a WiFiClient or WiFiServer to be used + with legacy Arduino WiFi shield and other boards and shields that + are compatible with the Arduino WiFi library. + + Copyright (C) 2016 Jens B. 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. + + See file LICENSE.txt for further informations on licensing terms. + + Parts of this class are based on + + - WiFiStream - Copyright (C) 2015-2016 Jesse Frush. All rights reserved. + + published under the same license. + + Last updated April 15th, 2016 + */ + +#ifndef WIFI_SERVER_STREAM_H +#define WIFI_SERVER_STREAM_H + +#include "WiFiStream.h" + +class WiFiServerStream : public WiFiStream +{ +protected: + WiFiServer _server = WiFiServer(3030); + bool _listening = false; + + /** + * check if TCP client is connected + * @return true if connected + */ + virtual inline bool connect_client() + { + if( _client && _client.connected() ) return true; + + if( _connected ) + { + stop(); + } + + // passive TCP connect (accept) + WiFiClient newClient = _server.available(); + if( !_client ) return false; // could this work on all platforms? if( !(_client && _client.connected()) ) return false; + _client = newClient; + + return true; + } + +public: + /** + * create a WiFi stream with a TCP server + */ + WiFiServerStream(uint16_t server_port) : WiFiStream(server_port), _server(WiFiServer(server_port)) {} + + /** + * maintain WiFi and TCP connection + * @return true if WiFi and TCP connection are established + */ + virtual inline bool maintain() + { + if( connect_client() ) return true; + + stop(); + + if( !_listening && WiFi.status() == WL_CONNECTED ) + { + // start TCP server after first WiFi connect + _server.begin(); + _listening = true; + } + + return false; + } + + /** + * stop client connection + */ + virtual inline void stop() + { + if( _client) + { + _client.stop(); + } + _connected = false; + } + +}; + +#endif //WIFI_SERVER_STREAM_H diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h index 4f21c109..16495102 100644 --- a/utility/WiFiStream.h +++ b/utility/WiFiStream.h @@ -1,10 +1,12 @@ /* WiFiStream.h - An Arduino Stream that wraps an instance of a WiFi server. For use + + An Arduino Stream extension for a WiFiClient or WiFiServer to be used with legacy Arduino WiFi shield and other boards and shields that are compatible with the Arduino WiFi library. Copyright (C) 2015-2016 Jesse Frush. All rights reserved. + Copyright (C) 2016 Jens B. 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 @@ -13,9 +15,9 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated April 10th, 2016 + Last updated April 15th, 2016 */ - + #ifndef WIFI_STREAM_H #define WIFI_STREAM_H @@ -24,57 +26,44 @@ class WiFiStream : public Stream { -private: - WiFiServer _server = WiFiServer(23); +protected: WiFiClient _client; + bool _connected = false; //configuration members - IPAddress _local_ip; - IPAddress _gateway; + IPAddress _local_ip; // DHCP IPAddress _subnet; - uint16_t _port = 0; - uint8_t _key_idx = 0; //WEP + IPAddress _gateway; + IPAddress _remote_ip; + uint16_t _port; + uint8_t _key_idx; //WEP const char *_key = nullptr; //WEP const char *_passphrase = nullptr; //WPA char *_ssid = nullptr; - bool _new_connection = false; - inline int connect_client() - { - if( !( _client && _client.connected() ) ) - { - WiFiClient newClient = _server.available(); - if( !newClient ) - { - return 0; - } - - _client = newClient; - } - return 1; - } + /** + * check if TCP client is connected + * @return true if connected + */ + virtual bool connect_client() = 0; - inline bool is_new_connection() - { - if (_new_connection && WiFi.status() == WL_CONNECTED) { - _new_connection = false; - return true; - } - _new_connection = true; - return false; - } +public: + /** constructor for TCP server */ + WiFiStream(uint16_t server_port) : _port(server_port) {} - inline bool is_ready() - { - uint8_t status = WiFi.status(); - return !( status == WL_NO_SHIELD || status == WL_CONNECTED ); - } + /** constructor for TCP client */ + WiFiStream(IPAddress server_ip, uint16_t server_port) : _remote_ip(server_ip), _port(server_port) {} -public: - WiFiStream() {}; + +/****************************************************************************** + * network configuration + ******************************************************************************/ #ifndef ESP8266 - // allows another way to configure a static IP before begin is called + /** + * configure a static local IP address without defining the local network + * DHCP will be used as long as local IP address is not defined + */ inline void config(IPAddress local_ip) { _local_ip = local_ip; @@ -82,12 +71,15 @@ class WiFiStream : public Stream } #endif - // allows another way to configure a static IP before begin is called + /** + * configure a static local IP address + * DHCP will be used as long as local IP address is not defined + */ inline void config(IPAddress local_ip, IPAddress gateway, IPAddress subnet) { _local_ip = local_ip; - _gateway = gateway; _subnet = subnet; + _gateway = gateway; #ifndef ESP8266 WiFi.config( local_ip, IPAddress(0, 0, 0, 0), gateway, subnet ); #else @@ -95,200 +87,81 @@ class WiFiStream : public Stream #endif } - // get DCHP IP - inline IPAddress localIP() + /** + * @return local IP address + */ + inline IPAddress getLocalIP() { return WiFi.localIP(); } +/****************************************************************************** + * network functions + ******************************************************************************/ + /** - * @return true if connected + * maintain WiFi and TCP connection + * @return true if WiFi and TCP connection are established */ - inline bool maintain() - { - if( connect_client() ) return true; - - stop(); - int result = 0; - if( WiFi.status() != WL_CONNECTED ) - { - if( _local_ip ) - { -#ifndef ESP8266 - WiFi.config( _local_ip ); -#else - WiFi.config( _local_ip, _gateway, _subnet ); -#endif - } - - if( _passphrase ) - { -#ifndef ESP8266 - result = WiFi.begin( _ssid, _passphrase); -#else - WiFi.begin( _ssid, _passphrase); - result = WiFi.status(); -#endif - } -#ifndef ESP8266 - else if( _key_idx && _key ) - { - result = WiFi.begin( _ssid, _key_idx, _key ); - } -#endif - else - { -#ifndef ESP8266 - result = WiFi.begin( _ssid); -#else - WiFi.begin( _ssid); - result = WiFi.status(); -#endif - } - } - if( result == 0 ) return false; + virtual bool maintain() = 0; - _server = WiFiServer( _port ); - _server.begin(); - return result; - } + /** + * close TCP client connection + */ + virtual void stop() = 0; /****************************************************************************** - * Connection functions with DHCP + * WiFi configuration ******************************************************************************/ - //OPEN networks - inline int begin(char *ssid, uint16_t port) + /** + * initialize WiFi without security (open) and initiate client connection + * if WiFi connection is already established + * @return WL_CONNECTED if WiFi connection is established + */ + inline int begin(char *ssid) { - if( is_new_connection() ) return WL_CONNECTED; - if( !is_ready() ) return 0; - _ssid = ssid; - _port = port; - - int result = WiFi.begin(ssid); - // will always return 0 for ESP8266 - if( result == 0 ) return 0; - _server = WiFiServer( port ); - _server.begin(); - return result; + WiFi.begin(ssid); + int result = WiFi.status(); + return WiFi.status(); } #ifndef ESP8266 - //WEP-encrypted networks - inline int begin(char *ssid, uint8_t key_idx, const char *key, uint16_t port) + /** + * initialize WiFi with WEP security and initiate client connection + * if WiFi connection is already established + * @return WL_CONNECTED if WiFi connection is established + */ + inline int begin(char *ssid, uint8_t key_idx, const char *key) { - if( is_new_connection() ) return WL_CONNECTED; - if( !is_ready() ) return 0; - _ssid = ssid; - _port = port; _key_idx = key_idx; _key = key; - int result = WiFi.begin( ssid, key_idx, key ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; + WiFi.begin( ssid, key_idx, key ); + return WiFi.status(); } #endif - //WPA-encrypted networks - inline int begin(char *ssid, const char *passphrase, uint16_t port) + /** + * initialize WiFi with WPA-PSK security and initiate client connection + * if WiFi connection is already established + * @return WL_CONNECTED if WiFi connection is established + */ + inline int begin(char *ssid, const char *passphrase) { - // TODO - figure out a cleaner way to handle this. The issue is that with the ESP8266 - // WiFi.begin does not wait so the connect state is is therefore not updated until the - // next time begin is called. The call to !is_ready() below however returns 0 if - // WL_CONNECTED is true. This is to allow a new connection with different parameters than - // the original connection. is_new_connection is a temporary solution. - if( is_new_connection() ) return WL_CONNECTED; - if( !is_ready() ) return 0; - _ssid = ssid; - _port = port; _passphrase = passphrase; - int result = WiFi.begin(ssid, passphrase); - // will always return 0 for ESP8266 - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - -/****************************************************************************** - * Connection functions without DHCP - ******************************************************************************/ - -// ESP8266 requires gateway and subnet so the following functions are not compatible -#ifndef ESP8266 - //OPEN networks with static IP - inline int begin(char *ssid, IPAddress local_ip, uint16_t port) - { - if( is_new_connection() ) return WL_CONNECTED; - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } - - //WEP-encrypted networks with static IP - inline int begin(char *ssid, IPAddress local_ip, uint8_t key_idx, const char *key, uint16_t port) - { - if( is_new_connection() ) return WL_CONNECTED; - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - _key_idx = key_idx; - _key = key; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid, key_idx, key ); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; + WiFi.begin(ssid, passphrase); + return WiFi.status(); } - //WPA-encrypted networks with static IP - inline int begin(char *ssid, IPAddress local_ip, const char *passphrase, uint16_t port) - { - if( is_new_connection() ) return WL_CONNECTED; - if( !is_ready() ) return 0; - - _ssid = ssid; - _port = port; - _local_ip = local_ip; - _passphrase = passphrase; - - WiFi.config( local_ip ); - int result = WiFi.begin( ssid, passphrase); - if( result == 0 ) return 0; - - _server = WiFiServer( port ); - _server.begin(); - return result; - } -#endif /****************************************************************************** - * Stream implementations + * stream functions ******************************************************************************/ inline int available() @@ -311,15 +184,11 @@ class WiFiStream : public Stream return connect_client() ? _client.read() : -1; } - inline void stop() - { - _client.stop(); - } - inline size_t write(uint8_t byte) { - if( connect_client() ) _client.write( byte ); + return connect_client() ? _client.write( byte ) : 0; } + }; #endif //WIFI_STREAM_H From 3d2085cd11d17519c160618c5fde569514297e65 Mon Sep 17 00:00:00 2001 From: Jens B Date: Sat, 16 Apr 2016 12:55:24 +0200 Subject: [PATCH 017/110] WiFiServer activation moved from constructor to maintain --- .../StandardFirmataWiFi.ino | 1 + utility/WiFiServerStream.h | 25 ++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index b84b8428..5a92dcea 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -918,6 +918,7 @@ void setup() */ while (!streamConnected && ++connectionAttempts <= MAX_CONN_ATTEMPTS) { delay(500); + DEBUG_PRINT("."); streamConnected = stream.maintain(); } if (streamConnected) { diff --git a/utility/WiFiServerStream.h b/utility/WiFiServerStream.h index 596d8788..f3a3143f 100644 --- a/utility/WiFiServerStream.h +++ b/utility/WiFiServerStream.h @@ -15,12 +15,12 @@ See file LICENSE.txt for further informations on licensing terms. Parts of this class are based on - + - WiFiStream - Copyright (C) 2015-2016 Jesse Frush. All rights reserved. - + published under the same license. - Last updated April 15th, 2016 + Last updated April 16th, 2016 */ #ifndef WIFI_SERVER_STREAM_H @@ -46,21 +46,21 @@ class WiFiServerStream : public WiFiStream { stop(); } - + // passive TCP connect (accept) - WiFiClient newClient = _server.available(); + WiFiClient newClient = _server.available(); if( !_client ) return false; // could this work on all platforms? if( !(_client && _client.connected()) ) return false; _client = newClient; - + return true; } - + public: /** * create a WiFi stream with a TCP server */ - WiFiServerStream(uint16_t server_port) : WiFiStream(server_port), _server(WiFiServer(server_port)) {} - + WiFiServerStream(uint16_t server_port) : WiFiStream(server_port) {} + /** * maintain WiFi and TCP connection * @return true if WiFi and TCP connection are established @@ -70,14 +70,15 @@ class WiFiServerStream : public WiFiStream if( connect_client() ) return true; stop(); - + if( !_listening && WiFi.status() == WL_CONNECTED ) { // start TCP server after first WiFi connect + _server = WiFiServer(_port); _server.begin(); _listening = true; } - + return false; } @@ -92,7 +93,7 @@ class WiFiServerStream : public WiFiStream } _connected = false; } - + }; #endif //WIFI_SERVER_STREAM_H From b6573c8ddd599ce9d7a99391056f80ad031cec7a Mon Sep 17 00:00:00 2001 From: Jens B Date: Sun, 17 Apr 2016 11:32:35 +0200 Subject: [PATCH 018/110] WiFiServerStream fix & host connection callback - fixed client accept in WiFiServerStream - added host connection callback hook to notfiy connect and disconnect --- utility/WiFiClientStream.h | 17 +++++++++++++---- utility/WiFiServerStream.h | 12 ++++++++++-- utility/WiFiStream.h | 14 ++++++++++++-- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/utility/WiFiClientStream.h b/utility/WiFiClientStream.h index 0eacd1d2..957c6727 100644 --- a/utility/WiFiClientStream.h +++ b/utility/WiFiClientStream.h @@ -15,12 +15,12 @@ See file LICENSE.txt for further informations on licensing terms. Parts of this class are based on - + - EthernetClientStream - Copyright (C) 2013 Norbert Truchsess. All rights reserved. - + published under the same license. - Last updated April 15th, 2016 + Last updated April 17th, 2016 */ #ifndef WIFI_CLIENT_STREAM_H @@ -55,9 +55,14 @@ class WiFiClientStream : public WiFiStream if( millis() - _time_connect >= MILLIS_RECONNECT ) { _connected = _client.connect( _remote_ip, _port ); - if( !_connected ) { + if( !_connected ) + { _time_connect = millis(); } + else if ( _currentHostConnectionCallback ) + { + (*_currentHostConnectionCallback)(HOST_CONNECTION_CONNECTED); + } } } @@ -87,6 +92,10 @@ class WiFiClientStream : public WiFiStream if( _client) { _client.stop(); + if ( _currentHostConnectionCallback ) + { + (*_currentHostConnectionCallback)(HOST_CONNECTION_DISCONNECTED); + } } _connected = false; _time_connect = millis(); diff --git a/utility/WiFiServerStream.h b/utility/WiFiServerStream.h index f3a3143f..e8f8eb1d 100644 --- a/utility/WiFiServerStream.h +++ b/utility/WiFiServerStream.h @@ -20,7 +20,7 @@ published under the same license. - Last updated April 16th, 2016 + Last updated April 17th, 2016 */ #ifndef WIFI_SERVER_STREAM_H @@ -49,8 +49,12 @@ class WiFiServerStream : public WiFiStream // passive TCP connect (accept) WiFiClient newClient = _server.available(); - if( !_client ) return false; // could this work on all platforms? if( !(_client && _client.connected()) ) return false; + if( !newClient ) return false; _client = newClient; + if ( _currentHostConnectionCallback ) + { + (*_currentHostConnectionCallback)(HOST_CONNECTION_CONNECTED); + } return true; } @@ -90,6 +94,10 @@ class WiFiServerStream : public WiFiStream if( _client) { _client.stop(); + if ( _currentHostConnectionCallback ) + { + (*_currentHostConnectionCallback)(HOST_CONNECTION_DISCONNECTED); + } } _connected = false; } diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h index 16495102..68a3b18f 100644 --- a/utility/WiFiStream.h +++ b/utility/WiFiStream.h @@ -15,20 +15,29 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated April 15th, 2016 + Last updated April 17th, 2016 */ - + #ifndef WIFI_STREAM_H #define WIFI_STREAM_H #include #include +#define HOST_CONNECTION_DISCONNECTED 0 +#define HOST_CONNECTION_CONNECTED 1 + +extern "C" { + // callback function types + typedef void (*hostConnectionCallbackFunction)(byte); +} + class WiFiStream : public Stream { protected: WiFiClient _client; bool _connected = false; + hostConnectionCallbackFunction _currentHostConnectionCallback; //configuration members IPAddress _local_ip; // DHCP @@ -54,6 +63,7 @@ class WiFiStream : public Stream /** constructor for TCP client */ WiFiStream(IPAddress server_ip, uint16_t server_port) : _remote_ip(server_ip), _port(server_port) {} + inline void attach( hostConnectionCallbackFunction newFunction ) { _currentHostConnectionCallback = newFunction; } /****************************************************************************** * network configuration From 57967d3fb7cc13eb4bb3f6bece78678dafd3a888 Mon Sep 17 00:00:00 2001 From: Jens B Date: Sun, 17 Apr 2016 11:38:27 +0200 Subject: [PATCH 019/110] WiFiServerStream connected state - fixed missing update of _connected when accepting a client --- utility/WiFiServerStream.h | 1 + 1 file changed, 1 insertion(+) diff --git a/utility/WiFiServerStream.h b/utility/WiFiServerStream.h index e8f8eb1d..fd0a9495 100644 --- a/utility/WiFiServerStream.h +++ b/utility/WiFiServerStream.h @@ -51,6 +51,7 @@ class WiFiServerStream : public WiFiStream WiFiClient newClient = _server.available(); if( !newClient ) return false; _client = newClient; + _connected = true; if ( _currentHostConnectionCallback ) { (*_currentHostConnectionCallback)(HOST_CONNECTION_CONNECTED); From ccaa9031e799bda45ed0aab4ca4c568b13c75987 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 17 Apr 2016 14:55:57 -0700 Subject: [PATCH 020/110] update some wifi config instructions --- .../StandardFirmataWiFi.ino | 21 +++++++-------- examples/StandardFirmataWiFi/wifiConfig.h | 27 ++++++++++--------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 5a92dcea..7fb6ef8f 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -22,14 +22,14 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: April 10th, 2016 + Last updated by Jeff Hoefs: April 17th, 2016 */ /* README - StandardFirmataWiFi is a WiFi server application. You will need a Firmata client library with - a network transport in order to establish a connection with StandardFirmataWiFi. + StandardFirmataWiFi enables the use of Firmata over a TCP connection. It can be configured as + either a TCP server or TCP client. To use StandardFirmataWiFi you will need to have one of the following boards or shields: @@ -49,10 +49,10 @@ - ESP8266 requires the Arduino ESP8266 core which can be obtained here: https://github.com/esp8266/Arduino - In order to use the WiFi Shield 101 with Firmata you will need a board with at least - 35k of Flash memory. This means you cannot use the WiFi Shield 101 with an Arduino Uno - or any other ATmega328p-based microcontroller or with an Arduino Leonardo or other - ATmega32u4-based microcontroller. Some boards that will work are: + In order to use the WiFi Shield 101 with Firmata you will need a board with at least 35k of Flash + memory. This means you cannot use the WiFi Shield 101 with an Arduino Uno or any other + ATmega328p-based microcontroller or with an Arduino Leonardo or other ATmega32u4-based + microcontroller. Some boards that will work are: - Arduino Zero - Arduino Due @@ -87,8 +87,7 @@ /* * Uncomment the following include to enable interfacing with Serial devices via hardware or - * software serial. Note that if enabled, this sketch will likely consume too much memory to run on - * an Arduino Uno or Leonardo or other ATmega328p-based or ATmega32u4-based boards. + * software serial. */ //#include "utility/SerialFirmata.h" @@ -921,10 +920,10 @@ void setup() DEBUG_PRINT("."); streamConnected = stream.maintain(); } - if (streamConnected) { + if (streamConnected) { DEBUG_PRINTLN( "TCP connection established" ); } else { - DEBUG_PRINTLN( "failed to establish TCP connection" ); + DEBUG_PRINTLN( "failed to establish TCP connection" ); } printWifiStatus(); diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index 85042d4c..3ee306f7 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -3,13 +3,13 @@ * * You must configure your particular hardware. Follow the steps below. * - * Currently StandardFirmataWiFi is configured as a Wi-Fi server. An option to - * configure as a Wi-Fi client will be added in the future. + * By default, StandardFirmataWiFi is configured as a TCP server, to configure + * as a TCP client, see STEP 2. *============================================================================*/ // STEP 1 [REQUIRED] // Uncomment / comment the appropriate set of includes for your hardware (OPTION A, B or C) -// Option A is enabled by default. +// Arduino MKR1000 or ESP8266 are enabled by default if compiling for either of those boards. /* * OPTION A: Configure for Arduino MKR1000 or Arduino WiFi Shield 101 @@ -75,8 +75,8 @@ * The appropriate libraries are included automatically when compiling for the ESP8266 so * continue on to STEP 2. * - * IMPORTANT: You must have the esp8266 board support installed. To easily install this board, open - * see the instructions here: https://github.com/esp8266/Arduino#installing-with-boards-manager. + * IMPORTANT: You must have the esp8266 board support installed. To easily install this board see + * the instructions here: https://github.com/esp8266/Arduino#installing-with-boards-manager. */ //do not modify the following 14 lines #ifdef ESP8266 @@ -108,12 +108,18 @@ //#define HUZZAH_WIFI -// STEP 2 [REQUIRED for all boards and shields] +// STEP 2 [OPTIONAL for all boards and shields] +// If you want to setup you board as a TCP client, uncomment the following define and replace +// the IP address with the IP address of your server. +//#define SERVER_IP 10, 0, 0, 15 + + +// STEP 3 [REQUIRED for all boards and shields] // replace this with your wireless network SSID char ssid[] = "your_network_name"; -// STEP 3 [OPTIONAL for all boards and shields] +// STEP 4 [OPTIONAL for all boards and shields] // If you want to use a static IP (v4) address, uncomment the line below. You can also change the IP. // If the first line is commented out, the WiFi shield will attempt to get an IP from the DHCP server. // If you are using a static IP with the ESP8266 then you must also uncomment the SUBNET and GATEWAY. @@ -122,11 +128,6 @@ char ssid[] = "your_network_name"; //#define GATEWAY_IP_ADDRESS 0,0,0,0 // REQUIRED for ESP8266_WIFI, optional for others -// STEP 4 [OPTIONAL for all boards and shields] -// uncomment and replace with the IP address of your server if the Arduino is the TCP client -//#define SERVER_IP 10, 0, 0, 15 - - // STEP 5 [REQUIRED for all boards and shields] // define your port number here, you will need this to open a TCP connection to your Arduino #define SERVER_PORT 3030 @@ -214,7 +215,7 @@ char wep_key[] = "your_wep_key"; #else WiFiServerStream stream(SERVER_PORT); #endif - + /*============================================================================== * PIN IGNORE MACROS (don't change anything here) *============================================================================*/ From 077aa1937a0858b7cac7aa46b2cb70b60069d565 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 17 Apr 2016 17:03:23 -0700 Subject: [PATCH 021/110] refactor setup function - split wifi init and firmata init into separate functions - add hostConnectionCallback --- .../StandardFirmataWiFi.ino | 165 ++++++++++-------- 1 file changed, 94 insertions(+), 71 deletions(-) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 7fb6ef8f..0d13c3d4 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -830,6 +830,28 @@ void systemResetCallback() isResetting = false; } +/* + * Called when a TCP connection is either connected or disconnected. + * TODO - figure out why the callback is not being called when using ESP8266 as a TCP server and + * why only connect is called when using ESP8266 as a TCP client. In both cases the actual + * connection is working but not reported via the callback. + */ +void hostConnectionCallback(byte state) +{ + switch (state) { + case HOST_CONNECTION_CONNECTED: + DEBUG_PRINTLN( "TCP connection established" ); + break; + case HOST_CONNECTION_DISCONNECTED: + DEBUG_PRINTLN( "TCP connection disconnected" ); + break; + } +} + +/* + * Print the status of the WiFi connection. This is the connection to the access point rather + * than the TCP connection. + */ void printWifiStatus() { if ( WiFi.status() != WL_CONNECTED ) { @@ -855,16 +877,51 @@ void printWifiStatus() { } } -void setup() +/* + * StandardFirmataWiFi communicates with WiFi shields over SPI. Therefore all + * SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. + * Additional pins may also need to be ignored depending on the particular board or + * shield in use. + */ +void ignoreWiFiPins() { - /* - * WIFI SETUP - */ - DEBUG_BEGIN(9600); + for (byte i = 0; i < TOTAL_PINS; i++) { +#if defined(ARDUINO_WIFI_SHIELD) + if (IS_IGNORE_WIFI_SHIELD(i) + #if defined(__AVR_ATmega32U4__) + || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 + || 28 == i + #endif //defined(__AVR_ATmega32U4__) + ) { +// don't ignore pins when using Wi-Fi 101 library with the MKR1000 +#elif defined (WIFI_101) && !defined(ARDUINO_SAMD_MKR1000) + if (IS_IGNORE_WIFI101_SHIELD(i)) { +#elif defined (HUZZAH_WIFI) + // TODO + if (false) { +#else + if (false) { +#endif + Firmata.setPinMode(i, PIN_MODE_IGNORE); + } + } - /* - * This statement will clarify how a connection is being made - */ + //Set up controls for the Arduino WiFi Shield SS for the SD Card +#ifdef ARDUINO_WIFI_SHIELD + // Arduino WiFi, Arduino WiFi Shield and Arduino Yun all have SD SS wired to D4 + pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata + digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA +#endif //defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + +#endif //ARDUINO_WIFI_SHIELD +} + +void initWiFi() +{ + // This statement will clarify how a connection is being made DEBUG_PRINT( "StandardFirmataWiFi will attempt a WiFi connection " ); #if defined(WIFI_101) DEBUG_PRINTLN( "using the WiFi 101 library." ); @@ -877,9 +934,7 @@ void setup() //else should never happen here as error-checking in wifiConfig.h will catch this #endif //defined(WIFI_101) - /* - * Configure WiFi IP Address - */ + // Configure WiFi IP Address #ifdef STATIC_IP_ADDRESS DEBUG_PRINT( "Using static IP: " ); DEBUG_PRINTLN( local_ip ); @@ -894,44 +949,39 @@ void setup() DEBUG_PRINTLN( "IP will be requested from DHCP ..." ); #endif - /* - * Configure WiFi security and initiate WiFi connection - */ + stream.attach(hostConnectionCallback); + + // Configure WiFi security and initiate WiFi connection #if defined(WIFI_WEP_SECURITY) - DEBUG_PRINT( "Attempting to connect to WEP SSID: " ); - DEBUG_PRINTLN(ssid); + DEBUG_PRINT( "Attempting to connect to WEP SSID: " ); + DEBUG_PRINTLN(ssid); stream.begin(ssid, wep_index, wep_key); #elif defined(WIFI_WPA_SECURITY) - DEBUG_PRINT( "Attempting to connect to WPA SSID: " ); - DEBUG_PRINTLN(ssid); + DEBUG_PRINT( "Attempting to connect to WPA SSID: " ); + DEBUG_PRINTLN(ssid); stream.begin(ssid, wpa_passphrase); #else //OPEN network - DEBUG_PRINTLN( "Attempting to connect to open SSID: " ); - DEBUG_PRINTLN(ssid); + DEBUG_PRINTLN( "Attempting to connect to open SSID: " ); + DEBUG_PRINTLN(ssid); stream.begin(ssid); #endif //defined(WIFI_WEP_SECURITY) DEBUG_PRINTLN( "WiFi setup done" ); - /* - * Wait for TCP connection to be established - */ - while (!streamConnected && ++connectionAttempts <= MAX_CONN_ATTEMPTS) { + // Wait for connection to access point to be established. This is necessary for ESP8266 + // or we won't have a connection state once printWiFiStatus() is called and the state + // will be reported as disconnected. We don't want to wait until the TCP connection is + // established before calling printWiFiStatus() because printing the IP address upon + // connection with the access point is useful when using DHCP + while (WiFi.status() != WL_CONNECTED && ++connectionAttempts <= MAX_CONN_ATTEMPTS) { delay(500); DEBUG_PRINT("."); - streamConnected = stream.maintain(); - } - if (streamConnected) { - DEBUG_PRINTLN( "TCP connection established" ); - } else { - DEBUG_PRINTLN( "failed to establish TCP connection" ); } printWifiStatus(); +} - /* - * FIRMATA SETUP - */ +void initFirmata() +{ Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); - Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); Firmata.attach(REPORT_ANALOG, reportAnalogCallback); @@ -941,47 +991,20 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); - // StandardFirmataWiFi communicates with WiFi shields over SPI. Therefore all - // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. - // Additional pins may also need to be ignored depending on the particular board or - // shield in use. + ignoreWiFiPins(); - for (byte i = 0; i < TOTAL_PINS; i++) { -#if defined(ARDUINO_WIFI_SHIELD) - if (IS_IGNORE_WIFI_SHIELD(i) - #if defined(__AVR_ATmega32U4__) - || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 - || 28 == i - #endif //defined(__AVR_ATmega32U4__) - ) { -// don't ignore pins when using Wi-Fi 101 library with the MKR1000 -#elif defined (WIFI_101) && !defined(ARDUINO_SAMD_MKR1000) - if (IS_IGNORE_WIFI101_SHIELD(i)) { -#elif defined (HUZZAH_WIFI) - // TODO - if (false) { -#else - if (false) { -#endif - Firmata.setPinMode(i, PIN_MODE_IGNORE); - } - } - - //Set up controls for the Arduino WiFi Shield SS for the SD Card -#ifdef ARDUINO_WIFI_SHIELD - // Arduino WiFi, Arduino WiFi Shield and Arduino Yun all have SD SS wired to D4 - pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata - digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; + // Initialize Firmata to use the WiFi stream object as the transport. + Firmata.begin(stream); + systemResetCallback(); // reset to default config +} -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA -#endif //defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +void setup() +{ + DEBUG_BEGIN(9600); -#endif //ARDUINO_WIFI_SHIELD + initWiFi(); - // start up Network Firmata: - Firmata.begin(stream); - systemResetCallback(); // reset to default config + initFirmata(); } /*============================================================================== From 55ed0f6b86464ba036ebc273debec4ae7f8e9bef Mon Sep 17 00:00:00 2001 From: Jens B Date: Sat, 23 Apr 2016 20:56:38 +0200 Subject: [PATCH 022/110] connection state management modified - check member _connected first in connect_client() to prevent querying connected() of disconnected _client - added method status() to check TCP connection state (ESP8266 only) --- utility/WiFiClientStream.h | 15 +++++++-------- utility/WiFiServerStream.h | 15 +++++++-------- utility/WiFiStream.h | 24 +++++++++++++++++++++++- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/utility/WiFiClientStream.h b/utility/WiFiClientStream.h index 957c6727..7fd30af6 100644 --- a/utility/WiFiClientStream.h +++ b/utility/WiFiClientStream.h @@ -20,7 +20,7 @@ published under the same license. - Last updated April 17th, 2016 + Last updated April 23rd, 2016 */ #ifndef WIFI_CLIENT_STREAM_H @@ -41,21 +41,20 @@ class WiFiClientStream : public WiFiStream */ virtual inline bool connect_client() { - if( _client && _client.connected() ) return true; - - if( _connected ) + if ( _connected ) { + if ( _client && _client.connected() ) return true; stop(); } // active TCP connect - if( WiFi.status() == WL_CONNECTED ) + if ( WiFi.status() == WL_CONNECTED ) { // if the client is disconnected, try to reconnect every 5 seconds - if( millis() - _time_connect >= MILLIS_RECONNECT ) + if ( millis() - _time_connect >= MILLIS_RECONNECT ) { _connected = _client.connect( _remote_ip, _port ); - if( !_connected ) + if ( !_connected ) { _time_connect = millis(); } @@ -89,7 +88,7 @@ class WiFiClientStream : public WiFiStream */ virtual inline void stop() { - if( _client) + if ( _client) { _client.stop(); if ( _currentHostConnectionCallback ) diff --git a/utility/WiFiServerStream.h b/utility/WiFiServerStream.h index fd0a9495..1404b056 100644 --- a/utility/WiFiServerStream.h +++ b/utility/WiFiServerStream.h @@ -20,7 +20,7 @@ published under the same license. - Last updated April 17th, 2016 + Last updated April 23rd, 2016 */ #ifndef WIFI_SERVER_STREAM_H @@ -40,16 +40,15 @@ class WiFiServerStream : public WiFiStream */ virtual inline bool connect_client() { - if( _client && _client.connected() ) return true; - - if( _connected ) + if ( _connected ) { + if ( _client && _client.connected() ) return true; stop(); } // passive TCP connect (accept) WiFiClient newClient = _server.available(); - if( !newClient ) return false; + if ( !newClient ) return false; _client = newClient; _connected = true; if ( _currentHostConnectionCallback ) @@ -72,11 +71,11 @@ class WiFiServerStream : public WiFiStream */ virtual inline bool maintain() { - if( connect_client() ) return true; + if ( connect_client() ) return true; stop(); - if( !_listening && WiFi.status() == WL_CONNECTED ) + if ( !_listening && WiFi.status() == WL_CONNECTED ) { // start TCP server after first WiFi connect _server = WiFiServer(_port); @@ -92,7 +91,7 @@ class WiFiServerStream : public WiFiStream */ virtual inline void stop() { - if( _client) + if ( _client) { _client.stop(); if ( _currentHostConnectionCallback ) diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h index 68a3b18f..4d83fe8d 100644 --- a/utility/WiFiStream.h +++ b/utility/WiFiStream.h @@ -15,7 +15,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated April 17th, 2016 + Last updated April 23rd, 2016 */ #ifndef WIFI_STREAM_H @@ -114,6 +114,28 @@ class WiFiStream : public Stream * @return true if WiFi and TCP connection are established */ virtual bool maintain() = 0; + +#ifdef ESP8266 + /** + * get status of TCP connection + * @return status of TCP connection + * CLOSED = 0 (typical) + * LISTEN = 1 (not used) + * SYN_SENT = 2 + * SYN_RCVD = 3 + * ESTABLISHED = 4 (typical) + * FIN_WAIT_1 = 5 + * FIN_WAIT_2 = 6 + * CLOSE_WAIT = 7 + * CLOSING = 8 + * LAST_ACK = 9 + * TIME_WAIT = 10 + */ + inline uint8_t status() + { + return _client.status(); + } +#endif /** * close TCP client connection From 7573a5839596ad2651de154f4bea576ac53d088d Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 24 Apr 2016 14:21:52 -0700 Subject: [PATCH 023/110] simplify pin ignore configuration - use generic names for init functions - add clarifications to comments --- .../StandardFirmataWiFi.ino | 53 +++++++------------ examples/StandardFirmataWiFi/wifiConfig.h | 19 +++++-- 2 files changed, 33 insertions(+), 39 deletions(-) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 0d13c3d4..448ccd4a 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -22,7 +22,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: April 17th, 2016 + Last updated by Jeff Hoefs: April 24th, 2016 */ /* @@ -36,7 +36,7 @@ - Arduino WiFi Shield (or clone) - Arduino WiFi Shield 101 - - Arduino MKR1000 board (built-in WiFi 101) + - Arduino MKR1000 board - ESP8266 WiFi board compatible with ESP8266 Arduino core Follow the instructions in the wifiConfig.h file (wifiConfig.h tab in Arduino IDE) to @@ -46,7 +46,7 @@ - WiFi Shield 101 requires version 0.7.0 or higher of the WiFi101 library (available in Arduino 1.6.8 or higher, or update the library via the Arduino Library Manager or clone from source: https://github.com/arduino-libraries/WiFi101) - - ESP8266 requires the Arduino ESP8266 core which can be obtained here: + - ESP8266 requires the Arduino ESP8266 core v2.1.0 or higher which can be obtained here: https://github.com/esp8266/Arduino In order to use the WiFi Shield 101 with Firmata you will need a board with at least 35k of Flash @@ -308,7 +308,7 @@ void checkDigitalInputs(void) } // ----------------------------------------------------------------------------- -// function forward declarations +// function forward declarations for xtensa compiler (ESP8266) void enableI2CPins(); void disableI2CPins(); void reportAnalogCallback(byte analogPin, int value); @@ -832,9 +832,9 @@ void systemResetCallback() /* * Called when a TCP connection is either connected or disconnected. - * TODO - figure out why the callback is not being called when using ESP8266 as a TCP server and - * why only connect is called when using ESP8266 as a TCP client. In both cases the actual - * connection is working but not reported via the callback. + * TODO: + * - report connected or reconnected state to host (to be added to protocol) + * - report current state to host (to be added to protocol) */ void hostConnectionCallback(byte state) { @@ -883,43 +883,30 @@ void printWifiStatus() { * Additional pins may also need to be ignored depending on the particular board or * shield in use. */ -void ignoreWiFiPins() +void ignorePins() { +#ifdef IS_IGNORE_PIN for (byte i = 0; i < TOTAL_PINS; i++) { -#if defined(ARDUINO_WIFI_SHIELD) - if (IS_IGNORE_WIFI_SHIELD(i) - #if defined(__AVR_ATmega32U4__) - || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 - || 28 == i - #endif //defined(__AVR_ATmega32U4__) - ) { -// don't ignore pins when using Wi-Fi 101 library with the MKR1000 -#elif defined (WIFI_101) && !defined(ARDUINO_SAMD_MKR1000) - if (IS_IGNORE_WIFI101_SHIELD(i)) { -#elif defined (HUZZAH_WIFI) - // TODO - if (false) { -#else - if (false) { -#endif + if (IS_IGNORE_PIN(i)) { Firmata.setPinMode(i, PIN_MODE_IGNORE); } } +#endif //Set up controls for the Arduino WiFi Shield SS for the SD Card #ifdef ARDUINO_WIFI_SHIELD - // Arduino WiFi, Arduino WiFi Shield and Arduino Yun all have SD SS wired to D4 + // Arduino WiFi Shield has SD SS wired to D4 pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA -#endif //defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#endif //defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -#endif //ARDUINO_WIFI_SHIELD +#endif //ARDUINO_WIFI_SHIELD } -void initWiFi() +void initTransport() { // This statement will clarify how a connection is being made DEBUG_PRINT( "StandardFirmataWiFi will attempt a WiFi connection " ); @@ -967,11 +954,7 @@ void initWiFi() #endif //defined(WIFI_WEP_SECURITY) DEBUG_PRINTLN( "WiFi setup done" ); - // Wait for connection to access point to be established. This is necessary for ESP8266 - // or we won't have a connection state once printWiFiStatus() is called and the state - // will be reported as disconnected. We don't want to wait until the TCP connection is - // established before calling printWiFiStatus() because printing the IP address upon - // connection with the access point is useful when using DHCP + // Wait for connection to access point to be established. while (WiFi.status() != WL_CONNECTED && ++connectionAttempts <= MAX_CONN_ATTEMPTS) { delay(500); DEBUG_PRINT("."); @@ -991,7 +974,7 @@ void initFirmata() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); - ignoreWiFiPins(); + ignorePins(); // Initialize Firmata to use the WiFi stream object as the transport. Firmata.begin(stream); @@ -1002,7 +985,7 @@ void setup() { DEBUG_BEGIN(9600); - initWiFi(); + initTransport(); initFirmata(); } diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index 3ee306f7..bedc7447 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -220,10 +220,21 @@ char wep_key[] = "your_wep_key"; * PIN IGNORE MACROS (don't change anything here) *============================================================================*/ +#if defined(WIFI_101) && !defined(ARDUINO_SAMD_MKR1000) // ignore SPI pins, pin 5 (reset WiFi101 shield), pin 7 (WiFi handshake) and pin 10 (WiFi SS) -// also don't ignore SS pin if it's not pin 10 -// Not needed for Arduino MKR1000. -#define IS_IGNORE_WIFI101_SHIELD(p) ((p) == 10 || (IS_PIN_SPI(p) && (p) != SS) || (p) == 5 || (p) == 7) +// also don't ignore SS pin if it's not pin 10. Not needed for Arduino MKR1000. +#define IS_IGNORE_PIN(p) ((p) == 10 || (IS_PIN_SPI(p) && (p) != SS) || (p) == 5 || (p) == 7) +#elif defined(ARDUINO_WIFI_SHIELD) && defined(__AVR_ATmega32U4__) // ignore SPI pins, pin 4 (SS for SD-Card on WiFi-shield), pin 7 (WiFi handshake) and pin 10 (WiFi SS) -#define IS_IGNORE_WIFI_SHIELD(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 7 || (p) == 10) +// On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 +#define IS_IGNORE_PIN(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 7 || (p) == 10 || (p) == 24 || (p) == 28) + +#elif defined(ARDUINO_WIFI_SHIELD) +// ignore SPI pins, pin 4 (SS for SD-Card on WiFi-shield), pin 7 (WiFi handshake) and pin 10 (WiFi SS) +#define IS_IGNORE_PIN(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 7 || (p) == 10) + +#elif defined(ESP8266_WIFI) && defined(SERIAL_DEBUG) +#define IS_IGNORE_PIN(p) ((p) == 1) + +#endif From 84492658d9c3482f37d8b79c7eaa69d7f75f137e Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Wed, 15 Jun 2016 22:48:16 -0700 Subject: [PATCH 024/110] enable CurieBLE.setConnectionInterval --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 19 +------------------ examples/StandardFirmataBLE/bleConfig.h | 6 ++++++ 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 621e9840..c7be9897 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated March 13th, 2016 + Last updated June 15th, 2016 */ #include @@ -763,27 +763,10 @@ void setup() stream.setLocalName(FIRMATA_BLE_LOCAL_NAME); -// setConnectionInterval is not available in the CurieBLE library included in the -// Intel Curie Boards package v1.0.5 (latest version via the Boards Manager). Without -// setConnectionInterval, the BLE reporting rate for analog input and I2C read continuous mode -// will be very slow (150ms instead of 30ms). -// However, you can manually update CurieBLE to get the functionality now. Follow these steps: -// 1. Install Intel Curie Boards v1.0.5 via the Arduino Boards manager (use Arduino 1.6.7 or newer) -// 2. Download or clone corelibs-arduino101: https://github.com/01org/corelibs-arduino101 -// 3. Make a copy of the CurieBLE directory found in corelibs-arduino101/libraries/ -// 4. Find the Arduino15 directory on your computer: -// OS X: ~/Library/Arduino15 -// Windows: C:\Users\(username)\AppData\Local\Arduino15 -// Linux: ~/.arduino15 -// 5. From the Arduino15 directory, navigate to: /packages/Intel/hardware/arc32/1.0.5/libraries/ -// 6. Replace the CurieBLE library with the version you copied in step 3 -// 7. Comment out the #ifndef statement below and the following #endif statement -#ifndef _VARIANT_ARDUINO_101_X_ // set the BLE connection interval - this is the fastest interval you can read inputs stream.setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); // set how often the BLE TX buffer is flushed (if not full) stream.setFlushInterval(FIRMATA_BLE_MAX_INTERVAL); -#endif #ifdef BLE_REQ for (byte i = 0; i < TOTAL_PINS; i++) { diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index c1bd1fe6..da5a5f20 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -5,6 +5,9 @@ * need a unique ble local name (see below). If you are using another supported BLE board or shield, * follow the instructions for the specific board or shield below. * + * Make sure you have the Intel Curie Boards package v1.0.6 or higher installed via the Arduino + * Boards Manager. + * * Supported boards and shields: * - Arduino 101 (recommended) * - RedBearLab BLE Shield (v2) ** to be verified ** @@ -52,6 +55,9 @@ BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); /* * Arduino 101 * + * Make sure you have the Intel Curie Boards package v1.0.6 or higher installed via the Arduino + * Boards Manager. + * * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 */ #ifdef _VARIANT_ARDUINO_101_X_ From 08436bd4dea85804b945086340f77bc41da0e860 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 18 Jun 2016 20:41:39 -0700 Subject: [PATCH 025/110] move EthernetClientStream.cpp to .h file Avoids linker issues with 3rd party board packages. Removed unnecessary includes. --- utility/EthernetClientStream.cpp | 113 +------------------------ utility/EthernetClientStream.h | 137 +++++++++++++++++++++++++------ 2 files changed, 114 insertions(+), 136 deletions(-) diff --git a/utility/EthernetClientStream.cpp b/utility/EthernetClientStream.cpp index 34078e31..f4f89685 100644 --- a/utility/EthernetClientStream.cpp +++ b/utility/EthernetClientStream.cpp @@ -1,114 +1,3 @@ /* - EthernetClientStream.cpp - An Arduino-Stream that wraps an instance of Client reconnecting to - the remote-ip in a transparent way. A disconnected client may be - recognized by the returnvalues -1 from calls to peek or read and - a 0 from calls to write. - - Copyright (C) 2013 Norbert Truchsess. 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. - - See file LICENSE.txt for further informations on licensing terms. - - formatted using the GNU C formatting and indenting + * Implementation is in EthernetClientStream.h to avoid linker issues. */ - -#include "EthernetClientStream.h" -#include - -//#define SERIAL_DEBUG -#include "firmataDebug.h" - -#define MILLIS_RECONNECT 5000 - -EthernetClientStream::EthernetClientStream(Client &client, IPAddress localip, IPAddress ip, const char* host, uint16_t port) -: client(client), - localip(localip), - ip(ip), - host(host), - port(port), - connected(false) -{ -} - -int -EthernetClientStream::available() -{ - return maintain() ? client.available() : 0; -} - -int -EthernetClientStream::read() -{ - return maintain() ? client.read() : -1; -} - -int -EthernetClientStream::peek() -{ - return maintain() ? client.peek() : -1; -} - -void EthernetClientStream::flush() -{ - if (maintain()) - client.flush(); -} - -size_t -EthernetClientStream::write(uint8_t c) -{ - return maintain() ? client.write(c) : 0; -} - -void -EthernetClientStream::maintain(IPAddress localip) -{ -// temporary hack to Firmata to compile for Intel Galileo -// the issue is documented here: https://github.com/firmata/arduino/issues/218 -#if !defined(ARDUINO_LINUX) - // ensure the local IP is updated in the case that it is changed by the DHCP server - if (this->localip != localip) - { - this->localip = localip; - if (connected) - stop(); - } -#endif -} - -void -EthernetClientStream::stop() -{ - client.stop(); - connected = false; - time_connect = millis(); -} - -bool -EthernetClientStream::maintain() -{ - if (client && client.connected()) - return true; - - if (connected) - { - stop(); - } - // if the client is disconnected, attempt to reconnect every 5 seconds - else if (millis()-time_connect >= MILLIS_RECONNECT) - { - connected = host ? client.connect(host, port) : client.connect(ip, port); - if (!connected) { - time_connect = millis(); - DEBUG_PRINTLN("connection failed. attempting to reconnect..."); - } else { - DEBUG_PRINTLN("connected"); - } - } - return connected; -} diff --git a/utility/EthernetClientStream.h b/utility/EthernetClientStream.h index bae34ce9..6b024983 100644 --- a/utility/EthernetClientStream.h +++ b/utility/EthernetClientStream.h @@ -14,39 +14,128 @@ See file LICENSE.txt for further informations on licensing terms. - formatted using the GNU C formatting and indenting + Last updated June 18th, 2016 */ #ifndef ETHERNETCLIENTSTREAM_H #define ETHERNETCLIENTSTREAM_H #include -#include #include -#include -#include + +//#define SERIAL_DEBUG +#include "firmataDebug.h" + +#define MILLIS_RECONNECT 5000 class EthernetClientStream : public Stream { -public: - EthernetClientStream(Client &client, IPAddress localip, IPAddress ip, const char* host, uint16_t port); - int available(); - int read(); - int peek(); - void flush(); - size_t write(uint8_t); - void maintain(IPAddress localip); - -private: - Client &client; - IPAddress localip; - IPAddress ip; - const char* host; - uint16_t port; - bool connected; - uint32_t time_connect; - bool maintain(); - void stop(); + public: + EthernetClientStream(Client &client, IPAddress localip, IPAddress ip, const char* host, uint16_t port); + int available(); + int read(); + int peek(); + void flush(); + size_t write(uint8_t); + void maintain(IPAddress localip); + + private: + Client &client; + IPAddress localip; + IPAddress ip; + const char* host; + uint16_t port; + bool connected; + uint32_t time_connect; + bool maintain(); + void stop(); }; -#endif + +/* + * EthernetClientStream.cpp + * Copied here as a hack to linker issues with 3rd party board packages that don't properly + * implement the Arduino network APIs. + */ +EthernetClientStream::EthernetClientStream(Client &client, IPAddress localip, IPAddress ip, const char* host, uint16_t port) + : client(client), + localip(localip), + ip(ip), + host(host), + port(port), + connected(false) +{ +} + +int +EthernetClientStream::available() +{ + return maintain() ? client.available() : 0; +} + +int +EthernetClientStream::read() +{ + return maintain() ? client.read() : -1; +} + +int +EthernetClientStream::peek() +{ + return maintain() ? client.peek() : -1; +} + +void EthernetClientStream::flush() +{ + if (maintain()) + client.flush(); +} + +size_t +EthernetClientStream::write(uint8_t c) +{ + return maintain() ? client.write(c) : 0; +} + +void +EthernetClientStream::maintain(IPAddress localip) +{ + // ensure the local IP is updated in the case that it is changed by the DHCP server + if (this->localip != localip) { + this->localip = localip; + if (connected) + stop(); + } +} + +void +EthernetClientStream::stop() +{ + client.stop(); + connected = false; + time_connect = millis(); +} + +bool +EthernetClientStream::maintain() +{ + if (client && client.connected()) + return true; + + if (connected) { + stop(); + } + // if the client is disconnected, attempt to reconnect every 5 seconds + else if (millis() - time_connect >= MILLIS_RECONNECT) { + connected = host ? client.connect(host, port) : client.connect(ip, port); + if (!connected) { + time_connect = millis(); + DEBUG_PRINTLN("connection failed. attempting to reconnect..."); + } else { + DEBUG_PRINTLN("connected"); + } + } + return connected; +} + +#endif /* ETHERNETCLIENTSTREAM_H */ From bcabc473a74e7e46b25dd82bdf1757263a2d0bfe Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 18 Jun 2016 21:39:34 -0700 Subject: [PATCH 026/110] consolidate StandardFirmataEthernet variants removed StandardFirmataEthernetPlus to reduce variants SerialFeature is commented out by default Broke up setup routine into several functions s --- .../StandardFirmataEthernet.ino | 95 +- .../StandardFirmataEthernet/ethernetConfig.h | 21 +- .../StandardFirmataEthernetPlus/LICENSE.txt | 458 --------- .../StandardFirmataEthernetPlus.ino | 909 ------------------ .../ethernetConfig.h | 55 -- 5 files changed, 73 insertions(+), 1465 deletions(-) delete mode 100755 examples/StandardFirmataEthernetPlus/LICENSE.txt delete mode 100644 examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino delete mode 100644 examples/StandardFirmataEthernetPlus/ethernetConfig.h diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 55e60953..f4e129db 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,14 +20,14 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: January 10th, 2016 + Last updated by Jeff Hoefs: June 18th, 2016 */ /* README - StandardFirmataEthernet is a client implementation. You will need a Firmata client library with - a network transport that can act as a server in order to establish a connection between + StandardFirmataEthernet is a TCP client implementation. You will need a Firmata client library + with a network transport that can act as a TCP server in order to establish a connection between StandardFirmataEthernet and the Firmata client application. To use StandardFirmataEthernet you will need to have one of the following @@ -58,9 +58,9 @@ #include /* - * Uncomment the #define SERIAL_DEBUG line below to receive serial output messages relating to your connection - * that may help in the event of connection issues. If defined, some boards may not begin executing this sketch - * until the Serial console is opened. + * Uncomment the #define SERIAL_DEBUG line below to receive serial output messages relating to your + * connection that may help in the event of connection issues. If defined, some boards may not begin + * executing this sketch until the Serial console is opened. */ //#define SERIAL_DEBUG #include "utility/firmataDebug.h" @@ -69,6 +69,17 @@ #include "ethernetConfig.h" #include "utility/EthernetClientStream.h" +/* + * Uncomment the following include to enable interfacing with Serial devices via hardware or + * software serial. + * + * DO NOT uncomment if you are running StandardFirmataEthernet on an Arduino Leonardo, + * Arduino Micro or other ATMega32u4-based board or you will not have enough Flash and RAM + * remaining to reliably run Firmata. Arduino Yun is okay because it doesn't import the Ethernet + * libraries. + */ +//#include "utility/SerialFirmata.h" + #define I2C_WRITE B00000000 #define I2C_READ B00001000 #define I2C_READ_CONTINUOUSLY B00010000 @@ -88,7 +99,6 @@ * GLOBAL VARIABLES *============================================================================*/ -/* network */ #if defined remote_ip && !defined remote_host #ifdef local_ip EthernetClientStream stream(client, local_ip, remote_ip, NULL, remote_port); @@ -304,7 +314,8 @@ void setPinModeCallback(byte pin, int mode) } } if (IS_PIN_ANALOG(pin)) { - reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting + // turn on/off reporting + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); } if (IS_PIN_DIGITAL(pin)) { if (mode == INPUT || mode == PIN_MODE_PULLUP) { @@ -801,10 +812,36 @@ void systemResetCallback() isResetting = false; } -void setup() +/* + * StandardFirmataEthernet communicates with Ethernet shields over SPI. Therefore all + * SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. + * Additional pins may also need to be ignored depending on the particular board or + * shield in use. + */ +void ignorePins() { - DEBUG_BEGIN(9600); +#ifdef IS_IGNORE_PIN + for (byte i = 0; i < TOTAL_PINS; i++) { + if (IS_IGNORE_PIN(i)) { + Firmata.setPinMode(i, PIN_MODE_IGNORE); + } + } +#endif +#ifdef WIZ5100_ETHERNET + // Arduino Ethernet and Arduino EthernetShield have SD SS wired to D4 + pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata + digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA +#endif + +#endif // WIZ5100_ETHERNET +} + +void initTransport() +{ #ifdef YUN_ETHERNET Bridge.begin(); #else @@ -816,9 +853,11 @@ void setup() #endif DEBUG_PRINTLN("connecting..."); +} +void initFirmata() +{ Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); - Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); Firmata.attach(REPORT_ANALOG, reportAnalogCallback); @@ -828,36 +867,22 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); -#ifdef WIZ5100_ETHERNET - // StandardFirmataEthernet communicates with Ethernet shields over SPI. Therefore all - // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. - // add Pin 10 and configure pin 53 as output if using a MEGA with an Ethernet shield. - - for (byte i = 0; i < TOTAL_PINS; i++) { - if (IS_IGNORE_ETHERNET_SHIELD(i) - #if defined(__AVR_ATmega32U4__) - || 24 == i // On Leonardo, pin 24 maps to D4 and pin 28 maps to D10 - || 28 == i - #endif - ) { - Firmata.setPinMode(i, PIN_MODE_IGNORE); - } - } - - // Arduino Ethernet and Arduino EthernetShield have SD SS wired to D4 - pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata - digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; -#endif // WIZ5100_ETHERNET - -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA -#endif + ignorePins(); // start up Network Firmata: Firmata.begin(stream); systemResetCallback(); // reset to default config } +void setup() +{ + DEBUG_BEGIN(9600); + + initTransport(); + + initFirmata(); +} + /*============================================================================== * LOOP() *============================================================================*/ diff --git a/examples/StandardFirmataEthernet/ethernetConfig.h b/examples/StandardFirmataEthernet/ethernetConfig.h index 4cccaa00..345eafc6 100644 --- a/examples/StandardFirmataEthernet/ethernetConfig.h +++ b/examples/StandardFirmataEthernet/ethernetConfig.h @@ -3,8 +3,8 @@ * * You must configure your particular hardware. Follow the steps below. * - * Currently StandardFirmataEthernet is configured as a client. An option to - * configure as a server may be added in the future. + * Currently StandardFirmataEthernet is configured as a TCP client. An + * option to configure as a server may be added in the future. *============================================================================*/ // STEP 1 [REQUIRED] @@ -35,6 +35,8 @@ EthernetClient client; * * On Yun there's no need to configure local_ip and mac address as this is automatically * configured on the linux-side of Yun. + * + * Note that it may take several seconds to establish a connection with the Yun. */ //#define YUN_ETHERNET @@ -44,24 +46,23 @@ EthernetClient client; YunClient client; #endif - -// STEP 2 [REQUIRED for all boards and shields] +// STEP 2[REQUIRED for all boards and shields] // replace with IP of the server you want to connect to, comment out if using 'remote_host' #define remote_ip IPAddress(10, 0, 0, 3) // *** REMOTE HOST IS NOT YET WORKING *** // replace with hostname of server you want to connect to, comment out if using 'remote_ip' // #define remote_host "server.local" -// STEP 3 [REQUIRED unless using Arduin Yun] +// STEP 3 [REQUIRED] // Replace with the port that your server is listening on #define remote_port 3030 -// STEP 4 [REQUIRED unless using Arduino Yun OR if not using DHCP] +// STEP 4 [REQUIRED unless using DHCP] // Replace with your board or ethernet shield's IP address // Comment out if you want to use DHCP #define local_ip IPAddress(10, 0, 0, 15) -// STEP 5 [REQUIRED unless using Arduino Yun] +// STEP 5 [REQUIRED] // replace with ethernet shield mac. Must be unique for your network const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; @@ -81,5 +82,9 @@ const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; * PIN IGNORE MACROS (don't change anything here) *============================================================================*/ +#if defined(WIZ5100_ETHERNET) + // ignore SPI pins, pin 10 (Ethernet SS) and pin 4 (SS for SD-Card on Ethernet shield) -#define IS_IGNORE_ETHERNET_SHIELD(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 10) +#define IS_IGNORE_PIN(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 10) + +#endif diff --git a/examples/StandardFirmataEthernetPlus/LICENSE.txt b/examples/StandardFirmataEthernetPlus/LICENSE.txt deleted file mode 100755 index 77cec6dd..00000000 --- a/examples/StandardFirmataEthernetPlus/LICENSE.txt +++ /dev/null @@ -1,458 +0,0 @@ - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -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 this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -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 -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser 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 Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "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 -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY 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 -LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - diff --git a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino b/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino deleted file mode 100644 index bbba246e..00000000 --- a/examples/StandardFirmataEthernetPlus/StandardFirmataEthernetPlus.ino +++ /dev/null @@ -1,909 +0,0 @@ -/* - Firmata is a generic protocol for communicating with microcontrollers - from software on a host computer. It is intended to work with - any host computer software package. - - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. - - https://github.com/firmata/arduino#firmata-client-libraries - - Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved. - Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. - Copyright (C) 2009-2016 Jeff Hoefs. 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. - - See file LICENSE.txt for further informations on licensing terms. - - Last updated by Jeff Hoefs: January 10th, 2016 -*/ - -/* - README - - StandardFirmataEthernetPlus is a client implementation. You will need a Firmata client library - with a network transport that can act as a server in order to establish a connection between - StandardFirmataEthernetPlus and the Firmata client application. - - StandardFirmataEthernetPlus adds additional features that may exceed the Flash and - RAM sizes of Arduino boards such as ATMega328p (Uno) and ATMega32u4 - (Leonardo, Micro, Yun, etc). It is best to use StandardFirmataPlus with a board that - has > 32k Flash and > 3k RAM such as: Arduino Mega, Arduino Due, Teensy 3.0/3.1/3.2, etc. - - This sketch consumes too much Flash and RAM to run reliably on an - Arduino Leonardo, Yun, ATMega32u4-based board. Use StandardFirmataEthernet.ino instead - for those boards and other boards that do not meet the Flash and RAM requirements. - - To use StandardFirmataEthernet you will need to have one of the following - boards or shields: - - - Arduino Ethernet shield (or clone) - - Arduino Ethernet board (or clone) - - Follow the instructions in the ethernetConfig.h file (ethernetConfig.h tab in Arduino IDE) to - configure your particular hardware. - - NOTE: If you are using an Arduino Ethernet shield you cannot use the following pins on - the following boards. Firmata will ignore any requests to use these pins: - - - Arduino Mega: (D4, D10, D50, D51, D52, D53) - - Arduino Due: (D4, D10) - - Arduino Zero: (D4, D10) - - Arduino Uno or other ATMega328p boards: (D4, D10, D11, D12, D13) - - If you are using an ArduinoEthernet board, the following pins cannot be used (same as Uno): - - D4, D10, D11, D12, D13 -*/ - -#include -#include -#include - -/* - * Uncomment the #define SERIAL_DEBUG line below to receive serial output messages relating to your connection - * that may help in the event of connection issues. If defined, some boards may not begin executing this sketch - * until the Serial console is opened. - */ -//#define SERIAL_DEBUG -#include "utility/firmataDebug.h" - -// follow the instructions in ethernetConfig.h to configure your particular hardware -#include "ethernetConfig.h" -#include "utility/EthernetClientStream.h" - -#include "utility/SerialFirmata.h" - -#define I2C_WRITE B00000000 -#define I2C_READ B00001000 -#define I2C_READ_CONTINUOUSLY B00010000 -#define I2C_STOP_READING B00011000 -#define I2C_READ_WRITE_MODE_MASK B00011000 -#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 -#define I2C_END_TX_MASK B01000000 -#define I2C_STOP_TX 1 -#define I2C_RESTART_TX 0 -#define I2C_MAX_QUERIES 8 -#define I2C_REGISTER_NOT_SPECIFIED -1 - -// the minimum interval for sampling analog input -#define MINIMUM_SAMPLING_INTERVAL 1 - -/*============================================================================== - * GLOBAL VARIABLES - *============================================================================*/ - -#if defined remote_ip && !defined remote_host -#ifdef local_ip -EthernetClientStream stream(client, local_ip, remote_ip, NULL, remote_port); -#else -EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), remote_ip, NULL, remote_port); -#endif -#endif - -#if !defined remote_ip && defined remote_host -#ifdef local_ip -EthernetClientStream stream(client, local_ip, IPAddress(0, 0, 0, 0), remote_host, remote_port); -#else -EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0), remote_host, remote_port); -#endif -#endif - -#ifdef FIRMATA_SERIAL_FEATURE -SerialFirmata serialFeature; -#endif - -/* analog inputs */ -int analogInputsToReport = 0; // bitwise array to store pin reporting - -/* digital input ports */ -byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence -byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent - -/* pins configuration */ -byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else - -/* timer variables */ -unsigned long currentMillis; // store the current value from millis() -unsigned long previousMillis; // for comparison with currentMillis -unsigned int samplingInterval = 19; // how often to sample analog inputs (in ms) - -/* i2c data */ -struct i2c_device_info { - byte addr; - int reg; - byte bytes; - byte stopTX; -}; - -/* for i2c read continuous mode */ -i2c_device_info query[I2C_MAX_QUERIES]; - -byte i2cRxData[64]; -boolean isI2CEnabled = false; -signed char queryIndex = -1; -// default delay time between i2c read request and Wire.requestFrom() -unsigned int i2cReadDelayTime = 0; - -Servo servos[MAX_SERVOS]; -byte servoPinMap[TOTAL_PINS]; -byte detachedServos[MAX_SERVOS]; -byte detachedServoCount = 0; -byte servoCount = 0; - -boolean isResetting = false; - -/* utility functions */ -void wireWrite(byte data) -{ -#if ARDUINO >= 100 - Wire.write((byte)data); -#else - Wire.send(data); -#endif -} - -byte wireRead(void) -{ -#if ARDUINO >= 100 - return Wire.read(); -#else - return Wire.receive(); -#endif -} - -/*============================================================================== - * FUNCTIONS - *============================================================================*/ - -void attachServo(byte pin, int minPulse, int maxPulse) -{ - if (servoCount < MAX_SERVOS) { - // reuse indexes of detached servos until all have been reallocated - if (detachedServoCount > 0) { - servoPinMap[pin] = detachedServos[detachedServoCount - 1]; - if (detachedServoCount > 0) detachedServoCount--; - } else { - servoPinMap[pin] = servoCount; - servoCount++; - } - if (minPulse > 0 && maxPulse > 0) { - servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); - } else { - servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin)); - } - } else { - Firmata.sendString("Max servos attached"); - } -} - -void detachServo(byte pin) -{ - servos[servoPinMap[pin]].detach(); - // if we're detaching the last servo, decrement the count - // otherwise store the index of the detached servo - if (servoPinMap[pin] == servoCount && servoCount > 0) { - servoCount--; - } else if (servoCount > 0) { - // keep track of detached servos because we want to reuse their indexes - // before incrementing the count of attached servos - detachedServoCount++; - detachedServos[detachedServoCount - 1] = servoPinMap[pin]; - } - - servoPinMap[pin] = 255; -} - -void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { - // allow I2C requests that don't require a register read - // for example, some devices using an interrupt pin to signify new data available - // do not always require the register read so upon interrupt you call Wire.requestFrom() - if (theRegister != I2C_REGISTER_NOT_SPECIFIED) { - Wire.beginTransmission(address); - wireWrite((byte)theRegister); - Wire.endTransmission(stopTX); // default = true - // do not set a value of 0 - if (i2cReadDelayTime > 0) { - // delay is necessary for some devices such as WiiNunchuck - delayMicroseconds(i2cReadDelayTime); - } - } else { - theRegister = 0; // fill the register with a dummy value - } - - Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom - - // check to be sure correct number of bytes were returned by slave - if (numBytes < Wire.available()) { - Firmata.sendString("I2C: Too many bytes received"); - } else if (numBytes > Wire.available()) { - Firmata.sendString("I2C: Too few bytes received"); - } - - i2cRxData[0] = address; - i2cRxData[1] = theRegister; - - for (int i = 0; i < numBytes && Wire.available(); i++) { - i2cRxData[2 + i] = wireRead(); - } - - // send slave address, register and received bytes - Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); -} - -void outputPort(byte portNumber, byte portValue, byte forceSend) -{ - // pins not configured as INPUT are cleared to zeros - portValue = portValue & portConfigInputs[portNumber]; - // only send if the value is different than previously sent - if (forceSend || previousPINs[portNumber] != portValue) { - Firmata.sendDigitalPort(portNumber, portValue); - previousPINs[portNumber] = portValue; - } -} - -/* ----------------------------------------------------------------------------- - * check all the active digital inputs for change of state, then add any events - * to the Stream output queue using Stream.write() */ -void checkDigitalInputs(void) -{ - /* Using non-looping code allows constants to be given to readPort(). - * The compiler will apply substantial optimizations if the inputs - * to readPort() are compile-time constants. */ - if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); - if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); - if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); - if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); - if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); - if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); - if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); - if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); - if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); - if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); - if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); - if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); - if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); - if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); - if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); - if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); -} - -// ----------------------------------------------------------------------------- -/* sets the pin mode to the correct state and sets the relevant bits in the - * two bit-arrays that track Digital I/O and PWM status - */ -void setPinModeCallback(byte pin, int mode) -{ - if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE) - return; - - if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) { - // disable i2c so pins can be used for other functions - // the following if statements should reconfigure the pins properly - disableI2CPins(); - } - if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) { - if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { - detachServo(pin); - } - } - if (IS_PIN_ANALOG(pin)) { - reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting - } - if (IS_PIN_DIGITAL(pin)) { - if (mode == INPUT || mode == PIN_MODE_PULLUP) { - portConfigInputs[pin / 8] |= (1 << (pin & 7)); - } else { - portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); - } - } - Firmata.setPinState(pin, 0); - switch (mode) { - case PIN_MODE_ANALOG: - if (IS_PIN_ANALOG(pin)) { - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver -#if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups -#endif - } - Firmata.setPinMode(pin, PIN_MODE_ANALOG); - } - break; - case INPUT: - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver -#if ARDUINO <= 100 - // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6 - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups -#endif - Firmata.setPinMode(pin, INPUT); - } - break; - case PIN_MODE_PULLUP: - if (IS_PIN_DIGITAL(pin)) { - pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP); - Firmata.setPinMode(pin, PIN_MODE_PULLUP); - Firmata.setPinState(pin, 1); - } - break; - case OUTPUT: - if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM - pinMode(PIN_TO_DIGITAL(pin), OUTPUT); - Firmata.setPinMode(pin, OUTPUT); - } - break; - case PIN_MODE_PWM: - if (IS_PIN_PWM(pin)) { - pinMode(PIN_TO_PWM(pin), OUTPUT); - analogWrite(PIN_TO_PWM(pin), 0); - Firmata.setPinMode(pin, PIN_MODE_PWM); - } - break; - case PIN_MODE_SERVO: - if (IS_PIN_DIGITAL(pin)) { - Firmata.setPinMode(pin, PIN_MODE_SERVO); - if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) { - // pass -1 for min and max pulse values to use default values set - // by Servo library - attachServo(pin, -1, -1); - } - } - break; - case PIN_MODE_I2C: - if (IS_PIN_I2C(pin)) { - // mark the pin as i2c - // the user must call I2C_CONFIG to enable I2C for a device - Firmata.setPinMode(pin, PIN_MODE_I2C); - } - break; - case PIN_MODE_SERIAL: -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.handlePinMode(pin, PIN_MODE_SERIAL); -#endif - break; - default: - Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM - } - // TODO: save status to EEPROM here, if changed -} - -/* - * Sets the value of an individual pin. Useful if you want to set a pin value but - * are not tracking the digital port state. - * Can only be used on pins configured as OUTPUT. - * Cannot be used to enable pull-ups on Digital INPUT pins. - */ -void setPinValueCallback(byte pin, int value) -{ - if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) { - if (Firmata.getPinMode(pin) == OUTPUT) { - Firmata.setPinState(pin, value); - digitalWrite(PIN_TO_DIGITAL(pin), value); - } - } -} - -void analogWriteCallback(byte pin, int value) -{ - if (pin < TOTAL_PINS) { - switch (Firmata.getPinMode(pin)) { - case PIN_MODE_SERVO: - if (IS_PIN_DIGITAL(pin)) - servos[servoPinMap[pin]].write(value); - Firmata.setPinState(pin, value); - break; - case PIN_MODE_PWM: - if (IS_PIN_PWM(pin)) - analogWrite(PIN_TO_PWM(pin), value); - Firmata.setPinState(pin, value); - break; - } - } -} - -void digitalWriteCallback(byte port, int value) -{ - byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0; - - if (port < TOTAL_PORTS) { - // create a mask of the pins on this port that are writable. - lastPin = port * 8 + 8; - if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; - for (pin = port * 8; pin < lastPin; pin++) { - // do not disturb non-digital pins (eg, Rx & Tx) - if (IS_PIN_DIGITAL(pin)) { - // do not touch pins in PWM, ANALOG, SERVO or other modes - if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) { - pinValue = ((byte)value & mask) ? 1 : 0; - if (Firmata.getPinMode(pin) == OUTPUT) { - pinWriteMask |= mask; - } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) { - // only handle INPUT here for backwards compatibility -#if ARDUINO > 100 - pinMode(pin, INPUT_PULLUP); -#else - // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier - pinWriteMask |= mask; -#endif - } - Firmata.setPinState(pin, pinValue); - } - } - mask = mask << 1; - } - writePort(port, (byte)value, pinWriteMask); - } -} - - -// ----------------------------------------------------------------------------- -/* sets bits in a bit array (int) to toggle the reporting of the analogIns - */ -//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { -//} -void reportAnalogCallback(byte analogPin, int value) -{ - if (analogPin < TOTAL_ANALOG_PINS) { - if (value == 0) { - analogInputsToReport = analogInputsToReport & ~ (1 << analogPin); - } else { - analogInputsToReport = analogInputsToReport | (1 << analogPin); - // prevent during system reset or all analog pin values will be reported - // which may report noise for unconnected analog pins - if (!isResetting) { - // Send pin value immediately. This is helpful when connected via - // ethernet, wi-fi or bluetooth so pin states can be known upon - // reconnecting. - Firmata.sendAnalog(analogPin, analogRead(analogPin)); - } - } - } - // TODO: save status to EEPROM here, if changed -} - -void reportDigitalCallback(byte port, int value) -{ - if (port < TOTAL_PORTS) { - reportPINs[port] = (byte)value; - // Send port value immediately. This is helpful when connected via - // ethernet, wi-fi or bluetooth so pin states can be known upon - // reconnecting. - if (value) outputPort(port, readPort(port, portConfigInputs[port]), true); - } - // do not disable analog reporting on these 8 pins, to allow some - // pins used for digital, others analog. Instead, allow both types - // of reporting to be enabled, but check if the pin is configured - // as analog when sampling the analog inputs. Likewise, while - // scanning digital pins, portConfigInputs will mask off values from any - // pins configured as analog -} - -/*============================================================================== - * SYSEX-BASED commands - *============================================================================*/ - -void sysexCallback(byte command, byte argc, byte *argv) -{ - byte mode; - byte stopTX; - byte slaveAddress; - byte data; - int slaveRegister; - unsigned int delayTime; - - switch (command) { - case I2C_REQUEST: - mode = argv[1] & I2C_READ_WRITE_MODE_MASK; - if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { - Firmata.sendString("10-bit addressing not supported"); - return; - } - else { - slaveAddress = argv[0]; - } - - // need to invert the logic here since 0 will be default for client - // libraries that have not updated to add support for restart tx - if (argv[1] & I2C_END_TX_MASK) { - stopTX = I2C_RESTART_TX; - } - else { - stopTX = I2C_STOP_TX; // default - } - - switch (mode) { - case I2C_WRITE: - Wire.beginTransmission(slaveAddress); - for (byte i = 2; i < argc; i += 2) { - data = argv[i] + (argv[i + 1] << 7); - wireWrite(data); - } - Wire.endTransmission(); - delayMicroseconds(70); - break; - case I2C_READ: - if (argc == 6) { - // a slave register is specified - slaveRegister = argv[2] + (argv[3] << 7); - data = argv[4] + (argv[5] << 7); // bytes to read - } - else { - // a slave register is NOT specified - slaveRegister = I2C_REGISTER_NOT_SPECIFIED; - data = argv[2] + (argv[3] << 7); // bytes to read - } - readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX); - break; - case I2C_READ_CONTINUOUSLY: - if ((queryIndex + 1) >= I2C_MAX_QUERIES) { - // too many queries, just ignore - Firmata.sendString("too many queries"); - break; - } - if (argc == 6) { - // a slave register is specified - slaveRegister = argv[2] + (argv[3] << 7); - data = argv[4] + (argv[5] << 7); // bytes to read - } - else { - // a slave register is NOT specified - slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED; - data = argv[2] + (argv[3] << 7); // bytes to read - } - queryIndex++; - query[queryIndex].addr = slaveAddress; - query[queryIndex].reg = slaveRegister; - query[queryIndex].bytes = data; - query[queryIndex].stopTX = stopTX; - break; - case I2C_STOP_READING: - byte queryIndexToSkip; - // if read continuous mode is enabled for only 1 i2c device, disable - // read continuous reporting for that device - if (queryIndex <= 0) { - queryIndex = -1; - } else { - queryIndexToSkip = 0; - // if read continuous mode is enabled for multiple devices, - // determine which device to stop reading and remove it's data from - // the array, shifiting other array data to fill the space - for (byte i = 0; i < queryIndex + 1; i++) { - if (query[i].addr == slaveAddress) { - queryIndexToSkip = i; - break; - } - } - - for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { - if (i < I2C_MAX_QUERIES) { - query[i].addr = query[i + 1].addr; - query[i].reg = query[i + 1].reg; - query[i].bytes = query[i + 1].bytes; - query[i].stopTX = query[i + 1].stopTX; - } - } - queryIndex--; - } - break; - default: - break; - } - break; - case I2C_CONFIG: - delayTime = (argv[0] + (argv[1] << 7)); - - if (delayTime > 0) { - i2cReadDelayTime = delayTime; - } - - if (!isI2CEnabled) { - enableI2CPins(); - } - - break; - case SERVO_CONFIG: - if (argc > 4) { - // these vars are here for clarity, they'll optimized away by the compiler - byte pin = argv[0]; - int minPulse = argv[1] + (argv[2] << 7); - int maxPulse = argv[3] + (argv[4] << 7); - - if (IS_PIN_DIGITAL(pin)) { - if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) { - detachServo(pin); - } - attachServo(pin, minPulse, maxPulse); - setPinModeCallback(pin, PIN_MODE_SERVO); - } - } - break; - case SAMPLING_INTERVAL: - if (argc > 1) { - samplingInterval = argv[0] + (argv[1] << 7); - if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { - samplingInterval = MINIMUM_SAMPLING_INTERVAL; - } - } else { - //Firmata.sendString("Not enough data"); - } - break; - case EXTENDED_ANALOG: - if (argc > 1) { - int val = argv[1]; - if (argc > 2) val |= (argv[2] << 7); - if (argc > 3) val |= (argv[3] << 14); - analogWriteCallback(argv[0], val); - } - break; - case CAPABILITY_QUERY: - Firmata.write(START_SYSEX); - Firmata.write(CAPABILITY_RESPONSE); - for (byte pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_DIGITAL(pin)) { - Firmata.write((byte)INPUT); - Firmata.write(1); - Firmata.write((byte)PIN_MODE_PULLUP); - Firmata.write(1); - Firmata.write((byte)OUTPUT); - Firmata.write(1); - } - if (IS_PIN_ANALOG(pin)) { - Firmata.write(PIN_MODE_ANALOG); - Firmata.write(10); // 10 = 10-bit resolution - } - if (IS_PIN_PWM(pin)) { - Firmata.write(PIN_MODE_PWM); - Firmata.write(DEFAULT_PWM_RESOLUTION); - } - if (IS_PIN_DIGITAL(pin)) { - Firmata.write(PIN_MODE_SERVO); - Firmata.write(14); - } - if (IS_PIN_I2C(pin)) { - Firmata.write(PIN_MODE_I2C); - Firmata.write(1); // TODO: could assign a number to map to SCL or SDA - } -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.handleCapability(pin); -#endif - Firmata.write(127); - } - Firmata.write(END_SYSEX); - break; - case PIN_STATE_QUERY: - if (argc > 0) { - byte pin = argv[0]; - Firmata.write(START_SYSEX); - Firmata.write(PIN_STATE_RESPONSE); - Firmata.write(pin); - if (pin < TOTAL_PINS) { - Firmata.write(Firmata.getPinMode(pin)); - Firmata.write((byte)Firmata.getPinState(pin) & 0x7F); - if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F); - if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F); - } - Firmata.write(END_SYSEX); - } - break; - case ANALOG_MAPPING_QUERY: - Firmata.write(START_SYSEX); - Firmata.write(ANALOG_MAPPING_RESPONSE); - for (byte pin = 0; pin < TOTAL_PINS; pin++) { - Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); - } - Firmata.write(END_SYSEX); - break; - - case SERIAL_MESSAGE: -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.handleSysex(command, argc, argv); -#endif - break; - } -} - -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - -/*============================================================================== - * SETUP() - *============================================================================*/ - -void systemResetCallback() -{ - isResetting = true; - - // initialize a defalt state - // TODO: option to load config from EEPROM instead of default - -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.reset(); -#endif - - if (isI2CEnabled) { - disableI2CPins(); - } - - for (byte i = 0; i < TOTAL_PORTS; i++) { - reportPINs[i] = false; // by default, reporting off - portConfigInputs[i] = 0; // until activated - previousPINs[i] = 0; - } - - for (byte i = 0; i < TOTAL_PINS; i++) { - // pins with analog capability default to analog input - // otherwise, pins default to digital output - if (IS_PIN_ANALOG(i)) { - // turns off pullup, configures everything - setPinModeCallback(i, PIN_MODE_ANALOG); - } else if (IS_PIN_DIGITAL(i)) { - // sets the output to 0, configures portConfigInputs - setPinModeCallback(i, OUTPUT); - } - - servoPinMap[i] = 255; - } - // by default, do not report any analog inputs - analogInputsToReport = 0; - - detachedServoCount = 0; - servoCount = 0; - - /* send digital inputs to set the initial state on the host computer, - * since once in the loop(), this firmware will only send on change */ - /* - TODO: this can never execute, since no pins default to digital input - but it will be needed when/if we support EEPROM stored config - for (byte i=0; i < TOTAL_PORTS; i++) { - outputPort(i, readPort(i, portConfigInputs[i]), true); - } - */ - isResetting = false; -} - -void setup() -{ - DEBUG_BEGIN(9600); - -#ifdef local_ip - Ethernet.begin((uint8_t *)mac, local_ip); //start ethernet -#else - Ethernet.begin((uint8_t *)mac); //start ethernet using dhcp -#endif - - DEBUG_PRINTLN("connecting..."); - - Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION); - - Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); - Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); - Firmata.attach(REPORT_ANALOG, reportAnalogCallback); - Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); - Firmata.attach(SET_PIN_MODE, setPinModeCallback); - Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback); - Firmata.attach(START_SYSEX, sysexCallback); - Firmata.attach(SYSTEM_RESET, systemResetCallback); - -#ifdef WIZ5100_ETHERNET - // StandardFirmataEthernetPlus communicates with Ethernet shields over SPI. Therefore all - // SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. - // add Pin 10 and configure pin 53 as output if using a MEGA with an Ethernet shield. - - for (byte i = 0; i < TOTAL_PINS; i++) { - if (IS_IGNORE_ETHERNET_SHIELD(i)) { - Firmata.setPinMode(i, PIN_MODE_IGNORE); - } - } - - // Arduino Ethernet and Arduino EthernetShield have SD SS wired to D4 - pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD card bypassing Firmata - digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low; -#endif // WIZ5100_ETHERNET - -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - pinMode(PIN_TO_DIGITAL(53), OUTPUT); // configure hardware SS as output on MEGA -#endif - - // start up Network Firmata: - Firmata.begin(stream); - systemResetCallback(); // reset to default config -} - -/*============================================================================== - * LOOP() - *============================================================================*/ -void loop() -{ - byte pin, analogPin; - - /* DIGITALREAD - as fast as possible, check for changes and output them to the - * Stream buffer using Stream.write() */ - checkDigitalInputs(); - - /* STREAMREAD - processing incoming messagse as soon as possible, while still - * checking digital inputs. */ - while (Firmata.available()) - Firmata.processInput(); - - // TODO - ensure that Stream buffer doesn't go over 60 bytes - - currentMillis = millis(); - if (currentMillis - previousMillis > samplingInterval) { - previousMillis += samplingInterval; - /* ANALOGREAD - do all analogReads() at the configured sampling interval */ - for (pin = 0; pin < TOTAL_PINS; pin++) { - if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) { - analogPin = PIN_TO_ANALOG(pin); - if (analogInputsToReport & (1 << analogPin)) { - Firmata.sendAnalog(analogPin, analogRead(analogPin)); - } - } - } - // report i2c data for all device with read continuous mode enabled - if (queryIndex > -1) { - for (byte i = 0; i < queryIndex + 1; i++) { - readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX); - } - } - } - -#ifdef FIRMATA_SERIAL_FEATURE - serialFeature.update(); -#endif - -#if !defined local_ip - // only necessary when using DHCP, ensures local IP is updated appropriately if it changes - if (Ethernet.maintain()) { - stream.maintain(Ethernet.localIP()); - } -#endif - -} diff --git a/examples/StandardFirmataEthernetPlus/ethernetConfig.h b/examples/StandardFirmataEthernetPlus/ethernetConfig.h deleted file mode 100644 index 105a8792..00000000 --- a/examples/StandardFirmataEthernetPlus/ethernetConfig.h +++ /dev/null @@ -1,55 +0,0 @@ -/*============================================================================== - * NETWORK CONFIGURATION - * - * You must configure your particular hardware. Follow the steps below. - * - * Currently StandardFirmataEthernetPlus is configured as a client. An option to - * configure as a server may be added in the future. - *============================================================================*/ - -/* - * Only WIZ5100-based shields and boards are currently supported for - * StandardFirmataEthernetPlus. - */ -#define WIZ5100_ETHERNET - -#ifdef WIZ5100_ETHERNET -#include -#include -EthernetClient client; -#endif - -// STEP 1 [REQUIRED for all boards and shields] -// replace with IP of the server you want to connect to, comment out if using 'remote_host' -#define remote_ip IPAddress(10, 0, 0, 3) -// *** REMOTE HOST IS NOT YET WORKING *** -// replace with hostname of server you want to connect to, comment out if using 'remote_ip' -// #define remote_host "server.local" - -// STEP 2 [REQUIRED] -// Replace with the port that your server is listening on -#define remote_port 3030 - -// STEP 3 [REQUIRED unless using DHCP] -// Replace with your board or ethernet shield's IP address -// Comment out if you want to use DHCP -#define local_ip IPAddress(10, 0, 0, 15) - -// STEP 4 [REQUIRED] -// replace with ethernet shield mac. Must be unique for your network -const byte mac[] = {0x90, 0xA2, 0xDA, 0x00, 0x53, 0xE5}; - -/*============================================================================== - * CONFIGURATION ERROR CHECK (don't change anything here) - *============================================================================*/ - -#if defined remote_ip && defined remote_host -#error "cannot define both remote_ip and remote_host at the same time in ethernetConfig.h" -#endif - -/*============================================================================== - * PIN IGNORE MACROS (don't change anything here) - *============================================================================*/ - -// ignore SPI pins, pin 10 (Ethernet SS) and pin 4 (SS for SD-Card on Ethernet shield) -#define IS_IGNORE_ETHERNET_SHIELD(p) ((IS_PIN_SPI(p) || (p) == 4) || (p) == 10) From 8cdf1b10ee582dd6df3cf2f663e7d4c703254194 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 18 Jun 2016 22:01:20 -0700 Subject: [PATCH 027/110] cleanup whitespace --- utility/WiFiStream.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utility/WiFiStream.h b/utility/WiFiStream.h index 4d83fe8d..1ad44bbb 100644 --- a/utility/WiFiStream.h +++ b/utility/WiFiStream.h @@ -114,7 +114,7 @@ class WiFiStream : public Stream * @return true if WiFi and TCP connection are established */ virtual bool maintain() = 0; - + #ifdef ESP8266 /** * get status of TCP connection @@ -131,7 +131,7 @@ class WiFiStream : public Stream * LAST_ACK = 9 * TIME_WAIT = 10 */ - inline uint8_t status() + inline uint8_t status() { return _client.status(); } From aac822a04931b8316a95a4236d3d8160c26783b2 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 18 Jun 2016 22:27:59 -0700 Subject: [PATCH 028/110] bump version to 2.5.3 --- Boards.h | 6 +++--- Firmata.cpp | 2 +- Firmata.h | 4 ++-- extras/revisions.txt | 18 ++++++++++++++++++ library.properties | 4 ++-- readme.md | 8 ++++---- release.sh | 4 ++-- utility/BLEStream.h | 2 +- 8 files changed, 33 insertions(+), 15 deletions(-) diff --git a/Boards.h b/Boards.h index f46c4eb0..553c6a43 100644 --- a/Boards.h +++ b/Boards.h @@ -1,7 +1,7 @@ /* Boards.h - Hardware Abstraction Layer for Firmata library Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2009-2015 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2016 Jeff Hoefs. 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 @@ -10,7 +10,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated December 19th, 2015 + Last updated April 10th, 2016 */ #ifndef Firmata_Boards_h @@ -702,7 +702,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) #define DEFAULT_PWM_RESOLUTION 10 - + // anything else #else #error "Please edit Boards.h with a hardware abstraction for this board" diff --git a/Firmata.cpp b/Firmata.cpp index 1047a6ce..1b3a4f9d 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.2 - 2016-2-15 + Firmata.cpp - Firmata library v2.5.3 - 2016-06-18 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/Firmata.h b/Firmata.h index 569bdf7e..9396f2c0 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.2 - 2016-2-15 + Firmata.h - Firmata library v2.5.3 - 2016-06-18 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2015 Jeff Hoefs. All rights reserved. @@ -30,7 +30,7 @@ */ #define FIRMATA_FIRMWARE_MAJOR_VERSION 2 #define FIRMATA_FIRMWARE_MINOR_VERSION 5 -#define FIRMATA_FIRMWARE_BUGFIX_VERSION 2 +#define FIRMATA_FIRMWARE_BUGFIX_VERSION 3 /* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for * the protocol version and the firmware version. diff --git a/extras/revisions.txt b/extras/revisions.txt index 3bb37dd7..a4f4e22c 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,21 @@ +FIRMATA 2.5.3 - Jun 18, 2016 + +[core library] +* Added ESP8266 support (Jens B. & Jacob Rosenthal) +* Added host connection callback (Jens B.) +* Added Wi-Fi TCP client (Jens B.) +* Added BLE transport (BLEStream based on BLESerial by Volta Molda) +* Fixed Arduino Galileo and Edison compile issues + +[StandardFirmata & variants] +* Added StandardFirmataBLE (for use with Arduino 101) +* Added ability to choose between Wi-Fi TCP client or server (Jens B.) +* Various updates to StandardFirmataWiFi (Jens B.) +* Increased I2C RX data buffer from 32 to 64 bytes (Rick Waldron) +* Removed StandardFirmataEthernetPlus +* Made StandardFirmataEtherent configurable (to optionally add Plus functionality) +* Improved configuration instructions for StandardFirmataEthernet and StandardFirmataWiFi + FIRMATA 2.5.2 - Feb 15, 2016 [core library] diff --git a/library.properties b/library.properties index 53f26f18..22d91aad 100644 --- a/library.properties +++ b/library.properties @@ -1,8 +1,8 @@ name=Firmata -version=2.5.2 +version=2.5.3 author=Firmata Developers maintainer=https://github.com/firmata/arduino -sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino boards. +sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino/Genuino boards. paragraph=The Firmata library implements the Firmata protocol for communicating with software on the host computer. This allows you to write custom firmware without having to create your own protocol and objects for the programming environment that you are using. category=Device Control url=https://github.com/firmata/arduino diff --git a/readme.md b/readme.md index b1ecaf18..1adffcc2 100644 --- a/readme.md +++ b/readme.md @@ -88,7 +88,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ##Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.2) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.3) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -99,7 +99,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.2) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.3) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -109,7 +109,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.2) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.3) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -118,7 +118,7 @@ for Arduino 1.0.x vs 1.6.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.2) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.3) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index 9c3f3299..8052714f 100644 --- a/release.sh +++ b/release.sh @@ -16,7 +16,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.2.zip +mv ./temp/Firmata.zip Firmata-2.5.3.zip #package for Arduino 1.6.x cp library.properties temp/Firmata @@ -31,5 +31,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.2.zip +mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.3.zip rm -r ./temp diff --git a/utility/BLEStream.h b/utility/BLEStream.h index bcf3b93d..731a4318 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -4,7 +4,7 @@ Based on BLESerial.cpp by Voita Molda https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h - Last updated April 04th, 2016 + Last updated April 4th, 2016 */ #ifndef _BLE_STREAM_H_ From 4759f26e83bd907cc7e1fa3a8f827459dea4c64c Mon Sep 17 00:00:00 2001 From: Shantanu Rahman Date: Sat, 30 Jul 2016 18:35:23 +0600 Subject: [PATCH 029/110] Removed some spelling mistakes in the comments In line 6 the `clink` should be click and in line 7 there should be a `in` before default browser --- examples/StandardFirmata/StandardFirmata.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 0539e6eb..7477e58a 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -3,8 +3,8 @@ from software on a host computer. It is intended to work with any host computer software package. - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. + To download a host software package, please click on the following link + to open the list of Firmata client libraries in your default browser. https://github.com/firmata/arduino#firmata-client-libraries From 048bc8f6be75588f4bce156f5e20a4f51b93974f Mon Sep 17 00:00:00 2001 From: Shantanu Rahman Date: Sat, 30 Jul 2016 23:26:22 +0600 Subject: [PATCH 030/110] More spelling corrections Actually did not realize on the first place that it was in all the files --- examples/AllInputsFirmata/AllInputsFirmata.ino | 2 +- examples/AnalogFirmata/AnalogFirmata.ino | 2 +- examples/EchoString/EchoString.ino | 2 +- examples/OldStandardFirmata/OldStandardFirmata.ino | 2 +- examples/ServoFirmata/ServoFirmata.ino | 2 +- examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino | 2 +- examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino | 2 +- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 4 ++-- examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 4 ++-- examples/StandardFirmataEthernet/StandardFirmataEthernet.ino | 4 ++-- examples/StandardFirmataPlus/StandardFirmataPlus.ino | 4 ++-- examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 4 ++-- 12 files changed, 17 insertions(+), 17 deletions(-) diff --git a/examples/AllInputsFirmata/AllInputsFirmata.ino b/examples/AllInputsFirmata/AllInputsFirmata.ino index 7cfcd60c..9a1439aa 100644 --- a/examples/AllInputsFirmata/AllInputsFirmata.ino +++ b/examples/AllInputsFirmata/AllInputsFirmata.ino @@ -3,7 +3,7 @@ * from software on a host computer. It is intended to work with * any host computer software package. * - * To download a host software package, please clink on the following link + * To download a host software package, please click on the following link * to open the download page in your default browser. * * http://firmata.org/wiki/Download diff --git a/examples/AnalogFirmata/AnalogFirmata.ino b/examples/AnalogFirmata/AnalogFirmata.ino index 8373f88d..7890bcfa 100644 --- a/examples/AnalogFirmata/AnalogFirmata.ino +++ b/examples/AnalogFirmata/AnalogFirmata.ino @@ -3,7 +3,7 @@ * from software on a host computer. It is intended to work with * any host computer software package. * - * To download a host software package, please clink on the following link + * To download a host software package, please click on the following link * to open the download page in your default browser. * * http://firmata.org/wiki/Download diff --git a/examples/EchoString/EchoString.ino b/examples/EchoString/EchoString.ino index 9849806a..3e794b3d 100644 --- a/examples/EchoString/EchoString.ino +++ b/examples/EchoString/EchoString.ino @@ -3,7 +3,7 @@ * from software on a host computer. It is intended to work with * any host computer software package. * - * To download a host software package, please clink on the following link + * To download a host software package, please click on the following link * to open the download page in your default browser. * * http://firmata.org/wiki/Download diff --git a/examples/OldStandardFirmata/OldStandardFirmata.ino b/examples/OldStandardFirmata/OldStandardFirmata.ino index 62dd54ea..2c63c2ab 100644 --- a/examples/OldStandardFirmata/OldStandardFirmata.ino +++ b/examples/OldStandardFirmata/OldStandardFirmata.ino @@ -3,7 +3,7 @@ * from software on a host computer. It is intended to work with * any host computer software package. * - * To download a host software package, please clink on the following link + * To download a host software package, please click on the following link * to open the download page in your default browser. * * http://firmata.org/wiki/Download diff --git a/examples/ServoFirmata/ServoFirmata.ino b/examples/ServoFirmata/ServoFirmata.ino index 1ccc411d..a2f92e31 100644 --- a/examples/ServoFirmata/ServoFirmata.ino +++ b/examples/ServoFirmata/ServoFirmata.ino @@ -3,7 +3,7 @@ * from software on a host computer. It is intended to work with * any host computer software package. * - * To download a host software package, please clink on the following link + * To download a host software package, please click on the following link * to open the download page in your default browser. * * http://firmata.org/wiki/Download diff --git a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino index f4a3eaab..d7f3a8bd 100644 --- a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino +++ b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino @@ -3,7 +3,7 @@ * from software on a host computer. It is intended to work with * any host computer software package. * - * To download a host software package, please clink on the following link + * To download a host software package, please click on the following link * to open the download page in your default browser. * * http://firmata.org/wiki/Download diff --git a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino index 56d388e9..d935be1b 100644 --- a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino +++ b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino @@ -3,7 +3,7 @@ * from software on a host computer. It is intended to work with * any host computer software package. * - * To download a host software package, please clink on the following link + * To download a host software package, please click on the following link * to open the download page in your default browser. * * http://firmata.org/wiki/Download diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index c7be9897..d6194749 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -3,8 +3,8 @@ from software on a host computer. It is intended to work with any host computer software package. - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. + To download a host software package, please click on the following link + to open the list of Firmata client libraries in your default browser. https://github.com/firmata/arduino#firmata-client-libraries diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 7f5baaae..b1fa79bf 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -3,8 +3,8 @@ from software on a host computer. It is intended to work with any host computer software package. - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. + To download a host software package, please click on the following link + to open the list of Firmata client libraries in your default browser. https://github.com/firmata/arduino#firmata-client-libraries diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index f4e129db..27e12bfe 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -3,8 +3,8 @@ from software on a host computer. It is intended to work with any host computer software package. - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. + To download a host software package, please click on the following link + to open the list of Firmata client libraries in your default browser. https://github.com/firmata/arduino#firmata-client-libraries diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index d9b78296..b94b06ad 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -3,8 +3,8 @@ from software on a host computer. It is intended to work with any host computer software package. - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. + To download a host software package, please click on the following link + to open the list of Firmata client libraries in your default browser. https://github.com/firmata/arduino#firmata-client-libraries diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 448ccd4a..5941d99a 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -3,8 +3,8 @@ from software on a host computer. It is intended to work with any host computer software package. - To download a host software package, please clink on the following link - to open the list of Firmata client libraries your default browser. + To download a host software package, please click on the following link + to open the list of Firmata client libraries in your default browser. https://github.com/firmata/arduino#firmata-client-libraries From 982056bb23dca1a2844ea9277b312d926d25505e Mon Sep 17 00:00:00 2001 From: Illia Grybkov Date: Thu, 1 Sep 2016 22:17:14 +0300 Subject: [PATCH 031/110] Update url of ThomasWeinert/carica-firmata --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 1adffcc2..1f6c1a3b 100644 --- a/readme.md +++ b/readme.md @@ -47,7 +47,7 @@ Most of the time you will be interacting with Arduino with a client library on t * [http://funnel.cc] * [http://code.google.com/p/as3glue/] * PHP - * [https://bitbucket.org/ThomasWeinert/carica-firmata] + * [https://github.com/ThomasWeinert/carica-firmata] * [https://github.com/oasynnoum/phpmake_firmata] * Haskell * [http://hackage.haskell.org/package/hArduino] From af6ad68b3e04a49da3ba89ccf811c64e00bfe062 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 5 Sep 2016 10:27:50 -0700 Subject: [PATCH 032/110] add links to vvvv and openFrameworks client libraries --- readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.md b/readme.md index 1f6c1a3b..a12af1ca 100644 --- a/readme.md +++ b/readme.md @@ -63,6 +63,10 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://www.wolfram.com/system-modeler/libraries/model-plug/] * golang * [https://github.com/kraman/go-firmata] +* vvvv + * [https://vvvv.org/blog/arduino-second-service] +* openFrameworks + * [http://openframeworks.cc/documentation/communication/ofArduino/] Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details. From 492faaec0fea5d431944d4fc0f92080c6a9ddf2b Mon Sep 17 00:00:00 2001 From: Kel Cecil Date: Wed, 12 Oct 2016 21:47:30 -0400 Subject: [PATCH 033/110] Add Rust firmata client library --- readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index a12af1ca..3214b1e0 100644 --- a/readme.md +++ b/readme.md @@ -61,12 +61,14 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/kfatehi/firmata] * Modelica * [https://www.wolfram.com/system-modeler/libraries/model-plug/] -* golang +* Go * [https://github.com/kraman/go-firmata] * vvvv * [https://vvvv.org/blog/arduino-second-service] * openFrameworks * [http://openframeworks.cc/documentation/communication/ofArduino/] +* Rust + * [https://github.com/zankich/rust-firmata] Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details. From 6ac21c62d5a5b1b800a80fafa974e4e04276effd Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 16 Oct 2016 13:13:01 -0700 Subject: [PATCH 034/110] fix compiler error for Arduino 1.0.6 and older --- Firmata.cpp | 1 + Firmata.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 1b3a4f9d..e647b41a 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -65,6 +65,7 @@ FirmataClass::FirmataClass() { firmwareVersionCount = 0; firmwareVersionVector = 0; + blinkVersionDisabled = false; systemReset(); } diff --git a/Firmata.h b/Firmata.h index 9396f2c0..f54051fb 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,7 +1,7 @@ /* Firmata.h - Firmata library v2.5.3 - 2016-06-18 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2009-2015 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2016 Jeff Hoefs. 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 @@ -201,7 +201,7 @@ class FirmataClass stringCallbackFunction currentStringCallback; sysexCallbackFunction currentSysexCallback; - boolean blinkVersionDisabled = false; + boolean blinkVersionDisabled; /* private methods ------------------------------ */ void processSysexMessage(void); From b75fff7c0d428e0fa34660a71dfe745368f105fd Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 16 Oct 2016 13:27:52 -0700 Subject: [PATCH 035/110] Fix compiler issues due to SofwareSerial When SerialFirmata was extracted from StandardFirmataPlus to a separate class it broke the ability to compile Firmata with versions of the Arduino IDE older than 1.6.6. This is because prior to 1.6.6 Arduino did not allow libraries to include other libraries unless the other library was included in the sketch. In this particular case that was not possible because SerialFirmata is compiled before the sketch is compiled. There were a couple of potential work arounds: 1. Only include SoftwareSerial when compiling in Arduino 1.6.6 or higher. 2. Split SerialFirmata into SoftwareSerialFirmata and HardwareSerialFirmata and then include SoftwareSerial in the sketch if SoftwareSerialFirmata is included. However this requires the user to modify the sketch. I opted for option 1. If users really need to use software serial with SerialFirmata in Arduino 1.6.5 or older, I can reconsider option 2 at a later time. --- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 2 ++ .../StandardFirmataEthernet.ino | 2 ++ examples/StandardFirmataPlus/StandardFirmataPlus.ino | 7 ++++++- examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 2 ++ utility/SerialFirmata.cpp | 4 +++- utility/SerialFirmata.h | 12 +++++++----- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index d6194749..7dfed667 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -34,6 +34,8 @@ * Uncomment the following include to enable interfacing * with Serial devices via hardware or software serial. */ +// In order to use software serial, you will need to compile this sketch with +// Arduino IDE v1.6.6 or higher. Hardware serial should work back to Arduino 1.0. //#include "utility/SerialFirmata.h" // follow the instructions in bleConfig.h to configure your BLE hardware diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 27e12bfe..7226984a 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -78,6 +78,8 @@ * remaining to reliably run Firmata. Arduino Yun is okay because it doesn't import the Ethernet * libraries. */ +// In order to use software serial, you will need to compile this sketch with +// Arduino IDE v1.6.6 or higher. Hardware serial should work back to Arduino 1.0. //#include "utility/SerialFirmata.h" #define I2C_WRITE B00000000 diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index b94b06ad..c83ab4a2 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: January 10th, 2016 + Last updated October 16th, 2016 */ /* @@ -36,6 +36,9 @@ - Ability to interface with serial devices using UART, USART, or SoftwareSerial depending on the capatilities of the board. + NOTE: In order to use SoftwareSerial with the Firmata Serial feature, + StandardFirmataPlus must be compiled with Arduino v1.6.6 or newer. + At the time of this writing, StandardFirmataPlus will still compile and run on ATMega328p and ATMega32u4-based boards, but future versions of this sketch may not as new features are added. @@ -45,6 +48,8 @@ #include #include +// In order to use software serial, you will need to compile this sketch with +// Arduino IDE v1.6.6 or higher. Hardware serial should work back to Arduino 1.0. #include "utility/SerialFirmata.h" #define I2C_WRITE B00000000 diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 5941d99a..247a26dd 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -89,6 +89,8 @@ * Uncomment the following include to enable interfacing with Serial devices via hardware or * software serial. */ +// In order to use software serial, you will need to compile this sketch with +// Arduino IDE v1.6.6 or higher. Hardware serial should work back to Arduino 1.0. //#include "utility/SerialFirmata.h" // follow the instructions in wifiConfig.h to configure your particular hardware diff --git a/utility/SerialFirmata.cpp b/utility/SerialFirmata.cpp index 9dba3f2b..b934f166 100644 --- a/utility/SerialFirmata.cpp +++ b/utility/SerialFirmata.cpp @@ -14,17 +14,19 @@ - handlePinMode calls Firmata::setPinMode - Last updated by Jeff Hoefs: January 10th, 2016 + Last updated October 16th, 2016 */ #include "SerialFirmata.h" SerialFirmata::SerialFirmata() { +#if defined(SoftwareSerial_h) swSerial0 = NULL; swSerial1 = NULL; swSerial2 = NULL; swSerial3 = NULL; +#endif serialIndex = -1; } diff --git a/utility/SerialFirmata.h b/utility/SerialFirmata.h index b3357f44..79915aaf 100644 --- a/utility/SerialFirmata.h +++ b/utility/SerialFirmata.h @@ -15,7 +15,7 @@ - Defines FIRMATA_SERIAL_FEATURE (could add to Configurable version as well) - Imports Firmata.h rather than ConfigurableFirmata.h - Last updated by Jeff Hoefs: January 10th, 2016 + Last updated October 16th, 2016 */ #ifndef SerialFirmata_h @@ -23,10 +23,10 @@ #include #include "FirmataFeature.h" -// SoftwareSerial is currently only supported for AVR-based boards and the Arduino 101 -// The third condition checks if the IDE is in the 1.0.x series, if so, include SoftwareSerial -// since it should be available to all boards in that IDE. -#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ARC32) || (ARDUINO >= 100 && ARDUINO < 10500) +// SoftwareSerial is currently only supported for AVR-based boards and the Arduino 101. +// Limited to Arduino 1.6.6 or higher because Arduino builder cannot find SoftwareSerial +// prior to this release. +#if (ARDUINO > 10605) && (defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ARC32)) #include #endif @@ -155,10 +155,12 @@ class SerialFirmata: public FirmataFeature int serialBytesToRead[SERIAL_READ_ARR_LEN]; signed char serialIndex; +#if defined(SoftwareSerial_h) Stream *swSerial0; Stream *swSerial1; Stream *swSerial2; Stream *swSerial3; +#endif Stream* getPortFromId(byte portId); From 5da81d652c5f90fba072ecae50d2408fa14de825 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 16 Oct 2016 13:57:07 -0700 Subject: [PATCH 036/110] forward declare some functions to avoid complier errors in old IDE versions --- examples/StandardFirmata/StandardFirmata.ino | 53 +++++++++--------- .../StandardFirmataBLE/StandardFirmataBLE.ino | 54 ++++++++++--------- .../StandardFirmataChipKIT.ino | 54 ++++++++++--------- .../StandardFirmataEthernet.ino | 54 ++++++++++--------- .../StandardFirmataPlus.ino | 51 +++++++++--------- .../StandardFirmataWiFi.ino | 54 ++++++++++--------- 6 files changed, 171 insertions(+), 149 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 7477e58a..7d817719 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: January 10th, 2016 + Last updated October 16th, 2016 */ #include @@ -91,6 +91,9 @@ byte servoCount = 0; boolean isResetting = false; +void setPinModeCallback(byte, int); +void reportAnalogCallback(byte analogPin, int value); +void sysexCallback(byte, byte, byte*); /* utility functions */ void wireWrite(byte data) @@ -153,6 +156,30 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available @@ -664,30 +691,6 @@ void sysexCallback(byte command, byte argc, byte *argv) } } -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - /*============================================================================== * SETUP() *============================================================================*/ diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 7dfed667..18e60e94 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated June 15th, 2016 + Last updated October 16th, 2016 */ #include @@ -108,6 +108,10 @@ byte servoCount = 0; boolean isResetting = false; +void setPinModeCallback(byte, int); +void reportAnalogCallback(byte analogPin, int value); +void sysexCallback(byte, byte, byte*); + /* utility functions */ void wireWrite(byte data) { @@ -169,6 +173,30 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available @@ -680,30 +708,6 @@ void sysexCallback(byte command, byte argc, byte *argv) } } -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - /*============================================================================== * SETUP() *============================================================================*/ diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index b1fa79bf..a4bcbefb 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: January 10th, 2016 + Last updated October 16th, 2016 */ #include // Gives us PWM and Servo on every pin @@ -88,6 +88,10 @@ byte servoCount = 0; boolean isResetting = false; +void setPinModeCallback(byte, int); +void reportAnalogCallback(byte analogPin, int value); +void sysexCallback(byte, byte, byte*); + /* utility functions */ void wireWrite(byte data) { @@ -149,6 +153,30 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available @@ -656,30 +684,6 @@ void sysexCallback(byte command, byte argc, byte *argv) } } -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - /*============================================================================== * SETUP() *============================================================================*/ diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 7226984a..6ddd228c 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: June 18th, 2016 + Last updated October 16th, 2016 */ /* @@ -161,6 +161,10 @@ byte servoCount = 0; boolean isResetting = false; +void setPinModeCallback(byte, int); +void reportAnalogCallback(byte analogPin, int value); +void sysexCallback(byte, byte, byte*); + /* utility functions */ void wireWrite(byte data) { @@ -222,6 +226,30 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available @@ -734,30 +762,6 @@ void sysexCallback(byte command, byte argc, byte *argv) } } -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - /*============================================================================== * SETUP() *============================================================================*/ diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index c83ab4a2..bb848d52 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -116,6 +116,9 @@ byte servoCount = 0; boolean isResetting = false; +void setPinModeCallback(byte, int); +void reportAnalogCallback(byte analogPin, int value); +void sysexCallback(byte, byte, byte*); /* utility functions */ void wireWrite(byte data) @@ -178,6 +181,30 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available @@ -689,30 +716,6 @@ void sysexCallback(byte command, byte argc, byte *argv) } } -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - /*============================================================================== * SETUP() *============================================================================*/ diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 247a26dd..c2225212 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -22,7 +22,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated by Jeff Hoefs: April 24th, 2016 + Last updated October 16th, 2016 */ /* @@ -174,6 +174,10 @@ byte servoCount = 0; boolean isResetting = false; +void setPinModeCallback(byte, int); +void reportAnalogCallback(byte analogPin, int value); +void sysexCallback(byte, byte, byte*); + /* utility functions */ void wireWrite(byte data) { @@ -235,6 +239,30 @@ void detachServo(byte pin) servoPinMap[pin] = 255; } +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, PIN_MODE_I2C); + } + } + + isI2CEnabled = true; + + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; +} + void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) { // allow I2C requests that don't require a register read // for example, some devices using an interrupt pin to signify new data available @@ -752,30 +780,6 @@ void sysexCallback(byte command, byte argc, byte *argv) } } -void enableI2CPins() -{ - byte i; - // is there a faster way to do this? would probaby require importing - // Arduino.h to get SCL and SDA pins - for (i = 0; i < TOTAL_PINS; i++) { - if (IS_PIN_I2C(i)) { - // mark pins as i2c so they are ignore in non i2c data requests - setPinModeCallback(i, PIN_MODE_I2C); - } - } - - isI2CEnabled = true; - - Wire.begin(); -} - -/* disable the i2c pins so they can be used for other functions */ -void disableI2CPins() { - isI2CEnabled = false; - // disable read continuous mode for all devices - queryIndex = -1; -} - /*============================================================================== * SETUP() *============================================================================*/ From 3d9d50a4f71cbd4b44625792f098e60629cba103 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 16 Oct 2016 14:09:43 -0700 Subject: [PATCH 037/110] explain why some functions are forward declared --- examples/StandardFirmata/StandardFirmata.ino | 2 ++ examples/StandardFirmataBLE/StandardFirmataBLE.ino | 2 ++ examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 2 ++ examples/StandardFirmataEthernet/StandardFirmataEthernet.ino | 2 ++ examples/StandardFirmataPlus/StandardFirmataPlus.ino | 2 ++ examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 2 ++ 6 files changed, 12 insertions(+) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 7d817719..d2b81bce 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -91,6 +91,8 @@ byte servoCount = 0; boolean isResetting = false; +// Forward declare a few functions to avoid compiler errors with older versions +// of the Arduino IDE. void setPinModeCallback(byte, int); void reportAnalogCallback(byte analogPin, int value); void sysexCallback(byte, byte, byte*); diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 18e60e94..a4e21bae 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -108,6 +108,8 @@ byte servoCount = 0; boolean isResetting = false; +// Forward declare a few functions to avoid compiler errors with older versions +// of the Arduino IDE. void setPinModeCallback(byte, int); void reportAnalogCallback(byte analogPin, int value); void sysexCallback(byte, byte, byte*); diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index a4bcbefb..8827638f 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -88,6 +88,8 @@ byte servoCount = 0; boolean isResetting = false; +// Forward declare a few functions to avoid compiler errors with older versions +// of the Arduino IDE. void setPinModeCallback(byte, int); void reportAnalogCallback(byte analogPin, int value); void sysexCallback(byte, byte, byte*); diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 6ddd228c..6ba7d244 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -161,6 +161,8 @@ byte servoCount = 0; boolean isResetting = false; +// Forward declare a few functions to avoid compiler errors with older versions +// of the Arduino IDE. void setPinModeCallback(byte, int); void reportAnalogCallback(byte analogPin, int value); void sysexCallback(byte, byte, byte*); diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index bb848d52..14eefdc9 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -116,6 +116,8 @@ byte servoCount = 0; boolean isResetting = false; +// Forward declare a few functions to avoid compiler errors with older versions +// of the Arduino IDE. void setPinModeCallback(byte, int); void reportAnalogCallback(byte analogPin, int value); void sysexCallback(byte, byte, byte*); diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index c2225212..e06b73ab 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -174,6 +174,8 @@ byte servoCount = 0; boolean isResetting = false; +// Forward declare a few functions to avoid compiler errors with older versions +// of the Arduino IDE. void setPinModeCallback(byte, int); void reportAnalogCallback(byte analogPin, int value); void sysexCallback(byte, byte, byte*); From 281b99fb5e293cf5e1b338c32a6663698e910ba0 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 16 Oct 2016 14:59:17 -0700 Subject: [PATCH 038/110] Respect default pin state when setting OUTPUT mode Only disable PWM when setting pinMode to OUTPUT if pin mode was previously set to PWM. --- examples/StandardFirmata/StandardFirmata.ino | 5 ++++- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 5 ++++- examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 5 ++++- examples/StandardFirmataEthernet/StandardFirmataEthernet.ino | 5 ++++- examples/StandardFirmataPlus/StandardFirmataPlus.ino | 5 ++++- examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 5 ++++- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index d2b81bce..c32639df 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -318,7 +318,10 @@ void setPinModeCallback(byte pin, int mode) break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + if (Firmata.getPinMode(pin) == PIN_MODE_PWM) { + // Disable PWM if pin mode was previously set to PWM. + digitalWrite(PIN_TO_DIGITAL(pin), LOW); + } pinMode(PIN_TO_DIGITAL(pin), OUTPUT); Firmata.setPinMode(pin, OUTPUT); } diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index a4e21bae..6ccf7d1b 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -335,7 +335,10 @@ void setPinModeCallback(byte pin, int mode) break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + if (Firmata.getPinMode(pin) == PIN_MODE_PWM) { + // Disable PWM if pin mode was previously set to PWM. + digitalWrite(PIN_TO_DIGITAL(pin), LOW); + } pinMode(PIN_TO_DIGITAL(pin), OUTPUT); Firmata.setPinMode(pin, OUTPUT); } diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 8827638f..87942c70 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -325,7 +325,10 @@ void setPinModeCallback(byte pin, int mode) break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + if (Firmata.getPinMode(pin) == PIN_MODE_PWM) { + // Disable PWM if pin mode was previously set to PWM. + digitalWrite(PIN_TO_DIGITAL(pin), LOW); + } pinMode(PIN_TO_DIGITAL(pin), OUTPUT); Firmata.setPinMode(pin, OUTPUT); } diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 6ba7d244..f5c86bcd 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -389,7 +389,10 @@ void setPinModeCallback(byte pin, int mode) break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + if (Firmata.getPinMode(pin) == PIN_MODE_PWM) { + // Disable PWM if pin mode was previously set to PWM. + digitalWrite(PIN_TO_DIGITAL(pin), LOW); + } pinMode(PIN_TO_DIGITAL(pin), OUTPUT); Firmata.setPinMode(pin, OUTPUT); } diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 14eefdc9..49a1969c 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -343,7 +343,10 @@ void setPinModeCallback(byte pin, int mode) break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + if (Firmata.getPinMode(pin) == PIN_MODE_PWM) { + // Disable PWM if pin mode was previously set to PWM. + digitalWrite(PIN_TO_DIGITAL(pin), LOW); + } pinMode(PIN_TO_DIGITAL(pin), OUTPUT); Firmata.setPinMode(pin, OUTPUT); } diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index e06b73ab..d4cbfab8 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -407,7 +407,10 @@ void setPinModeCallback(byte pin, int mode) break; case OUTPUT: if (IS_PIN_DIGITAL(pin)) { - digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + if (Firmata.getPinMode(pin) == PIN_MODE_PWM) { + // Disable PWM if pin mode was previously set to PWM. + digitalWrite(PIN_TO_DIGITAL(pin), LOW); + } pinMode(PIN_TO_DIGITAL(pin), OUTPUT); Firmata.setPinMode(pin, OUTPUT); } From f332d770b9d365bad67d2e8763e2f4c6a25bc546 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 16 Oct 2016 21:01:03 -0700 Subject: [PATCH 039/110] add Teensy 3.5 and 3.6 to Boards.h --- Boards.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Boards.h b/Boards.h index 553c6a43..f19c21aa 100644 --- a/Boards.h +++ b/Boards.h @@ -343,6 +343,36 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) +// Teensy 3.5 and 3.6 +// reference: https://github.com/PaulStoffregen/cores/blob/master/teensy3/pins_arduino.h +#elif defined(__MK64FX512__) || defined(__MK66FX1M0__) +#define TOTAL_ANALOG_PINS 27 // 3.5 has 27 and 3.6 has 25 +#define TOTAL_PINS 70 // 43 digital + 21 analog-digital + 6 analog (64-69) +#define VERSION_BLINK_PIN 13 +#define PIN_SERIAL1_RX 0 +#define PIN_SERIAL1_TX 1 +#define PIN_SERIAL2_RX 9 +#define PIN_SERIAL2_TX 10 +#define PIN_SERIAL3_RX 7 +#define PIN_SERIAL3_TX 8 +// The following 2 UARTs are not yet available via SerialFirmata +#define PIN_SERIAL4_RX 31 +#define PIN_SERIAL5_TX 32 +#define PIN_SERIAL6_RX 34 +#define PIN_SERIAL6_TX 33 +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 63) +#define IS_PIN_ANALOG(p) (((p) >= 14 && (p) <= 23) || ((p) >= 31 && (p) <= 39) || ((p) >= 49 && (p) <= 50) || ((p) >= 64 && (p) <= 69)) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) +#define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1)) +#define PIN_TO_DIGITAL(p) (p) +// A0-A9 = D14-D23; A12-A20 = D31-D39; A23-A24 = D49-D50; A10-A11 = D64-D65; A21-A22 = D66-D67; A25-A26 = D68-D69 +#define PIN_TO_ANALOG(p) (((p) <= 23) ? (p) - 14 : (((p) <= 39) ? (p) - 19 : (((p) <= 50) ? (p) - 26 : (((p) <= 65) ? (p) - 55 : (((p) <= 67) ? (p) - 45 : (p) - 43))))) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) + + // Teensy 3.0, 3.1 and 3.2 #elif defined(__MK20DX128__) || defined(__MK20DX256__) #define TOTAL_ANALOG_PINS 14 From 39c8e706c408f9775645ba199c383e450282846f Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 23 Oct 2016 20:50:19 -0700 Subject: [PATCH 040/110] bump bugfix version --- Boards.h | 2 +- Firmata.cpp | 2 +- Firmata.h | 4 ++-- extras/LICENSE.txt => LICENSE.txt | 0 extras/revisions.txt | 10 ++++++++++ library.properties | 2 +- readme.md | 8 ++++---- release.sh | 4 ++-- 8 files changed, 21 insertions(+), 11 deletions(-) rename extras/LICENSE.txt => LICENSE.txt (100%) diff --git a/Boards.h b/Boards.h index f19c21aa..218a8dd5 100644 --- a/Boards.h +++ b/Boards.h @@ -10,7 +10,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated April 10th, 2016 + Last updated October 16th, 2016 */ #ifndef Firmata_Boards_h diff --git a/Firmata.cpp b/Firmata.cpp index e647b41a..a5eb3848 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.3 - 2016-06-18 + Firmata.cpp - Firmata library v2.5.4 - 2016-10-23 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/Firmata.h b/Firmata.h index f54051fb..92c6e06e 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.3 - 2016-06-18 + Firmata.h - Firmata library v2.5.4 - 2016-10-23 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. @@ -30,7 +30,7 @@ */ #define FIRMATA_FIRMWARE_MAJOR_VERSION 2 #define FIRMATA_FIRMWARE_MINOR_VERSION 5 -#define FIRMATA_FIRMWARE_BUGFIX_VERSION 3 +#define FIRMATA_FIRMWARE_BUGFIX_VERSION 4 /* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for * the protocol version and the firmware version. diff --git a/extras/LICENSE.txt b/LICENSE.txt similarity index 100% rename from extras/LICENSE.txt rename to LICENSE.txt diff --git a/extras/revisions.txt b/extras/revisions.txt index a4f4e22c..983e75c4 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,13 @@ +FIRMATA 2.5.4 - Oct 23, 2016 + +[core library] +* Added Teensy 3.5 and 3.6 to Boards.h +* Assign blinkVersionDisabled in constructor to fix compiler issue in Arduino 1.0.6 + +[StandardFirmata & variants] +* Only disable PWM when setting pinMode to OUTPUT if pinMode was previously PWM +* Forward declare some functions to fix compiler issues with older IDE versions + FIRMATA 2.5.3 - Jun 18, 2016 [core library] diff --git a/library.properties b/library.properties index 22d91aad..7e44fe16 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.5.3 +version=2.5.4 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino/Genuino boards. diff --git a/readme.md b/readme.md index 3214b1e0..2df140e8 100644 --- a/readme.md +++ b/readme.md @@ -94,7 +94,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ##Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.3) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.4) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -105,7 +105,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.3) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.4) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -115,7 +115,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.3) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.4) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -124,7 +124,7 @@ for Arduino 1.0.x vs 1.6.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.3) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.4) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index 8052714f..ef624129 100644 --- a/release.sh +++ b/release.sh @@ -16,7 +16,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.3.zip +mv ./temp/Firmata.zip Firmata-2.5.4.zip #package for Arduino 1.6.x cp library.properties temp/Firmata @@ -31,5 +31,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.3.zip +mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.4.zip rm -r ./temp From bdd3916f682cf1e4c4e8c9ade9d948740baf1a96 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 28 Oct 2016 07:41:51 -0700 Subject: [PATCH 041/110] Split parsing functionality into new lib --- FirmataParser.cpp | 301 ++++++++++++++++++++++++++++++++++++++++++++++ FirmataParser.h | 157 ++++++++++++++++++++++++ 2 files changed, 458 insertions(+) create mode 100644 FirmataParser.cpp create mode 100644 FirmataParser.h diff --git a/FirmataParser.cpp b/FirmataParser.cpp new file mode 100644 index 00000000..20bc20c0 --- /dev/null +++ b/FirmataParser.cpp @@ -0,0 +1,301 @@ +/* + Firmata.cpp - Firmata library v2.5.4 - 2016-10-23 + Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (C) 2009-2016 Jeff Hoefs. 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. + + See file LICENSE.txt for further informations on licensing terms. +*/ + +//****************************************************************************** +//* Includes +//****************************************************************************** + +#include "FirmataParser.h" + +//****************************************************************************** +//* Constructors +//****************************************************************************** + +/** + * The Firmata class. + * An instance named "Firmata" is created automatically for the user. + */ +FirmataParser::FirmataParser() +: + executeMultiByteCommand(0), + multiByteChannel(0), + storedInputData{0}, + waitForData(0), + parsingSysex(false), + sysexBytesRead(0), + currentAnalogCallback((callbackFunction)NULL), + currentDigitalCallback((callbackFunction)NULL), + currentReportAnalogCallback((callbackFunction)NULL), + currentReportDigitalCallback((callbackFunction)NULL), + currentPinModeCallback((callbackFunction)NULL), + currentPinValueCallback((callbackFunction)NULL), + currentReportFirmwareCallback((systemCallbackFunction)NULL), + currentReportVersionCallback((systemCallbackFunction)NULL), + currentSystemResetCallback((systemCallbackFunction)NULL), + currentStringCallback((stringCallbackFunction)NULL), + currentSysexCallback((sysexCallbackFunction)NULL) +{ +} + +//****************************************************************************** +//* Public Methods +//****************************************************************************** + +//------------------------------------------------------------------------------ +// Serial Receive Handling + +/** + * Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally. + * Calls callback function for STRING_DATA and all other sysex messages. + * @private + */ +void FirmataParser::processSysexMessage(void) +{ + switch (storedInputData[0]) { //first byte in buffer is command + case REPORT_FIRMWARE: + if (currentReportFirmwareCallback) + (*currentReportFirmwareCallback)(); + break; + case STRING_DATA: + if (currentStringCallback) { + size_t bufferLength = (sysexBytesRead - 1) / 2; + size_t i = 1; + size_t j = 0; + while (j < bufferLength) { + // The string length will only be at most half the size of the + // stored input buffer so we can decode the string within the buffer. + storedInputData[j] = storedInputData[i]; + i++; + storedInputData[j] += (storedInputData[i] << 7); + i++; + j++; + } + // Make sure string is null terminated. This may be the case for data + // coming from client libraries in languages that don't null terminate + // strings. + if (storedInputData[j - 1] != '\0') { + storedInputData[j] = '\0'; + } + (*currentStringCallback)((char *)&storedInputData[0]); + } + break; + default: + if (currentSysexCallback) + (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); + } +} + +/** + * Parse data from the input stream. + * @param inputData A single byte to be added to the parser. + */ +void FirmataParser::parse(uint8_t inputData) +{ + uint8_t command; + + if (parsingSysex) { + if (inputData == END_SYSEX) { + //stop sysex byte + parsingSysex = false; + //fire off handler function + processSysexMessage(); + } else { + //normal data byte - add to buffer + storedInputData[sysexBytesRead] = inputData; + sysexBytesRead++; + } + } else if ( (waitForData > 0) && (inputData < 128) ) { + waitForData--; + storedInputData[waitForData] = inputData; + if ( (waitForData == 0) && executeMultiByteCommand ) { // got the whole message + switch (executeMultiByteCommand) { + case ANALOG_MESSAGE: + if (currentAnalogCallback) { + (*currentAnalogCallback)(multiByteChannel, + (storedInputData[0] << 7) + + storedInputData[1]); + } + break; + case DIGITAL_MESSAGE: + if (currentDigitalCallback) { + (*currentDigitalCallback)(multiByteChannel, + (storedInputData[0] << 7) + + storedInputData[1]); + } + break; + case SET_PIN_MODE: + if (currentPinModeCallback) + (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); + break; + case SET_DIGITAL_PIN_VALUE: + if (currentPinValueCallback) + (*currentPinValueCallback)(storedInputData[1], storedInputData[0]); + break; + case REPORT_ANALOG: + if (currentReportAnalogCallback) + (*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]); + break; + case REPORT_DIGITAL: + if (currentReportDigitalCallback) + (*currentReportDigitalCallback)(multiByteChannel, storedInputData[0]); + break; + } + executeMultiByteCommand = 0; + } + } else { + // remove channel info from command byte if less than 0xF0 + if (inputData < 0xF0) { + command = inputData & 0xF0; + multiByteChannel = inputData & 0x0F; + } else { + command = inputData; + // commands in the 0xF* range don't use channel data + } + switch (command) { + case ANALOG_MESSAGE: + case DIGITAL_MESSAGE: + case SET_PIN_MODE: + case SET_DIGITAL_PIN_VALUE: + waitForData = 2; // two data bytes needed + executeMultiByteCommand = command; + break; + case REPORT_ANALOG: + case REPORT_DIGITAL: + waitForData = 1; // one data byte needed + executeMultiByteCommand = command; + break; + case START_SYSEX: + parsingSysex = true; + sysexBytesRead = 0; + break; + case SYSTEM_RESET: + systemReset(); + break; + case REPORT_VERSION: + if (currentReportVersionCallback) + (*currentReportVersionCallback)(); + break; + } + } +} + +/** + * @return Returns true if the parser is actively parsing data. + */ +bool FirmataParser::isParsingMessage(void) +{ + return (waitForData > 0 || parsingSysex); +} + +/** + * Attach a generic sysex callback function to a command (options are: ANALOG_MESSAGE, + * DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE). + * @param command The ID of the command to attach a callback function to. + * @param newFunction A reference to the callback function to attach. + */ +void FirmataParser::attach(uint8_t command, callbackFunction newFunction) +{ + switch (command) { + case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; + case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; + case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; + case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; + case SET_PIN_MODE: currentPinModeCallback = newFunction; break; + case SET_DIGITAL_PIN_VALUE: currentPinValueCallback = newFunction; break; + } +} + +/** + * Attach a system callback function (options are: REPORT_FIRMWARE, REPORT_VERSION + * and SYSTEM_RESET). + * @param command The ID of the command to attach a callback function to. + * @param newFunction A reference to the callback function to attach. + */ +void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction) +{ + switch (command) { + case REPORT_FIRMWARE: currentReportFirmwareCallback = newFunction; break; + case REPORT_VERSION: currentReportVersionCallback = newFunction; break; + case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; + } +} + +/** + * Attach a callback function for the STRING_DATA command. + * @param command Must be set to STRING_DATA or it will be ignored. + * @param newFunction A reference to the string callback function to attach. + */ +void FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction) +{ + switch (command) { + case STRING_DATA: currentStringCallback = newFunction; break; + } +} + +/** + * Attach a generic sysex callback function to sysex command. + * @param command The ID of the command to attach a callback function to. + * @param newFunction A reference to the sysex callback function to attach. + */ +void FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction) +{ + currentSysexCallback = newFunction; +} + +/** + * Detach a callback function for a specified command (such as SYSTEM_RESET, STRING_DATA, + * ANALOG_MESSAGE, DIGITAL_MESSAGE, etc). + * @param command The ID of the command to detatch the callback function from. + */ +void FirmataParser::detach(uint8_t command) +{ + switch (command) { + case REPORT_FIRMWARE: + case REPORT_VERSION: + case SYSTEM_RESET: + attach(command, (systemCallbackFunction)NULL); + break; + case STRING_DATA: currentStringCallback = (stringCallbackFunction)NULL; break; + case START_SYSEX: currentSysexCallback = (sysexCallbackFunction)NULL; break; + default: + attach(command, (callbackFunction)NULL); + } +} + +//****************************************************************************** +//* Private Methods +//****************************************************************************** + +/** + * Resets the system state upon a SYSTEM_RESET message from the host software. + * @private + */ +void FirmataParser::systemReset(void) +{ + size_t i; + + waitForData = 0; // this flag says the next serial input will be data + executeMultiByteCommand = 0; // execute this after getting multi-byte data + multiByteChannel = 0; // channel data for multiByteCommands + + for (i = 0; i < MAX_DATA_BYTES; i++) { + storedInputData[i] = 0; + } + + parsingSysex = false; + sysexBytesRead = 0; + + if (currentSystemResetCallback) + (*currentSystemResetCallback)(); +} + diff --git a/FirmataParser.h b/FirmataParser.h new file mode 100644 index 00000000..33fc88b3 --- /dev/null +++ b/FirmataParser.h @@ -0,0 +1,157 @@ +/* + FirmataParser.h - Firmata library v2.5.4 - 2016-10-23 + Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (C) 2009-2016 Jeff Hoefs. 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. + + See file LICENSE.txt for further informations on licensing terms. +*/ + +#ifndef FirmataParser_h +#define FirmataParser_h + +#if defined(__cplusplus) && !defined(ARDUINO) + #include + #include +#else + #include + #include +#endif + +/* Version numbers for the protocol. The protocol is still changing, so these + * version numbers are important. + * Query using the REPORT_VERSION message. + */ +#define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes +#define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes +#define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases + +#ifdef MAX_DATA_BYTES +#undef MAX_DATA_BYTES +#endif +#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages + +// message command bytes (128-255/0x80-0xFF) +#ifdef DIGITAL_MESSAGE +#undef DIGITAL_MESSAGE +#endif +#define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) + +#ifdef ANALOG_MESSAGE +#undef ANALOG_MESSAGE +#endif +#define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) + +#ifdef REPORT_ANALOG +#undef REPORT_ANALOG +#endif +#define REPORT_ANALOG 0xC0 // enable analog input by pin # + +#ifdef REPORT_DIGITAL +#undef REPORT_DIGITAL +#endif +#define REPORT_DIGITAL 0xD0 // enable digital input by port pair + +// + +#ifdef SET_PIN_MODE +#undef SET_PIN_MODE +#endif +#define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc + +#ifdef SET_DIGITAL_PIN_VALUE +#undef SET_DIGITAL_PIN_VALUE +#endif +#define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin + +// + +#ifdef REPORT_VERSION +#undef REPORT_VERSION +#endif +#define REPORT_VERSION 0xF9 // report protocol version + +#ifdef SYSTEM_RESET +#undef SYSTEM_RESET +#endif +#define SYSTEM_RESET 0xFF // reset from MIDI + +// + +#ifdef START_SYSEX +#undef START_SYSEX +#endif +#define START_SYSEX 0xF0 // start a MIDI Sysex message + +#ifdef END_SYSEX +#undef END_SYSEX +#endif +#define END_SYSEX 0xF7 // end a MIDI Sysex message + +// extended command set using sysex (0-127/0x00-0x7F) +/* 0x00-0x0F reserved for user-defined commands */ +#ifdef STRING_DATA +#undef STRING_DATA +#endif +#define STRING_DATA 0x71 // a string message with 14-bits per char + +#ifdef REPORT_FIRMWARE +#undef REPORT_FIRMWARE +#endif +#define REPORT_FIRMWARE 0x79 // report name and version of the firmware + +extern "C" { + // callback function types + typedef void (*callbackFunction)(uint8_t, int); + typedef void (*systemCallbackFunction)(void); + typedef void (*stringCallbackFunction)(char *); + typedef void (*sysexCallbackFunction)(uint8_t command, uint8_t argc, uint8_t *argv); +} + +class FirmataParser +{ + public: + FirmataParser(); + /* serial receive handling */ + void parse(uint8_t value); + bool isParsingMessage(void); + /* attach & detach callback functions to messages */ + void attach(uint8_t command, callbackFunction newFunction); + void attach(uint8_t command, systemCallbackFunction newFunction); + void attach(uint8_t command, stringCallbackFunction newFunction); + void attach(uint8_t command, sysexCallbackFunction newFunction); + void detach(uint8_t command); + + private: + /* input message handling */ + uint8_t executeMultiByteCommand; // execute this after getting multi-byte data + uint8_t multiByteChannel; // channel data for multiByteCommands + uint8_t storedInputData[MAX_DATA_BYTES]; // multi-byte data + size_t waitForData; // this flag says the next serial input will be data + /* sysex */ + bool parsingSysex; + size_t sysexBytesRead; + + /* callback functions */ + callbackFunction currentAnalogCallback; + callbackFunction currentDigitalCallback; + callbackFunction currentReportAnalogCallback; + callbackFunction currentReportDigitalCallback; + callbackFunction currentPinModeCallback; + callbackFunction currentPinValueCallback; + systemCallbackFunction currentReportFirmwareCallback; + systemCallbackFunction currentReportVersionCallback; + systemCallbackFunction currentSystemResetCallback; + stringCallbackFunction currentStringCallback; + sysexCallbackFunction currentSysexCallback; + + /* private methods ------------------------------ */ + void processSysexMessage(void); + void systemReset(void); +}; + +#endif /* FirmataParser_h */ From 835920987a870ed8ecc71b426742bd9b02fdab12 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 30 Oct 2016 18:54:17 -0700 Subject: [PATCH 042/110] Update FirmataClass to use FirmataParser --- Firmata.cpp | 209 ++++++++-------------------------------------------- Firmata.h | 73 ++---------------- 2 files changed, 36 insertions(+), 246 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index a5eb3848..ff7f8429 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -23,6 +23,20 @@ extern "C" { #include } +//****************************************************************************** +//* Static Members +//****************************************************************************** +// make one instance for the user to use +FirmataClass Firmata; + +void printVersion (void) { + Firmata.printVersion(); +} + +void printFirmwareVersion (void) { + Firmata.printFirmwareVersion(); +} + //****************************************************************************** //* Support Functions //****************************************************************************** @@ -66,7 +80,8 @@ FirmataClass::FirmataClass() firmwareVersionCount = 0; firmwareVersionVector = 0; blinkVersionDisabled = false; - systemReset(); + parser.attach(REPORT_FIRMWARE, ::printFirmwareVersion); + parser.attach(REPORT_VERSION, ::printVersion); } //****************************************************************************** @@ -228,46 +243,6 @@ int FirmataClass::available(void) return FirmataStream->available(); } -/** - * Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally. - * Calls callback function for STRING_DATA and all other sysex messages. - * @private - */ -void FirmataClass::processSysexMessage(void) -{ - switch (storedInputData[0]) { //first byte in buffer is command - case REPORT_FIRMWARE: - printFirmwareVersion(); - break; - case STRING_DATA: - if (currentStringCallback) { - byte bufferLength = (sysexBytesRead - 1) / 2; - byte i = 1; - byte j = 0; - while (j < bufferLength) { - // The string length will only be at most half the size of the - // stored input buffer so we can decode the string within the buffer. - storedInputData[j] = storedInputData[i]; - i++; - storedInputData[j] += (storedInputData[i] << 7); - i++; - j++; - } - // Make sure string is null terminated. This may be the case for data - // coming from client libraries in languages that don't null terminate - // strings. - if (storedInputData[j - 1] != '\0') { - storedInputData[j] = '\0'; - } - (*currentStringCallback)((char *)&storedInputData[0]); - } - break; - default: - if (currentSysexCallback) - (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); - } -} - /** * Read a single int from the input stream. If the value is not = -1, pass it on to parse(byte) */ @@ -275,7 +250,7 @@ void FirmataClass::processInput(void) { int inputData = FirmataStream->read(); // this is 'int' to handle -1 when no data if (inputData != -1) { - parse(inputData); + parser.parse(inputData); } } @@ -285,91 +260,7 @@ void FirmataClass::processInput(void) */ void FirmataClass::parse(byte inputData) { - int command; - - if (parsingSysex) { - if (inputData == END_SYSEX) { - //stop sysex byte - parsingSysex = false; - //fire off handler function - processSysexMessage(); - } else { - //normal data byte - add to buffer - storedInputData[sysexBytesRead] = inputData; - sysexBytesRead++; - } - } else if ( (waitForData > 0) && (inputData < 128) ) { - waitForData--; - storedInputData[waitForData] = inputData; - if ( (waitForData == 0) && executeMultiByteCommand ) { // got the whole message - switch (executeMultiByteCommand) { - case ANALOG_MESSAGE: - if (currentAnalogCallback) { - (*currentAnalogCallback)(multiByteChannel, - (storedInputData[0] << 7) - + storedInputData[1]); - } - break; - case DIGITAL_MESSAGE: - if (currentDigitalCallback) { - (*currentDigitalCallback)(multiByteChannel, - (storedInputData[0] << 7) - + storedInputData[1]); - } - break; - case SET_PIN_MODE: - if (currentPinModeCallback) - (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); - break; - case SET_DIGITAL_PIN_VALUE: - if (currentPinValueCallback) - (*currentPinValueCallback)(storedInputData[1], storedInputData[0]); - break; - case REPORT_ANALOG: - if (currentReportAnalogCallback) - (*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]); - break; - case REPORT_DIGITAL: - if (currentReportDigitalCallback) - (*currentReportDigitalCallback)(multiByteChannel, storedInputData[0]); - break; - } - executeMultiByteCommand = 0; - } - } else { - // remove channel info from command byte if less than 0xF0 - if (inputData < 0xF0) { - command = inputData & 0xF0; - multiByteChannel = inputData & 0x0F; - } else { - command = inputData; - // commands in the 0xF* range don't use channel data - } - switch (command) { - case ANALOG_MESSAGE: - case DIGITAL_MESSAGE: - case SET_PIN_MODE: - case SET_DIGITAL_PIN_VALUE: - waitForData = 2; // two data bytes needed - executeMultiByteCommand = command; - break; - case REPORT_ANALOG: - case REPORT_DIGITAL: - waitForData = 1; // one data byte needed - executeMultiByteCommand = command; - break; - case START_SYSEX: - parsingSysex = true; - sysexBytesRead = 0; - break; - case SYSTEM_RESET: - systemReset(); - break; - case REPORT_VERSION: - Firmata.printVersion(); - break; - } - } + parser.parse(inputData); } /** @@ -377,7 +268,7 @@ void FirmataClass::parse(byte inputData) */ boolean FirmataClass::isParsingMessage(void) { - return (waitForData > 0 || parsingSysex); + return parser.isParsingMessage(); } //------------------------------------------------------------------------------ @@ -495,16 +386,9 @@ void FirmataClass::write(byte c) * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the callback function to attach. */ -void FirmataClass::attach(byte command, callbackFunction newFunction) +void FirmataClass::attach(uint8_t command, callbackFunction newFunction) { - switch (command) { - case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; - case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; - case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; - case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; - case SET_PIN_MODE: currentPinModeCallback = newFunction; break; - case SET_DIGITAL_PIN_VALUE: currentPinValueCallback = newFunction; break; - } + parser.attach(command, (callbackFunction)newFunction); } /** @@ -512,11 +396,9 @@ void FirmataClass::attach(byte command, callbackFunction newFunction) * @param command Must be set to SYSTEM_RESET or it will be ignored. * @param newFunction A reference to the system reset callback function to attach. */ -void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction) +void FirmataClass::attach(uint8_t command, systemCallbackFunction newFunction) { - switch (command) { - case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; - } + parser.attach(command, (systemCallbackFunction)newFunction); } /** @@ -524,11 +406,9 @@ void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction) * @param command Must be set to STRING_DATA or it will be ignored. * @param newFunction A reference to the string callback function to attach. */ -void FirmataClass::attach(byte command, stringCallbackFunction newFunction) +void FirmataClass::attach(uint8_t command, stringCallbackFunction newFunction) { - switch (command) { - case STRING_DATA: currentStringCallback = newFunction; break; - } + parser.attach(command, (stringCallbackFunction)newFunction); } /** @@ -536,9 +416,9 @@ void FirmataClass::attach(byte command, stringCallbackFunction newFunction) * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the sysex callback function to attach. */ -void FirmataClass::attach(byte command, sysexCallbackFunction newFunction) +void FirmataClass::attach(uint8_t command, sysexCallbackFunction newFunction) { - currentSysexCallback = newFunction; + parser.attach(command, (sysexCallbackFunction)newFunction); } /** @@ -546,15 +426,9 @@ void FirmataClass::attach(byte command, sysexCallbackFunction newFunction) * ANALOG_MESSAGE, DIGITAL_MESSAGE, etc). * @param command The ID of the command to detatch the callback function from. */ -void FirmataClass::detach(byte command) +void FirmataClass::detach(uint8_t command) { - switch (command) { - case SYSTEM_RESET: currentSystemResetCallback = NULL; break; - case STRING_DATA: currentStringCallback = NULL; break; - case START_SYSEX: currentSysexCallback = NULL; break; - default: - attach(command, (callbackFunction)NULL); - } + parser.detach(command); } /** @@ -623,29 +497,6 @@ void FirmataClass::setPinState(byte pin, int state) //* Private Methods //****************************************************************************** -/** - * Resets the system state upon a SYSTEM_RESET message from the host software. - * @private - */ -void FirmataClass::systemReset(void) -{ - byte i; - - waitForData = 0; // this flag says the next serial input will be data - executeMultiByteCommand = 0; // execute this after getting multi-byte data - multiByteChannel = 0; // channel data for multiByteCommands - - for (i = 0; i < MAX_DATA_BYTES; i++) { - storedInputData[i] = 0; - } - - parsingSysex = false; - sysexBytesRead = 0; - - if (currentSystemResetCallback) - (*currentSystemResetCallback)(); -} - /** * Flashing the pin for the version number * @private @@ -665,5 +516,3 @@ void FirmataClass::strobeBlinkPin(byte pin, int count, int onInterval, int offIn } } -// make one instance for the user to use -FirmataClass Firmata; diff --git a/Firmata.h b/Firmata.h index 92c6e06e..9fba25bd 100644 --- a/Firmata.h +++ b/Firmata.h @@ -15,14 +15,7 @@ #define Firmata_h #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */ - -/* Version numbers for the protocol. The protocol is still changing, so these - * version numbers are important. - * Query using the REPORT_VERSION message. - */ -#define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes -#define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes -#define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases +#include "FirmataParser.h" /* Version numbers for the Firmata library. * The firmware version will not always equal the protocol version going forward. @@ -39,34 +32,11 @@ #define FIRMATA_MINOR_VERSION 5 // same as FIRMATA_PROTOCOL_MINOR_VERSION #define FIRMATA_BUGFIX_VERSION 1 // same as FIRMATA_PROTOCOL_BUGFIX_VERSION -#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages - -// Arduino 101 also defines SET_PIN_MODE as a macro in scss_registers.h -#ifdef SET_PIN_MODE -#undef SET_PIN_MODE -#endif - -// message command bytes (128-255/0x80-0xFF) -#define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) -#define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) -#define REPORT_ANALOG 0xC0 // enable analog input by pin # -#define REPORT_DIGITAL 0xD0 // enable digital input by port pair -// -#define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc -#define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin -// -#define REPORT_VERSION 0xF9 // report protocol version -#define SYSTEM_RESET 0xFF // reset from MIDI -// -#define START_SYSEX 0xF0 // start a MIDI Sysex message -#define END_SYSEX 0xF7 // end a MIDI Sysex message - // extended command set using sysex (0-127/0x00-0x7F) /* 0x00-0x0F reserved for user-defined commands */ #define SERIAL_MESSAGE 0x60 // communicate with serial devices, including other boards #define ENCODER_DATA 0x61 // reply with encoders current positions #define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq -#define STRING_DATA 0x71 // a string message with 14-bits per char #define STEPPER_DATA 0x72 // control a stepper motor #define ONEWIRE_DATA 0x73 // send an OneWire read/write/reset/select/skip/search request #define SHIFT_DATA 0x75 // a bitstream to/from a shift register @@ -80,7 +50,6 @@ #define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution #define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers #define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info -#define REPORT_FIRMWARE 0x79 // report name and version of the firmware #define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop #define SCHEDULER_DATA 0x7B // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler #define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages @@ -117,14 +86,6 @@ #define ENCODER 0x09 // same as PIN_MODE_ENCODER #define IGNORE 0x7F // same as PIN_MODE_IGNORE -extern "C" { - // callback function types - typedef void (*callbackFunction)(byte, int); - typedef void (*systemResetCallbackFunction)(void); - typedef void (*stringCallbackFunction)(char *); - typedef void (*sysexCallbackFunction)(byte command, byte argc, byte *argv); -} - // TODO make it a subclass of a generic Serial/Stream base class class FirmataClass { @@ -155,11 +116,11 @@ class FirmataClass void sendSysex(byte command, byte bytec, byte *bytev); void write(byte c); /* attach & detach callback functions to messages */ - void attach(byte command, callbackFunction newFunction); - void attach(byte command, systemResetCallbackFunction newFunction); - void attach(byte command, stringCallbackFunction newFunction); - void attach(byte command, sysexCallbackFunction newFunction); - void detach(byte command); + void attach(uint8_t command, callbackFunction newFunction); + void attach(uint8_t command, systemCallbackFunction newFunction); + void attach(uint8_t command, stringCallbackFunction newFunction); + void attach(uint8_t command, sysexCallbackFunction newFunction); + void detach(uint8_t command); /* access pin state and config */ byte getPinMode(byte pin); @@ -174,38 +135,18 @@ class FirmataClass void endSysex(void); private: + FirmataParser parser; Stream *FirmataStream; /* firmware name and version */ byte firmwareVersionCount; byte *firmwareVersionVector; - /* input message handling */ - byte waitForData; // this flag says the next serial input will be data - byte executeMultiByteCommand; // execute this after getting multi-byte data - byte multiByteChannel; // channel data for multiByteCommands - byte storedInputData[MAX_DATA_BYTES]; // multi-byte data - /* sysex */ - boolean parsingSysex; - int sysexBytesRead; /* pin configuration */ byte pinConfig[TOTAL_PINS]; int pinState[TOTAL_PINS]; - /* callback functions */ - callbackFunction currentAnalogCallback; - callbackFunction currentDigitalCallback; - callbackFunction currentReportAnalogCallback; - callbackFunction currentReportDigitalCallback; - callbackFunction currentPinModeCallback; - callbackFunction currentPinValueCallback; - systemResetCallbackFunction currentSystemResetCallback; - stringCallbackFunction currentStringCallback; - sysexCallbackFunction currentSysexCallback; - boolean blinkVersionDisabled; /* private methods ------------------------------ */ - void processSysexMessage(void); - void systemReset(void); void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); }; From b976cf5b346b88b97511383a871ad0c823ff61a2 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 30 Oct 2016 19:23:49 -0700 Subject: [PATCH 043/110] ensure release.sh bundles all .cpp and .h files --- release.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/release.sh b/release.sh index ef624129..d4a03c2f 100644 --- a/release.sh +++ b/release.sh @@ -7,9 +7,8 @@ mkdir -p temp/Firmata cp -r examples temp/Firmata cp -r extras temp/Firmata cp -r utility temp/Firmata -cp Boards.h temp/Firmata -cp Firmata.cpp temp/Firmata -cp Firmata.h temp/Firmata +cp *.cpp temp/Firmata +cp *.h temp/Firmata cp keywords.txt temp/Firmata cp readme.md temp/Firmata cd temp @@ -23,9 +22,8 @@ cp library.properties temp/Firmata cd temp/Firmata mv readme.md ./extras/ mkdir src -mv Boards.h ./src/ -mv Firmata.cpp ./src/ -mv Firmata.h ./src/ +mv *.cpp ./src/ +mv *.h ./src/ mv utility ./src/ cd .. find . -name "*.DS_Store" -type f -delete From b4690be6e43482dc619cabe72368d2398c7130c3 Mon Sep 17 00:00:00 2001 From: Waleed El-Badry Date: Thu, 3 Nov 2016 21:24:06 +0200 Subject: [PATCH 044/110] Update Readme.md - Removed dead link of .NET client library (**Firmata.NET**) - Added new link to **FirmataVB** free library --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 2df140e8..62a5ad97 100644 --- a/readme.md +++ b/readme.md @@ -42,7 +42,7 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/reapzor/FiloFirmata] * .NET * [https://github.com/SolidSoils/Arduino] - * [http://www.imagitronics.org/projects/firmatanet/] + * [http://www.acraigie.com/programming/firmatavb/default.html] * Flash/AS3 * [http://funnel.cc] * [http://code.google.com/p/as3glue/] From 3c7aa05787dc2e94e3b1f9342431ffa5e7cef33a Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 6 Nov 2016 21:41:53 -0800 Subject: [PATCH 045/110] Update FirmataParser to support older compilers --- FirmataParser.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/FirmataParser.cpp b/FirmataParser.cpp index 20bc20c0..ad0ac2df 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -29,7 +29,6 @@ FirmataParser::FirmataParser() : executeMultiByteCommand(0), multiByteChannel(0), - storedInputData{0}, waitForData(0), parsingSysex(false), sysexBytesRead(0), From d38adba3c8ed41864077297bff2f487fb91bd482 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 6 Nov 2016 22:09:46 -0800 Subject: [PATCH 046/110] Split marshalling functionality into new lib --- FirmataConstants.h | 281 ++++++++++++++++++++++++++++++++++++++++++ FirmataMarshaller.cpp | 165 +++++++++++++++++++++++++ FirmataMarshaller.h | 55 +++++++++ 3 files changed, 501 insertions(+) create mode 100644 FirmataConstants.h create mode 100644 FirmataMarshaller.cpp create mode 100644 FirmataMarshaller.h diff --git a/FirmataConstants.h b/FirmataConstants.h new file mode 100644 index 00000000..eda1cc8e --- /dev/null +++ b/FirmataConstants.h @@ -0,0 +1,281 @@ +/* + Firmata.h - Firmata library v2.5.4 - 2016-10-23 + Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (C) 2009-2016 Jeff Hoefs. 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. + + See file LICENSE.txt for further informations on licensing terms. +*/ + +#ifndef FirmataConstants_h +#define FirmataConstants_h + +/* Version numbers for the Firmata library. + * The firmware version will not always equal the protocol version going forward. + * Query using the REPORT_FIRMWARE message. + */ +#define FIRMATA_FIRMWARE_MAJOR_VERSION 2 +#define FIRMATA_FIRMWARE_MINOR_VERSION 5 +#define FIRMATA_FIRMWARE_BUGFIX_VERSION 4 + +/* Version numbers for the protocol. The protocol is still changing, so these + * version numbers are important. + * Query using the REPORT_VERSION message. + */ +#define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes +#define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes +#define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases + +#ifdef MAX_DATA_BYTES +#undef MAX_DATA_BYTES +#endif +#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages + +// message command bytes (128-255/0x80-0xFF) + +#ifdef DIGITAL_MESSAGE +#undef DIGITAL_MESSAGE +#endif +#define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) + +#ifdef ANALOG_MESSAGE +#undef ANALOG_MESSAGE +#endif +#define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) + +#ifdef REPORT_ANALOG +#undef REPORT_ANALOG +#endif +#define REPORT_ANALOG 0xC0 // enable analog input by pin # + +#ifdef REPORT_DIGITAL +#undef REPORT_DIGITAL +#endif +#define REPORT_DIGITAL 0xD0 // enable digital input by port pair + +// + +#ifdef SET_PIN_MODE +#undef SET_PIN_MODE +#endif +#define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc + +#ifdef SET_DIGITAL_PIN_VALUE +#undef SET_DIGITAL_PIN_VALUE +#endif +#define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin + +// + +#ifdef REPORT_VERSION +#undef REPORT_VERSION +#endif +#define REPORT_VERSION 0xF9 // report protocol version + +#ifdef SYSTEM_RESET +#undef SYSTEM_RESET +#endif +#define SYSTEM_RESET 0xFF // reset from MIDI + +// + +#ifdef START_SYSEX +#undef START_SYSEX +#endif +#define START_SYSEX 0xF0 // start a MIDI Sysex message + +#ifdef END_SYSEX +#undef END_SYSEX +#endif +#define END_SYSEX 0xF7 // end a MIDI Sysex message + +// extended command set using sysex (0-127/0x00-0x7F) +/* 0x00-0x0F reserved for user-defined commands */ + +#ifdef SERIAL_MESSAGE +#undef SERIAL_MESSAGE +#endif +#define SERIAL_MESSAGE 0x60 // communicate with serial devices, including other boards + +#ifdef ENCODER_DATA +#undef ENCODER_DATA +#endif +#define ENCODER_DATA 0x61 // reply with encoders current positions + +#ifdef SERVO_CONFIG +#undef SERVO_CONFIG +#endif +#define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq + +#ifdef STRING_DATA +#undef STRING_DATA +#endif +#define STRING_DATA 0x71 // a string message with 14-bits per char + +#ifdef STEPPER_DATA +#undef STEPPER_DATA +#endif +#define STEPPER_DATA 0x72 // control a stepper motor + +#ifdef ONEWIRE_DATA +#undef ONEWIRE_DATA +#endif +#define ONEWIRE_DATA 0x73 // send an OneWire read/write/reset/select/skip/search request + +#ifdef SHIFT_DATA +#undef SHIFT_DATA +#endif +#define SHIFT_DATA 0x75 // a bitstream to/from a shift register + +#ifdef I2C_REQUEST +#undef I2C_REQUEST +#endif +#define I2C_REQUEST 0x76 // send an I2C read/write request + +#ifdef I2C_REPLY +#undef I2C_REPLY +#endif +#define I2C_REPLY 0x77 // a reply to an I2C read request + +#ifdef I2C_CONFIG +#undef I2C_CONFIG +#endif +#define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins + +#ifdef REPORT_FIRMWARE +#undef REPORT_FIRMWARE +#endif +#define REPORT_FIRMWARE 0x79 // report name and version of the firmware + +#ifdef EXTENDED_ANALOG +#undef EXTENDED_ANALOG +#endif +#define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin + +#ifdef PIN_STATE_QUERY +#undef PIN_STATE_QUERY +#endif +#define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value + +#ifdef PIN_STATE_RESPONSE +#undef PIN_STATE_RESPONSE +#endif +#define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value + +#ifdef CAPABILITY_QUERY +#undef CAPABILITY_QUERY +#endif +#define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins + +#ifdef CAPABILITY_RESPONSE +#undef CAPABILITY_RESPONSE +#endif +#define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution + +#ifdef ANALOG_MAPPING_QUERY +#undef ANALOG_MAPPING_QUERY +#endif +#define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers + +#ifdef ANALOG_MAPPING_RESPONSE +#undef ANALOG_MAPPING_RESPONSE +#endif +#define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info + +#ifdef SAMPLING_INTERVAL +#undef SAMPLING_INTERVAL +#endif +#define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop + +#ifdef SCHEDULER_DATA +#undef SCHEDULER_DATA +#endif +#define SCHEDULER_DATA 0x7B // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler + +#ifdef SYSEX_NON_REALTIME +#undef SYSEX_NON_REALTIME +#endif +#define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages + +#ifdef SYSEX_REALTIME +#undef SYSEX_REALTIME +#endif +#define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages + +// pin modes + +#ifdef PIN_MODE_INPUT +#undef PIN_MODE_INPUT +#endif +#define PIN_MODE_INPUT 0x00 // same as INPUT defined in Arduino.h + +#ifdef PIN_MODE_OUTPUT +#undef PIN_MODE_OUTPUT +#endif +#define PIN_MODE_OUTPUT 0x01 // same as OUTPUT defined in Arduino.h + +#ifdef PIN_MODE_ANALOG +#undef PIN_MODE_ANALOG +#endif +#define PIN_MODE_ANALOG 0x02 // analog pin in analogInput mode + +#ifdef PIN_MODE_PWM +#undef PIN_MODE_PWM +#endif +#define PIN_MODE_PWM 0x03 // digital pin in PWM output mode + +#ifdef PIN_MODE_SERVO +#undef PIN_MODE_SERVO +#endif +#define PIN_MODE_SERVO 0x04 // digital pin in Servo output mode + +#ifdef PIN_MODE_SHIFT +#undef PIN_MODE_SHIFT +#endif +#define PIN_MODE_SHIFT 0x05 // shiftIn/shiftOut mode + +#ifdef PIN_MODE_I2C +#undef PIN_MODE_I2C +#endif +#define PIN_MODE_I2C 0x06 // pin included in I2C setup + +#ifdef PIN_MODE_ONEWIRE +#undef PIN_MODE_ONEWIRE +#endif +#define PIN_MODE_ONEWIRE 0x07 // pin configured for 1-wire + +#ifdef PIN_MODE_STEPPER +#undef PIN_MODE_STEPPER +#endif +#define PIN_MODE_STEPPER 0x08 // pin configured for stepper motor + +#ifdef PIN_MODE_ENCODER +#undef PIN_MODE_ENCODER +#endif +#define PIN_MODE_ENCODER 0x09 // pin configured for rotary encoders + +#ifdef PIN_MODE_SERIAL +#undef PIN_MODE_SERIAL +#endif +#define PIN_MODE_SERIAL 0x0A // pin configured for serial communication + +#ifdef PIN_MODE_PULLUP +#undef PIN_MODE_PULLUP +#endif +#define PIN_MODE_PULLUP 0x0B // enable internal pull-up resistor for pin + +#ifdef PIN_MODE_IGNORE +#undef PIN_MODE_IGNORE +#endif +#define PIN_MODE_IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse + +#ifdef TOTAL_PIN_MODES +#undef TOTAL_PIN_MODES +#endif +#define TOTAL_PIN_MODES 13 + +#endif // FirmataConstants_h diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp new file mode 100644 index 00000000..88500358 --- /dev/null +++ b/FirmataMarshaller.cpp @@ -0,0 +1,165 @@ +/* + Firmata.cpp - Firmata library v2.5.4 - 2016-10-23 + Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (C) 2009-2016 Jeff Hoefs. 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. + + See file LICENSE.txt for further informations on licensing terms. +*/ + +//****************************************************************************** +//* Includes +//****************************************************************************** + +#include "FirmataMarshaller.h" + +#if defined(__cplusplus) && !defined(ARDUINO) + #include +#else + #include +#endif + +//****************************************************************************** +//* Support Functions +//****************************************************************************** + +/** + * Split a 16-bit integer into two 7-bit values and write each value. + * @param value The 16-bit value to be split and written separately. + */ +void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value) +{ + FirmataStream->write(value & 0x7F); // LSB + FirmataStream->write(value >> 7 & 0x7F); // MSB +} + +//****************************************************************************** +//* Constructors +//****************************************************************************** + +/** + * The FirmataMarshaller class. + */ +FirmataMarshaller::FirmataMarshaller() +: + FirmataStream((Stream *)NULL) +{ +} + +//****************************************************************************** +//* Public Methods +//****************************************************************************** + +/** + * Reassign the Firmata stream transport. + * @param s A reference to the Stream transport object. This can be any type of + * transport that implements the Stream interface. Some examples include Ethernet, WiFi + * and other UARTs on the board (Serial1, Serial2, etc). + */ +void FirmataMarshaller::begin(Stream &s) +{ + FirmataStream = &s; +} + +/** + * Closes the FirmataMarshaller stream by setting its stream reference to `(Stream *)NULL` + */ +void FirmataMarshaller::end(void) +{ + FirmataStream = (Stream *)NULL; +} + +//****************************************************************************** +//* Output Stream Handling +//****************************************************************************** + +/** + * Send an analog message to the Firmata host application. The range of pins is limited to [0..15] + * when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits + * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG + * message. + * @param pin The analog pin to send the value of (limited to pins 0 - 15). + * @param value The value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc). + * The maximum value is 14-bits (16384). + */ +void FirmataMarshaller::sendAnalog(uint8_t pin, uint16_t value) +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + // pin can only be 0-15, so chop higher bits + FirmataStream->write(ANALOG_MESSAGE | (pin & 0xF)); + sendValueAsTwo7bitBytes(value); +} + +/* (intentionally left out asterix here) + * STUB - NOT IMPLEMENTED + * Send a single digital pin value to the Firmata host application. + * @param pin The digital pin to send the value of. + * @param value The value of the pin. + */ +void FirmataMarshaller::sendDigital(uint8_t pin, uint16_t value) +{ + /* TODO add single pin digital messages to the protocol, this needs to + * track the last digital data sent so that it can be sure to change just + * one bit in the packet. This is complicated by the fact that the + * numbering of the pins will probably differ on Arduino, Wiring, and + * other boards. + */ + + // TODO: the digital message should not be sent on the serial port every + // time sendDigital() is called. Instead, it should add it to an int + // which will be sent on a schedule. If a pin changes more than once + // before the digital message is sent on the serial port, it should send a + // digital message for each change. + + // if(value == 0) + // sendDigitalPortPair(); +} + + +/** + * Send an 8-bit port in a single digital message (protocol v2 and later). + * Send 14-bits in a single digital message (protocol v1). + * @param portNumber The port number to send. Note that this is not the same as a "port" on the + * physical microcontroller. Ports are defined in order per every 8 pins in ascending order + * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. + * @param portData The value of the port. The value of each pin in the port is represented by a bit. + */ +void FirmataMarshaller::sendDigitalPort(uint8_t portNumber, uint16_t portData) +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); + FirmataStream->write((uint8_t)portData % 128); // Tx bits 0-6 (protocol v1 and higher) + FirmataStream->write(portData >> 7); // Tx bits 7-13 (bit 7 only for protocol v2 and higher) +} + +/** + * Send a sysex message where all values after the command byte are packet as 2 7-bit bytes + * (this is not always the case so this function is not always used to send sysex messages). + * @param command The sysex command byte. + * @param bytec The number of data bytes in the message (excludes start, command and end bytes). + * @param bytev A pointer to the array of data bytes to send in the message. + */ +void FirmataMarshaller::sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + size_t i; + FirmataStream->write(START_SYSEX); + FirmataStream->write(command); + for (i = 0; i < bytec; ++i) { + sendValueAsTwo7bitBytes(bytev[i]); + } + FirmataStream->write(END_SYSEX); +} + +/** + * Send a string to the Firmata host application. + * @param string A pointer to the char string + */ +void FirmataMarshaller::sendString(const char *string) +{ + sendSysex(STRING_DATA, strlen(string), (uint8_t *)string); +} diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h new file mode 100644 index 00000000..71ad888e --- /dev/null +++ b/FirmataMarshaller.h @@ -0,0 +1,55 @@ +/* + Firmata.h - Firmata library v2.5.4 - 2016-10-23 + Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (C) 2009-2016 Jeff Hoefs. 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. + + See file LICENSE.txt for further informations on licensing terms. +*/ + +#ifndef FirmataMarshaller_h +#define FirmataMarshaller_h + +#if defined(__cplusplus) && !defined(ARDUINO) + #include + #include +#else + #include + #include +#endif + +#include + +#include "FirmataConstants.h" + +class FirmataMarshaller +{ + friend class FirmataClass; + public: + /* constructors */ + FirmataMarshaller(); + + /* public methods */ + void begin(Stream &s); + void end(); + + /* serial send handling */ + void sendAnalog(uint8_t pin, uint16_t value); + void sendDigital(uint8_t pin, uint16_t value); + void sendDigitalPort(uint8_t portNumber, uint16_t portData); + void sendString(const char *string); + void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev); + + private: + /* utility methods */ + void sendValueAsTwo7bitBytes(uint16_t value); + + Stream *FirmataStream; +}; + +#endif /* FirmataMarshaller_h */ + From 5668cfca5e93aab88a4be89b46313ba9376f6969 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 6 Nov 2016 22:09:58 -0800 Subject: [PATCH 047/110] Update FirmataClass to use FirmataMarshaller --- Firmata.cpp | 34 +++++++------------- Firmata.h | 44 +++----------------------- FirmataParser.h | 82 +------------------------------------------------ 3 files changed, 16 insertions(+), 144 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index ff7f8429..3a55d538 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -47,8 +47,7 @@ void printFirmwareVersion (void) { */ void FirmataClass::sendValueAsTwo7bitBytes(int value) { - FirmataStream->write(value & 0x7F); // LSB - FirmataStream->write(value >> 7 & 0x7F); // MSB + marshaller.sendValueAsTwo7bitBytes(value); } /** @@ -106,10 +105,8 @@ void FirmataClass::begin(void) void FirmataClass::begin(long speed) { Serial.begin(speed); - FirmataStream = &Serial; blinkVersion(); - printVersion(); // send the protocol version - printFirmwareVersion(); // send the firmware name and version + begin(Serial); } /** @@ -121,10 +118,11 @@ void FirmataClass::begin(long speed) void FirmataClass::begin(Stream &s) { FirmataStream = &s; + marshaller.begin(s); // do not call blinkVersion() here because some hardware such as the // Ethernet shield use pin 13 - printVersion(); - printFirmwareVersion(); + printVersion(); // send the protocol version + printFirmwareVersion(); // send the firmware name and version } /** @@ -182,7 +180,7 @@ void FirmataClass::printFirmwareVersion(void) FirmataStream->write(firmwareVersionVector[0]); // major version number FirmataStream->write(firmwareVersionVector[1]); // minor version number for (i = 2; i < firmwareVersionCount; ++i) { - sendValueAsTwo7bitBytes(firmwareVersionVector[i]); + marshaller.sendValueAsTwo7bitBytes(firmwareVersionVector[i]); } endSysex(); } @@ -285,9 +283,7 @@ boolean FirmataClass::isParsingMessage(void) */ void FirmataClass::sendAnalog(byte pin, int value) { - // pin can only be 0-15, so chop higher bits - FirmataStream->write(ANALOG_MESSAGE | (pin & 0xF)); - sendValueAsTwo7bitBytes(value); + marshaller.sendAnalog(pin, value); } /* (intentionally left out asterix here) @@ -326,9 +322,7 @@ void FirmataClass::sendDigital(byte pin, int value) */ void FirmataClass::sendDigitalPort(byte portNumber, int portData) { - FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); - FirmataStream->write((byte)portData % 128); // Tx bits 0-6 (protocol v1 and higher) - FirmataStream->write(portData >> 7); // Tx bits 7-13 (bit 7 only for protocol v2 and higher) + marshaller.sendDigitalPort(portNumber, portData); } /** @@ -340,13 +334,7 @@ void FirmataClass::sendDigitalPort(byte portNumber, int portData) */ void FirmataClass::sendSysex(byte command, byte bytec, byte *bytev) { - byte i; - startSysex(); - FirmataStream->write(command); - for (i = 0; i < bytec; i++) { - sendValueAsTwo7bitBytes(bytev[i]); - } - endSysex(); + marshaller.sendSysex(command, bytec, bytev); } /** @@ -357,7 +345,7 @@ void FirmataClass::sendSysex(byte command, byte bytec, byte *bytev) void FirmataClass::sendString(byte command, const char *string) { if (command == STRING_DATA) { - sendSysex(command, strlen(string), (byte *)string); + marshaller.sendString(string); } } @@ -367,7 +355,7 @@ void FirmataClass::sendString(byte command, const char *string) */ void FirmataClass::sendString(const char *string) { - sendString(STRING_DATA, string); + marshaller.sendString(string); } /** diff --git a/Firmata.h b/Firmata.h index 9fba25bd..1d35767b 100644 --- a/Firmata.h +++ b/Firmata.h @@ -15,16 +15,10 @@ #define Firmata_h #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */ +#include "FirmataConstants.h" +#include "FirmataMarshaller.h" #include "FirmataParser.h" -/* Version numbers for the Firmata library. - * The firmware version will not always equal the protocol version going forward. - * Query using the REPORT_FIRMWARE message. - */ -#define FIRMATA_FIRMWARE_MAJOR_VERSION 2 -#define FIRMATA_FIRMWARE_MINOR_VERSION 5 -#define FIRMATA_FIRMWARE_BUGFIX_VERSION 4 - /* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for * the protocol version and the firmware version. */ @@ -34,26 +28,6 @@ // extended command set using sysex (0-127/0x00-0x7F) /* 0x00-0x0F reserved for user-defined commands */ -#define SERIAL_MESSAGE 0x60 // communicate with serial devices, including other boards -#define ENCODER_DATA 0x61 // reply with encoders current positions -#define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq -#define STEPPER_DATA 0x72 // control a stepper motor -#define ONEWIRE_DATA 0x73 // send an OneWire read/write/reset/select/skip/search request -#define SHIFT_DATA 0x75 // a bitstream to/from a shift register -#define I2C_REQUEST 0x76 // send an I2C read/write request -#define I2C_REPLY 0x77 // a reply to an I2C read request -#define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins -#define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin -#define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value -#define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value -#define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins -#define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution -#define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers -#define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info -#define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop -#define SCHEDULER_DATA 0x7B // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler -#define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages -#define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages // these are DEPRECATED to make the naming more consistent #define FIRMATA_STRING 0x71 // same as STRING_DATA #define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST @@ -63,18 +37,6 @@ // pin modes //#define INPUT 0x00 // defined in Arduino.h //#define OUTPUT 0x01 // defined in Arduino.h -#define PIN_MODE_ANALOG 0x02 // analog pin in analogInput mode -#define PIN_MODE_PWM 0x03 // digital pin in PWM output mode -#define PIN_MODE_SERVO 0x04 // digital pin in Servo output mode -#define PIN_MODE_SHIFT 0x05 // shiftIn/shiftOut mode -#define PIN_MODE_I2C 0x06 // pin included in I2C setup -#define PIN_MODE_ONEWIRE 0x07 // pin configured for 1-wire -#define PIN_MODE_STEPPER 0x08 // pin configured for stepper motor -#define PIN_MODE_ENCODER 0x09 // pin configured for rotary encoders -#define PIN_MODE_SERIAL 0x0A // pin configured for serial communication -#define PIN_MODE_PULLUP 0x0B // enable internal pull-up resistor for pin -#define PIN_MODE_IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse -#define TOTAL_PIN_MODES 13 // DEPRECATED as of Firmata v2.5 #define ANALOG 0x02 // same as PIN_MODE_ANALOG #define PWM 0x03 // same as PIN_MODE_PWM @@ -135,6 +97,7 @@ class FirmataClass void endSysex(void); private: + FirmataMarshaller marshaller; FirmataParser parser; Stream *FirmataStream; /* firmware name and version */ @@ -148,6 +111,7 @@ class FirmataClass /* private methods ------------------------------ */ void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); + friend void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value); }; extern FirmataClass Firmata; diff --git a/FirmataParser.h b/FirmataParser.h index 33fc88b3..f38179d9 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -22,87 +22,7 @@ #include #endif -/* Version numbers for the protocol. The protocol is still changing, so these - * version numbers are important. - * Query using the REPORT_VERSION message. - */ -#define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes -#define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes -#define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases - -#ifdef MAX_DATA_BYTES -#undef MAX_DATA_BYTES -#endif -#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages - -// message command bytes (128-255/0x80-0xFF) -#ifdef DIGITAL_MESSAGE -#undef DIGITAL_MESSAGE -#endif -#define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) - -#ifdef ANALOG_MESSAGE -#undef ANALOG_MESSAGE -#endif -#define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) - -#ifdef REPORT_ANALOG -#undef REPORT_ANALOG -#endif -#define REPORT_ANALOG 0xC0 // enable analog input by pin # - -#ifdef REPORT_DIGITAL -#undef REPORT_DIGITAL -#endif -#define REPORT_DIGITAL 0xD0 // enable digital input by port pair - -// - -#ifdef SET_PIN_MODE -#undef SET_PIN_MODE -#endif -#define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc - -#ifdef SET_DIGITAL_PIN_VALUE -#undef SET_DIGITAL_PIN_VALUE -#endif -#define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin - -// - -#ifdef REPORT_VERSION -#undef REPORT_VERSION -#endif -#define REPORT_VERSION 0xF9 // report protocol version - -#ifdef SYSTEM_RESET -#undef SYSTEM_RESET -#endif -#define SYSTEM_RESET 0xFF // reset from MIDI - -// - -#ifdef START_SYSEX -#undef START_SYSEX -#endif -#define START_SYSEX 0xF0 // start a MIDI Sysex message - -#ifdef END_SYSEX -#undef END_SYSEX -#endif -#define END_SYSEX 0xF7 // end a MIDI Sysex message - -// extended command set using sysex (0-127/0x00-0x7F) -/* 0x00-0x0F reserved for user-defined commands */ -#ifdef STRING_DATA -#undef STRING_DATA -#endif -#define STRING_DATA 0x71 // a string message with 14-bits per char - -#ifdef REPORT_FIRMWARE -#undef REPORT_FIRMWARE -#endif -#define REPORT_FIRMWARE 0x79 // report name and version of the firmware +#include "FirmataConstants.h" extern "C" { // callback function types From 94d007a4a8e758a71b1deb205a138c6444e34094 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Tue, 8 Nov 2016 22:52:50 -0800 Subject: [PATCH 048/110] Compiler optimizations for new classes --- Firmata.h | 2 +- FirmataMarshaller.cpp | 8 ++++++++ FirmataMarshaller.h | 14 ++++++-------- FirmataParser.cpp | 1 + FirmataParser.h | 2 +- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Firmata.h b/Firmata.h index 1d35767b..1d8608ed 100644 --- a/Firmata.h +++ b/Firmata.h @@ -111,7 +111,7 @@ class FirmataClass /* private methods ------------------------------ */ void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); - friend void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value); + friend void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value) const; }; extern FirmataClass Firmata; diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 88500358..4e05802b 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -23,6 +23,8 @@ #include #endif +#include "FirmataConstants.h" + //****************************************************************************** //* Support Functions //****************************************************************************** @@ -32,6 +34,7 @@ * @param value The 16-bit value to be split and written separately. */ void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value) +const { FirmataStream->write(value & 0x7F); // LSB FirmataStream->write(value >> 7 & 0x7F); // MSB @@ -87,6 +90,7 @@ void FirmataMarshaller::end(void) * The maximum value is 14-bits (16384). */ void FirmataMarshaller::sendAnalog(uint8_t pin, uint16_t value) +const { if ( (Stream *)NULL == FirmataStream ) { return; } // pin can only be 0-15, so chop higher bits @@ -101,6 +105,7 @@ void FirmataMarshaller::sendAnalog(uint8_t pin, uint16_t value) * @param value The value of the pin. */ void FirmataMarshaller::sendDigital(uint8_t pin, uint16_t value) +const { /* TODO add single pin digital messages to the protocol, this needs to * track the last digital data sent so that it can be sure to change just @@ -129,6 +134,7 @@ void FirmataMarshaller::sendDigital(uint8_t pin, uint16_t value) * @param portData The value of the port. The value of each pin in the port is represented by a bit. */ void FirmataMarshaller::sendDigitalPort(uint8_t portNumber, uint16_t portData) +const { if ( (Stream *)NULL == FirmataStream ) { return; } FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); @@ -144,6 +150,7 @@ void FirmataMarshaller::sendDigitalPort(uint8_t portNumber, uint16_t portData) * @param bytev A pointer to the array of data bytes to send in the message. */ void FirmataMarshaller::sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) +const { if ( (Stream *)NULL == FirmataStream ) { return; } size_t i; @@ -160,6 +167,7 @@ void FirmataMarshaller::sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) * @param string A pointer to the char string */ void FirmataMarshaller::sendString(const char *string) +const { sendSysex(STRING_DATA, strlen(string), (uint8_t *)string); } diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 71ad888e..8d7fb6e4 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -24,8 +24,6 @@ #include -#include "FirmataConstants.h" - class FirmataMarshaller { friend class FirmataClass; @@ -38,15 +36,15 @@ class FirmataMarshaller void end(); /* serial send handling */ - void sendAnalog(uint8_t pin, uint16_t value); - void sendDigital(uint8_t pin, uint16_t value); - void sendDigitalPort(uint8_t portNumber, uint16_t portData); - void sendString(const char *string); - void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev); + void sendAnalog(uint8_t pin, uint16_t value) const; + void sendDigital(uint8_t pin, uint16_t value) const; + void sendDigitalPort(uint8_t portNumber, uint16_t portData) const; + void sendString(const char *string) const; + void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) const; private: /* utility methods */ - void sendValueAsTwo7bitBytes(uint16_t value); + void sendValueAsTwo7bitBytes(uint16_t value) const; Stream *FirmataStream; }; diff --git a/FirmataParser.cpp b/FirmataParser.cpp index ad0ac2df..0d053d14 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -192,6 +192,7 @@ void FirmataParser::parse(uint8_t inputData) * @return Returns true if the parser is actively parsing data. */ bool FirmataParser::isParsingMessage(void) +const { return (waitForData > 0 || parsingSysex); } diff --git a/FirmataParser.h b/FirmataParser.h index f38179d9..ed1a8aa7 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -38,7 +38,7 @@ class FirmataParser FirmataParser(); /* serial receive handling */ void parse(uint8_t value); - bool isParsingMessage(void); + bool isParsingMessage(void) const; /* attach & detach callback functions to messages */ void attach(uint8_t command, callbackFunction newFunction); void attach(uint8_t command, systemCallbackFunction newFunction); From 6463281413c16f0bc66b96b5445be3b983e6e88a Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Tue, 15 Nov 2016 20:54:15 -0800 Subject: [PATCH 049/110] Abstract FirmataParser memory allocation scheme --- Firmata.cpp | 2 + Firmata.h | 1 + FirmataParser.cpp | 234 +++++++++++++++++++++++++++++++--------------- FirmataParser.h | 17 +++- 4 files changed, 175 insertions(+), 79 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 3a55d538..9846e4a7 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -75,6 +75,8 @@ void FirmataClass::endSysex(void) * An instance named "Firmata" is created automatically for the user. */ FirmataClass::FirmataClass() +: + parser(FirmataParser(parserBuffer, MAX_DATA_BYTES)) { firmwareVersionCount = 0; firmwareVersionVector = 0; diff --git a/Firmata.h b/Firmata.h index 1d8608ed..3b56c5a6 100644 --- a/Firmata.h +++ b/Firmata.h @@ -97,6 +97,7 @@ class FirmataClass void endSysex(void); private: + uint8_t parserBuffer[MAX_DATA_BYTES]; FirmataMarshaller marshaller; FirmataParser parser; Stream *FirmataStream; diff --git a/FirmataParser.cpp b/FirmataParser.cpp index 0d053d14..d39a0aa1 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -17,33 +17,41 @@ #include "FirmataParser.h" +#include "FirmataConstants.h" + //****************************************************************************** //* Constructors //****************************************************************************** /** - * The Firmata class. - * An instance named "Firmata" is created automatically for the user. + * The FirmataParser class. + * @param dataBuffer A pointer to an external buffer used to store parsed data + * @param dataBufferSize The size of the external buffer */ -FirmataParser::FirmataParser() +FirmataParser::FirmataParser(uint8_t * const dataBuffer, size_t dataBufferSize) : - executeMultiByteCommand(0), - multiByteChannel(0), - waitForData(0), - parsingSysex(false), - sysexBytesRead(0), - currentAnalogCallback((callbackFunction)NULL), - currentDigitalCallback((callbackFunction)NULL), - currentReportAnalogCallback((callbackFunction)NULL), - currentReportDigitalCallback((callbackFunction)NULL), - currentPinModeCallback((callbackFunction)NULL), - currentPinValueCallback((callbackFunction)NULL), - currentReportFirmwareCallback((systemCallbackFunction)NULL), - currentReportVersionCallback((systemCallbackFunction)NULL), - currentSystemResetCallback((systemCallbackFunction)NULL), - currentStringCallback((stringCallbackFunction)NULL), - currentSysexCallback((sysexCallbackFunction)NULL) + dataBuffer(dataBuffer), + dataBufferSize(dataBufferSize), + executeMultiByteCommand(0), + multiByteChannel(0), + waitForData(0), + parsingSysex(false), + sysexBytesRead(0), + currentDataBufferOverflowCallbackContext((void *)NULL), + currentAnalogCallback((callbackFunction)NULL), + currentDigitalCallback((callbackFunction)NULL), + currentReportAnalogCallback((callbackFunction)NULL), + currentReportDigitalCallback((callbackFunction)NULL), + currentPinModeCallback((callbackFunction)NULL), + currentPinValueCallback((callbackFunction)NULL), + currentReportFirmwareCallback((systemCallbackFunction)NULL), + currentReportVersionCallback((systemCallbackFunction)NULL), + currentSystemResetCallback((systemCallbackFunction)NULL), + currentStringCallback((stringCallbackFunction)NULL), + currentSysexCallback((sysexCallbackFunction)NULL), + currentDataBufferOverflowCallback((dataBufferOverflowCallbackFunction)NULL) { + allowBufferUpdate = ((uint8_t *)NULL == dataBuffer); } //****************************************************************************** @@ -53,47 +61,6 @@ FirmataParser::FirmataParser() //------------------------------------------------------------------------------ // Serial Receive Handling -/** - * Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally. - * Calls callback function for STRING_DATA and all other sysex messages. - * @private - */ -void FirmataParser::processSysexMessage(void) -{ - switch (storedInputData[0]) { //first byte in buffer is command - case REPORT_FIRMWARE: - if (currentReportFirmwareCallback) - (*currentReportFirmwareCallback)(); - break; - case STRING_DATA: - if (currentStringCallback) { - size_t bufferLength = (sysexBytesRead - 1) / 2; - size_t i = 1; - size_t j = 0; - while (j < bufferLength) { - // The string length will only be at most half the size of the - // stored input buffer so we can decode the string within the buffer. - storedInputData[j] = storedInputData[i]; - i++; - storedInputData[j] += (storedInputData[i] << 7); - i++; - j++; - } - // Make sure string is null terminated. This may be the case for data - // coming from client libraries in languages that don't null terminate - // strings. - if (storedInputData[j - 1] != '\0') { - storedInputData[j] = '\0'; - } - (*currentStringCallback)((char *)&storedInputData[0]); - } - break; - default: - if (currentSysexCallback) - (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); - } -} - /** * Parse data from the input stream. * @param inputData A single byte to be added to the parser. @@ -110,43 +77,43 @@ void FirmataParser::parse(uint8_t inputData) processSysexMessage(); } else { //normal data byte - add to buffer - storedInputData[sysexBytesRead] = inputData; - sysexBytesRead++; + bufferDataAtPosition(inputData, sysexBytesRead); + ++sysexBytesRead; } } else if ( (waitForData > 0) && (inputData < 128) ) { - waitForData--; - storedInputData[waitForData] = inputData; + --waitForData; + bufferDataAtPosition(inputData, waitForData); if ( (waitForData == 0) && executeMultiByteCommand ) { // got the whole message switch (executeMultiByteCommand) { case ANALOG_MESSAGE: if (currentAnalogCallback) { (*currentAnalogCallback)(multiByteChannel, - (storedInputData[0] << 7) - + storedInputData[1]); + (dataBuffer[0] << 7) + + dataBuffer[1]); } break; case DIGITAL_MESSAGE: if (currentDigitalCallback) { (*currentDigitalCallback)(multiByteChannel, - (storedInputData[0] << 7) - + storedInputData[1]); + (dataBuffer[0] << 7) + + dataBuffer[1]); } break; case SET_PIN_MODE: if (currentPinModeCallback) - (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); + (*currentPinModeCallback)(dataBuffer[1], dataBuffer[0]); break; case SET_DIGITAL_PIN_VALUE: if (currentPinValueCallback) - (*currentPinValueCallback)(storedInputData[1], storedInputData[0]); + (*currentPinValueCallback)(dataBuffer[1], dataBuffer[0]); break; case REPORT_ANALOG: if (currentReportAnalogCallback) - (*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]); + (*currentReportAnalogCallback)(multiByteChannel, dataBuffer[0]); break; case REPORT_DIGITAL: if (currentReportDigitalCallback) - (*currentReportDigitalCallback)(multiByteChannel, storedInputData[0]); + (*currentReportDigitalCallback)(multiByteChannel, dataBuffer[0]); break; } executeMultiByteCommand = 0; @@ -197,6 +164,31 @@ const return (waitForData > 0 || parsingSysex); } +/** + * Provides a mechanism to either set or update the working buffer of the parser. + * The method will be enabled when no buffer has been provided, or an overflow + * condition exists. + * @param dataBuffer A pointer to an external buffer used to store parsed data + * @param dataBufferSize The size of the external buffer + */ +int FirmataParser::setDataBufferOfSize(uint8_t * dataBuffer, size_t dataBufferSize) +{ + int result; + + if ( !allowBufferUpdate ) { + result = __LINE__; + } else if ((uint8_t *)NULL == dataBuffer) { + result = __LINE__; + } else { + this->dataBuffer = dataBuffer; + this->dataBufferSize = dataBufferSize; + allowBufferUpdate = false; + result = 0; + } + + return result; +} + /** * Attach a generic sysex callback function to a command (options are: ANALOG_MESSAGE, * DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE). @@ -249,9 +241,21 @@ void FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction) */ void FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction) { + (void)command; currentSysexCallback = newFunction; } +/** + * Attach a buffer overflow callback + * @param newFunction A reference to the buffer overflow callback function to attach. + * @param context The context supplied by the end-user, and provided during the execution of the callback + */ +void FirmataParser::attach(dataBufferOverflowCallbackFunction newFunction, void * context) +{ + currentDataBufferOverflowCallback = newFunction; + currentDataBufferOverflowCallbackContext = context; +} + /** * Detach a callback function for a specified command (such as SYSTEM_RESET, STRING_DATA, * ANALOG_MESSAGE, DIGITAL_MESSAGE, etc). @@ -272,10 +276,91 @@ void FirmataParser::detach(uint8_t command) } } +/** + * Detach the buffer overflow callback + * @param Any pointer of type dataBufferOverflowCallbackFunction. + */ +void FirmataParser::detach(dataBufferOverflowCallbackFunction) +{ + currentDataBufferOverflowCallback = (dataBufferOverflowCallbackFunction)NULL; + currentDataBufferOverflowCallbackContext = (void *)NULL; +} + //****************************************************************************** //* Private Methods //****************************************************************************** +/** + * Buffer abstraction to prevent memory corruption + * @param data The byte to put into the buffer + * @param pos The position to insert the byte into the buffer + * @return writeError A boolean to indicate if an error occured + * @private + */ +bool FirmataParser::bufferDataAtPosition(const uint8_t data, const size_t pos) +{ + bool bufferOverflow = (pos >= dataBufferSize); + + // Notify of overflow condition + if ( bufferOverflow + && ((dataBufferOverflowCallbackFunction)NULL != currentDataBufferOverflowCallback) ) + { + allowBufferUpdate = true; + currentDataBufferOverflowCallback(currentDataBufferOverflowCallbackContext); + // Check if overflow was resolved during callback + bufferOverflow = (pos >= dataBufferSize); + } + + // Write data to buffer if no overflow condition persist + if ( !bufferOverflow ) + { + dataBuffer[pos] = data; + } + + return bufferOverflow; +} + +/** + * Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally. + * Calls callback function for STRING_DATA and all other sysex messages. + * @private + */ +void FirmataParser::processSysexMessage(void) +{ + switch (dataBuffer[0]) { //first byte in buffer is command + case REPORT_FIRMWARE: + if (currentReportFirmwareCallback) + (*currentReportFirmwareCallback)(); + break; + case STRING_DATA: + if (currentStringCallback) { + size_t bufferLength = (sysexBytesRead - 1) / 2; + size_t i = 1; + size_t j = 0; + while (j < bufferLength) { + // The string length will only be at most half the size of the + // stored input buffer so we can decode the string within the buffer. + bufferDataAtPosition(dataBuffer[i], j); + ++i; + bufferDataAtPosition((dataBuffer[j] + (dataBuffer[i] << 7)), j); + ++i; + ++j; + } + // Make sure string is null terminated. This may be the case for data + // coming from client libraries in languages that don't null terminate + // strings. + if (dataBuffer[j - 1] != '\0') { + bufferDataAtPosition('\0', j); + } + (*currentStringCallback)((char *)&dataBuffer[0]); + } + break; + default: + if (currentSysexCallback) + (*currentSysexCallback)(dataBuffer[0], sysexBytesRead - 1, dataBuffer + 1); + } +} + /** * Resets the system state upon a SYSTEM_RESET message from the host software. * @private @@ -288,8 +373,8 @@ void FirmataParser::systemReset(void) executeMultiByteCommand = 0; // execute this after getting multi-byte data multiByteChannel = 0; // channel data for multiByteCommands - for (i = 0; i < MAX_DATA_BYTES; i++) { - storedInputData[i] = 0; + for (i = 0; i < dataBufferSize; ++i) { + dataBuffer[i] = 0; } parsingSysex = false; @@ -298,4 +383,3 @@ void FirmataParser::systemReset(void) if (currentSystemResetCallback) (*currentSystemResetCallback)(); } - diff --git a/FirmataParser.h b/FirmataParser.h index ed1a8aa7..1fb57d87 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -22,10 +22,9 @@ #include #endif -#include "FirmataConstants.h" - extern "C" { // callback function types + typedef void (*dataBufferOverflowCallbackFunction)(void * context); typedef void (*callbackFunction)(uint8_t, int); typedef void (*systemCallbackFunction)(void); typedef void (*stringCallbackFunction)(char *); @@ -35,27 +34,35 @@ extern "C" { class FirmataParser { public: - FirmataParser(); + FirmataParser(uint8_t * dataBuffer = (uint8_t *)NULL, size_t dataBufferSize = 0); /* serial receive handling */ void parse(uint8_t value); bool isParsingMessage(void) const; + int setDataBufferOfSize(uint8_t * dataBuffer, size_t dataBufferSize); /* attach & detach callback functions to messages */ void attach(uint8_t command, callbackFunction newFunction); void attach(uint8_t command, systemCallbackFunction newFunction); void attach(uint8_t command, stringCallbackFunction newFunction); void attach(uint8_t command, sysexCallbackFunction newFunction); + void attach(dataBufferOverflowCallbackFunction newFunction, void * context); void detach(uint8_t command); + void detach(dataBufferOverflowCallbackFunction); private: /* input message handling */ + bool allowBufferUpdate; + uint8_t * dataBuffer; // multi-byte data + size_t dataBufferSize; uint8_t executeMultiByteCommand; // execute this after getting multi-byte data uint8_t multiByteChannel; // channel data for multiByteCommands - uint8_t storedInputData[MAX_DATA_BYTES]; // multi-byte data size_t waitForData; // this flag says the next serial input will be data /* sysex */ bool parsingSysex; size_t sysexBytesRead; + /* callback context */ + void * currentDataBufferOverflowCallbackContext; + /* callback functions */ callbackFunction currentAnalogCallback; callbackFunction currentDigitalCallback; @@ -68,10 +75,12 @@ class FirmataParser systemCallbackFunction currentSystemResetCallback; stringCallbackFunction currentStringCallback; sysexCallbackFunction currentSysexCallback; + dataBufferOverflowCallbackFunction currentDataBufferOverflowCallback; /* private methods ------------------------------ */ void processSysexMessage(void); void systemReset(void); + bool bufferDataAtPosition(const uint8_t data, const size_t pos); }; #endif /* FirmataParser_h */ From bebfe5dbca945a51580019d2a5594f003b7db18b Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 2 Dec 2016 09:32:02 -0500 Subject: [PATCH 050/110] Add cast for compatibility with the next version of CurieBLE --- utility/BLEStream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 731a4318..56b36488 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -118,7 +118,7 @@ bool BLEStream::poll() void BLEStream::end() { - this->_rxCharacteristic.setEventHandler(BLEWritten, NULL); + this->_rxCharacteristic.setEventHandler(BLEWritten, (void(*)(BLECentral&, BLECharacteristic&))NULL); this->_rxHead = this->_rxTail = 0; flush(); BLEPeripheral::disconnect(); From 999f95f1c4a88df665fe9c24ccc6e56469862be0 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Wed, 14 Dec 2016 13:26:13 -0500 Subject: [PATCH 051/110] Add support for Arduino MKRZero --- Boards.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Boards.h b/Boards.h index 218a8dd5..9e9ffdac 100644 --- a/Boards.h +++ b/Boards.h @@ -260,6 +260,23 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) // deprecated since v2.4 +// Arduino MKRZero +#elif defined(ARDUINO_SAMD_MKRZERO) +#define TOTAL_ANALOG_PINS 7 +#define TOTAL_PINS 34 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog + 3 usb + 1 aref + 5 sd + 1 bottom pad + 1 led + 1 battery adc +#define IS_PIN_DIGITAL(p) ((((p) >= 0 && (p) <= 21) || (p) == 32) && !IS_PIN_SERIAL(p)) +#define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 33) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14 +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 15) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 + + // Arduino Zero // Note this will work with an Arduino Zero Pro, but not with an Arduino M0 Pro // Arduino M0 Pro does not properly map pins to the board labeled pin numbers From 74df9031ee2574fd431b17aa89625a488e627dd6 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 11 Nov 2016 18:56:01 -0800 Subject: [PATCH 052/110] Add FirmataMarshaller::sendCapabilityQuery --- FirmataMarshaller.cpp | 11 +++++++++++ FirmataMarshaller.h | 1 + 2 files changed, 12 insertions(+) diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 4e05802b..9054254e 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -98,6 +98,17 @@ const sendValueAsTwo7bitBytes(value); } +/** + * Send a capability query to the Firmata host application. The resulting sysex message will have + * a CAPABILITY_RESPONSE command byte, followed by a list of byte tuples (mode and mode resolution) + * for each pin; where each pin list is terminated by 0x7F (128). + */ +void FirmataMarshaller::sendCapabilityQuery(void) +const +{ + sendSysex(CAPABILITY_QUERY, 0, NULL); +} + /* (intentionally left out asterix here) * STUB - NOT IMPLEMENTED * Send a single digital pin value to the Firmata host application. diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 8d7fb6e4..1a3edb78 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -37,6 +37,7 @@ class FirmataMarshaller /* serial send handling */ void sendAnalog(uint8_t pin, uint16_t value) const; + void sendCapabilityQuery(void) const; void sendDigital(uint8_t pin, uint16_t value) const; void sendDigitalPort(uint8_t portNumber, uint16_t portData) const; void sendString(const char *string) const; From 34ecce380268edd9331678e588683796b6e7e61a Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 2 Feb 2017 08:49:24 -0800 Subject: [PATCH 053/110] Support Firmata's core functionality Core functionality as described by the protocol https://github.com/firmata/protocol/blob/master/protocol.md#message-types Provided contextual callbacks to FirmataParser to allow multiple instances to run simultaneously. --- Firmata.cpp | 89 +++++++++++++++++++++++------ Firmata.h | 49 ++++++++++++++-- FirmataMarshaller.cpp | 130 ++++++++++++++++++++++++++++++++++++------ FirmataMarshaller.h | 11 +++- FirmataParser.cpp | 119 +++++++++++++++++++++++++++----------- FirmataParser.h | 44 ++++++++------ 6 files changed, 353 insertions(+), 89 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 9846e4a7..4b43362c 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -29,13 +29,16 @@ extern "C" { // make one instance for the user to use FirmataClass Firmata; -void printVersion (void) { - Firmata.printVersion(); -} - -void printFirmwareVersion (void) { - Firmata.printFirmwareVersion(); -} +/* callback functions */ +callbackFunction FirmataClass::currentAnalogCallback = (callbackFunction)NULL; +callbackFunction FirmataClass::currentDigitalCallback = (callbackFunction)NULL; +callbackFunction FirmataClass::currentPinModeCallback = (callbackFunction)NULL; +callbackFunction FirmataClass::currentPinValueCallback = (callbackFunction)NULL; +callbackFunction FirmataClass::currentReportAnalogCallback = (callbackFunction)NULL; +callbackFunction FirmataClass::currentReportDigitalCallback = (callbackFunction)NULL; +stringCallbackFunction FirmataClass::currentStringCallback = (stringCallbackFunction)NULL; +sysexCallbackFunction FirmataClass::currentSysexCallback = (sysexCallbackFunction)NULL; +systemCallbackFunction FirmataClass::currentSystemResetCallback = (systemCallbackFunction)NULL; //****************************************************************************** //* Support Functions @@ -81,8 +84,19 @@ FirmataClass::FirmataClass() firmwareVersionCount = 0; firmwareVersionVector = 0; blinkVersionDisabled = false; - parser.attach(REPORT_FIRMWARE, ::printFirmwareVersion); - parser.attach(REPORT_VERSION, ::printVersion); + + // Establish callback translation to parser callbacks + parser.attach(ANALOG_MESSAGE, (FirmataParser::callbackFunction)staticAnalogCallback, (void *)NULL); + parser.attach(DIGITAL_MESSAGE, (FirmataParser::callbackFunction)staticDigitalCallback, (void *)NULL); + parser.attach(REPORT_ANALOG, (FirmataParser::callbackFunction)staticReportAnalogCallback, (void *)NULL); + parser.attach(REPORT_DIGITAL, (FirmataParser::callbackFunction)staticReportDigitalCallback, (void *)NULL); + parser.attach(SET_PIN_MODE, (FirmataParser::callbackFunction)staticPinModeCallback, (void *)NULL); + parser.attach(SET_DIGITAL_PIN_VALUE, (FirmataParser::callbackFunction)staticPinValueCallback, (void *)NULL); + parser.attach(STRING_DATA, (FirmataParser::stringCallbackFunction)staticStringCallback, (void *)NULL); + parser.attach(START_SYSEX, (FirmataParser::sysexCallbackFunction)staticSysexCallback, (void *)NULL); + parser.attach(REPORT_FIRMWARE, (FirmataParser::systemCallbackFunction)staticReportFirmwareCallback, this); + parser.attach(REPORT_VERSION, (FirmataParser::systemCallbackFunction)staticReportVersionCallback, this); + parser.attach(SYSTEM_RESET, (FirmataParser::systemCallbackFunction)staticSystemResetCallback, (void *)NULL); } //****************************************************************************** @@ -296,6 +310,8 @@ void FirmataClass::sendAnalog(byte pin, int value) */ void FirmataClass::sendDigital(byte pin, int value) { + (void)pin; + (void)value; /* TODO add single pin digital messages to the protocol, this needs to * track the last digital data sent so that it can be sure to change just * one bit in the packet. This is complicated by the fact that the @@ -376,9 +392,28 @@ void FirmataClass::write(byte c) * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the callback function to attach. */ -void FirmataClass::attach(uint8_t command, callbackFunction newFunction) -{ - parser.attach(command, (callbackFunction)newFunction); +void FirmataClass::attach(uint8_t command, ::callbackFunction newFunction) +{ + switch (command) { + case ANALOG_MESSAGE: + currentAnalogCallback = newFunction; + break; + case DIGITAL_MESSAGE: + currentDigitalCallback = newFunction; + break; + case REPORT_ANALOG: + currentReportAnalogCallback = newFunction; + break; + case REPORT_DIGITAL: + currentReportDigitalCallback = newFunction; + break; + case SET_PIN_MODE: + currentPinModeCallback = newFunction; + break; + case SET_DIGITAL_PIN_VALUE: + currentPinValueCallback = newFunction; + break; + } } /** @@ -388,7 +423,11 @@ void FirmataClass::attach(uint8_t command, callbackFunction newFunction) */ void FirmataClass::attach(uint8_t command, systemCallbackFunction newFunction) { - parser.attach(command, (systemCallbackFunction)newFunction); + switch (command) { + case SYSTEM_RESET: + currentSystemResetCallback = newFunction; + break; + } } /** @@ -398,7 +437,11 @@ void FirmataClass::attach(uint8_t command, systemCallbackFunction newFunction) */ void FirmataClass::attach(uint8_t command, stringCallbackFunction newFunction) { - parser.attach(command, (stringCallbackFunction)newFunction); + switch (command) { + case STRING_DATA: + currentStringCallback = newFunction; + break; + } } /** @@ -408,7 +451,8 @@ void FirmataClass::attach(uint8_t command, stringCallbackFunction newFunction) */ void FirmataClass::attach(uint8_t command, sysexCallbackFunction newFunction) { - parser.attach(command, (sysexCallbackFunction)newFunction); + (void)command; + currentSysexCallback = newFunction; } /** @@ -418,7 +462,20 @@ void FirmataClass::attach(uint8_t command, sysexCallbackFunction newFunction) */ void FirmataClass::detach(uint8_t command) { - parser.detach(command); + switch (command) { + case SYSTEM_RESET: + attach(command, (systemCallbackFunction)NULL); + break; + case STRING_DATA: + attach(command, (stringCallbackFunction)NULL); + break; + case START_SYSEX: + attach(command, (sysexCallbackFunction)NULL); + break; + default: + attach(command, (callbackFunction)NULL); + break; + } } /** diff --git a/Firmata.h b/Firmata.h index 3b56c5a6..f46e8198 100644 --- a/Firmata.h +++ b/Firmata.h @@ -48,27 +48,40 @@ #define ENCODER 0x09 // same as PIN_MODE_ENCODER #define IGNORE 0x7F // same as PIN_MODE_IGNORE +extern "C" { + // callback function types + typedef void (*callbackFunction)(uint8_t, int); + typedef void (*systemCallbackFunction)(void); + typedef void (*stringCallbackFunction)(char *); + typedef void (*sysexCallbackFunction)(uint8_t command, uint8_t argc, uint8_t *argv); +} + // TODO make it a subclass of a generic Serial/Stream base class class FirmataClass { public: FirmataClass(); + /* Arduino constructors */ void begin(); void begin(long); void begin(Stream &s); + /* querying functions */ void printVersion(void); void blinkVersion(void); void printFirmwareVersion(void); + //void setFirmwareVersion(byte major, byte minor); // see macro below void setFirmwareNameAndVersion(const char *name, byte major, byte minor); void disableBlinkVersion(); + /* serial receive handling */ int available(void); void processInput(void); void parse(unsigned char value); boolean isParsingMessage(void); + /* serial send handling */ void sendAnalog(byte pin, int value); void sendDigital(byte pin, int value); // TODO implement this @@ -77,16 +90,18 @@ class FirmataClass void sendString(byte command, const char *string); void sendSysex(byte command, byte bytec, byte *bytev); void write(byte c); + /* attach & detach callback functions to messages */ - void attach(uint8_t command, callbackFunction newFunction); - void attach(uint8_t command, systemCallbackFunction newFunction); - void attach(uint8_t command, stringCallbackFunction newFunction); - void attach(uint8_t command, sysexCallbackFunction newFunction); + void attach(uint8_t command, ::callbackFunction newFunction); + void attach(uint8_t command, ::systemCallbackFunction newFunction); + void attach(uint8_t command, ::stringCallbackFunction newFunction); + void attach(uint8_t command, ::sysexCallbackFunction newFunction); void detach(uint8_t command); /* access pin state and config */ byte getPinMode(byte pin); void setPinMode(byte pin, byte config); + /* access pin state */ int getPinState(byte pin); void setPinState(byte pin, int state); @@ -101,9 +116,11 @@ class FirmataClass FirmataMarshaller marshaller; FirmataParser parser; Stream *FirmataStream; + /* firmware name and version */ byte firmwareVersionCount; byte *firmwareVersionVector; + /* pin configuration */ byte pinConfig[TOTAL_PINS]; int pinState[TOTAL_PINS]; @@ -113,6 +130,30 @@ class FirmataClass /* private methods ------------------------------ */ void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); friend void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value) const; + + /* callback functions */ + static callbackFunction currentAnalogCallback; + static callbackFunction currentDigitalCallback; + static callbackFunction currentPinModeCallback; + static callbackFunction currentPinValueCallback; + static callbackFunction currentReportAnalogCallback; + static callbackFunction currentReportDigitalCallback; + static stringCallbackFunction currentStringCallback; + static sysexCallbackFunction currentSysexCallback; + static systemCallbackFunction currentSystemResetCallback; + + /* static callbacks */ + inline static void staticAnalogCallback (void *, uint8_t command, uint16_t value) { if ( currentAnalogCallback ) { currentAnalogCallback(command,(int)value); } } + inline static void staticDigitalCallback (void *, uint8_t command, uint16_t value) { if ( currentDigitalCallback ) { currentDigitalCallback(command, (int)value); } } + inline static void staticPinModeCallback (void *, uint8_t command, uint16_t value) { if ( currentPinModeCallback ) { currentPinModeCallback(command, (int)value); } } + inline static void staticPinValueCallback (void *, uint8_t command, uint16_t value) { if ( currentPinValueCallback ) { currentPinValueCallback(command, (int)value); } } + inline static void staticReportAnalogCallback (void *, uint8_t command, uint16_t value) { if ( currentReportAnalogCallback ) { currentReportAnalogCallback(command, (int)value); } } + inline static void staticReportDigitalCallback (void *, uint8_t command, uint16_t value) { if ( currentReportDigitalCallback ) { currentReportDigitalCallback(command, (int)value); } } + inline static void staticStringCallback (void *, char * c_str) { if ( currentStringCallback ) { currentStringCallback(c_str); } } + inline static void staticSysexCallback (void *, uint8_t command, size_t argc, uint8_t *argv) { if ( currentSysexCallback ) { currentSysexCallback(command, (uint8_t)argc, argv); } } + inline static void staticReportFirmwareCallback (void * context) { if ( context ) { ((FirmataClass *)context)->printFirmwareVersion(); } } + inline static void staticReportVersionCallback (void * context) { if ( context ) { ((FirmataClass *)context)->printVersion(); } } + inline static void staticSystemResetCallback (void *) { if ( currentSystemResetCallback ) { currentSystemResetCallback(); } } }; extern FirmataClass Firmata; diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 9054254e..0440af22 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -29,6 +29,40 @@ //* Support Functions //****************************************************************************** +/** + * Request or halt a stream of analog readings from the Firmata host application. The range of pins is + * limited to [0..15] when using the REPORT_ANALOG. The maximum result of the REPORT_ANALOG is limited to 14 bits + * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG + * message. + * @param pin The analog pin for which to request the value (limited to pins 0 - 15). + * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream + * @note The maximum resulting value is 14-bits (16384). + */ +void FirmataMarshaller::reportAnalog(uint8_t pin, bool stream_enable) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + // pin can only be 0-15, so chop higher bits + FirmataStream->write(REPORT_ANALOG | (pin & 0xF)); + FirmataStream->write(stream_enable); +} + +/** + * Request or halt an 8-bit port stream from the Firmata host application (protocol v2 and later). + * Send 14-bits in a single digital message (protocol v1). + * @param portNumber The port number for which to request the value. Note that this is not the same as a "port" on the + * physical microcontroller. Ports are defined in order per every 8 pins in ascending order + * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. + * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream + */ +void FirmataMarshaller::reportDigitalPort(uint8_t portNumber, bool stream_enable) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(REPORT_DIGITAL | (portNumber & 0xF)); + FirmataStream->write(stream_enable); +} + /** * Split a 16-bit integer into two 7-bit values and write each value. * @param value The 16-bit value to be split and written separately. @@ -80,6 +114,62 @@ void FirmataMarshaller::end(void) //* Output Stream Handling //****************************************************************************** +/** + * Halt the stream of analog readings from the Firmata host application. The range of pins is + * limited to [0..15] when using the REPORT_ANALOG. The maximum result of the REPORT_ANALOG is limited to 14 bits + * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG + * message. + * @param pin The analog pin for which to request the value (limited to pins 0 - 15). + */ +void FirmataMarshaller::reportAnalogDisable(uint8_t pin) +const +{ + reportAnalog(pin, false); +} + +/** + * Request a stream of analog readings from the Firmata host application. The range of pins is + * limited to [0..15] when using the REPORT_ANALOG. The maximum result of the REPORT_ANALOG is limited to 14 bits + * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG + * message. + * @param pin The analog pin for which to request the value (limited to pins 0 - 15). + * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream + * @note The maximum resulting value is 14-bits (16384). + */ +void FirmataMarshaller::reportAnalogEnable(uint8_t pin) +const +{ + reportAnalog(pin, true); +} + +/** + * Halt an 8-bit port stream from the Firmata host application (protocol v2 and later). + * Send 14-bits in a single digital message (protocol v1). + * @param portNumber The port number for which to request the value. Note that this is not the same as a "port" on the + * physical microcontroller. Ports are defined in order per every 8 pins in ascending order + * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. + * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream + */ +void FirmataMarshaller::reportDigitalPortDisable(uint8_t portNumber) +const +{ + reportDigitalPort(portNumber, false); +} + +/** + * Request an 8-bit port stream from the Firmata host application (protocol v2 and later). + * Send 14-bits in a single digital message (protocol v1). + * @param portNumber The port number for which to request the value. Note that this is not the same as a "port" on the + * physical microcontroller. Ports are defined in order per every 8 pins in ascending order + * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. + * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream + */ +void FirmataMarshaller::reportDigitalPortEnable(uint8_t portNumber) +const +{ + reportDigitalPort(portNumber, true); +} + /** * Send an analog message to the Firmata host application. The range of pins is limited to [0..15] * when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits @@ -109,30 +199,18 @@ const sendSysex(CAPABILITY_QUERY, 0, NULL); } -/* (intentionally left out asterix here) - * STUB - NOT IMPLEMENTED +/** * Send a single digital pin value to the Firmata host application. * @param pin The digital pin to send the value of. * @param value The value of the pin. */ -void FirmataMarshaller::sendDigital(uint8_t pin, uint16_t value) +void FirmataMarshaller::sendDigital(uint8_t pin, uint8_t value) const { - /* TODO add single pin digital messages to the protocol, this needs to - * track the last digital data sent so that it can be sure to change just - * one bit in the packet. This is complicated by the fact that the - * numbering of the pins will probably differ on Arduino, Wiring, and - * other boards. - */ - - // TODO: the digital message should not be sent on the serial port every - // time sendDigital() is called. Instead, it should add it to an int - // which will be sent on a schedule. If a pin changes more than once - // before the digital message is sent on the serial port, it should send a - // digital message for each change. - - // if(value == 0) - // sendDigitalPortPair(); + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(SET_DIGITAL_PIN_VALUE); + FirmataStream->write(pin & 0x7F); + FirmataStream->write(value != 0); } @@ -153,6 +231,22 @@ const FirmataStream->write(portData >> 7); // Tx bits 7-13 (bit 7 only for protocol v2 and higher) } +/** + * Send the pin mode/configuration. The pin configuration (or mode) in Firmata represents the + * current function of the pin. Examples are digital input or output, analog input, pwm, i2c, + * serial (uart), etc. + * @param pin The pin to configure. + * @param config The configuration value for the specified pin. + */ +void FirmataMarshaller::sendPinMode(uint8_t pin, uint8_t config) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(SET_PIN_MODE); + FirmataStream->write(pin); + FirmataStream->write(config); +} + /** * Send a sysex message where all values after the command byte are packet as 2 7-bit bytes * (this is not always the case so this function is not always used to send sysex messages). diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 1a3edb78..33f8de50 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -36,18 +36,25 @@ class FirmataMarshaller void end(); /* serial send handling */ + void reportAnalogDisable(uint8_t pin) const; + void reportAnalogEnable(uint8_t pin) const; + void reportDigitalPortDisable(uint8_t portNumber) const; + void reportDigitalPortEnable(uint8_t portNumber) const; void sendAnalog(uint8_t pin, uint16_t value) const; void sendCapabilityQuery(void) const; - void sendDigital(uint8_t pin, uint16_t value) const; + void sendDigital(uint8_t pin, uint8_t value) const; void sendDigitalPort(uint8_t portNumber, uint16_t portData) const; + void sendPinMode(uint8_t pin, uint8_t config) const; void sendString(const char *string) const; void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) const; private: /* utility methods */ + void reportAnalog(uint8_t pin, bool stream_enable) const; + void reportDigitalPort(uint8_t portNumber, bool stream_enable) const; void sendValueAsTwo7bitBytes(uint16_t value) const; - Stream *FirmataStream; + Stream * FirmataStream; }; #endif /* FirmataMarshaller_h */ diff --git a/FirmataParser.cpp b/FirmataParser.cpp index d39a0aa1..1fc17d9b 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -37,19 +37,30 @@ FirmataParser::FirmataParser(uint8_t * const dataBuffer, size_t dataBufferSize) waitForData(0), parsingSysex(false), sysexBytesRead(0), + currentAnalogCallbackContext((void *)NULL), + currentDigitalCallbackContext((void *)NULL), + currentReportAnalogCallbackContext((void *)NULL), + currentReportDigitalCallbackContext((void *)NULL), + currentPinModeCallbackContext((void *)NULL), + currentPinValueCallbackContext((void *)NULL), + currentReportFirmwareCallbackContext((void *)NULL), + currentReportVersionCallbackContext((void *)NULL), currentDataBufferOverflowCallbackContext((void *)NULL), + currentStringCallbackContext((void *)NULL), + currentSysexCallbackContext((void *)NULL), + currentSystemResetCallbackContext((void *)NULL), currentAnalogCallback((callbackFunction)NULL), currentDigitalCallback((callbackFunction)NULL), currentReportAnalogCallback((callbackFunction)NULL), currentReportDigitalCallback((callbackFunction)NULL), currentPinModeCallback((callbackFunction)NULL), currentPinValueCallback((callbackFunction)NULL), - currentReportFirmwareCallback((systemCallbackFunction)NULL), - currentReportVersionCallback((systemCallbackFunction)NULL), - currentSystemResetCallback((systemCallbackFunction)NULL), + currentDataBufferOverflowCallback((dataBufferOverflowCallbackFunction)NULL), currentStringCallback((stringCallbackFunction)NULL), currentSysexCallback((sysexCallbackFunction)NULL), - currentDataBufferOverflowCallback((dataBufferOverflowCallbackFunction)NULL) + currentReportFirmwareCallback((systemCallbackFunction)NULL), + currentReportVersionCallback((systemCallbackFunction)NULL), + currentSystemResetCallback((systemCallbackFunction)NULL) { allowBufferUpdate = ((uint8_t *)NULL == dataBuffer); } @@ -87,33 +98,35 @@ void FirmataParser::parse(uint8_t inputData) switch (executeMultiByteCommand) { case ANALOG_MESSAGE: if (currentAnalogCallback) { - (*currentAnalogCallback)(multiByteChannel, + (*currentAnalogCallback)(this, + multiByteChannel, (dataBuffer[0] << 7) + dataBuffer[1]); } break; case DIGITAL_MESSAGE: if (currentDigitalCallback) { - (*currentDigitalCallback)(multiByteChannel, + (*currentDigitalCallback)(this, + multiByteChannel, (dataBuffer[0] << 7) + dataBuffer[1]); } break; case SET_PIN_MODE: if (currentPinModeCallback) - (*currentPinModeCallback)(dataBuffer[1], dataBuffer[0]); + (*currentPinModeCallback)(this, dataBuffer[1], dataBuffer[0]); break; case SET_DIGITAL_PIN_VALUE: if (currentPinValueCallback) - (*currentPinValueCallback)(dataBuffer[1], dataBuffer[0]); + (*currentPinValueCallback)(this, dataBuffer[1], dataBuffer[0]); break; case REPORT_ANALOG: if (currentReportAnalogCallback) - (*currentReportAnalogCallback)(multiByteChannel, dataBuffer[0]); + (*currentReportAnalogCallback)(this, multiByteChannel, dataBuffer[0]); break; case REPORT_DIGITAL: if (currentReportDigitalCallback) - (*currentReportDigitalCallback)(multiByteChannel, dataBuffer[0]); + (*currentReportDigitalCallback)(this, multiByteChannel, dataBuffer[0]); break; } executeMultiByteCommand = 0; @@ -149,7 +162,7 @@ void FirmataParser::parse(uint8_t inputData) break; case REPORT_VERSION: if (currentReportVersionCallback) - (*currentReportVersionCallback)(); + (*currentReportVersionCallback)(this); break; } } @@ -194,16 +207,35 @@ int FirmataParser::setDataBufferOfSize(uint8_t * dataBuffer, size_t dataBufferSi * DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE). * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the callback function to attach. + * @param context The context for the callback function. */ -void FirmataParser::attach(uint8_t command, callbackFunction newFunction) +void FirmataParser::attach(uint8_t command, callbackFunction newFunction, void * context) { switch (command) { - case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; - case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; - case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; - case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; - case SET_PIN_MODE: currentPinModeCallback = newFunction; break; - case SET_DIGITAL_PIN_VALUE: currentPinValueCallback = newFunction; break; + case ANALOG_MESSAGE: + currentAnalogCallback = newFunction; + currentAnalogCallbackContext = context; + break; + case DIGITAL_MESSAGE: + currentDigitalCallback = newFunction; + currentDigitalCallbackContext = context; + break; + case REPORT_ANALOG: + currentReportAnalogCallback = newFunction; + currentReportAnalogCallbackContext = context; + break; + case REPORT_DIGITAL: + currentReportDigitalCallback = newFunction; + currentReportDigitalCallbackContext = context; + break; + case SET_PIN_MODE: + currentPinModeCallback = newFunction; + currentPinModeCallbackContext = context; + break; + case SET_DIGITAL_PIN_VALUE: + currentPinValueCallback = newFunction; + currentPinValueCallbackContext = context; + break; } } @@ -212,13 +244,23 @@ void FirmataParser::attach(uint8_t command, callbackFunction newFunction) * and SYSTEM_RESET). * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the callback function to attach. + * @param context The context for the callback function. */ -void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction) +void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction, void * context) { switch (command) { - case REPORT_FIRMWARE: currentReportFirmwareCallback = newFunction; break; - case REPORT_VERSION: currentReportVersionCallback = newFunction; break; - case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; + case REPORT_FIRMWARE: + currentReportFirmwareCallback = newFunction; + currentReportFirmwareCallbackContext = context; + break; + case REPORT_VERSION: + currentReportVersionCallback = newFunction; + currentReportVersionCallbackContext = context; + break; + case SYSTEM_RESET: + currentSystemResetCallback = newFunction; + currentSystemResetCallbackContext = context; + break; } } @@ -226,11 +268,15 @@ void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction) * Attach a callback function for the STRING_DATA command. * @param command Must be set to STRING_DATA or it will be ignored. * @param newFunction A reference to the string callback function to attach. + * @param context The context for the callback function. */ -void FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction) +void FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction, void * context) { switch (command) { - case STRING_DATA: currentStringCallback = newFunction; break; + case STRING_DATA: + currentStringCallback = newFunction; + currentStringCallbackContext = context; + break; } } @@ -238,11 +284,13 @@ void FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction) * Attach a generic sysex callback function to sysex command. * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the sysex callback function to attach. + * @param context The context for the callback function. */ -void FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction) +void FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction, void * context) { (void)command; currentSysexCallback = newFunction; + currentSysexCallbackContext = context; } /** @@ -267,12 +315,17 @@ void FirmataParser::detach(uint8_t command) case REPORT_FIRMWARE: case REPORT_VERSION: case SYSTEM_RESET: - attach(command, (systemCallbackFunction)NULL); + attach(command, (systemCallbackFunction)NULL, NULL); + break; + case STRING_DATA: + attach(command, (stringCallbackFunction)NULL, NULL); + break; + case START_SYSEX: + attach(command, (sysexCallbackFunction)NULL, NULL); break; - case STRING_DATA: currentStringCallback = (stringCallbackFunction)NULL; break; - case START_SYSEX: currentSysexCallback = (sysexCallbackFunction)NULL; break; default: - attach(command, (callbackFunction)NULL); + attach(command, (callbackFunction)NULL, NULL); + break; } } @@ -330,7 +383,7 @@ void FirmataParser::processSysexMessage(void) switch (dataBuffer[0]) { //first byte in buffer is command case REPORT_FIRMWARE: if (currentReportFirmwareCallback) - (*currentReportFirmwareCallback)(); + (*currentReportFirmwareCallback)(this); break; case STRING_DATA: if (currentStringCallback) { @@ -352,12 +405,12 @@ void FirmataParser::processSysexMessage(void) if (dataBuffer[j - 1] != '\0') { bufferDataAtPosition('\0', j); } - (*currentStringCallback)((char *)&dataBuffer[0]); + (*currentStringCallback)(this, (char *)&dataBuffer[0]); } break; default: if (currentSysexCallback) - (*currentSysexCallback)(dataBuffer[0], sysexBytesRead - 1, dataBuffer + 1); + (*currentSysexCallback)(this, dataBuffer[0], sysexBytesRead - 1, dataBuffer + 1); } } @@ -381,5 +434,5 @@ void FirmataParser::systemReset(void) sysexBytesRead = 0; if (currentSystemResetCallback) - (*currentSystemResetCallback)(); + (*currentSystemResetCallback)(this); } diff --git a/FirmataParser.h b/FirmataParser.h index 1fb57d87..c2022d83 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -22,29 +22,29 @@ #include #endif -extern "C" { - // callback function types - typedef void (*dataBufferOverflowCallbackFunction)(void * context); - typedef void (*callbackFunction)(uint8_t, int); - typedef void (*systemCallbackFunction)(void); - typedef void (*stringCallbackFunction)(char *); - typedef void (*sysexCallbackFunction)(uint8_t command, uint8_t argc, uint8_t *argv); -} - class FirmataParser { public: + /* callback function types */ + typedef void (*callbackFunction)(void * context, uint8_t command, uint16_t value); + typedef void (*dataBufferOverflowCallbackFunction)(void * context); + typedef void (*stringCallbackFunction)(void * context, char * c_str); + typedef void (*sysexCallbackFunction)(void * context, uint8_t command, size_t argc, uint8_t * argv); + typedef void (*systemCallbackFunction)(void * context); + FirmataParser(uint8_t * dataBuffer = (uint8_t *)NULL, size_t dataBufferSize = 0); + /* serial receive handling */ void parse(uint8_t value); bool isParsingMessage(void) const; int setDataBufferOfSize(uint8_t * dataBuffer, size_t dataBufferSize); + /* attach & detach callback functions to messages */ - void attach(uint8_t command, callbackFunction newFunction); - void attach(uint8_t command, systemCallbackFunction newFunction); - void attach(uint8_t command, stringCallbackFunction newFunction); - void attach(uint8_t command, sysexCallbackFunction newFunction); + void attach(uint8_t command, callbackFunction newFunction, void * context); void attach(dataBufferOverflowCallbackFunction newFunction, void * context); + void attach(uint8_t command, stringCallbackFunction newFunction, void * context); + void attach(uint8_t command, sysexCallbackFunction newFunction, void * context); + void attach(uint8_t command, systemCallbackFunction newFunction, void * context); void detach(uint8_t command); void detach(dataBufferOverflowCallbackFunction); @@ -56,12 +56,24 @@ class FirmataParser uint8_t executeMultiByteCommand; // execute this after getting multi-byte data uint8_t multiByteChannel; // channel data for multiByteCommands size_t waitForData; // this flag says the next serial input will be data + /* sysex */ bool parsingSysex; size_t sysexBytesRead; /* callback context */ + void * currentAnalogCallbackContext; + void * currentDigitalCallbackContext; + void * currentReportAnalogCallbackContext; + void * currentReportDigitalCallbackContext; + void * currentPinModeCallbackContext; + void * currentPinValueCallbackContext; + void * currentReportFirmwareCallbackContext; + void * currentReportVersionCallbackContext; void * currentDataBufferOverflowCallbackContext; + void * currentStringCallbackContext; + void * currentSysexCallbackContext; + void * currentSystemResetCallbackContext; /* callback functions */ callbackFunction currentAnalogCallback; @@ -70,12 +82,12 @@ class FirmataParser callbackFunction currentReportDigitalCallback; callbackFunction currentPinModeCallback; callbackFunction currentPinValueCallback; + dataBufferOverflowCallbackFunction currentDataBufferOverflowCallback; + stringCallbackFunction currentStringCallback; + sysexCallbackFunction currentSysexCallback; systemCallbackFunction currentReportFirmwareCallback; systemCallbackFunction currentReportVersionCallback; systemCallbackFunction currentSystemResetCallback; - stringCallbackFunction currentStringCallback; - sysexCallbackFunction currentSysexCallback; - dataBufferOverflowCallbackFunction currentDataBufferOverflowCallback; /* private methods ------------------------------ */ void processSysexMessage(void); From 29b4399c8f4d6bd572234455de4c1e02df4dd760 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Tue, 7 Feb 2017 10:00:55 -0800 Subject: [PATCH 054/110] Address code review comments/concerns --- FirmataMarshaller.cpp | 25 ++++++++++++++++--------- FirmataMarshaller.h | 1 + FirmataParser.cpp | 42 ++++++++++++++++++++++++++---------------- FirmataParser.h | 10 +++++----- 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 0440af22..13589564 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -124,7 +124,7 @@ void FirmataMarshaller::end(void) void FirmataMarshaller::reportAnalogDisable(uint8_t pin) const { - reportAnalog(pin, false); + reportAnalog(pin, false); } /** @@ -133,13 +133,11 @@ const * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG * message. * @param pin The analog pin for which to request the value (limited to pins 0 - 15). - * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream - * @note The maximum resulting value is 14-bits (16384). */ void FirmataMarshaller::reportAnalogEnable(uint8_t pin) const { - reportAnalog(pin, true); + reportAnalog(pin, true); } /** @@ -148,12 +146,11 @@ const * @param portNumber The port number for which to request the value. Note that this is not the same as a "port" on the * physical microcontroller. Ports are defined in order per every 8 pins in ascending order * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. - * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream */ void FirmataMarshaller::reportDigitalPortDisable(uint8_t portNumber) const { - reportDigitalPort(portNumber, false); + reportDigitalPort(portNumber, false); } /** @@ -162,12 +159,11 @@ const * @param portNumber The port number for which to request the value. Note that this is not the same as a "port" on the * physical microcontroller. Ports are defined in order per every 8 pins in ascending order * of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc. - * @param stream_enable A zero value will disable the stream, a non-zero will enable the stream */ void FirmataMarshaller::reportDigitalPortEnable(uint8_t portNumber) const { - reportDigitalPort(portNumber, true); + reportDigitalPort(portNumber, true); } /** @@ -188,10 +184,21 @@ const sendValueAsTwo7bitBytes(value); } +/** + * Send an analog mapping query to the Firmata host application. The resulting sysex message will + * have an ANALOG_MAPPING_RESPONSE command byte, followed by a list of pins [0-n]; where each + * pin will specify its corresponding analog pin number or 0x7F (127) if not applicable. + */ +void FirmataMarshaller::sendAnalogMappingQuery(void) +const +{ + sendSysex(ANALOG_MAPPING_QUERY, 0, NULL); +} + /** * Send a capability query to the Firmata host application. The resulting sysex message will have * a CAPABILITY_RESPONSE command byte, followed by a list of byte tuples (mode and mode resolution) - * for each pin; where each pin list is terminated by 0x7F (128). + * for each pin; where each pin list is terminated by 0x7F (127). */ void FirmataMarshaller::sendCapabilityQuery(void) const diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 33f8de50..b0c1790f 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -41,6 +41,7 @@ class FirmataMarshaller void reportDigitalPortDisable(uint8_t portNumber) const; void reportDigitalPortEnable(uint8_t portNumber) const; void sendAnalog(uint8_t pin, uint16_t value) const; + void sendAnalogMappingQuery(void) const; void sendCapabilityQuery(void) const; void sendDigital(uint8_t pin, uint8_t value) const; void sendDigitalPort(uint8_t portNumber, uint16_t portData) const; diff --git a/FirmataParser.cpp b/FirmataParser.cpp index 1fc17d9b..48bdb52f 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -98,7 +98,7 @@ void FirmataParser::parse(uint8_t inputData) switch (executeMultiByteCommand) { case ANALOG_MESSAGE: if (currentAnalogCallback) { - (*currentAnalogCallback)(this, + (*currentAnalogCallback)(currentAnalogCallbackContext, multiByteChannel, (dataBuffer[0] << 7) + dataBuffer[1]); @@ -106,7 +106,7 @@ void FirmataParser::parse(uint8_t inputData) break; case DIGITAL_MESSAGE: if (currentDigitalCallback) { - (*currentDigitalCallback)(this, + (*currentDigitalCallback)(currentDigitalCallbackContext, multiByteChannel, (dataBuffer[0] << 7) + dataBuffer[1]); @@ -114,19 +114,19 @@ void FirmataParser::parse(uint8_t inputData) break; case SET_PIN_MODE: if (currentPinModeCallback) - (*currentPinModeCallback)(this, dataBuffer[1], dataBuffer[0]); + (*currentPinModeCallback)(currentPinModeCallbackContext, dataBuffer[1], dataBuffer[0]); break; case SET_DIGITAL_PIN_VALUE: if (currentPinValueCallback) - (*currentPinValueCallback)(this, dataBuffer[1], dataBuffer[0]); + (*currentPinValueCallback)(currentPinValueCallbackContext, dataBuffer[1], dataBuffer[0]); break; case REPORT_ANALOG: if (currentReportAnalogCallback) - (*currentReportAnalogCallback)(this, multiByteChannel, dataBuffer[0]); + (*currentReportAnalogCallback)(currentReportAnalogCallbackContext, multiByteChannel, dataBuffer[0]); break; case REPORT_DIGITAL: if (currentReportDigitalCallback) - (*currentReportDigitalCallback)(this, multiByteChannel, dataBuffer[0]); + (*currentReportDigitalCallback)(currentReportDigitalCallbackContext, multiByteChannel, dataBuffer[0]); break; } executeMultiByteCommand = 0; @@ -162,7 +162,7 @@ void FirmataParser::parse(uint8_t inputData) break; case REPORT_VERSION: if (currentReportVersionCallback) - (*currentReportVersionCallback)(this); + (*currentReportVersionCallback)(currentReportVersionCallbackContext); break; } } @@ -207,7 +207,9 @@ int FirmataParser::setDataBufferOfSize(uint8_t * dataBuffer, size_t dataBufferSi * DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE). * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the callback function to attach. - * @param context The context for the callback function. + * @param context An optional context to be provided to the callback function (NULL by default). + * @note The context parameter is provided so you can pass a parameter, by reference, to + * your callback function. */ void FirmataParser::attach(uint8_t command, callbackFunction newFunction, void * context) { @@ -244,7 +246,9 @@ void FirmataParser::attach(uint8_t command, callbackFunction newFunction, void * * and SYSTEM_RESET). * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the callback function to attach. - * @param context The context for the callback function. + * @param context An optional context to be provided to the callback function (NULL by default). + * @note The context parameter is provided so you can pass a parameter, by reference, to + * your callback function. */ void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction, void * context) { @@ -268,7 +272,9 @@ void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction, * Attach a callback function for the STRING_DATA command. * @param command Must be set to STRING_DATA or it will be ignored. * @param newFunction A reference to the string callback function to attach. - * @param context The context for the callback function. + * @param context An optional context to be provided to the callback function (NULL by default). + * @note The context parameter is provided so you can pass a parameter, by reference, to + * your callback function. */ void FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction, void * context) { @@ -284,7 +290,9 @@ void FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction, * Attach a generic sysex callback function to sysex command. * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the sysex callback function to attach. - * @param context The context for the callback function. + * @param context An optional context to be provided to the callback function (NULL by default). + * @note The context parameter is provided so you can pass a parameter, by reference, to + * your callback function. */ void FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction, void * context) { @@ -296,7 +304,9 @@ void FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction, v /** * Attach a buffer overflow callback * @param newFunction A reference to the buffer overflow callback function to attach. - * @param context The context supplied by the end-user, and provided during the execution of the callback + * @param context An optional context to be provided to the callback function (NULL by default). + * @note The context parameter is provided so you can pass a parameter, by reference, to + * your callback function. */ void FirmataParser::attach(dataBufferOverflowCallbackFunction newFunction, void * context) { @@ -383,7 +393,7 @@ void FirmataParser::processSysexMessage(void) switch (dataBuffer[0]) { //first byte in buffer is command case REPORT_FIRMWARE: if (currentReportFirmwareCallback) - (*currentReportFirmwareCallback)(this); + (*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext); break; case STRING_DATA: if (currentStringCallback) { @@ -405,12 +415,12 @@ void FirmataParser::processSysexMessage(void) if (dataBuffer[j - 1] != '\0') { bufferDataAtPosition('\0', j); } - (*currentStringCallback)(this, (char *)&dataBuffer[0]); + (*currentStringCallback)(currentStringCallbackContext, (char *)&dataBuffer[0]); } break; default: if (currentSysexCallback) - (*currentSysexCallback)(this, dataBuffer[0], sysexBytesRead - 1, dataBuffer + 1); + (*currentSysexCallback)(currentSysexCallbackContext, dataBuffer[0], sysexBytesRead - 1, dataBuffer + 1); } } @@ -434,5 +444,5 @@ void FirmataParser::systemReset(void) sysexBytesRead = 0; if (currentSystemResetCallback) - (*currentSystemResetCallback)(this); + (*currentSystemResetCallback)(currentSystemResetCallbackContext); } diff --git a/FirmataParser.h b/FirmataParser.h index c2022d83..8f8c1336 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -40,11 +40,11 @@ class FirmataParser int setDataBufferOfSize(uint8_t * dataBuffer, size_t dataBufferSize); /* attach & detach callback functions to messages */ - void attach(uint8_t command, callbackFunction newFunction, void * context); - void attach(dataBufferOverflowCallbackFunction newFunction, void * context); - void attach(uint8_t command, stringCallbackFunction newFunction, void * context); - void attach(uint8_t command, sysexCallbackFunction newFunction, void * context); - void attach(uint8_t command, systemCallbackFunction newFunction, void * context); + void attach(uint8_t command, callbackFunction newFunction, void * context = NULL); + void attach(dataBufferOverflowCallbackFunction newFunction, void * context = NULL); + void attach(uint8_t command, stringCallbackFunction newFunction, void * context = NULL); + void attach(uint8_t command, sysexCallbackFunction newFunction, void * context = NULL); + void attach(uint8_t command, systemCallbackFunction newFunction, void * context = NULL); void detach(uint8_t command); void detach(dataBufferOverflowCallbackFunction); From 1819548d4eeab18090b7432eb32518a53e32dd78 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 23 Feb 2017 17:49:22 -0800 Subject: [PATCH 055/110] namespace firmata Continues to expose the API that was previously exposed, but also allows a consumer to use the complete API fully encapsulated in the `firmata` namespace --- Firmata.cpp | 4 +- Firmata.h | 35 +++-- FirmataConstants.h | 298 ++++++++---------------------------------- FirmataDefines.h | 283 +++++++++++++++++++++++++++++++++++++++ FirmataMarshaller.cpp | 2 + FirmataMarshaller.h | 7 +- FirmataParser.cpp | 2 + FirmataParser.h | 4 + 8 files changed, 378 insertions(+), 257 deletions(-) create mode 100644 FirmataDefines.h diff --git a/Firmata.cpp b/Firmata.cpp index 4b43362c..34a5cfec 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -18,10 +18,10 @@ #include "Firmata.h" #include "HardwareSerial.h" -extern "C" { #include #include -} + +using namespace firmata; //****************************************************************************** //* Static Members diff --git a/Firmata.h b/Firmata.h index f46e8198..67596ceb 100644 --- a/Firmata.h +++ b/Firmata.h @@ -15,7 +15,7 @@ #define Firmata_h #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */ -#include "FirmataConstants.h" +#include "FirmataDefines.h" #include "FirmataMarshaller.h" #include "FirmataParser.h" @@ -48,18 +48,17 @@ #define ENCODER 0x09 // same as PIN_MODE_ENCODER #define IGNORE 0x7F // same as PIN_MODE_IGNORE -extern "C" { - // callback function types - typedef void (*callbackFunction)(uint8_t, int); - typedef void (*systemCallbackFunction)(void); - typedef void (*stringCallbackFunction)(char *); - typedef void (*sysexCallbackFunction)(uint8_t command, uint8_t argc, uint8_t *argv); -} +namespace firmata { // TODO make it a subclass of a generic Serial/Stream base class class FirmataClass { public: + typedef void (*callbackFunction)(uint8_t, int); + typedef void (*systemCallbackFunction)(void); + typedef void (*stringCallbackFunction)(char *); + typedef void (*sysexCallbackFunction)(uint8_t command, uint8_t argc, uint8_t *argv); + FirmataClass(); /* Arduino constructors */ @@ -92,10 +91,10 @@ class FirmataClass void write(byte c); /* attach & detach callback functions to messages */ - void attach(uint8_t command, ::callbackFunction newFunction); - void attach(uint8_t command, ::systemCallbackFunction newFunction); - void attach(uint8_t command, ::stringCallbackFunction newFunction); - void attach(uint8_t command, ::sysexCallbackFunction newFunction); + void attach(uint8_t command, callbackFunction newFunction); + void attach(uint8_t command, systemCallbackFunction newFunction); + void attach(uint8_t command, stringCallbackFunction newFunction); + void attach(uint8_t command, sysexCallbackFunction newFunction); void detach(uint8_t command); /* access pin state and config */ @@ -156,7 +155,17 @@ class FirmataClass inline static void staticSystemResetCallback (void *) { if ( currentSystemResetCallback ) { currentSystemResetCallback(); } } }; -extern FirmataClass Firmata; +} // namespace firmata + +extern "C" { + // callback function types + typedef firmata::FirmataClass::callbackFunction callbackFunction; + typedef firmata::FirmataClass::systemCallbackFunction systemCallbackFunction; + typedef firmata::FirmataClass::stringCallbackFunction stringCallbackFunction; + typedef firmata::FirmataClass::sysexCallbackFunction sysexCallbackFunction; +} + +extern firmata::FirmataClass Firmata; /*============================================================================== * MACROS diff --git a/FirmataConstants.h b/FirmataConstants.h index eda1cc8e..636009aa 100644 --- a/FirmataConstants.h +++ b/FirmataConstants.h @@ -14,268 +14,84 @@ #ifndef FirmataConstants_h #define FirmataConstants_h +namespace firmata { /* Version numbers for the Firmata library. * The firmware version will not always equal the protocol version going forward. * Query using the REPORT_FIRMWARE message. */ -#define FIRMATA_FIRMWARE_MAJOR_VERSION 2 -#define FIRMATA_FIRMWARE_MINOR_VERSION 5 -#define FIRMATA_FIRMWARE_BUGFIX_VERSION 4 +static const int FIRMATA_FIRMWARE_MAJOR_VERSION = 2; +static const int FIRMATA_FIRMWARE_MINOR_VERSION = 5; +static const int FIRMATA_FIRMWARE_BUGFIX_VERSION = 4; /* Version numbers for the protocol. The protocol is still changing, so these * version numbers are important. * Query using the REPORT_VERSION message. */ -#define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes -#define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes -#define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases +static const int FIRMATA_PROTOCOL_MAJOR_VERSION = 2; // for non-compatible changes +static const int FIRMATA_PROTOCOL_MINOR_VERSION = 5; // for backwards compatible changes +static const int FIRMATA_PROTOCOL_BUGFIX_VERSION = 1; // for bugfix releases -#ifdef MAX_DATA_BYTES -#undef MAX_DATA_BYTES -#endif -#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages +static const int MAX_DATA_BYTES = 64; // max number of data bytes in incoming messages // message command bytes (128-255/0x80-0xFF) -#ifdef DIGITAL_MESSAGE -#undef DIGITAL_MESSAGE -#endif -#define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins) - -#ifdef ANALOG_MESSAGE -#undef ANALOG_MESSAGE -#endif -#define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM) - -#ifdef REPORT_ANALOG -#undef REPORT_ANALOG -#endif -#define REPORT_ANALOG 0xC0 // enable analog input by pin # - -#ifdef REPORT_DIGITAL -#undef REPORT_DIGITAL -#endif -#define REPORT_DIGITAL 0xD0 // enable digital input by port pair - +static const int DIGITAL_MESSAGE = 0x90; // send data for a digital port (collection of 8 pins) +static const int ANALOG_MESSAGE = 0xE0; // send data for an analog pin (or PWM) +static const int REPORT_ANALOG = 0xC0; // enable analog input by pin # +static const int REPORT_DIGITAL = 0xD0; // enable digital input by port pair // - -#ifdef SET_PIN_MODE -#undef SET_PIN_MODE -#endif -#define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc - -#ifdef SET_DIGITAL_PIN_VALUE -#undef SET_DIGITAL_PIN_VALUE -#endif -#define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin - +static const int SET_PIN_MODE = 0xF4; // set a pin to INPUT/OUTPUT/PWM/etc +static const int SET_DIGITAL_PIN_VALUE = 0xF5; // set value of an individual digital pin // - -#ifdef REPORT_VERSION -#undef REPORT_VERSION -#endif -#define REPORT_VERSION 0xF9 // report protocol version - -#ifdef SYSTEM_RESET -#undef SYSTEM_RESET -#endif -#define SYSTEM_RESET 0xFF // reset from MIDI - +static const int REPORT_VERSION = 0xF9; // report protocol version +static const int SYSTEM_RESET = 0xFF; // reset from MIDI // - -#ifdef START_SYSEX -#undef START_SYSEX -#endif -#define START_SYSEX 0xF0 // start a MIDI Sysex message - -#ifdef END_SYSEX -#undef END_SYSEX -#endif -#define END_SYSEX 0xF7 // end a MIDI Sysex message +static const int START_SYSEX = 0xF0; // start a MIDI Sysex message +static const int END_SYSEX = 0xF7; // end a MIDI Sysex message // extended command set using sysex (0-127/0x00-0x7F) /* 0x00-0x0F reserved for user-defined commands */ -#ifdef SERIAL_MESSAGE -#undef SERIAL_MESSAGE -#endif -#define SERIAL_MESSAGE 0x60 // communicate with serial devices, including other boards - -#ifdef ENCODER_DATA -#undef ENCODER_DATA -#endif -#define ENCODER_DATA 0x61 // reply with encoders current positions - -#ifdef SERVO_CONFIG -#undef SERVO_CONFIG -#endif -#define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq - -#ifdef STRING_DATA -#undef STRING_DATA -#endif -#define STRING_DATA 0x71 // a string message with 14-bits per char - -#ifdef STEPPER_DATA -#undef STEPPER_DATA -#endif -#define STEPPER_DATA 0x72 // control a stepper motor - -#ifdef ONEWIRE_DATA -#undef ONEWIRE_DATA -#endif -#define ONEWIRE_DATA 0x73 // send an OneWire read/write/reset/select/skip/search request - -#ifdef SHIFT_DATA -#undef SHIFT_DATA -#endif -#define SHIFT_DATA 0x75 // a bitstream to/from a shift register - -#ifdef I2C_REQUEST -#undef I2C_REQUEST -#endif -#define I2C_REQUEST 0x76 // send an I2C read/write request - -#ifdef I2C_REPLY -#undef I2C_REPLY -#endif -#define I2C_REPLY 0x77 // a reply to an I2C read request - -#ifdef I2C_CONFIG -#undef I2C_CONFIG -#endif -#define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins - -#ifdef REPORT_FIRMWARE -#undef REPORT_FIRMWARE -#endif -#define REPORT_FIRMWARE 0x79 // report name and version of the firmware - -#ifdef EXTENDED_ANALOG -#undef EXTENDED_ANALOG -#endif -#define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin - -#ifdef PIN_STATE_QUERY -#undef PIN_STATE_QUERY -#endif -#define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value - -#ifdef PIN_STATE_RESPONSE -#undef PIN_STATE_RESPONSE -#endif -#define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value - -#ifdef CAPABILITY_QUERY -#undef CAPABILITY_QUERY -#endif -#define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins - -#ifdef CAPABILITY_RESPONSE -#undef CAPABILITY_RESPONSE -#endif -#define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution - -#ifdef ANALOG_MAPPING_QUERY -#undef ANALOG_MAPPING_QUERY -#endif -#define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers - -#ifdef ANALOG_MAPPING_RESPONSE -#undef ANALOG_MAPPING_RESPONSE -#endif -#define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info - -#ifdef SAMPLING_INTERVAL -#undef SAMPLING_INTERVAL -#endif -#define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop - -#ifdef SCHEDULER_DATA -#undef SCHEDULER_DATA -#endif -#define SCHEDULER_DATA 0x7B // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler - -#ifdef SYSEX_NON_REALTIME -#undef SYSEX_NON_REALTIME -#endif -#define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages - -#ifdef SYSEX_REALTIME -#undef SYSEX_REALTIME -#endif -#define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages +static const int SERIAL_MESSAGE = 0x60; // communicate with serial devices, including other boards +static const int ENCODER_DATA = 0x61; // reply with encoders current positions +static const int SERVO_CONFIG = 0x70; // set max angle, minPulse, maxPulse, freq +static const int STRING_DATA = 0x71; // a string message with 14-bits per char +static const int STEPPER_DATA = 0x72; // control a stepper motor +static const int ONEWIRE_DATA = 0x73; // send an OneWire read/write/reset/select/skip/search request +static const int SHIFT_DATA = 0x75; // a bitstream to/from a shift register +static const int I2C_REQUEST = 0x76; // send an I2C read/write request +static const int I2C_REPLY = 0x77; // a reply to an I2C read request +static const int I2C_CONFIG = 0x78; // config I2C settings such as delay times and power pins +static const int REPORT_FIRMWARE = 0x79; // report name and version of the firmware +static const int EXTENDED_ANALOG = 0x6F; // analog write (PWM, Servo, etc) to any pin +static const int PIN_STATE_QUERY = 0x6D; // ask for a pin's current mode and value +static const int PIN_STATE_RESPONSE = 0x6E; // reply with pin's current mode and value +static const int CAPABILITY_QUERY = 0x6B; // ask for supported modes and resolution of all pins +static const int CAPABILITY_RESPONSE = 0x6C; // reply with supported modes and resolution +static const int ANALOG_MAPPING_QUERY = 0x69; // ask for mapping of analog to pin numbers +static const int ANALOG_MAPPING_RESPONSE = 0x6A; // reply with mapping info +static const int SAMPLING_INTERVAL = 0x7A; // set the poll rate of the main loop +static const int SCHEDULER_DATA = 0x7B; // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler +static const int SYSEX_NON_REALTIME = 0x7E; // MIDI Reserved for non-realtime messages +static const int SYSEX_REALTIME = 0x7F; // MIDI Reserved for realtime messages // pin modes - -#ifdef PIN_MODE_INPUT -#undef PIN_MODE_INPUT -#endif -#define PIN_MODE_INPUT 0x00 // same as INPUT defined in Arduino.h - -#ifdef PIN_MODE_OUTPUT -#undef PIN_MODE_OUTPUT -#endif -#define PIN_MODE_OUTPUT 0x01 // same as OUTPUT defined in Arduino.h - -#ifdef PIN_MODE_ANALOG -#undef PIN_MODE_ANALOG -#endif -#define PIN_MODE_ANALOG 0x02 // analog pin in analogInput mode - -#ifdef PIN_MODE_PWM -#undef PIN_MODE_PWM -#endif -#define PIN_MODE_PWM 0x03 // digital pin in PWM output mode - -#ifdef PIN_MODE_SERVO -#undef PIN_MODE_SERVO -#endif -#define PIN_MODE_SERVO 0x04 // digital pin in Servo output mode - -#ifdef PIN_MODE_SHIFT -#undef PIN_MODE_SHIFT -#endif -#define PIN_MODE_SHIFT 0x05 // shiftIn/shiftOut mode - -#ifdef PIN_MODE_I2C -#undef PIN_MODE_I2C -#endif -#define PIN_MODE_I2C 0x06 // pin included in I2C setup - -#ifdef PIN_MODE_ONEWIRE -#undef PIN_MODE_ONEWIRE -#endif -#define PIN_MODE_ONEWIRE 0x07 // pin configured for 1-wire - -#ifdef PIN_MODE_STEPPER -#undef PIN_MODE_STEPPER -#endif -#define PIN_MODE_STEPPER 0x08 // pin configured for stepper motor - -#ifdef PIN_MODE_ENCODER -#undef PIN_MODE_ENCODER -#endif -#define PIN_MODE_ENCODER 0x09 // pin configured for rotary encoders - -#ifdef PIN_MODE_SERIAL -#undef PIN_MODE_SERIAL -#endif -#define PIN_MODE_SERIAL 0x0A // pin configured for serial communication - -#ifdef PIN_MODE_PULLUP -#undef PIN_MODE_PULLUP -#endif -#define PIN_MODE_PULLUP 0x0B // enable internal pull-up resistor for pin - -#ifdef PIN_MODE_IGNORE -#undef PIN_MODE_IGNORE -#endif -#define PIN_MODE_IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse - -#ifdef TOTAL_PIN_MODES -#undef TOTAL_PIN_MODES -#endif -#define TOTAL_PIN_MODES 13 +static const int PIN_MODE_INPUT = 0x00; // same as INPUT defined in Arduino.h +static const int PIN_MODE_OUTPUT = 0x01; // same as OUTPUT defined in Arduino.h +static const int PIN_MODE_ANALOG = 0x02; // analog pin in analogInput mode +static const int PIN_MODE_PWM = 0x03; // digital pin in PWM output mode +static const int PIN_MODE_SERVO = 0x04; // digital pin in Servo output mode +static const int PIN_MODE_SHIFT = 0x05; // shiftIn/shiftOut mode +static const int PIN_MODE_I2C = 0x06; // pin included in I2C setup +static const int PIN_MODE_ONEWIRE = 0x07; // pin configured for 1-wire +static const int PIN_MODE_STEPPER = 0x08; // pin configured for stepper motor +static const int PIN_MODE_ENCODER = 0x09; // pin configured for rotary encoders +static const int PIN_MODE_SERIAL = 0x0A; // pin configured for serial communication +static const int PIN_MODE_PULLUP = 0x0B; // enable internal pull-up resistor for pin +static const int PIN_MODE_IGNORE = 0x7F; // pin configured to be ignored by digitalWrite and capabilityResponse + +static const int TOTAL_PIN_MODES = 13; + +} // namespace firmata #endif // FirmataConstants_h diff --git a/FirmataDefines.h b/FirmataDefines.h new file mode 100644 index 00000000..c3420bf9 --- /dev/null +++ b/FirmataDefines.h @@ -0,0 +1,283 @@ +/* + Firmata.h - Firmata library v2.5.4 - 2016-10-23 + Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (C) 2009-2016 Jeff Hoefs. 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. + + See file LICENSE.txt for further informations on licensing terms. +*/ + +#ifndef FirmataDefines_h +#define FirmataDefines_h + +#include "FirmataConstants.h" + +/* Version numbers for the Firmata library. + * The firmware version will not always equal the protocol version going forward. + * Query using the REPORT_FIRMWARE message. + */ +#define FIRMATA_FIRMWARE_MAJOR_VERSION firmata::FIRMATA_FIRMWARE_MAJOR_VERSION +#define FIRMATA_FIRMWARE_MINOR_VERSION firmata::FIRMATA_FIRMWARE_MINOR_VERSION +#define FIRMATA_FIRMWARE_BUGFIX_VERSION firmata::FIRMATA_FIRMWARE_BUGFIX_VERSION + +/* Version numbers for the protocol. The protocol is still changing, so these + * version numbers are important. + * Query using the REPORT_VERSION message. + */ +#define FIRMATA_PROTOCOL_MAJOR_VERSION firmata::FIRMATA_PROTOCOL_MAJOR_VERSION // for non-compatible changes +#define FIRMATA_PROTOCOL_MINOR_VERSION firmata::FIRMATA_PROTOCOL_MINOR_VERSION // for backwards compatible changes +#define FIRMATA_PROTOCOL_BUGFIX_VERSION firmata::FIRMATA_PROTOCOL_BUGFIX_VERSION // for bugfix releases + +#ifdef MAX_DATA_BYTES +#undef MAX_DATA_BYTES +#endif +#define MAX_DATA_BYTES firmata::MAX_DATA_BYTES // max number of data bytes in incoming messages + +// message command bytes (128-255/0x80-0xFF) + +#ifdef DIGITAL_MESSAGE +#undef DIGITAL_MESSAGE +#endif +#define DIGITAL_MESSAGE firmata::DIGITAL_MESSAGE // send data for a digital port (collection of 8 pins) + +#ifdef ANALOG_MESSAGE +#undef ANALOG_MESSAGE +#endif +#define ANALOG_MESSAGE firmata::ANALOG_MESSAGE // send data for an analog pin (or PWM) + +#ifdef REPORT_ANALOG +#undef REPORT_ANALOG +#endif +#define REPORT_ANALOG firmata::REPORT_ANALOG // enable analog input by pin # + +#ifdef REPORT_DIGITAL +#undef REPORT_DIGITAL +#endif +#define REPORT_DIGITAL firmata::REPORT_DIGITAL // enable digital input by port pair + +// + +#ifdef SET_PIN_MODE +#undef SET_PIN_MODE +#endif +#define SET_PIN_MODE firmata::SET_PIN_MODE // set a pin to INPUT/OUTPUT/PWM/etc + +#ifdef SET_DIGITAL_PIN_VALUE +#undef SET_DIGITAL_PIN_VALUE +#endif +#define SET_DIGITAL_PIN_VALUE firmata::SET_DIGITAL_PIN_VALUE // set value of an individual digital pin + +// + +#ifdef REPORT_VERSION +#undef REPORT_VERSION +#endif +#define REPORT_VERSION firmata::REPORT_VERSION // report protocol version + +#ifdef SYSTEM_RESET +#undef SYSTEM_RESET +#endif +#define SYSTEM_RESET firmata::SYSTEM_RESET // reset from MIDI + +// + +#ifdef START_SYSEX +#undef START_SYSEX +#endif +#define START_SYSEX firmata::START_SYSEX // start a MIDI Sysex message + +#ifdef END_SYSEX +#undef END_SYSEX +#endif +#define END_SYSEX firmata::END_SYSEX // end a MIDI Sysex message + +// extended command set using sysex (0-127/0x00-0x7F) +/* 0x00-0x0F reserved for user-defined commands */ + +#ifdef SERIAL_MESSAGE +#undef SERIAL_MESSAGE +#endif +#define SERIAL_MESSAGE firmata::SERIAL_MESSAGE // communicate with serial devices, including other boards + +#ifdef ENCODER_DATA +#undef ENCODER_DATA +#endif +#define ENCODER_DATA firmata::ENCODER_DATA // reply with encoders current positions + +#ifdef SERVO_CONFIG +#undef SERVO_CONFIG +#endif +#define SERVO_CONFIG firmata::SERVO_CONFIG // set max angle, minPulse, maxPulse, freq + +#ifdef STRING_DATA +#undef STRING_DATA +#endif +#define STRING_DATA firmata::STRING_DATA // a string message with 14-bits per char + +#ifdef STEPPER_DATA +#undef STEPPER_DATA +#endif +#define STEPPER_DATA firmata::STEPPER_DATA // control a stepper motor + +#ifdef ONEWIRE_DATA +#undef ONEWIRE_DATA +#endif +#define ONEWIRE_DATA firmata::ONEWIRE_DATA // send an OneWire read/write/reset/select/skip/search request + +#ifdef SHIFT_DATA +#undef SHIFT_DATA +#endif +#define SHIFT_DATA firmata::SHIFT_DATA // a bitstream to/from a shift register + +#ifdef I2C_REQUEST +#undef I2C_REQUEST +#endif +#define I2C_REQUEST firmata::I2C_REQUEST // send an I2C read/write request + +#ifdef I2C_REPLY +#undef I2C_REPLY +#endif +#define I2C_REPLY firmata::I2C_REPLY // a reply to an I2C read request + +#ifdef I2C_CONFIG +#undef I2C_CONFIG +#endif +#define I2C_CONFIG firmata::I2C_CONFIG // config I2C settings such as delay times and power pins + +#ifdef REPORT_FIRMWARE +#undef REPORT_FIRMWARE +#endif +#define REPORT_FIRMWARE firmata::REPORT_FIRMWARE // report name and version of the firmware + +#ifdef EXTENDED_ANALOG +#undef EXTENDED_ANALOG +#endif +#define EXTENDED_ANALOG firmata::EXTENDED_ANALOG // analog write (PWM, Servo, etc) to any pin + +#ifdef PIN_STATE_QUERY +#undef PIN_STATE_QUERY +#endif +#define PIN_STATE_QUERY firmata::PIN_STATE_QUERY // ask for a pin's current mode and value + +#ifdef PIN_STATE_RESPONSE +#undef PIN_STATE_RESPONSE +#endif +#define PIN_STATE_RESPONSE firmata::PIN_STATE_RESPONSE // reply with pin's current mode and value + +#ifdef CAPABILITY_QUERY +#undef CAPABILITY_QUERY +#endif +#define CAPABILITY_QUERY firmata::CAPABILITY_QUERY // ask for supported modes and resolution of all pins + +#ifdef CAPABILITY_RESPONSE +#undef CAPABILITY_RESPONSE +#endif +#define CAPABILITY_RESPONSE firmata::CAPABILITY_RESPONSE // reply with supported modes and resolution + +#ifdef ANALOG_MAPPING_QUERY +#undef ANALOG_MAPPING_QUERY +#endif +#define ANALOG_MAPPING_QUERY firmata::ANALOG_MAPPING_QUERY // ask for mapping of analog to pin numbers + +#ifdef ANALOG_MAPPING_RESPONSE +#undef ANALOG_MAPPING_RESPONSE +#endif +#define ANALOG_MAPPING_RESPONSE firmata::ANALOG_MAPPING_RESPONSE // reply with mapping info + +#ifdef SAMPLING_INTERVAL +#undef SAMPLING_INTERVAL +#endif +#define SAMPLING_INTERVAL firmata::SAMPLING_INTERVAL // set the poll rate of the main loop + +#ifdef SCHEDULER_DATA +#undef SCHEDULER_DATA +#endif +#define SCHEDULER_DATA firmata::SCHEDULER_DATA // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler + +#ifdef SYSEX_NON_REALTIME +#undef SYSEX_NON_REALTIME +#endif +#define SYSEX_NON_REALTIME firmata::SYSEX_NON_REALTIME // MIDI Reserved for non-realtime messages + +#ifdef SYSEX_REALTIME +#undef SYSEX_REALTIME +#endif +#define SYSEX_REALTIME firmata::SYSEX_REALTIME // MIDI Reserved for realtime messages + +// pin modes + +#ifdef PIN_MODE_INPUT +#undef PIN_MODE_INPUT +#endif +#define PIN_MODE_INPUT firmata::PIN_MODE_INPUT // same as INPUT defined in Arduino.h + +#ifdef PIN_MODE_OUTPUT +#undef PIN_MODE_OUTPUT +#endif +#define PIN_MODE_OUTPUT firmata::PIN_MODE_OUTPUT // same as OUTPUT defined in Arduino.h + +#ifdef PIN_MODE_ANALOG +#undef PIN_MODE_ANALOG +#endif +#define PIN_MODE_ANALOG firmata::PIN_MODE_ANALOG // analog pin in analogInput mode + +#ifdef PIN_MODE_PWM +#undef PIN_MODE_PWM +#endif +#define PIN_MODE_PWM firmata::PIN_MODE_PWM // digital pin in PWM output mode + +#ifdef PIN_MODE_SERVO +#undef PIN_MODE_SERVO +#endif +#define PIN_MODE_SERVO firmata::PIN_MODE_SERVO // digital pin in Servo output mode + +#ifdef PIN_MODE_SHIFT +#undef PIN_MODE_SHIFT +#endif +#define PIN_MODE_SHIFT firmata::PIN_MODE_SHIFT // shiftIn/shiftOut mode + +#ifdef PIN_MODE_I2C +#undef PIN_MODE_I2C +#endif +#define PIN_MODE_I2C firmata::PIN_MODE_I2C // pin included in I2C setup + +#ifdef PIN_MODE_ONEWIRE +#undef PIN_MODE_ONEWIRE +#endif +#define PIN_MODE_ONEWIRE firmata::PIN_MODE_ONEWIRE // pin configured for 1-wire + +#ifdef PIN_MODE_STEPPER +#undef PIN_MODE_STEPPER +#endif +#define PIN_MODE_STEPPER firmata::PIN_MODE_STEPPER // pin configured for stepper motor + +#ifdef PIN_MODE_ENCODER +#undef PIN_MODE_ENCODER +#endif +#define PIN_MODE_ENCODER firmata::PIN_MODE_ENCODER // pin configured for rotary encoders + +#ifdef PIN_MODE_SERIAL +#undef PIN_MODE_SERIAL +#endif +#define PIN_MODE_SERIAL firmata::PIN_MODE_SERIAL // pin configured for serial communication + +#ifdef PIN_MODE_PULLUP +#undef PIN_MODE_PULLUP +#endif +#define PIN_MODE_PULLUP firmata::PIN_MODE_PULLUP // enable internal pull-up resistor for pin + +#ifdef PIN_MODE_IGNORE +#undef PIN_MODE_IGNORE +#endif +#define PIN_MODE_IGNORE firmata::PIN_MODE_IGNORE // pin configured to be ignored by digitalWrite and capabilityResponse + +#ifdef TOTAL_PIN_MODES +#undef TOTAL_PIN_MODES +#endif +#define TOTAL_PIN_MODES firmata::TOTAL_PIN_MODES + +#endif // FirmataConstants_h diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 13589564..8580349b 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -25,6 +25,8 @@ #include "FirmataConstants.h" +using namespace firmata; + //****************************************************************************** //* Support Functions //****************************************************************************** diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index b0c1790f..9940d93b 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -24,9 +24,12 @@ #include +namespace firmata { + class FirmataMarshaller { - friend class FirmataClass; + friend class FirmataClass; + public: /* constructors */ FirmataMarshaller(); @@ -58,5 +61,7 @@ class FirmataMarshaller Stream * FirmataStream; }; +} // namespace firmata + #endif /* FirmataMarshaller_h */ diff --git a/FirmataParser.cpp b/FirmataParser.cpp index 48bdb52f..ea324122 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -19,6 +19,8 @@ #include "FirmataConstants.h" +using namespace firmata; + //****************************************************************************** //* Constructors //****************************************************************************** diff --git a/FirmataParser.h b/FirmataParser.h index 8f8c1336..629ee2a4 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -22,6 +22,8 @@ #include #endif +namespace firmata { + class FirmataParser { public: @@ -95,4 +97,6 @@ class FirmataParser bool bufferDataAtPosition(const uint8_t data, const size_t pos); }; +} // firmata + #endif /* FirmataParser_h */ From 60045161fc2f6a27fdbdb69245c4af1dcaa54bb7 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 24 Feb 2017 17:43:55 -0800 Subject: [PATCH 056/110] Remove redundant naming --- FirmataConstants.h | 14 +++++++------- FirmataDefines.h | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/FirmataConstants.h b/FirmataConstants.h index 636009aa..282aeac0 100644 --- a/FirmataConstants.h +++ b/FirmataConstants.h @@ -19,19 +19,19 @@ namespace firmata { * The firmware version will not always equal the protocol version going forward. * Query using the REPORT_FIRMWARE message. */ -static const int FIRMATA_FIRMWARE_MAJOR_VERSION = 2; -static const int FIRMATA_FIRMWARE_MINOR_VERSION = 5; -static const int FIRMATA_FIRMWARE_BUGFIX_VERSION = 4; +static const int FIRMWARE_MAJOR_VERSION = 2; +static const int FIRMWARE_MINOR_VERSION = 5; +static const int FIRMWARE_BUGFIX_VERSION = 4; /* Version numbers for the protocol. The protocol is still changing, so these * version numbers are important. * Query using the REPORT_VERSION message. */ -static const int FIRMATA_PROTOCOL_MAJOR_VERSION = 2; // for non-compatible changes -static const int FIRMATA_PROTOCOL_MINOR_VERSION = 5; // for backwards compatible changes -static const int FIRMATA_PROTOCOL_BUGFIX_VERSION = 1; // for bugfix releases +static const int PROTOCOL_MAJOR_VERSION = 2; // for non-compatible changes +static const int PROTOCOL_MINOR_VERSION = 5; // for backwards compatible changes +static const int PROTOCOL_BUGFIX_VERSION = 1; // for bugfix releases -static const int MAX_DATA_BYTES = 64; // max number of data bytes in incoming messages +static const int MAX_DATA_BYTES = 64; // max number of data bytes in incoming messages // message command bytes (128-255/0x80-0xFF) diff --git a/FirmataDefines.h b/FirmataDefines.h index c3420bf9..0bce3e49 100644 --- a/FirmataDefines.h +++ b/FirmataDefines.h @@ -20,17 +20,17 @@ * The firmware version will not always equal the protocol version going forward. * Query using the REPORT_FIRMWARE message. */ -#define FIRMATA_FIRMWARE_MAJOR_VERSION firmata::FIRMATA_FIRMWARE_MAJOR_VERSION -#define FIRMATA_FIRMWARE_MINOR_VERSION firmata::FIRMATA_FIRMWARE_MINOR_VERSION -#define FIRMATA_FIRMWARE_BUGFIX_VERSION firmata::FIRMATA_FIRMWARE_BUGFIX_VERSION +#define FIRMATA_FIRMWARE_MAJOR_VERSION firmata::FIRMWARE_MAJOR_VERSION +#define FIRMATA_FIRMWARE_MINOR_VERSION firmata::FIRMWARE_MINOR_VERSION +#define FIRMATA_FIRMWARE_BUGFIX_VERSION firmata::FIRMWARE_BUGFIX_VERSION /* Version numbers for the protocol. The protocol is still changing, so these * version numbers are important. * Query using the REPORT_VERSION message. */ -#define FIRMATA_PROTOCOL_MAJOR_VERSION firmata::FIRMATA_PROTOCOL_MAJOR_VERSION // for non-compatible changes -#define FIRMATA_PROTOCOL_MINOR_VERSION firmata::FIRMATA_PROTOCOL_MINOR_VERSION // for backwards compatible changes -#define FIRMATA_PROTOCOL_BUGFIX_VERSION firmata::FIRMATA_PROTOCOL_BUGFIX_VERSION // for bugfix releases +#define FIRMATA_PROTOCOL_MAJOR_VERSION firmata::PROTOCOL_MAJOR_VERSION // for non-compatible changes +#define FIRMATA_PROTOCOL_MINOR_VERSION firmata::PROTOCOL_MINOR_VERSION // for backwards compatible changes +#define FIRMATA_PROTOCOL_BUGFIX_VERSION firmata::PROTOCOL_BUGFIX_VERSION // for bugfix releases #ifdef MAX_DATA_BYTES #undef MAX_DATA_BYTES From 3cd149c5021fcff4a7c784fcab93ceb74154f986 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sat, 25 Feb 2017 20:07:11 -0800 Subject: [PATCH 057/110] Unify sysex payload naming to DATA --- FirmataConstants.h | 2 +- FirmataDefines.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/FirmataConstants.h b/FirmataConstants.h index 282aeac0..538fb5d3 100644 --- a/FirmataConstants.h +++ b/FirmataConstants.h @@ -52,7 +52,7 @@ static const int END_SYSEX = 0xF7; // end a MIDI Sysex message // extended command set using sysex (0-127/0x00-0x7F) /* 0x00-0x0F reserved for user-defined commands */ -static const int SERIAL_MESSAGE = 0x60; // communicate with serial devices, including other boards +static const int SERIAL_DATA = 0x60; // communicate with serial devices, including other boards static const int ENCODER_DATA = 0x61; // reply with encoders current positions static const int SERVO_CONFIG = 0x70; // set max angle, minPulse, maxPulse, freq static const int STRING_DATA = 0x71; // a string message with 14-bits per char diff --git a/FirmataDefines.h b/FirmataDefines.h index 0bce3e49..3d36f205 100644 --- a/FirmataDefines.h +++ b/FirmataDefines.h @@ -101,7 +101,7 @@ #ifdef SERIAL_MESSAGE #undef SERIAL_MESSAGE #endif -#define SERIAL_MESSAGE firmata::SERIAL_MESSAGE // communicate with serial devices, including other boards +#define SERIAL_MESSAGE firmata::SERIAL_DATA // communicate with serial devices, including other boards #ifdef ENCODER_DATA #undef ENCODER_DATA From 7165b6a6697589e069e6c1c1f0a17952da2044ca Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 23 Feb 2017 20:53:30 -0800 Subject: [PATCH 058/110] sendPinStateQuery --- FirmataMarshaller.cpp | 13 +++++++++++++ FirmataMarshaller.h | 1 + 2 files changed, 14 insertions(+) diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 8580349b..c2bdf8bd 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -256,6 +256,19 @@ const FirmataStream->write(config); } +/** + * Send a pin state query to the Firmata host application. The resulting sysex message will have + * a PIN_STATE_RESPONSE command byte, followed by the pin number, the pin mode and a stream of + * bits to indicate any *data* written to the pin (pin state). + * @param pin The pin to query + * @note The pin state is any data written to the pin (i.e. pin state != pin value) + */ +void FirmataMarshaller::sendPinStateQuery(uint8_t pin) +const +{ + sendSysex(PIN_STATE_QUERY, 1, &pin); +} + /** * Send a sysex message where all values after the command byte are packet as 2 7-bit bytes * (this is not always the case so this function is not always used to send sysex messages). diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 9940d93b..7b22d84a 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -49,6 +49,7 @@ class FirmataMarshaller void sendDigital(uint8_t pin, uint8_t value) const; void sendDigitalPort(uint8_t portNumber, uint16_t portData) const; void sendPinMode(uint8_t pin, uint8_t config) const; + void sendPinStateQuery(uint8_t pin) const; void sendString(const char *string) const; void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) const; From 2e09889b2197ea2f260dc71ebddbef8ee238a6fe Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 26 Feb 2017 01:06:52 -0800 Subject: [PATCH 059/110] setSamplingInterval --- FirmataMarshaller.cpp | 13 ++++++++++++- FirmataMarshaller.h | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index c2bdf8bd..cd42b791 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -266,7 +266,7 @@ const void FirmataMarshaller::sendPinStateQuery(uint8_t pin) const { - sendSysex(PIN_STATE_QUERY, 1, &pin); + sendSysex(PIN_STATE_QUERY, sizeof(pin), &pin); } /** @@ -298,3 +298,14 @@ const { sendSysex(STRING_DATA, strlen(string), (uint8_t *)string); } + +/** + * The sampling interval sets how often analog data and i2c data is reported to the client. + * @param interval_ms The interval (in milliseconds) at which to sample + * @note The default sampling interval is 19ms + */ +void FirmataMarshaller::setSamplingInterval(uint16_t interval_ms) +const +{ + sendSysex(SAMPLING_INTERVAL, sizeof(interval_ms), &interval_ms); +} diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 7b22d84a..be076b2b 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -52,6 +52,7 @@ class FirmataMarshaller void sendPinStateQuery(uint8_t pin) const; void sendString(const char *string) const; void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) const; + void setSamplingInterval(uint16_t interval_ms) const; private: /* utility methods */ From d0bef9e4cf0446b7721091403dc72dec130a9c83 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 26 Feb 2017 10:43:10 -0800 Subject: [PATCH 060/110] sendExtendedAnalog includes support function transformByteStreamToMessageBytes(), which replaces sendValueAsTwo7bitBytes() --- Firmata.cpp | 4 +-- Firmata.h | 2 +- FirmataMarshaller.cpp | 77 ++++++++++++++++++++++++++++++++++--------- FirmataMarshaller.h | 3 +- 4 files changed, 67 insertions(+), 19 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 34a5cfec..a55f6f79 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -50,7 +50,7 @@ systemCallbackFunction FirmataClass::currentSystemResetCallback = (systemCallbac */ void FirmataClass::sendValueAsTwo7bitBytes(int value) { - marshaller.sendValueAsTwo7bitBytes(value); + marshaller.transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast(&value), sizeof(value)); } /** @@ -196,7 +196,7 @@ void FirmataClass::printFirmwareVersion(void) FirmataStream->write(firmwareVersionVector[0]); // major version number FirmataStream->write(firmwareVersionVector[1]); // minor version number for (i = 2; i < firmwareVersionCount; ++i) { - marshaller.sendValueAsTwo7bitBytes(firmwareVersionVector[i]); + sendValueAsTwo7bitBytes(firmwareVersionVector[i]); } endSysex(); } diff --git a/Firmata.h b/Firmata.h index 67596ceb..05cdcfd3 100644 --- a/Firmata.h +++ b/Firmata.h @@ -128,7 +128,7 @@ class FirmataClass /* private methods ------------------------------ */ void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); - friend void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value) const; + friend void FirmataMarshaller::transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; /* callback functions */ static callbackFunction currentAnalogCallback; diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index cd42b791..14ecf560 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -66,14 +66,57 @@ const } /** - * Split a 16-bit integer into two 7-bit values and write each value. - * @param value The 16-bit value to be split and written separately. + * An alternative to the normal analog message, this extended version allows addressing beyond + * pin 15 and supports sending analog values with any number of bits. + * @param pin The analog pin to which the value is sent. + * @param bytec The size of the storage for the analog value + * @param bytev The pointer to the location of the analog value */ -void FirmataMarshaller::sendValueAsTwo7bitBytes(uint16_t value) +void FirmataMarshaller::sendExtendedAnalog(uint8_t pin, size_t bytec, uint8_t * bytev) const { - FirmataStream->write(value & 0x7F); // LSB - FirmataStream->write(value >> 7 & 0x7F); // MSB + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(START_SYSEX); + FirmataStream->write(EXTENDED_ANALOG); + FirmataStream->write(pin); + transformByteStreamToMessageBytes(bytec, bytev, bytec); + FirmataStream->write(END_SYSEX); +} + +/** + * Transform 8-bit stream into 7-bit message + * @param bytec The number of data bytes in the message. + * @param bytev A pointer to the array of data bytes to send in the message. + * @param max_bytes Force message to be n bytes, regardless of data bits. + */ +void FirmataMarshaller::transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes) +const +{ + static const size_t transmit_bits = 7; + static const uint8_t transmit_mask = ((1 << transmit_bits) - 1); + + size_t bytes_sent = 0; + size_t outstanding_bits = 0; + uint8_t outstanding_bit_cache = *bytev; + + if ( !max_bytes ) { max_bytes = static_cast(-1); } + for (size_t i = 0 ; (i < bytec) && (bytes_sent < max_bytes) ; ++i) { + uint8_t transmit_byte = (outstanding_bit_cache|(bytev[i] << outstanding_bits)); + FirmataStream->write(transmit_mask & transmit_byte); + ++bytes_sent; + outstanding_bit_cache = (bytev[i] >> (transmit_bits - outstanding_bits)); + outstanding_bits = (outstanding_bits + (8 - transmit_bits)); + for ( ; (outstanding_bits >= transmit_bits) && (bytes_sent < max_bytes) ; ) { + transmit_byte = outstanding_bit_cache; + FirmataStream->write(transmit_mask & transmit_byte); + ++bytes_sent; + outstanding_bit_cache >>= transmit_bits; + outstanding_bits -= transmit_bits; + } + } + if ( outstanding_bits && (bytes_sent < max_bytes) ) { + FirmataStream->write(static_cast((1 << outstanding_bits) - 1) & outstanding_bit_cache); + } } //****************************************************************************** @@ -173,17 +216,20 @@ const * when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG * message. - * @param pin The analog pin to send the value of (limited to pins 0 - 15). + * @param pin The analog pin to which the value is sent. * @param value The value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc). - * The maximum value is 14-bits (16384). */ void FirmataMarshaller::sendAnalog(uint8_t pin, uint16_t value) const { if ( (Stream *)NULL == FirmataStream ) { return; } - // pin can only be 0-15, so chop higher bits - FirmataStream->write(ANALOG_MESSAGE | (pin & 0xF)); - sendValueAsTwo7bitBytes(value); + + if ( (0xF >= pin) && (0x3FFF >= value) ) { + FirmataStream->write(ANALOG_MESSAGE|pin); + transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast(&value), 2); + } else { + sendExtendedAnalog(pin, sizeof(value), reinterpret_cast(&value)); + } } /** @@ -236,8 +282,9 @@ const { if ( (Stream *)NULL == FirmataStream ) { return; } FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); - FirmataStream->write((uint8_t)portData % 128); // Tx bits 0-6 (protocol v1 and higher) - FirmataStream->write(portData >> 7); // Tx bits 7-13 (bit 7 only for protocol v2 and higher) + // Tx bits 0-6 (protocol v1 and higher) + // Tx bits 7-13 (bit 7 only for protocol v2 and higher) + transformByteStreamToMessageBytes(sizeof(portData), reinterpret_cast(&portData), 2); } /** @@ -284,7 +331,7 @@ const FirmataStream->write(START_SYSEX); FirmataStream->write(command); for (i = 0; i < bytec; ++i) { - sendValueAsTwo7bitBytes(bytev[i]); + transformByteStreamToMessageBytes(sizeof(bytev[i]), reinterpret_cast(&bytev[i]), 2); } FirmataStream->write(END_SYSEX); } @@ -296,7 +343,7 @@ const void FirmataMarshaller::sendString(const char *string) const { - sendSysex(STRING_DATA, strlen(string), (uint8_t *)string); + sendSysex(STRING_DATA, strlen(string), reinterpret_cast(const_cast(string))); } /** @@ -307,5 +354,5 @@ const void FirmataMarshaller::setSamplingInterval(uint16_t interval_ms) const { - sendSysex(SAMPLING_INTERVAL, sizeof(interval_ms), &interval_ms); + sendSysex(SAMPLING_INTERVAL, sizeof(interval_ms), reinterpret_cast(&interval_ms)); } diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index be076b2b..01bc0318 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -58,7 +58,8 @@ class FirmataMarshaller /* utility methods */ void reportAnalog(uint8_t pin, bool stream_enable) const; void reportDigitalPort(uint8_t portNumber, bool stream_enable) const; - void sendValueAsTwo7bitBytes(uint16_t value) const; + void sendExtendedAnalog(uint8_t pin, size_t bytec, uint8_t * bytev) const; + void transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; Stream * FirmataStream; }; From fa5b3d6e39dac27effaca749e6abf50e53c54397 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 26 Feb 2017 11:52:39 -0800 Subject: [PATCH 061/110] Address bug caught code review --- FirmataMarshaller.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 14ecf560..522abea8 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -218,6 +218,7 @@ const * message. * @param pin The analog pin to which the value is sent. * @param value The value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc). + * @note The maximum value is 14-bits (16384). */ void FirmataMarshaller::sendAnalog(uint8_t pin, uint16_t value) const @@ -226,7 +227,7 @@ const if ( (0xF >= pin) && (0x3FFF >= value) ) { FirmataStream->write(ANALOG_MESSAGE|pin); - transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast(&value), 2); + transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast(&value), sizeof(value)); } else { sendExtendedAnalog(pin, sizeof(value), reinterpret_cast(&value)); } @@ -313,7 +314,11 @@ const void FirmataMarshaller::sendPinStateQuery(uint8_t pin) const { - sendSysex(PIN_STATE_QUERY, sizeof(pin), &pin); + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(START_SYSEX); + FirmataStream->write(PIN_STATE_QUERY); + FirmataStream->write(pin); + FirmataStream->write(END_SYSEX); } /** From 9433b27cc0dc634b265b078f9b2b1d220ccceb5f Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sun, 26 Feb 2017 16:40:42 -0800 Subject: [PATCH 062/110] Add system calls to Marshaller --- Firmata.cpp | 15 ++------- FirmataMarshaller.cpp | 74 +++++++++++++++++++++++++++++++++++++++++-- FirmataMarshaller.h | 5 +++ 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index a55f6f79..901b3460 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -146,9 +146,7 @@ void FirmataClass::begin(Stream &s) */ void FirmataClass::printVersion(void) { - FirmataStream->write(REPORT_VERSION); - FirmataStream->write(FIRMATA_PROTOCOL_MAJOR_VERSION); - FirmataStream->write(FIRMATA_PROTOCOL_MINOR_VERSION); + marshaller.sendVersion(FIRMATA_PROTOCOL_MAJOR_VERSION, FIRMATA_PROTOCOL_MINOR_VERSION); } /** @@ -188,17 +186,8 @@ void FirmataClass::disableBlinkVersion() */ void FirmataClass::printFirmwareVersion(void) { - byte i; - if (firmwareVersionCount) { // make sure that the name has been set before reporting - startSysex(); - FirmataStream->write(REPORT_FIRMWARE); - FirmataStream->write(firmwareVersionVector[0]); // major version number - FirmataStream->write(firmwareVersionVector[1]); // minor version number - for (i = 2; i < firmwareVersionCount; ++i) { - sendValueAsTwo7bitBytes(firmwareVersionVector[i]); - } - endSysex(); + marshaller.sendFirmwareVersion(static_cast(firmwareVersionVector[0]), static_cast(firmwareVersionVector[1]), (firmwareVersionCount - 2), reinterpret_cast(&firmwareVersionVector[2])); } } diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 522abea8..53a57162 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -159,6 +159,28 @@ void FirmataMarshaller::end(void) //* Output Stream Handling //****************************************************************************** +/** + * Query the target's firmware name and version + */ +void FirmataMarshaller::queryFirmwareVersion(void) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(START_SYSEX); + FirmataStream->write(REPORT_FIRMWARE); + FirmataStream->write(END_SYSEX); +} + +/** + * Query the target's Firmata protocol version + */ +void FirmataMarshaller::queryVersion(void) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(REPORT_VERSION); +} + /** * Halt the stream of analog readings from the Firmata host application. The range of pins is * limited to [0..15] when using the REPORT_ANALOG. The maximum result of the REPORT_ANALOG is limited to 14 bits @@ -224,7 +246,6 @@ void FirmataMarshaller::sendAnalog(uint8_t pin, uint16_t value) const { if ( (Stream *)NULL == FirmataStream ) { return; } - if ( (0xF >= pin) && (0x3FFF >= value) ) { FirmataStream->write(ANALOG_MESSAGE|pin); transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast(&value), sizeof(value)); @@ -285,7 +306,43 @@ const FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); // Tx bits 0-6 (protocol v1 and higher) // Tx bits 7-13 (bit 7 only for protocol v2 and higher) - transformByteStreamToMessageBytes(sizeof(portData), reinterpret_cast(&portData), 2); + transformByteStreamToMessageBytes(sizeof(portData), reinterpret_cast(&portData), sizeof(portData)); +} + +/** + * Sends the firmware name and version to the Firmata host application. + * @param major The major verison number + * @param minor The minor version number + * @param bytec The length of the firmware name + * @param bytev The firmware name array + */ +void FirmataMarshaller::sendFirmwareVersion(uint8_t major, uint8_t minor, size_t bytec, uint8_t *bytev) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + size_t i; + FirmataStream->write(START_SYSEX); + FirmataStream->write(REPORT_FIRMWARE); + FirmataStream->write(major); + FirmataStream->write(minor); + for (i = 0; i < bytec; ++i) { + transformByteStreamToMessageBytes(sizeof(bytev[i]), reinterpret_cast(&bytev[i]), sizeof(bytev[i])); + } + FirmataStream->write(END_SYSEX); +} + +/** + * Send the Firmata protocol version to the Firmata host application. + * @param major The major verison number + * @param minor The minor version number + */ +void FirmataMarshaller::sendVersion(uint8_t major, uint8_t minor) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(REPORT_VERSION); + FirmataStream->write(major); + FirmataStream->write(minor); } /** @@ -336,7 +393,7 @@ const FirmataStream->write(START_SYSEX); FirmataStream->write(command); for (i = 0; i < bytec; ++i) { - transformByteStreamToMessageBytes(sizeof(bytev[i]), reinterpret_cast(&bytev[i]), 2); + transformByteStreamToMessageBytes(sizeof(bytev[i]), reinterpret_cast(&bytev[i]), sizeof(bytev[i])); } FirmataStream->write(END_SYSEX); } @@ -361,3 +418,14 @@ const { sendSysex(SAMPLING_INTERVAL, sizeof(interval_ms), reinterpret_cast(&interval_ms)); } + +/** + * Perform a software reset on the target. For example, StandardFirmata.ino will initialize + * everything to a known state and reset the parsing buffer. + */ +void FirmataMarshaller::systemReset(void) +const +{ + if ( (Stream *)NULL == FirmataStream ) { return; } + FirmataStream->write(SYSTEM_RESET); +} diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 01bc0318..348daac7 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -39,6 +39,8 @@ class FirmataMarshaller void end(); /* serial send handling */ + void queryFirmwareVersion(void) const; + void queryVersion(void) const; void reportAnalogDisable(uint8_t pin) const; void reportAnalogEnable(uint8_t pin) const; void reportDigitalPortDisable(uint8_t portNumber) const; @@ -48,11 +50,14 @@ class FirmataMarshaller void sendCapabilityQuery(void) const; void sendDigital(uint8_t pin, uint8_t value) const; void sendDigitalPort(uint8_t portNumber, uint16_t portData) const; + void sendFirmwareVersion(uint8_t major, uint8_t minor, size_t bytec, uint8_t *bytev) const; + void sendVersion(uint8_t major, uint8_t minor) const; void sendPinMode(uint8_t pin, uint8_t config) const; void sendPinStateQuery(uint8_t pin) const; void sendString(const char *string) const; void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) const; void setSamplingInterval(uint16_t interval_ms) const; + void systemReset(void) const; private: /* utility methods */ From 168a0c050f8c690120743468ab433cafcc119e66 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Mon, 6 Mar 2017 21:57:46 -0800 Subject: [PATCH 063/110] prepare release and bump bugfix version --- Firmata.cpp | 2 +- Firmata.h | 2 +- FirmataConstants.h | 4 ++-- FirmataDefines.h | 2 +- FirmataMarshaller.cpp | 2 +- FirmataMarshaller.h | 2 +- FirmataParser.cpp | 2 +- FirmataParser.h | 2 +- extras/revisions.txt | 16 ++++++++++++++++ library.properties | 2 +- readme.md | 8 ++++---- release.sh | 4 ++-- 12 files changed, 32 insertions(+), 16 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 901b3460..250d5f12 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.4 - 2016-10-23 + Firmata.cpp - Firmata library v2.5.5 - 2017-03-06 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/Firmata.h b/Firmata.h index 05cdcfd3..60eef9eb 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.4 - 2016-10-23 + Firmata.h - Firmata library v2.5.5 - 2017-03-06 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/FirmataConstants.h b/FirmataConstants.h index 538fb5d3..de84ceda 100644 --- a/FirmataConstants.h +++ b/FirmataConstants.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.4 - 2016-10-23 + FirmataConstants.h Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. @@ -21,7 +21,7 @@ namespace firmata { */ static const int FIRMWARE_MAJOR_VERSION = 2; static const int FIRMWARE_MINOR_VERSION = 5; -static const int FIRMWARE_BUGFIX_VERSION = 4; +static const int FIRMWARE_BUGFIX_VERSION = 5; /* Version numbers for the protocol. The protocol is still changing, so these * version numbers are important. diff --git a/FirmataDefines.h b/FirmataDefines.h index 3d36f205..fb95fb59 100644 --- a/FirmataDefines.h +++ b/FirmataDefines.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.4 - 2016-10-23 + FirmataDefines.h Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 53a57162..2b1f45a9 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.4 - 2016-10-23 + FirmataMarshaller.cpp Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 348daac7..2a8650c7 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.4 - 2016-10-23 + FirmataMarshaller.h Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/FirmataParser.cpp b/FirmataParser.cpp index ea324122..e446078d 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.4 - 2016-10-23 + FirmataParser.cpp Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/FirmataParser.h b/FirmataParser.h index 629ee2a4..a9516dae 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -1,5 +1,5 @@ /* - FirmataParser.h - Firmata library v2.5.4 - 2016-10-23 + FirmataParser.h Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. diff --git a/extras/revisions.txt b/extras/revisions.txt index 983e75c4..689dc0c4 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,19 @@ +FIRMATA 2.5.5 - Mar 6, 2017 + +[core library] +* Updated BLEStream for compatibility with CurieBLE v2 (Sandeep Mistry) +* Added support for MKRZero (Sandeep Mistry) + +This update also includes a number of changes from an ongoing refactor by +Zak Fields of the Firmata core. These changes don't impact user facing sketches, +they are all internal only. Changes include: + +* Split out parser logic into new lib free of Arduino-specific dependencies. +* Add new class to support cross platform marshalling of Firmata procedure calls. +* Split out core constants to separate file. +* Split out core defines to separate file. +* Added firmata namespace to core library classes. + FIRMATA 2.5.4 - Oct 23, 2016 [core library] diff --git a/library.properties b/library.properties index 7e44fe16..4d8df5ae 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.5.4 +version=2.5.5 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino/Genuino boards. diff --git a/readme.md b/readme.md index 62a5ad97..8b370815 100644 --- a/readme.md +++ b/readme.md @@ -94,7 +94,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ##Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.4) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.5) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -105,7 +105,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.4) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.5) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -115,7 +115,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.4) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.5) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -124,7 +124,7 @@ for Arduino 1.0.x vs 1.6.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.4) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.5) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index d4a03c2f..7fc12d1c 100644 --- a/release.sh +++ b/release.sh @@ -15,7 +15,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.4.zip +mv ./temp/Firmata.zip Firmata-2.5.5.zip #package for Arduino 1.6.x cp library.properties temp/Firmata @@ -29,5 +29,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.4.zip +mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.5.zip rm -r ./temp From fd76083dad2dedd18ae058f3657e3645c8b39bde Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Mon, 13 Mar 2017 00:07:37 -0700 Subject: [PATCH 064/110] firmware callbacks --- Firmata.cpp | 2 +- Firmata.h | 4 ++-- FirmataParser.cpp | 43 ++++++++++++++++++++++++++++++++++--------- FirmataParser.h | 8 +++++--- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 250d5f12..6134ebfa 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -94,7 +94,7 @@ FirmataClass::FirmataClass() parser.attach(SET_DIGITAL_PIN_VALUE, (FirmataParser::callbackFunction)staticPinValueCallback, (void *)NULL); parser.attach(STRING_DATA, (FirmataParser::stringCallbackFunction)staticStringCallback, (void *)NULL); parser.attach(START_SYSEX, (FirmataParser::sysexCallbackFunction)staticSysexCallback, (void *)NULL); - parser.attach(REPORT_FIRMWARE, (FirmataParser::systemCallbackFunction)staticReportFirmwareCallback, this); + parser.attach(REPORT_FIRMWARE, (FirmataParser::versionCallbackFunction)staticReportFirmwareCallback, this); parser.attach(REPORT_VERSION, (FirmataParser::systemCallbackFunction)staticReportVersionCallback, this); parser.attach(SYSTEM_RESET, (FirmataParser::systemCallbackFunction)staticSystemResetCallback, (void *)NULL); } diff --git a/Firmata.h b/Firmata.h index 60eef9eb..cda11a6e 100644 --- a/Firmata.h +++ b/Firmata.h @@ -148,9 +148,9 @@ class FirmataClass inline static void staticPinValueCallback (void *, uint8_t command, uint16_t value) { if ( currentPinValueCallback ) { currentPinValueCallback(command, (int)value); } } inline static void staticReportAnalogCallback (void *, uint8_t command, uint16_t value) { if ( currentReportAnalogCallback ) { currentReportAnalogCallback(command, (int)value); } } inline static void staticReportDigitalCallback (void *, uint8_t command, uint16_t value) { if ( currentReportDigitalCallback ) { currentReportDigitalCallback(command, (int)value); } } - inline static void staticStringCallback (void *, char * c_str) { if ( currentStringCallback ) { currentStringCallback(c_str); } } + inline static void staticStringCallback (void *, const char * c_str) { if ( currentStringCallback ) { currentStringCallback((char *)c_str); } } inline static void staticSysexCallback (void *, uint8_t command, size_t argc, uint8_t *argv) { if ( currentSysexCallback ) { currentSysexCallback(command, (uint8_t)argc, argv); } } - inline static void staticReportFirmwareCallback (void * context) { if ( context ) { ((FirmataClass *)context)->printFirmwareVersion(); } } + inline static void staticReportFirmwareCallback (void * context, size_t, size_t, const char *) { if ( context ) { ((FirmataClass *)context)->printFirmwareVersion(); } } inline static void staticReportVersionCallback (void * context) { if ( context ) { ((FirmataClass *)context)->printVersion(); } } inline static void staticSystemResetCallback (void *) { if ( currentSystemResetCallback ) { currentSystemResetCallback(); } } }; diff --git a/FirmataParser.cpp b/FirmataParser.cpp index e446078d..415e6e07 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -60,7 +60,7 @@ FirmataParser::FirmataParser(uint8_t * const dataBuffer, size_t dataBufferSize) currentDataBufferOverflowCallback((dataBufferOverflowCallbackFunction)NULL), currentStringCallback((stringCallbackFunction)NULL), currentSysexCallback((sysexCallbackFunction)NULL), - currentReportFirmwareCallback((systemCallbackFunction)NULL), + currentReportFirmwareCallback((versionCallbackFunction)NULL), currentReportVersionCallback((systemCallbackFunction)NULL), currentSystemResetCallback((systemCallbackFunction)NULL) { @@ -244,21 +244,34 @@ void FirmataParser::attach(uint8_t command, callbackFunction newFunction, void * } /** - * Attach a system callback function (options are: REPORT_FIRMWARE, REPORT_VERSION - * and SYSTEM_RESET). + * Attach a version callback function (supported option: REPORT_FIRMWARE). * @param command The ID of the command to attach a callback function to. * @param newFunction A reference to the callback function to attach. * @param context An optional context to be provided to the callback function (NULL by default). * @note The context parameter is provided so you can pass a parameter, by reference, to * your callback function. */ -void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction, void * context) +void FirmataParser::attach(uint8_t command, versionCallbackFunction newFunction, void * context) { switch (command) { case REPORT_FIRMWARE: currentReportFirmwareCallback = newFunction; currentReportFirmwareCallbackContext = context; break; + } +} + +/** + * Attach a system callback function (supported options are: SYSTEM_RESET, REPORT_VERSION). + * @param command The ID of the command to attach a callback function to. + * @param newFunction A reference to the callback function to attach. + * @param context An optional context to be provided to the callback function (NULL by default). + * @note The context parameter is provided so you can pass a parameter, by reference, to + * your callback function. + */ +void FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction, void * context) +{ + switch (command) { case REPORT_VERSION: currentReportVersionCallback = newFunction; currentReportVersionCallbackContext = context; @@ -325,6 +338,8 @@ void FirmataParser::detach(uint8_t command) { switch (command) { case REPORT_FIRMWARE: + attach(command, (versionCallbackFunction)NULL, NULL); + break; case REPORT_VERSION: case SYSTEM_RESET: attach(command, (systemCallbackFunction)NULL, NULL); @@ -394,14 +409,24 @@ void FirmataParser::processSysexMessage(void) { switch (dataBuffer[0]) { //first byte in buffer is command case REPORT_FIRMWARE: - if (currentReportFirmwareCallback) - (*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext); + if (currentReportFirmwareCallback) { + size_t sv_major = dataBuffer[1], sv_minor = dataBuffer[2]; + size_t i = 0, j = 3; + while (j < sysexBytesRead) { + // The string length will only be at most half the size of the + // stored input buffer so we can decode the string within the buffer. + bufferDataAtPosition(dataBuffer[j], i); + ++i; + ++j; + } + bufferDataAtPosition('\0', i); // Terminate the string + (*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext, sv_major, sv_minor, (const char *)&dataBuffer[0]); + } break; case STRING_DATA: if (currentStringCallback) { size_t bufferLength = (sysexBytesRead - 1) / 2; - size_t i = 1; - size_t j = 0; + size_t i = 1, j = 0; while (j < bufferLength) { // The string length will only be at most half the size of the // stored input buffer so we can decode the string within the buffer. @@ -417,7 +442,7 @@ void FirmataParser::processSysexMessage(void) if (dataBuffer[j - 1] != '\0') { bufferDataAtPosition('\0', j); } - (*currentStringCallback)(currentStringCallbackContext, (char *)&dataBuffer[0]); + (*currentStringCallback)(currentStringCallbackContext, (const char *)&dataBuffer[0]); } break; default: diff --git a/FirmataParser.h b/FirmataParser.h index a9516dae..1790b521 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -30,9 +30,10 @@ class FirmataParser /* callback function types */ typedef void (*callbackFunction)(void * context, uint8_t command, uint16_t value); typedef void (*dataBufferOverflowCallbackFunction)(void * context); - typedef void (*stringCallbackFunction)(void * context, char * c_str); + typedef void (*stringCallbackFunction)(void * context, const char * c_str); typedef void (*sysexCallbackFunction)(void * context, uint8_t command, size_t argc, uint8_t * argv); typedef void (*systemCallbackFunction)(void * context); + typedef void (*versionCallbackFunction)(void * context, size_t sv_major, size_t sv_minor, const char * firmware); FirmataParser(uint8_t * dataBuffer = (uint8_t *)NULL, size_t dataBufferSize = 0); @@ -47,6 +48,7 @@ class FirmataParser void attach(uint8_t command, stringCallbackFunction newFunction, void * context = NULL); void attach(uint8_t command, sysexCallbackFunction newFunction, void * context = NULL); void attach(uint8_t command, systemCallbackFunction newFunction, void * context = NULL); + void attach(uint8_t command, versionCallbackFunction newFunction, void * context = NULL); void detach(uint8_t command); void detach(dataBufferOverflowCallbackFunction); @@ -87,14 +89,14 @@ class FirmataParser dataBufferOverflowCallbackFunction currentDataBufferOverflowCallback; stringCallbackFunction currentStringCallback; sysexCallbackFunction currentSysexCallback; - systemCallbackFunction currentReportFirmwareCallback; + versionCallbackFunction currentReportFirmwareCallback; systemCallbackFunction currentReportVersionCallback; systemCallbackFunction currentSystemResetCallback; /* private methods ------------------------------ */ + bool bufferDataAtPosition(const uint8_t data, const size_t pos); void processSysexMessage(void); void systemReset(void); - bool bufferDataAtPosition(const uint8_t data, const size_t pos); }; } // firmata From d96a110dcc529ced004ba1462d3cdd6fb8763e3e Mon Sep 17 00:00:00 2001 From: chiararuggeri Date: Thu, 16 Mar 2017 10:01:52 +0100 Subject: [PATCH 065/110] Add support for Arduino Primo board --- Boards.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Boards.h b/Boards.h index 9e9ffdac..f2b61da2 100644 --- a/Boards.h +++ b/Boards.h @@ -299,6 +299,21 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) // deprecated since v2.4 +// Arduino Primo +#elif defined(ARDUINO_PRIMO) +#define TOTAL_ANALOG_PINS 6 +#define TOTAL_PINS 22 //14 digital + 6 analog + 2 i2c +#define VERSION_BLINK_PIN LED_BUILTIN +#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < 20) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 20) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS+2) +#define IS_PIN_I2C(p) ((p) == PIN_WIRE_SDA || (p) == PIN_WIRE_SCL) // SDA = 20, SCL = 21 +#define IS_PIN_SPI(p) ((p) == SS || (p)== MOSI || (p) == MISO || (p == SCK)) // 10, 11, 12, 13 +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 14) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // Arduino 101 #elif defined(_VARIANT_ARDUINO_101_X_) From eb5e7cdf08878a823e91fcfeab98bee130fdf0cc Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Wed, 15 Mar 2017 22:15:52 -0700 Subject: [PATCH 066/110] Improve decoding algorithm --- FirmataParser.cpp | 61 +++++++++++++++++++++++++---------------------- FirmataParser.h | 1 + 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/FirmataParser.cpp b/FirmataParser.cpp index 415e6e07..d402fdf0 100644 --- a/FirmataParser.cpp +++ b/FirmataParser.cpp @@ -400,6 +400,25 @@ bool FirmataParser::bufferDataAtPosition(const uint8_t data, const size_t pos) return bufferOverflow; } +/** + * Transform 7-bit firmata message into 8-bit stream + * @param bytec The encoded data byte length of the message (max: 16383). + * @param bytev A pointer to the encoded array of data bytes. + * @return The length of the decoded data. + * @note The conversion will be done in place on the provided buffer. + * @private + */ +size_t FirmataParser::decodeByteStream(size_t bytec, uint8_t * bytev) { + size_t decoded_bytes, i; + + for ( i = 0, decoded_bytes = 0 ; i < bytec ; ++decoded_bytes, ++i ) { + bytev[decoded_bytes] = bytev[i]; + bytev[decoded_bytes] |= (uint8_t)(bytev[++i] << 7); + } + + return decoded_bytes; +} + /** * Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally. * Calls callback function for STRING_DATA and all other sysex messages. @@ -410,39 +429,25 @@ void FirmataParser::processSysexMessage(void) switch (dataBuffer[0]) { //first byte in buffer is command case REPORT_FIRMWARE: if (currentReportFirmwareCallback) { - size_t sv_major = dataBuffer[1], sv_minor = dataBuffer[2]; - size_t i = 0, j = 3; - while (j < sysexBytesRead) { - // The string length will only be at most half the size of the - // stored input buffer so we can decode the string within the buffer. - bufferDataAtPosition(dataBuffer[j], i); - ++i; - ++j; + const size_t major_version_offset = 1; + const size_t minor_version_offset = 2; + const size_t string_offset = 3; + // Test for malformed REPORT_FIRMWARE message (used to query firmware prior to Firmata v3.0.0) + if ( 3 > sysexBytesRead ) { + (*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext, 0, 0, (const char *)NULL); + } else { + const size_t end_of_string = (string_offset + decodeByteStream((sysexBytesRead - string_offset), &dataBuffer[string_offset])); + bufferDataAtPosition('\0', end_of_string); // NULL terminate the string + (*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext, (size_t)dataBuffer[major_version_offset], (size_t)dataBuffer[minor_version_offset], (const char *)&dataBuffer[string_offset]); } - bufferDataAtPosition('\0', i); // Terminate the string - (*currentReportFirmwareCallback)(currentReportFirmwareCallbackContext, sv_major, sv_minor, (const char *)&dataBuffer[0]); } break; case STRING_DATA: if (currentStringCallback) { - size_t bufferLength = (sysexBytesRead - 1) / 2; - size_t i = 1, j = 0; - while (j < bufferLength) { - // The string length will only be at most half the size of the - // stored input buffer so we can decode the string within the buffer. - bufferDataAtPosition(dataBuffer[i], j); - ++i; - bufferDataAtPosition((dataBuffer[j] + (dataBuffer[i] << 7)), j); - ++i; - ++j; - } - // Make sure string is null terminated. This may be the case for data - // coming from client libraries in languages that don't null terminate - // strings. - if (dataBuffer[j - 1] != '\0') { - bufferDataAtPosition('\0', j); - } - (*currentStringCallback)(currentStringCallbackContext, (const char *)&dataBuffer[0]); + const size_t string_offset = 1; + const size_t end_of_string = (string_offset + decodeByteStream((sysexBytesRead - string_offset), &dataBuffer[string_offset])); + bufferDataAtPosition('\0', end_of_string); // NULL terminate the string + (*currentStringCallback)(currentStringCallbackContext, (const char *)&dataBuffer[string_offset]); } break; default: diff --git a/FirmataParser.h b/FirmataParser.h index 1790b521..bb0c8be8 100644 --- a/FirmataParser.h +++ b/FirmataParser.h @@ -95,6 +95,7 @@ class FirmataParser /* private methods ------------------------------ */ bool bufferDataAtPosition(const uint8_t data, const size_t pos); + size_t decodeByteStream(size_t bytec, uint8_t * bytev); void processSysexMessage(void); void systemReset(void); }; From 8f834594fd1d3eb86b89b77b52f9fc3546791bed Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sat, 18 Mar 2017 11:25:15 -0700 Subject: [PATCH 067/110] Fix bug #363 - string encoding --- Firmata.cpp | 2 +- Firmata.h | 2 +- FirmataMarshaller.cpp | 12 ++++++------ FirmataMarshaller.h | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index 6134ebfa..bd229ac9 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -50,7 +50,7 @@ systemCallbackFunction FirmataClass::currentSystemResetCallback = (systemCallbac */ void FirmataClass::sendValueAsTwo7bitBytes(int value) { - marshaller.transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast(&value), sizeof(value)); + marshaller.encodeByteStream(sizeof(value), reinterpret_cast(&value), sizeof(value)); } /** diff --git a/Firmata.h b/Firmata.h index cda11a6e..90c1932d 100644 --- a/Firmata.h +++ b/Firmata.h @@ -128,7 +128,7 @@ class FirmataClass /* private methods ------------------------------ */ void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); - friend void FirmataMarshaller::transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; + friend void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; /* callback functions */ static callbackFunction currentAnalogCallback; diff --git a/FirmataMarshaller.cpp b/FirmataMarshaller.cpp index 2b1f45a9..6cb52002 100644 --- a/FirmataMarshaller.cpp +++ b/FirmataMarshaller.cpp @@ -79,7 +79,7 @@ const FirmataStream->write(START_SYSEX); FirmataStream->write(EXTENDED_ANALOG); FirmataStream->write(pin); - transformByteStreamToMessageBytes(bytec, bytev, bytec); + encodeByteStream(bytec, bytev, bytec); FirmataStream->write(END_SYSEX); } @@ -89,7 +89,7 @@ const * @param bytev A pointer to the array of data bytes to send in the message. * @param max_bytes Force message to be n bytes, regardless of data bits. */ -void FirmataMarshaller::transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes) +void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes) const { static const size_t transmit_bits = 7; @@ -248,7 +248,7 @@ const if ( (Stream *)NULL == FirmataStream ) { return; } if ( (0xF >= pin) && (0x3FFF >= value) ) { FirmataStream->write(ANALOG_MESSAGE|pin); - transformByteStreamToMessageBytes(sizeof(value), reinterpret_cast(&value), sizeof(value)); + encodeByteStream(sizeof(value), reinterpret_cast(&value), sizeof(value)); } else { sendExtendedAnalog(pin, sizeof(value), reinterpret_cast(&value)); } @@ -306,7 +306,7 @@ const FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF)); // Tx bits 0-6 (protocol v1 and higher) // Tx bits 7-13 (bit 7 only for protocol v2 and higher) - transformByteStreamToMessageBytes(sizeof(portData), reinterpret_cast(&portData), sizeof(portData)); + encodeByteStream(sizeof(portData), reinterpret_cast(&portData), sizeof(portData)); } /** @@ -326,7 +326,7 @@ const FirmataStream->write(major); FirmataStream->write(minor); for (i = 0; i < bytec; ++i) { - transformByteStreamToMessageBytes(sizeof(bytev[i]), reinterpret_cast(&bytev[i]), sizeof(bytev[i])); + encodeByteStream(sizeof(bytev[i]), reinterpret_cast(&bytev[i])); } FirmataStream->write(END_SYSEX); } @@ -393,7 +393,7 @@ const FirmataStream->write(START_SYSEX); FirmataStream->write(command); for (i = 0; i < bytec; ++i) { - transformByteStreamToMessageBytes(sizeof(bytev[i]), reinterpret_cast(&bytev[i]), sizeof(bytev[i])); + encodeByteStream(sizeof(bytev[i]), reinterpret_cast(&bytev[i])); } FirmataStream->write(END_SYSEX); } diff --git a/FirmataMarshaller.h b/FirmataMarshaller.h index 2a8650c7..3fa83f6a 100644 --- a/FirmataMarshaller.h +++ b/FirmataMarshaller.h @@ -64,7 +64,7 @@ class FirmataMarshaller void reportAnalog(uint8_t pin, bool stream_enable) const; void reportDigitalPort(uint8_t portNumber, bool stream_enable) const; void sendExtendedAnalog(uint8_t pin, size_t bytec, uint8_t * bytev) const; - void transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; + void encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; Stream * FirmataStream; }; From f1bd40f3d977b3e93323cc541ef336f580601029 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 18 Mar 2017 16:28:59 -0700 Subject: [PATCH 068/110] add tests for sending and receiving strings --- test/firmata_test/firmata_test.ino | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/firmata_test/firmata_test.ino b/test/firmata_test/firmata_test.ino index ce40afa5..db058535 100644 --- a/test/firmata_test/firmata_test.ino +++ b/test/firmata_test/firmata_test.ino @@ -58,6 +58,12 @@ void setupDigitalPort() _digitalPortValue = 0; } +char * _receivedString; +void handleStringCallback(char *str) +{ + _receivedString = str; +} + test(processWriteDigital_0) { setupDigitalPort(); @@ -134,3 +140,33 @@ test(setFirmwareVersionDoesNotLeakMemory) assertEqual(0, initialMemory - freeMemory()); } + +test(sendStringShouldEncode2BytesPerChar) +{ + FakeStream stream; + Firmata.begin(stream); + // reset the buffer because the firmware name string will be sent on Firmata.begin + stream.reset(); + + char testString[] = "hi!"; + Firmata.sendString(testString); + + byte expected[] = { START_SYSEX, STRING_DATA, 'h', 0, 'i', 0, '!', 0, END_SYSEX }; + + int len = stream.bytesWritten().length(); + assertEqual(sizeof(expected), len); + for (byte i = 0; i < len; i++) { + assertEqual(expected[i], (byte)stream.bytesWritten().charAt(i)); + } +} + +test(receivedStringShouldDecodeFrom2BytesPerChar) +{ + Firmata.attach(STRING_DATA, handleStringCallback); + + byte message[] = { START_SYSEX, STRING_DATA, 'b', 0, 'y', 0, 'e', 0, '!', 0, END_SYSEX }; + processMessage(message, 11); + + assertEqual("bye!", _receivedString); +} + From f13a61bce62406fc182083cf0c527f25b3ef38c1 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 18 Mar 2017 16:47:46 -0700 Subject: [PATCH 069/110] bugfix release --- Boards.h | 4 ++-- Firmata.cpp | 4 ++-- Firmata.h | 4 ++-- FirmataConstants.h | 4 ++-- extras/revisions.txt | 7 +++++++ library.properties | 2 +- readme.md | 8 ++++---- release.sh | 4 ++-- 8 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Boards.h b/Boards.h index f2b61da2..7003565e 100644 --- a/Boards.h +++ b/Boards.h @@ -1,7 +1,7 @@ /* Boards.h - Hardware Abstraction Layer for Firmata library Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2017 Jeff Hoefs. 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 @@ -10,7 +10,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 + Last updated March 16th, 2017 */ #ifndef Firmata_Boards_h diff --git a/Firmata.cpp b/Firmata.cpp index bd229ac9..8e48bc79 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,7 +1,7 @@ /* - Firmata.cpp - Firmata library v2.5.5 - 2017-03-06 + Firmata.cpp - Firmata library v2.5.6 - 2017-03-18 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2017 Jeff Hoefs. 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 diff --git a/Firmata.h b/Firmata.h index 90c1932d..ec951657 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,7 +1,7 @@ /* - Firmata.h - Firmata library v2.5.5 - 2017-03-06 + Firmata.h - Firmata library v2.5.6 - 2017-03-18 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2017 Jeff Hoefs. 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 diff --git a/FirmataConstants.h b/FirmataConstants.h index de84ceda..e8d21812 100644 --- a/FirmataConstants.h +++ b/FirmataConstants.h @@ -1,7 +1,7 @@ /* FirmataConstants.h Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. - Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2017 Jeff Hoefs. 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 @@ -21,7 +21,7 @@ namespace firmata { */ static const int FIRMWARE_MAJOR_VERSION = 2; static const int FIRMWARE_MINOR_VERSION = 5; -static const int FIRMWARE_BUGFIX_VERSION = 5; +static const int FIRMWARE_BUGFIX_VERSION = 6; /* Version numbers for the protocol. The protocol is still changing, so these * version numbers are important. diff --git a/extras/revisions.txt b/extras/revisions.txt index 689dc0c4..3acc700f 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,10 @@ +FIRMATA 2.5.6 - Mar 18, 2017 + +[core library] +* Fixed string encoder/decoder bug that also affected I2C (Zak Fields) +* Added support for Arduino Primo (chiararuggeri) +* Added unit tests for Firmata string message encoding/decoding + FIRMATA 2.5.5 - Mar 6, 2017 [core library] diff --git a/library.properties b/library.properties index 4d8df5ae..791ce146 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.5.5 +version=2.5.6 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino/Genuino boards. diff --git a/readme.md b/readme.md index 8b370815..7138c4a9 100644 --- a/readme.md +++ b/readme.md @@ -94,7 +94,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ##Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.5) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.6) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -105,7 +105,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.5) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -115,7 +115,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ###Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.5) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -124,7 +124,7 @@ for Arduino 1.0.x vs 1.6.x). ###Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.5) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index 7fc12d1c..11a9b725 100644 --- a/release.sh +++ b/release.sh @@ -15,7 +15,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.5.zip +mv ./temp/Firmata.zip Firmata-2.5.6.zip #package for Arduino 1.6.x cp library.properties temp/Firmata @@ -29,5 +29,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.5.zip +mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.6.zip rm -r ./temp From 182673a52783dcd7862afeff7cc14b9d067e350e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?FRANCE=20Fr=C3=A9d=C3=A9ric?= Date: Sun, 9 Apr 2017 10:28:52 +0200 Subject: [PATCH 070/110] Adapt markdown --- readme.md | 108 +++++++++++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 49 deletions(-) diff --git a/readme.md b/readme.md index 7138c4a9..a97a035b 100644 --- a/readme.md +++ b/readme.md @@ -1,78 +1,88 @@ -#Firmata +# Firmata -[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/firmata/arduino?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/firmata/arduino?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Firmata is a protocol for communicating with microcontrollers from software on a host computer. The [protocol](https://github.com/firmata/protocol) can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The Arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. If you would like to contribute to Firmata, please see the [Contributing](#contributing) section below. -##Usage +# Contents + +- [Usage](#usage) +- [Firmata Client Libraries](#firmata-client-libraries) +- [Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher](#updating-firmata-in-the-arduino-ide---arduino-1.6.4-and-higher) + - [Mac OSX:](#mac-osx:) + - [Windows](#windows:) + - [Linux](#linux:) +- [Using the Source code rather than release archive (only for versions older than Arduino 1.6.3)](#using-the-source-code-rather-than-release-archive-only-for-versions-older-than-arduino-1.6.3) + +## Usage There are two main models of usage of Firmata. In one model, the author of the Arduino sketch uses the various methods provided by the Firmata library to selectively send and receive data between the Arduino device and the software running on the host computer. For example, a user can send analog data to the host using ``` Firmata.sendAnalog(analogPin, analogRead(analogPin)) ``` or send data packed in a string using ``` Firmata.sendString(stringToSend) ```. See File -> Examples -> Firmata -> AnalogFirmata & EchoString respectively for examples. The second and more common model is to load a general purpose sketch called StandardFirmata (or one of the variants such as StandardFirmataPlus or StandardFirmataEthernet depending on your needs) on the Arduino board and then use the host computer exclusively to interact with the Arduino board. StandardFirmata is located in the Arduino IDE in File -> Examples -> Firmata. -##Firmata Client Libraries +## Firmata Client Libraries Most of the time you will be interacting with Arduino with a client library on the host computers. Several Firmata client libraries have been implemented in a variety of popular programming languages: * processing - * [https://github.com/firmata/processing] - * [http://funnel.cc] + * [https://github.com/firmata/processing](https://github.com/firmata/processing) + * [http://funnel.cc](http://funnel.cc) * python - * [https://github.com/MrYsLab/pymata-aio] - * [https://github.com/MrYsLab/PyMata] - * [https://github.com/tino/pyFirmata] - * [https://github.com/lupeke/python-firmata] - * [https://github.com/firmata/pyduino] + * [https://github.com/MrYsLab/pymata-aio](https://github.com/MrYsLab/pymata-aio) + * [https://github.com/MrYsLab/PyMata]([https://github.com/MrYsLab/PyMata) + * [https://github.com/tino/pyFirmata](https://github.com/tino/pyFirmata) + * [https://github.com/lupeke/python-firmata](https://github.com/lupeke/python-firmata) + * [https://github.com/firmata/pyduino](https://github.com/firmata/pyduino) * perl - * [https://github.com/ntruchsess/perl-firmata] - * [https://github.com/rcaputo/rx-firmata] + * [https://github.com/ntruchsess/perl-firmata](https://github.com/ntruchsess/perl-firmata) + * [https://github.com/rcaputo/rx-firmata](https://github.com/rcaputo/rx-firmata) * ruby - * [https://github.com/hardbap/firmata] - * [https://github.com/PlasticLizard/rufinol] - * [http://funnel.cc] + * [https://github.com/hardbap/firmata](https://github.com/hardbap/firmata) + * [https://github.com/PlasticLizard/rufinol](https://github.com/PlasticLizard/rufinol) + * [http://funnel.cc](http://funnel.cc) * clojure - * [https://github.com/nakkaya/clodiuno] - * [https://github.com/peterschwarz/clj-firmata] + * [https://github.com/nakkaya/clodiuno](https://github.com/nakkaya/clodiuno) + * [https://github.com/peterschwarz/clj-firmata](https://github.com/peterschwarz/clj-firmata) * javascript - * [https://github.com/jgautier/firmata] - * [https://github.com/rwldrn/johnny-five] - * [http://breakoutjs.com] + * [https://github.com/jgautier/firmata](https://github.com/jgautier/firmata) + * [https://github.com/rwldrn/johnny-five](https://github.com/rwldrn/johnny-five) + * [http://breakoutjs.com](http://breakoutjs.com) * java - * [https://github.com/kurbatov/firmata4j] - * [https://github.com/4ntoine/Firmata] - * [https://github.com/reapzor/FiloFirmata] + * [https://github.com/kurbatov/firmata4j](https://github.com/kurbatov/firmata4j) + * [https://github.com/4ntoine/Firmata](https://github.com/4ntoine/Firmata) + * [https://github.com/reapzor/FiloFirmata](https://github.com/reapzor/FiloFirmata) * .NET - * [https://github.com/SolidSoils/Arduino] - * [http://www.acraigie.com/programming/firmatavb/default.html] + * [https://github.com/SolidSoils/Arduino](https://github.com/SolidSoils/Arduino) + * [http://www.acraigie.com/programming/firmatavb/default.html](http://www.acraigie.com/programming/firmatavb/default.html) * Flash/AS3 - * [http://funnel.cc] - * [http://code.google.com/p/as3glue/] + * [http://funnel.cc](http://funnel.cc) + * [http://code.google.com/p/as3glue/](http://code.google.com/p/as3glue/) * PHP - * [https://github.com/ThomasWeinert/carica-firmata] - * [https://github.com/oasynnoum/phpmake_firmata] + * [https://github.com/ThomasWeinert/carica-firmata]() + * [https://github.com/oasynnoum/phpmake_firmata](https://github.com/oasynnoum/phpmake_firmata) * Haskell - * [http://hackage.haskell.org/package/hArduino] + * [http://hackage.haskell.org/package/hArduino](http://hackage.haskell.org/package/hArduino) * iOS - * [https://github.com/jacobrosenthal/iosfirmata] + * [https://github.com/jacobrosenthal/iosfirmata](https://github.com/jacobrosenthal/iosfirmata) * Dart - * [https://github.com/nfrancois/firmata] + * [https://github.com/nfrancois/firmata](https://github.com/nfrancois/firmata) * Max/MSP - * [http://www.maxuino.org/] + * [http://www.maxuino.org/](http://www.maxuino.org/) * Elixir - * [https://github.com/kfatehi/firmata] + * [https://github.com/kfatehi/firmata](https://github.com/kfatehi/firmata) * Modelica - * [https://www.wolfram.com/system-modeler/libraries/model-plug/] + * [https://www.wolfram.com/system-modeler/libraries/model-plug/](https://www.wolfram.com/system-modeler/libraries/model-plug/) * Go - * [https://github.com/kraman/go-firmata] + * [https://github.com/kraman/go-firmata](https://github.com/kraman/go-firmata) * vvvv - * [https://vvvv.org/blog/arduino-second-service] + * [https://vvvv.org/blog/arduino-second-service](https://vvvv.org/blog/arduino-second-service) * openFrameworks - * [http://openframeworks.cc/documentation/communication/ofArduino/] + * [http://openframeworks.cc/documentation/communication/ofArduino/](http://openframeworks.cc/documentation/communication/ofArduino/) * Rust - * [https://github.com/zankich/rust-firmata] + * [https://github.com/zankich/rust-firmata](https://github.com/zankich/rust-firmata) Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details. -##Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher +## Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher If you want to update to the latest stable version: @@ -81,7 +91,7 @@ If you want to update to the latest stable version: 3. Click the `Select version` dropdown and select the most recent version (note you can also install previous versions) 4. Click `Install`. -###Cloning Firmata +### Cloning Firmata If you are contributing to Firmata or otherwise need a version newer than the latest tagged release, you can clone Firmata directly to your Arduino/libraries/ directory (where 3rd party libraries are installed). This only works for Arduino 1.6.4 and higher, for older versions you need to clone into the Arduino application directory (see section below titled "Using the Source code rather than release archive"). Be sure to change the name to Firmata as follows: @@ -92,13 +102,13 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir *Update path above if you're using Windows or Linux or changed the default Arduino directory on OS X* -##Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) +## Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.6) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* -###Mac OSX: +### Mac OSX: The Firmata library is contained within the Arduino package. @@ -112,7 +122,7 @@ for Arduino 1.0.x vs 1.6.x) *If you are using the Java 7 version of Arduino 1.5.7 or higher, the file path will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory).* -###Windows: +### Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing `Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download @@ -121,7 +131,7 @@ for Arduino 1.0.x vs 1.6.x). *Update the path and Arduino version as necessary* -###Linux: +### Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing `Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download @@ -130,7 +140,7 @@ for Arduino 1.0.x vs 1.6.x). *Update the path and Arduino version as necessary* -###Using the Source code rather than release archive (only for versions older than Arduino 1.6.3) +### Using the Source code rather than release archive (only for versions older than Arduino 1.6.3) *It is recommended you update to Arduino 1.6.4 or higher if possible, that way you can clone directly into the external Arduino/libraries/ directory which persists between Arduino application updates. Otherwise you will need to move your clone each time you update to a newer version of the Arduino IDE.* @@ -155,8 +165,8 @@ To generate properly formatted versions of Firmata (for Arduino 1.0.x and Arduin `release.sh` script. - -##Contributing + +## Contributing If you discover a bug or would like to propose a new feature, please open a new [issue](https://github.com/firmata/arduino/issues?sort=created&state=open). Due to the limited memory of standard Arduino boards we cannot add every requested feature to StandardFirmata. Requests to add new features to StandardFirmata will be evaluated by the Firmata developers. However it is still possible to add new features to other Firmata implementations (Firmata is a protocol whereas StandardFirmata is just one of many possible implementations). From 4a13241563c53c52d051713267e1c090ce25b56a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?FRANCE=20Fr=C3=A9d=C3=A9ric?= Date: Sun, 9 Apr 2017 10:35:44 +0200 Subject: [PATCH 071/110] Adapt markdown Content table --- readme.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index a97a035b..2b00f9c6 100644 --- a/readme.md +++ b/readme.md @@ -8,11 +8,14 @@ Firmata is a protocol for communicating with microcontrollers from software on a - [Usage](#usage) - [Firmata Client Libraries](#firmata-client-libraries) -- [Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher](#updating-firmata-in-the-arduino-ide---arduino-1.6.4-and-higher) - - [Mac OSX:](#mac-osx:) - - [Windows](#windows:) - - [Linux](#linux:) -- [Using the Source code rather than release archive (only for versions older than Arduino 1.6.3)](#using-the-source-code-rather-than-release-archive-only-for-versions-older-than-arduino-1.6.3) +- [Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher](#updating-firmata-in-the-arduino-ide---arduino-164-and-higher) +- [Cloning Firmata](#cloning-firmata) +- [Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x)](#updating-firmata-in-the-arduino-ide---older-versions---163-or-10x) + - [Mac OSX:](#mac-osx) + - [Windows](#windows) + - [Linux](#linux) +- [Using the Source code rather than release archive (only for versions older than Arduino 1.6.3)](#using-the-source-code-rather-than-release-archive-only-for-versions-older-than-arduino-163) +- [Contributing](#contributing) ## Usage From 4cfb2bc062b2660e745f76900ef0be6a737491e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?FRANCE=20Fr=C3=A9d=C3=A9ric?= Date: Sun, 9 Apr 2017 10:41:27 +0200 Subject: [PATCH 072/110] Adapt markdown Content table --- readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index 2b00f9c6..88e6c508 100644 --- a/readme.md +++ b/readme.md @@ -10,10 +10,10 @@ Firmata is a protocol for communicating with microcontrollers from software on a - [Firmata Client Libraries](#firmata-client-libraries) - [Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher](#updating-firmata-in-the-arduino-ide---arduino-164-and-higher) - [Cloning Firmata](#cloning-firmata) -- [Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x)](#updating-firmata-in-the-arduino-ide---older-versions---163-or-10x) - - [Mac OSX:](#mac-osx) - - [Windows](#windows) - - [Linux](#linux) +- [Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x)](#updating-firmata-in-the-arduino-ide---older-versions--163-or-10x) + - [Mac OSX:](#mac-osx) + - [Windows](#windows) + - [Linux](#linux) - [Using the Source code rather than release archive (only for versions older than Arduino 1.6.3)](#using-the-source-code-rather-than-release-archive-only-for-versions-older-than-arduino-163) - [Contributing](#contributing) From c63a34ef9a08d398d5e6ab83d056d71d430270a2 Mon Sep 17 00:00:00 2001 From: Santiago Castro Date: Tue, 18 Apr 2017 02:37:00 -0300 Subject: [PATCH 073/110] Fix broken Markdown headings --- test/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/readme.md b/test/readme.md index 726cbcba..ab8f8c3d 100644 --- a/test/readme.md +++ b/test/readme.md @@ -1,4 +1,4 @@ -#Testing Firmata +# Testing Firmata Tests tests are written using the [ArduinoUnit](https://github.com/mmurdoch/arduinounit) library (version 2.0). From 7507bb9cac70959e59392bc0bbbb7e4be97580fb Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Wed, 19 Apr 2017 09:38:08 -0400 Subject: [PATCH 074/110] Add support for Arduino MKRFox1200 --- Boards.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Boards.h b/Boards.h index 7003565e..7efb9be4 100644 --- a/Boards.h +++ b/Boards.h @@ -276,6 +276,22 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) // deprecated since v2.4 +// Arduino MKRFox1200 +#elif defined(ARDUINO_SAMD_MKRFox1200) +#define TOTAL_ANALOG_PINS 7 +#define TOTAL_PINS 33 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog + 3 usb + 1 aref + 5 sd + 1 bottom pad + 1 battery adc +#define IS_PIN_DIGITAL(p) ((((p) >= 0 && (p) <= 21)) && !IS_PIN_SERIAL(p)) +#define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 32) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14 +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 15) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 + // Arduino Zero // Note this will work with an Arduino Zero Pro, but not with an Arduino M0 Pro From d4a9ba96706bb1a979049bc63c0bf824e390a218 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Wed, 19 Apr 2017 13:05:18 -0400 Subject: [PATCH 075/110] MKRZero, MKR1000, MKRFox1200: remove !IS_PIN_SERIAL check in IS_PIN_DIGITAL --- Boards.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Boards.h b/Boards.h index 7efb9be4..8b18cff5 100644 --- a/Boards.h +++ b/Boards.h @@ -247,7 +247,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #elif defined(ARDUINO_SAMD_MKR1000) #define TOTAL_ANALOG_PINS 7 #define TOTAL_PINS 22 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog -#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21) && !IS_PIN_SERIAL(p)) +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 21) #define IS_PIN_ANALOG(p) ((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 @@ -264,7 +264,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #elif defined(ARDUINO_SAMD_MKRZERO) #define TOTAL_ANALOG_PINS 7 #define TOTAL_PINS 34 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog + 3 usb + 1 aref + 5 sd + 1 bottom pad + 1 led + 1 battery adc -#define IS_PIN_DIGITAL(p) ((((p) >= 0 && (p) <= 21) || (p) == 32) && !IS_PIN_SERIAL(p)) +#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21) || (p) == 32) #define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 33) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 @@ -280,7 +280,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #elif defined(ARDUINO_SAMD_MKRFox1200) #define TOTAL_ANALOG_PINS 7 #define TOTAL_PINS 33 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog + 3 usb + 1 aref + 5 sd + 1 bottom pad + 1 battery adc -#define IS_PIN_DIGITAL(p) ((((p) >= 0 && (p) <= 21)) && !IS_PIN_SERIAL(p)) +#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21)) #define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 32) #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 From 138a39fcc201b620986248d1140610f643b53d3a Mon Sep 17 00:00:00 2001 From: "Frederic.Pillon" Date: Tue, 1 Aug 2017 08:49:26 +0200 Subject: [PATCH 076/110] Add support for STM32 MCU based boards Signed-off-by: Frederic.Pillon --- Boards.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Boards.h b/Boards.h index 8b18cff5..3fba60c6 100644 --- a/Boards.h +++ b/Boards.h @@ -780,6 +780,26 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) #define DEFAULT_PWM_RESOLUTION 10 +// STM32 based boards +#elif defined(ARDUINO_ARCH_STM32) +#define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS +#define TOTAL_PINS NUM_DIGITAL_PINS +#define TOTAL_PORTS MAX_NB_PORT +#define VERSION_BLINK_PIN LED_BUILTIN +// PIN_SERIALY_RX/TX defined in the variant.h +#define IS_PIN_DIGITAL(p) (digitalPinIsValid(p) && !pinIsSerial(p)) +#define IS_PIN_ANALOG(p) ((p >= A0) && (p < AEND) && !pinIsSerial(p)) +#define IS_PIN_PWM(p) (IS_PIN_DIGITAL(p) && digitalPinHasPWM(p)) +#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_I2C(p) (IS_PIN_DIGITAL(p) && digitalPinHasI2C(p)) +#define IS_PIN_SPI(p) (IS_PIN_DIGITAL(p) && digitalPinHasSPI(p)) +#define IS_PIN_INTERRUPT(p) (IS_PIN_DIGITAL(p) && (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT))) +#define IS_PIN_SERIAL(p) (digitalPinHasSerial(p) && !pinIsSerial(p)) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) (p-A0) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) +#define DEFAULT_PWM_RESOLUTION PWM_RESOLUTION // anything else #else From d1848c18ea5392ba38794efd23940246491affa4 Mon Sep 17 00:00:00 2001 From: MJPees Date: Sun, 9 Jul 2017 13:49:52 +0200 Subject: [PATCH 077/110] added server mode server mode implemented. --- .../StandardFirmataEthernet.ino | 25 ++- .../StandardFirmataEthernet/ethernetConfig.h | 16 +- utility/EthernetServerStream.cpp | 3 + utility/EthernetServerStream.h | 146 ++++++++++++++++++ 4 files changed, 178 insertions(+), 12 deletions(-) create mode 100644 utility/EthernetServerStream.cpp create mode 100644 utility/EthernetServerStream.h diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index f5c86bcd..07f7a89d 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -26,8 +26,8 @@ /* README - StandardFirmataEthernet is a TCP client implementation. You will need a Firmata client library - with a network transport that can act as a TCP server in order to establish a connection between + StandardFirmataEthernet is a TCP client/server implementation. You will need a Firmata client library + with a network transport that can act as a TCP server or client in order to establish a connection between StandardFirmataEthernet and the Firmata client application. To use StandardFirmataEthernet you will need to have one of the following @@ -68,6 +68,7 @@ // follow the instructions in ethernetConfig.h to configure your particular hardware #include "ethernetConfig.h" #include "utility/EthernetClientStream.h" +#include "utility/EthernetServerStream.h" /* * Uncomment the following include to enable interfacing with Serial devices via hardware or @@ -103,17 +104,25 @@ #if defined remote_ip && !defined remote_host #ifdef local_ip -EthernetClientStream stream(client, local_ip, remote_ip, NULL, remote_port); +EthernetClientStream stream(client, local_ip, remote_ip, NULL, network_port); #else -EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), remote_ip, NULL, remote_port); +EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), remote_ip, NULL, network_port); #endif #endif #if !defined remote_ip && defined remote_host #ifdef local_ip -EthernetClientStream stream(client, local_ip, IPAddress(0, 0, 0, 0), remote_host, remote_port); +EthernetClientStream stream(client, local_ip, IPAddress(0, 0, 0, 0), remote_host, network_port ); #else -EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0), remote_host, remote_port); +EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0), remote_host, network_port); +#endif +#endif + +#if !defined remote_ip && !defined remote_host +#ifdef local_ip +EthernetServerStream stream(local_ip, network_port); +#else +EthernetServerStream stream(IPAddress(0, 0, 0, 0), network_port); #endif #endif @@ -864,6 +873,10 @@ void initTransport() #endif DEBUG_PRINTLN("connecting..."); + + DEBUG_PRINT("IP Address: "); + IPAddress ip = Ethernet.localIP(); + DEBUG_PRINTLN(ip); } void initFirmata() diff --git a/examples/StandardFirmataEthernet/ethernetConfig.h b/examples/StandardFirmataEthernet/ethernetConfig.h index 345eafc6..baf3465a 100644 --- a/examples/StandardFirmataEthernet/ethernetConfig.h +++ b/examples/StandardFirmataEthernet/ethernetConfig.h @@ -3,8 +3,8 @@ * * You must configure your particular hardware. Follow the steps below. * - * Currently StandardFirmataEthernet is configured as a TCP client. An - * option to configure as a server may be added in the future. + * By default, StandardFirmataEthernet is configured as a TCP client. + * To configure as a TCP server, see STEP 2 *============================================================================*/ // STEP 1 [REQUIRED] @@ -46,16 +46,20 @@ EthernetClient client; YunClient client; #endif -// STEP 2[REQUIRED for all boards and shields] -// replace with IP of the server you want to connect to, comment out if using 'remote_host' +// STEP 2 [REQUIRED for all boards and shields] +// TCP Client configuration: +// To configure your board as a TCP client, set the IP address of the server you want to connect to. +// TCP Server configuration: +// To configure your board as a TCP server, comment out the following line and also ensure that +// remote_host is also commented out. #define remote_ip IPAddress(10, 0, 0, 3) // *** REMOTE HOST IS NOT YET WORKING *** // replace with hostname of server you want to connect to, comment out if using 'remote_ip' // #define remote_host "server.local" // STEP 3 [REQUIRED] -// Replace with the port that your server is listening on -#define remote_port 3030 +// Replace with the port that your client or server is listening on. +#define network_port 3030 // STEP 4 [REQUIRED unless using DHCP] // Replace with your board or ethernet shield's IP address diff --git a/utility/EthernetServerStream.cpp b/utility/EthernetServerStream.cpp new file mode 100644 index 00000000..de466f54 --- /dev/null +++ b/utility/EthernetServerStream.cpp @@ -0,0 +1,3 @@ +/* + * Implementation is in EthernetServerStream.h to avoid linker issues. + */ diff --git a/utility/EthernetServerStream.h b/utility/EthernetServerStream.h new file mode 100644 index 00000000..e80c799c --- /dev/null +++ b/utility/EthernetServerStream.h @@ -0,0 +1,146 @@ +/* + EthernetServerStream.h + + Copyright (C) 2017 Marc Josef Pees. 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. + + See file LICENSE.txt for further informations on licensing terms. + + Last updated July 10th, 2017 + */ + +#ifndef ETHERNETSERVERSTREAM_H +#define ETHERNETSERVERSTREAM_H + +#include +#include +#include + +//#define SERIAL_DEBUG +#include "firmataDebug.h" + +class EthernetServerStream : public Stream +{ + public: + EthernetServerStream(IPAddress localip, uint16_t port); + int available(); + int read(); + int peek(); + void flush(); + size_t write(uint8_t); + void maintain(IPAddress localip); + + private: + EthernetClient client; + IPAddress localip; + uint16_t port; + bool connected; + bool maintain(); + void stop(); + + protected: + EthernetServer server = EthernetServer(3030); + bool listening = false; + bool connect_client(); +}; + + +/* + * EthernetServerStream.cpp + * Copied here as a hack to linker issues with 3rd party board packages that don't properly + * implement the Arduino network APIs. + */ +EthernetServerStream::EthernetServerStream(IPAddress localip, uint16_t port) + : localip(localip), + port(port), + connected(false) +{ +} + +bool EthernetServerStream::connect_client() + { + if ( connected ) + { + if ( client && client.connected() ) return true; + stop(); + } + + EthernetClient newClient = server.available(); + if ( !newClient ) return false; + client = newClient; + connected = true; + return true; + } + +int +EthernetServerStream::available() +{ + return maintain() ? client.available() : 0; +} + +int +EthernetServerStream::read() +{ + return maintain() ? client.read() : -1; +} + +int +EthernetServerStream::peek() +{ + return maintain() ? client.peek() : -1; +} + +void EthernetServerStream::flush() +{ + if (maintain()) + client.flush(); +} + +size_t +EthernetServerStream::write(uint8_t c) +{ + return maintain() ? client.write(c) : 0; +} + +void +EthernetServerStream::maintain(IPAddress localip) +{ + // ensure the local IP is updated in the case that it is changed by the DHCP server + if (this->localip != localip) { + this->localip = localip; + if (connected) + stop(); + } +} + +void +EthernetServerStream::stop() +{ + if(client) + { + client.stop(); + } + connected = false; +} + +bool +EthernetServerStream::maintain() +{ + if (connect_client()) return true; + + stop(); + + if(!listening) + { + server = EthernetServer(port); + server.begin(); + listening = true; + } + return false; +} + +#endif /* ETHERNETSERVERSTREAM_H */ From 0651617e541bfbcf7b5bb1c5d5378a649652ff12 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 13 Aug 2017 21:40:51 -0700 Subject: [PATCH 078/110] Improve StandardFirmataEthernet logging --- .../StandardFirmataEthernet.ino | 30 ++++++++++++------- utility/EthernetClientStream.h | 4 +-- utility/EthernetServerStream.h | 1 + 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 07f7a89d..ca3a3e3e 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -11,7 +11,7 @@ Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved. Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. - Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved. + Copyright (C) 2009-2017 Jeff Hoefs. 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 @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 + Last updated August 13th, 2017 */ /* @@ -832,6 +832,17 @@ void systemResetCallback() isResetting = false; } +void printEthernetStatus() +{ + DEBUG_PRINT("Local IP Address: "); + IPAddress ip = Ethernet.localIP(); + DEBUG_PRINTLN(ip); +#ifdef remote_ip + DEBUG_PRINT("Connecting to server at: "); + DEBUG_PRINTLN(remote_ip); +#endif +} + /* * StandardFirmataEthernet communicates with Ethernet shields over SPI. Therefore all * SPI pins must be set to IGNORE. Otherwise Firmata would break SPI communication. @@ -868,15 +879,14 @@ void initTransport() #ifdef local_ip Ethernet.begin((uint8_t *)mac, local_ip); //start ethernet #else - Ethernet.begin((uint8_t *)mac); //start ethernet using dhcp + DEBUG_PRINTLN("Local IP will be requested from DHCP..."); + //start ethernet using dhcp + if (Ethernet.begin((uint8_t *)mac) == 0) { + DEBUG_PRINTLN("Failed to configure Ethernet using DHCP"); + } #endif #endif - - DEBUG_PRINTLN("connecting..."); - - DEBUG_PRINT("IP Address: "); - IPAddress ip = Ethernet.localIP(); - DEBUG_PRINTLN(ip); + printEthernetStatus(); } void initFirmata() @@ -895,7 +905,7 @@ void initFirmata() // start up Network Firmata: Firmata.begin(stream); - systemResetCallback(); // reset to default config + systemResetCallback(); // Initialize default configuration } void setup() diff --git a/utility/EthernetClientStream.h b/utility/EthernetClientStream.h index 6b024983..1b7d2e29 100644 --- a/utility/EthernetClientStream.h +++ b/utility/EthernetClientStream.h @@ -130,9 +130,9 @@ EthernetClientStream::maintain() connected = host ? client.connect(host, port) : client.connect(ip, port); if (!connected) { time_connect = millis(); - DEBUG_PRINTLN("connection failed. attempting to reconnect..."); + DEBUG_PRINTLN("Connection failed. Attempting to reconnect..."); } else { - DEBUG_PRINTLN("connected"); + DEBUG_PRINTLN("Connected"); } } return connected; diff --git a/utility/EthernetServerStream.h b/utility/EthernetServerStream.h index e80c799c..56f541e9 100644 --- a/utility/EthernetServerStream.h +++ b/utility/EthernetServerStream.h @@ -73,6 +73,7 @@ bool EthernetServerStream::connect_client() if ( !newClient ) return false; client = newClient; connected = true; + DEBUG_PRINTLN("Connected"); return true; } From ac32d18e44bde5e27f3300f002d0e4b558b62763 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 15 Aug 2017 12:05:48 +0700 Subject: [PATCH 079/110] add Adafruit nrf52 boards --- Boards.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Boards.h b/Boards.h index 3fba60c6..942b2ffc 100644 --- a/Boards.h +++ b/Boards.h @@ -801,6 +801,24 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) (p) #define DEFAULT_PWM_RESOLUTION PWM_RESOLUTION +// Adafruit Bluefruit nRF52 boards +#elif defined(ARDUINO_NRF52_ADAFRUIT) +#define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS +#define TOTAL_PINS 32 +#define VERSION_BLINK_PIN LED_BUILTIN +#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p) ((p) == PIN_A0 || (p) == PIN_A1 || (p) == PIN_A2 || (p) == PIN_A3 || \ + (p) == PIN_A4 || (p) == PIN_A5 || (p) == PIN_A6 || (p) == PIN_A7) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_I2C(p) ((p) == PIN_WIRE_SDA || (p) == PIN_WIRE_SCL) +#define IS_PIN_SPI(p) ((p) == SS || (p)== MOSI || (p) == MISO || (p == SCK)) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ( ((p) == PIN_A0) ? 0 : ((p) == PIN_A1) ? 1 : ((p) == PIN_A2) ? 2 : ((p) == PIN_A3) ? 3 : \ + ((p) == PIN_A4) ? 4 : ((p) == PIN_A5) ? 5 : ((p) == PIN_A6) ? 6 : ((p) == PIN_A7) ? 7 : (127)) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) + // anything else #else #error "Please edit Boards.h with a hardware abstraction for this board" From 4fce1f33b6b7c81e262f8a20d7c85cca42df8e91 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 18 Aug 2017 01:06:01 -0700 Subject: [PATCH 080/110] Fix I2C config parameter interpretation The current implementation pulls bytes out of the sysex buffer, regardless of whether or not the user specified such bytes. --- examples/StandardFirmata/StandardFirmata.ino | 2 +- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 2 +- examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino | 2 +- examples/StandardFirmataEthernet/StandardFirmataEthernet.ino | 2 +- examples/StandardFirmataPlus/StandardFirmataPlus.ino | 2 +- examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index c32639df..8439ee91 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -586,7 +586,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_CONFIG: delayTime = (argv[0] + (argv[1] << 7)); - if (delayTime > 0) { + if (argc > 1 && delayTime > 0) { i2cReadDelayTime = delayTime; } diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 6ccf7d1b..e962ed3e 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -603,7 +603,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_CONFIG: delayTime = (argv[0] + (argv[1] << 7)); - if (delayTime > 0) { + if (argc > 1 && delayTime > 0) { i2cReadDelayTime = delayTime; } diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 87942c70..42e7857e 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -588,7 +588,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_CONFIG: delayTime = (argv[0] + (argv[1] << 7)); - if (delayTime > 0) { + if (argc > 1 && delayTime > 0) { i2cReadDelayTime = delayTime; } diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index ca3a3e3e..376cf23a 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -666,7 +666,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_CONFIG: delayTime = (argv[0] + (argv[1] << 7)); - if (delayTime > 0) { + if (argc > 1 && delayTime > 0) { i2cReadDelayTime = delayTime; } diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 49a1969c..52885ac0 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -611,7 +611,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_CONFIG: delayTime = (argv[0] + (argv[1] << 7)); - if (delayTime > 0) { + if (argc > 1 && delayTime > 0) { i2cReadDelayTime = delayTime; } diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index d4cbfab8..307d764e 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -675,7 +675,7 @@ void sysexCallback(byte command, byte argc, byte *argv) case I2C_CONFIG: delayTime = (argv[0] + (argv[1] << 7)); - if (delayTime > 0) { + if (argc > 1 && delayTime > 0) { i2cReadDelayTime = delayTime; } From a939ca10352eedcea4b6250b997495e2cb205868 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 19 Aug 2017 14:01:44 -0700 Subject: [PATCH 081/110] bugfix release --- Boards.h | 2 +- Firmata.cpp | 2 +- Firmata.h | 2 +- FirmataConstants.h | 2 +- examples/StandardFirmata/StandardFirmata.ino | 2 +- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 2 +- .../StandardFirmataChipKIT.ino | 2 +- .../StandardFirmataEthernet.ino | 2 +- examples/StandardFirmataPlus/StandardFirmataPlus.ino | 2 +- examples/StandardFirmataWiFi/StandardFirmataWiFi.ino | 2 +- extras/revisions.txt | 12 ++++++++++++ library.properties | 2 +- readme.md | 10 ++++------ release.sh | 6 +++--- 14 files changed, 30 insertions(+), 20 deletions(-) diff --git a/Boards.h b/Boards.h index 942b2ffc..69bd3db0 100644 --- a/Boards.h +++ b/Boards.h @@ -10,7 +10,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated March 16th, 2017 + Last updated August 14th, 2017 */ #ifndef Firmata_Boards_h diff --git a/Firmata.cpp b/Firmata.cpp index 8e48bc79..e35c3dcb 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.6 - 2017-03-18 + Firmata.cpp - Firmata library v2.5.7 - 2017-08-19 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved. diff --git a/Firmata.h b/Firmata.h index ec951657..c07b38d3 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.6 - 2017-03-18 + Firmata.h - Firmata library v2.5.7 - 2017-08-19 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved. diff --git a/FirmataConstants.h b/FirmataConstants.h index e8d21812..dee84079 100644 --- a/FirmataConstants.h +++ b/FirmataConstants.h @@ -21,7 +21,7 @@ namespace firmata { */ static const int FIRMWARE_MAJOR_VERSION = 2; static const int FIRMWARE_MINOR_VERSION = 5; -static const int FIRMWARE_BUGFIX_VERSION = 6; +static const int FIRMWARE_BUGFIX_VERSION = 7; /* Version numbers for the protocol. The protocol is still changing, so these * version numbers are important. diff --git a/examples/StandardFirmata/StandardFirmata.ino b/examples/StandardFirmata/StandardFirmata.ino index 8439ee91..b043c11e 100755 --- a/examples/StandardFirmata/StandardFirmata.ino +++ b/examples/StandardFirmata/StandardFirmata.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 + Last updated August 17th, 2017 */ #include diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index e962ed3e..57756587 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 + Last updated August 17th, 2017 */ #include diff --git a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino index 42e7857e..e13d166d 100644 --- a/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino +++ b/examples/StandardFirmataChipKIT/StandardFirmataChipKIT.ino @@ -21,7 +21,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 + Last updated August 17th, 2017 */ #include // Gives us PWM and Servo on every pin diff --git a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino index 376cf23a..f512ccea 100644 --- a/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino +++ b/examples/StandardFirmataEthernet/StandardFirmataEthernet.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated August 13th, 2017 + Last updated August 17th, 2017 */ /* diff --git a/examples/StandardFirmataPlus/StandardFirmataPlus.ino b/examples/StandardFirmataPlus/StandardFirmataPlus.ino index 52885ac0..8fb51ebe 100644 --- a/examples/StandardFirmataPlus/StandardFirmataPlus.ino +++ b/examples/StandardFirmataPlus/StandardFirmataPlus.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 + Last updated August 17th, 2017 */ /* diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 307d764e..4f7e4163 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -22,7 +22,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated October 16th, 2016 + Last updated August 17th, 2017 */ /* diff --git a/extras/revisions.txt b/extras/revisions.txt index 3acc700f..6290a72e 100644 --- a/extras/revisions.txt +++ b/extras/revisions.txt @@ -1,3 +1,15 @@ +FIRMATA 2.5.7 - Aug 19, 2017 + +[core library] +* Added support for Adafruit nrf52 boards (hathach) +* Added TCP server option to StandardFirmataEthernet (MJPees) +* Added support for STM32-based boards (fpistm) +* Added support for MKRFox1200 (sandeepmistry) + +[StandardFirmata & variants] +* Fixed I2C config parameter interpretation (zfields) +* Improve debug output in StandardFirmataEthernet + FIRMATA 2.5.6 - Mar 18, 2017 [core library] diff --git a/library.properties b/library.properties index 791ce146..83431fc9 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.5.6 +version=2.5.7 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino/Genuino boards. diff --git a/readme.md b/readme.md index 88e6c508..f9f8c15a 100644 --- a/readme.md +++ b/readme.md @@ -107,7 +107,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ## Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.6) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.7) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -118,7 +118,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.7) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -128,7 +128,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ### Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.7) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -137,7 +137,7 @@ for Arduino 1.0.x vs 1.6.x). ### Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.6) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.7) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -167,8 +167,6 @@ $ git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Content To generate properly formatted versions of Firmata (for Arduino 1.0.x and Arduino 1.6.x), run the `release.sh` script. - - ## Contributing If you discover a bug or would like to propose a new feature, please open a new [issue](https://github.com/firmata/arduino/issues?sort=created&state=open). Due to the limited memory of standard Arduino boards we cannot add every requested feature to StandardFirmata. Requests to add new features to StandardFirmata will be evaluated by the Firmata developers. However it is still possible to add new features to other Firmata implementations (Firmata is a protocol whereas StandardFirmata is just one of many possible implementations). diff --git a/release.sh b/release.sh index 11a9b725..05cb74e4 100644 --- a/release.sh +++ b/release.sh @@ -15,9 +15,9 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.6.zip +mv ./temp/Firmata.zip Arduino-1.0.x-Firmata-2.5.7.zip -#package for Arduino 1.6.x +#package for Arduino 1.6.x and 1.8.x cp library.properties temp/Firmata cd temp/Firmata mv readme.md ./extras/ @@ -29,5 +29,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.6.x-Firmata-2.5.6.zip +mv ./temp/Firmata.zip Firmata-2.5.7.zip rm -r ./temp From defa0ea92b524b4473b81428fe3c7dfc91c520bc Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Fri, 1 Dec 2017 09:54:19 -0500 Subject: [PATCH 082/110] Add support for Arduino MKR WAN 1300 and MKR GSM 1400 --- Boards.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Boards.h b/Boards.h index 69bd3db0..ae3e0639 100644 --- a/Boards.h +++ b/Boards.h @@ -292,6 +292,37 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) (p) // deprecated since v2.4 +// Arduino MKR WAN 1300 +#elif defined(ARDUINO_SAMD_MKRWAN1300) +#define TOTAL_ANALOG_PINS 7 +#define TOTAL_PINS 33 +#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21)) +#define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 32) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14 +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 15) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 + +// Arduino MKR GSM 1400 +#elif defined(ARDUINO_SAMD_MKRGSM1400) +#define TOTAL_ANALOG_PINS 7 +#define TOTAL_PINS 33 +#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21)) +#define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 32) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4 +#define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12 +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14 +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) ((p) - 15) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // deprecated since v2.4 // Arduino Zero // Note this will work with an Arduino Zero Pro, but not with an Arduino M0 Pro From e0594d44263c561e0809e8950ee3f9d91fd7e0a1 Mon Sep 17 00:00:00 2001 From: "Frederic.Pillon" Date: Mon, 29 Jan 2018 10:28:36 +0100 Subject: [PATCH 083/110] [STM32] Avoid using non standard constant AEND is an internal STM32 core constant and should not be used. Replaced by (A0 + TOTAL_ANALOG_PINS) Signed-off-by: Frederic.Pillon --- Boards.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Boards.h b/Boards.h index 69bd3db0..69c12481 100644 --- a/Boards.h +++ b/Boards.h @@ -788,7 +788,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define VERSION_BLINK_PIN LED_BUILTIN // PIN_SERIALY_RX/TX defined in the variant.h #define IS_PIN_DIGITAL(p) (digitalPinIsValid(p) && !pinIsSerial(p)) -#define IS_PIN_ANALOG(p) ((p >= A0) && (p < AEND) && !pinIsSerial(p)) +#define IS_PIN_ANALOG(p) ((p >= A0) && (p < (A0 + TOTAL_ANALOG_PINS)) && !pinIsSerial(p)) #define IS_PIN_PWM(p) (IS_PIN_DIGITAL(p) && digitalPinHasPWM(p)) #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) #define IS_PIN_I2C(p) (IS_PIN_DIGITAL(p) && digitalPinHasI2C(p)) From 73a73631338f2849d2083ed7b7320ea89204cd11 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 3 Mar 2018 12:26:57 -0800 Subject: [PATCH 084/110] update link to list of host software packages --- examples/AllInputsFirmata/AllInputsFirmata.ino | 4 ++-- examples/AnalogFirmata/AnalogFirmata.ino | 4 ++-- examples/EchoString/EchoString.ino | 4 ++-- examples/OldStandardFirmata/OldStandardFirmata.ino | 4 ++-- examples/ServoFirmata/ServoFirmata.ino | 4 ++-- examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino | 4 ++-- examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/AllInputsFirmata/AllInputsFirmata.ino b/examples/AllInputsFirmata/AllInputsFirmata.ino index 9a1439aa..fb9b0fdc 100644 --- a/examples/AllInputsFirmata/AllInputsFirmata.ino +++ b/examples/AllInputsFirmata/AllInputsFirmata.ino @@ -4,9 +4,9 @@ * any host computer software package. * * To download a host software package, please click on the following link - * to open the download page in your default browser. + * to open the list of Firmata client libraries in your default browser. * - * http://firmata.org/wiki/Download + * https://github.com/firmata/arduino#firmata-client-libraries */ /* diff --git a/examples/AnalogFirmata/AnalogFirmata.ino b/examples/AnalogFirmata/AnalogFirmata.ino index 7890bcfa..689c6851 100644 --- a/examples/AnalogFirmata/AnalogFirmata.ino +++ b/examples/AnalogFirmata/AnalogFirmata.ino @@ -4,9 +4,9 @@ * any host computer software package. * * To download a host software package, please click on the following link - * to open the download page in your default browser. + * to open the list of Firmata client libraries in your default browser. * - * http://firmata.org/wiki/Download + * https://github.com/firmata/arduino#firmata-client-libraries */ /* This firmware supports as many analog ports as possible, all analog inputs, diff --git a/examples/EchoString/EchoString.ino b/examples/EchoString/EchoString.ino index 3e794b3d..e1651d50 100644 --- a/examples/EchoString/EchoString.ino +++ b/examples/EchoString/EchoString.ino @@ -4,9 +4,9 @@ * any host computer software package. * * To download a host software package, please click on the following link - * to open the download page in your default browser. + * to open the list of Firmata client libraries in your default browser. * - * http://firmata.org/wiki/Download + * https://github.com/firmata/arduino#firmata-client-libraries */ /* This sketch accepts strings and raw sysex messages and echos them back. diff --git a/examples/OldStandardFirmata/OldStandardFirmata.ino b/examples/OldStandardFirmata/OldStandardFirmata.ino index 2c63c2ab..5b79de57 100644 --- a/examples/OldStandardFirmata/OldStandardFirmata.ino +++ b/examples/OldStandardFirmata/OldStandardFirmata.ino @@ -4,9 +4,9 @@ * any host computer software package. * * To download a host software package, please click on the following link - * to open the download page in your default browser. + * to open the list of Firmata client libraries in your default browser. * - * http://firmata.org/wiki/Download + * https://github.com/firmata/arduino#firmata-client-libraries */ /* diff --git a/examples/ServoFirmata/ServoFirmata.ino b/examples/ServoFirmata/ServoFirmata.ino index a2f92e31..52b1f1bb 100644 --- a/examples/ServoFirmata/ServoFirmata.ino +++ b/examples/ServoFirmata/ServoFirmata.ino @@ -4,9 +4,9 @@ * any host computer software package. * * To download a host software package, please click on the following link - * to open the download page in your default browser. + * to open the list of Firmata client libraries in your default browser. * - * http://firmata.org/wiki/Download + * https://github.com/firmata/arduino#firmata-client-libraries */ /* This firmware supports as many servos as possible using the Servo library diff --git a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino index d7f3a8bd..98a6adf8 100644 --- a/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino +++ b/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino @@ -4,9 +4,9 @@ * any host computer software package. * * To download a host software package, please click on the following link - * to open the download page in your default browser. + * to open the list of Firmata client libraries in your default browser. * - * http://firmata.org/wiki/Download + * https://github.com/firmata/arduino#firmata-client-libraries */ /* Supports as many analog inputs and analog PWM outputs as possible. diff --git a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino index d935be1b..91db3337 100644 --- a/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino +++ b/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino @@ -4,9 +4,9 @@ * any host computer software package. * * To download a host software package, please click on the following link - * to open the download page in your default browser. + * to open the list of Firmata client libraries in your default browser. * - * http://firmata.org/wiki/Download + * https://github.com/firmata/arduino#firmata-client-libraries */ /* Supports as many digital inputs and outputs as possible. From a1a306757a1746b1ad1697bf0e64f5c880a98c8c Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sat, 3 Mar 2018 12:28:33 -0800 Subject: [PATCH 085/110] update firmata.js url --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index f9f8c15a..46692a5b 100644 --- a/readme.md +++ b/readme.md @@ -46,7 +46,7 @@ Most of the time you will be interacting with Arduino with a client library on t * [https://github.com/nakkaya/clodiuno](https://github.com/nakkaya/clodiuno) * [https://github.com/peterschwarz/clj-firmata](https://github.com/peterschwarz/clj-firmata) * javascript - * [https://github.com/jgautier/firmata](https://github.com/jgautier/firmata) + * [https://github.com/firmata/firmata.js](https://github.com/firmata/firmata.js) * [https://github.com/rwldrn/johnny-five](https://github.com/rwldrn/johnny-five) * [http://breakoutjs.com](http://breakoutjs.com) * java From e3a29322d8c00220970a84074c683ea6ba479e61 Mon Sep 17 00:00:00 2001 From: Christopher Stawarz Date: Mon, 19 Mar 2018 13:54:22 -0400 Subject: [PATCH 086/110] Moved configuration of BLE connection and flush intervals to bleConfig.h These are hardware-specific settings, so they don't belong with the hardware-agnostic code in StandardFirmataBLE.ino. For Arduino 101, specify connection intervals in milliseconds, as expected by BLEPeripheral::setConnectionInterval in Intel Curie Boards package v2.0.2. --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 11 ---- examples/StandardFirmataBLE/bleConfig.h | 58 +++++++++++++------ utility/BLEStream.h | 17 +----- 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 57756587..97cfb73f 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -56,10 +56,6 @@ // the minimum interval for sampling analog input #define MINIMUM_SAMPLING_INTERVAL 1 -// min cannot be < 0x0006. Adjust max if necessary -#define FIRMATA_BLE_MIN_INTERVAL 0x0006 // 7.5ms (7.5 / 1.25) -#define FIRMATA_BLE_MAX_INTERVAL 0x0018 // 30ms (30 / 1.25) - /*============================================================================== * GLOBAL VARIABLES *============================================================================*/ @@ -772,13 +768,6 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); - stream.setLocalName(FIRMATA_BLE_LOCAL_NAME); - - // set the BLE connection interval - this is the fastest interval you can read inputs - stream.setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); - // set how often the BLE TX buffer is flushed (if not full) - stream.setFlushInterval(FIRMATA_BLE_MAX_INTERVAL); - #ifdef BLE_REQ for (byte i = 0; i < TOTAL_PINS; i++) { if (IS_IGNORE_BLE_PINS(i)) { diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index da5a5f20..5fd20ce3 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -5,7 +5,7 @@ * need a unique ble local name (see below). If you are using another supported BLE board or shield, * follow the instructions for the specific board or shield below. * - * Make sure you have the Intel Curie Boards package v1.0.6 or higher installed via the Arduino + * Make sure you have the Intel Curie Boards package v2.0.2 or higher installed via the Arduino * Boards Manager. * * Supported boards and shields: @@ -19,6 +19,22 @@ // within the same physical space #define FIRMATA_BLE_LOCAL_NAME "FIRMATA" +/* + * Arduino 101 + * + * Make sure you have the Intel Curie Boards package v2.0.2 or higher installed via the Arduino + * Boards Manager. + * + * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 + */ +#ifdef _VARIANT_ARDUINO_101_X_ +// After conversion to units of 1.25ms, both values must be between +// 0x0006 (7.5ms) and 0x0c80 (4s) +#define FIRMATA_BLE_MIN_INTERVAL 8 // ( 8 * 1000) / 1250 == 0x06 -> 7.5ms +#define FIRMATA_BLE_MAX_INTERVAL 30 // (30 * 1000) / 1250 == 0x18 -> 30ms +#endif + + /* * RedBearLab BLE Shield * @@ -36,15 +52,27 @@ //#define REDBEAR_BLE_SHIELD #ifdef REDBEAR_BLE_SHIELD -#include -#include -#include "utility/BLEStream.h" - #define BLE_REQ 9 #define BLE_RDY 8 #define BLE_RST 4 // 4 or 7 via jumper on shield +#endif -BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); + +/* + * Generic settings + */ +#if !defined(FIRMATA_BLE_MIN_INTERVAL) && !defined(FIRMATA_BLE_MAX_INTERVAL) +// BLE connection interval - this is the fastest interval you can read inputs. +// These values apply to all devices using the Arduino BLEPeripheral library +// with a Nordic nRF8001 or nRF51822. Both values must be between +// 0x0006 (7.5ms) and 0x0c80 (4s). +#define FIRMATA_BLE_MIN_INTERVAL 0x0006 // 7.5ms (7.5 / 1.25) +#define FIRMATA_BLE_MAX_INTERVAL 0x0018 // 30ms (30 / 1.25) +#endif + +#if !defined(FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL) +// How often the BLE TX buffer is flushed (if not full) +#define FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL 30 // 30ms #endif @@ -52,21 +80,19 @@ BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); * END BLE CONFIGURATION - you should not need to change anything below this line *================================================================================================*/ -/* - * Arduino 101 - * - * Make sure you have the Intel Curie Boards package v1.0.6 or higher installed via the Arduino - * Boards Manager. - * - * Test script: https://gist.github.com/soundanalogous/927360b797574ed50e27 - */ #ifdef _VARIANT_ARDUINO_101_X_ -#include #include "utility/BLEStream.h" BLEStream stream; #endif +#ifdef REDBEAR_BLE_SHIELD +#include +#include "utility/BLEStream.h" +BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); +#endif + + /* * RedBearLab BLE Nano (with default switch settings) * @@ -81,7 +107,6 @@ BLEStream stream; * the pins are currently mapped in Firmata only for the default (factory) jumper settings. */ // #ifdef BLE_NANO -// #include // #include "utility/BLEStream.h" // BLEStream stream; // #endif @@ -96,7 +121,6 @@ BLEStream stream; */ // #if defined(BLEND_MICRO) || defined(BLEND) // #include -// #include // #include "utility/BLEStream.h" // #define BLE_REQ 6 diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 56b36488..9a0d61fd 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -19,9 +19,6 @@ #define _MAX_ATTR_DATA_LEN_ BLE_ATTRIBUTE_MAX_VALUE_LENGTH #endif -#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 80 -#define BLESTREAM_MIN_FLUSH_INTERVAL 8 // minimum interval for flushing the TX buffer - // #define BLE_SERIAL_DEBUG class BLEStream : public BLEPeripheral, public Stream @@ -32,7 +29,6 @@ class BLEStream : public BLEPeripheral, public Stream void begin(...); bool poll(); void end(); - void setFlushInterval(int); virtual int available(void); virtual int peek(void); @@ -45,7 +41,6 @@ class BLEStream : public BLEPeripheral, public Stream private: bool _connected; unsigned long _flushed; - int _flushInterval; static BLEStream* _instance; size_t _rxHead; @@ -85,7 +80,6 @@ BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : this->_txCount = 0; this->_rxHead = this->_rxTail = 0; this->_flushed = 0; - this->_flushInterval = BLESTREAM_TXBUFFER_FLUSH_INTERVAL; BLEStream::_instance = this; addAttribute(this->_uartService); @@ -100,6 +94,8 @@ BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : void BLEStream::begin(...) { + BLEPeripheral::setLocalName(FIRMATA_BLE_LOCAL_NAME); + BLEPeripheral::setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); BLEPeripheral::begin(); #ifdef BLE_SERIAL_DEBUG Serial.println(F("BLEStream::begin()")); @@ -110,7 +106,7 @@ bool BLEStream::poll() { // BLEPeripheral::poll is called each time connected() is called this->_connected = BLEPeripheral::connected(); - if (millis() > this->_flushed + this->_flushInterval) { + if (millis() > this->_flushed + FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL) { flush(); } return this->_connected; @@ -214,13 +210,6 @@ BLEStream::operator bool() return retval; } -void BLEStream::setFlushInterval(int interval) -{ - if (interval > BLESTREAM_MIN_FLUSH_INTERVAL) { - this->_flushInterval = interval; - } -} - void BLEStream::_received(const unsigned char* data, size_t size) { for (size_t i = 0; i < size; i++) { From c2e8da390e59f1093227cb9549c720f3290d7f8c Mon Sep 17 00:00:00 2001 From: Christopher Stawarz Date: Mon, 19 Mar 2018 14:08:34 -0400 Subject: [PATCH 087/110] Added support for the Adafruit Feather M0 Bluefruit LE (and potentially other Bluefruit LE boards/modules that communicate with the nRF51822 via SPI) to StandardFirmataBLE --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 2 +- examples/StandardFirmataBLE/bleConfig.h | 34 +++++ utility/BluefruitLE_SPI_Stream.cpp | 3 + utility/BluefruitLE_SPI_Stream.h | 127 ++++++++++++++++++ 4 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 utility/BluefruitLE_SPI_Stream.cpp create mode 100644 utility/BluefruitLE_SPI_Stream.h diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 97cfb73f..7fa3a749 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -768,7 +768,7 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); -#ifdef BLE_REQ +#ifdef IS_IGNORE_BLE_PINS for (byte i = 0; i < TOTAL_PINS; i++) { if (IS_IGNORE_BLE_PINS(i)) { Firmata.setPinMode(i, PIN_MODE_IGNORE); diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index 5fd20ce3..906bf77a 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -12,6 +12,7 @@ * - Arduino 101 (recommended) * - RedBearLab BLE Shield (v2) ** to be verified ** * - RedBearLab BLE Nano ** works with modifications ** + * - Adafruit Feather M0 Bluefruit LE * *================================================================================================*/ @@ -58,6 +59,31 @@ #endif +/* + * Adafruit Feather M0 Bluefruit LE + * + * If you are using an Adafruit Feather M0 Bluefruit LE, uncomment the define below. + * This configuration should also work with other Bluefruit LE boards/modules that communicate + * with the nRF51822 via SPI (e.g. Bluefruit LE SPI Friend, Bluefruit LE Shield), although + * you may need to change the values of BLE_SPI_CS, BLE_SPI_IRQ, and/or BLE_SPI_RST below. + * + * You will need to install a lightly-modified version of the Adafruit BluefruitLE nRF51 + * package, available at: + * https://github.com/cstawarz/Adafruit_BluefruitLE_nRF51/archive/firmata_fixes.zip + */ +//#define BLUEFRUIT_LE_SPI + +#ifdef BLUEFRUIT_LE_SPI +// Both values must be between 10ms and 4s +#define FIRMATA_BLE_MIN_INTERVAL 10 // 10ms +#define FIRMATA_BLE_MAX_INTERVAL 20 // 20ms + +#define BLE_SPI_CS 8 +#define BLE_SPI_IRQ 7 +#define BLE_SPI_RST 4 +#endif + + /* * Generic settings */ @@ -93,6 +119,12 @@ BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); #endif +#ifdef BLUEFRUIT_LE_SPI +#include "utility/BluefruitLE_SPI_Stream.h" +BluefruitLE_SPI_Stream stream(BLE_SPI_CS, BLE_SPI_IRQ, BLE_SPI_RST); +#endif + + /* * RedBearLab BLE Nano (with default switch settings) * @@ -133,4 +165,6 @@ BLEStream stream(BLE_REQ, BLE_RDY, BLE_RST); #if defined(BLE_REQ) && defined(BLE_RDY) && defined(BLE_RST) #define IS_IGNORE_BLE_PINS(p) ((p) == BLE_REQ || (p) == BLE_RDY || (p) == BLE_RST) +#elif defined(BLE_SPI_CS) && defined(BLE_SPI_IRQ) && defined(BLE_SPI_RST) +#define IS_IGNORE_BLE_PINS(p) ((p) == BLE_SPI_CS || (p) == BLE_SPI_IRQ || (p) == BLE_SPI_RST) #endif diff --git a/utility/BluefruitLE_SPI_Stream.cpp b/utility/BluefruitLE_SPI_Stream.cpp new file mode 100644 index 00000000..93953e96 --- /dev/null +++ b/utility/BluefruitLE_SPI_Stream.cpp @@ -0,0 +1,3 @@ +/* + * Implementation is in BluefruitLE_SPI_Stream.h to avoid linker issues. + */ diff --git a/utility/BluefruitLE_SPI_Stream.h b/utility/BluefruitLE_SPI_Stream.h new file mode 100644 index 00000000..43f8f929 --- /dev/null +++ b/utility/BluefruitLE_SPI_Stream.h @@ -0,0 +1,127 @@ +/* + BluefruitLE_SPI_Stream.h + + Documentation for the various AT commands used below is available at + https://learn.adafruit.com/adafruit-feather-m0-bluefruit-le/at-commands + */ + +#ifndef _BLUEFRUIT_LE_SPI_STREAM_H_ +#define _BLUEFRUIT_LE_SPI_STREAM_H_ + +#include + + +class BluefruitLE_SPI_Stream : public Stream +{ + public: + BluefruitLE_SPI_Stream(int8_t csPin, int8_t irqPin, int8_t rstPin); + + void begin(); + bool poll(); + void end(); + + // Print overrides + size_t write(uint8_t byte); + using Print::write; // Expose other write variants + + // Stream overrides + int available(); + int read(); + int peek(); + void flush(); + + private: + Adafruit_BluefruitLE_SPI ble; + + uint8_t txBuffer[SDEP_MAX_PACKETSIZE]; + size_t txCount; +}; + + +BluefruitLE_SPI_Stream::BluefruitLE_SPI_Stream(int8_t csPin, int8_t irqPin, int8_t rstPin) : + ble(csPin, irqPin, rstPin), + txCount(0) +{ } + +void BluefruitLE_SPI_Stream::begin() +{ + // Initialize the SPI interface + ble.begin(); + + // Perform a factory reset to make sure everything is in a known state + ble.factoryReset(); + + // Disable command echo from Bluefruit + ble.echo(false); + + // Change the MODE LED to indicate BLE UART activity + ble.println("AT+HWMODELED=BLEUART"); + + // Set local name + ble.print("AT+GAPDEVNAME="); + ble.println(FIRMATA_BLE_LOCAL_NAME); + + // Set connection interval + ble.print("AT+GAPINTERVALS="); + ble.print(FIRMATA_BLE_MIN_INTERVAL); + ble.print(","); + ble.print(FIRMATA_BLE_MAX_INTERVAL); + ble.println(",,,"); + + // Disable real and simulated mode switch (i.e. "+++") command + ble.println("AT+MODESWITCHEN=local,0"); + ble.enableModeSwitchCommand(false); + + // Switch to data mode + ble.setMode(BLUEFRUIT_MODE_DATA); +} + +bool BluefruitLE_SPI_Stream::poll() +{ + // If there's outgoing data in the buffer, just send it. The firmware on + // the nRF51822 will decide when to transmit the data in its TX FIFO. + if (txCount) flush(); + + // In order to check for a connection, we would need to switch from data to + // command mode and back again. However, due to the internal workings of + // Adafruit_BluefruitLE_SPI, this can lead to unread incoming data being + // lost. Therefore, we always return true. + return true; +} + +void BluefruitLE_SPI_Stream::end() +{ + flush(); + ble.end(); +} + +size_t BluefruitLE_SPI_Stream::write(uint8_t byte) +{ + txBuffer[txCount++] = byte; + if (txCount == sizeof(txBuffer)) flush(); + return 1; +} + +int BluefruitLE_SPI_Stream::available() +{ + return ble.available(); +} + +int BluefruitLE_SPI_Stream::read() +{ + return ble.read(); +} + +int BluefruitLE_SPI_Stream::peek() +{ + return ble.peek(); +} + +void BluefruitLE_SPI_Stream::flush() +{ + ble.write(txBuffer, txCount); + txCount = 0; +} + + +#endif // _BLUEFRUIT_LE_SPI_STREAM_H_ From 5b8b9f0060f645cda5c28b41a2ed7d89f19b48d9 Mon Sep 17 00:00:00 2001 From: Christopher Stawarz Date: Wed, 4 Apr 2018 13:34:58 -0400 Subject: [PATCH 088/110] Restored use of setter methods for BLE configuration --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 7 +++ examples/StandardFirmataBLE/bleConfig.h | 2 - utility/BLEStream.h | 17 +++++-- utility/BluefruitLE_SPI_Stream.h | 44 ++++++++++++++++--- 4 files changed, 58 insertions(+), 12 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 7fa3a749..65cf3cbd 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -768,6 +768,13 @@ void setup() Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(SYSTEM_RESET, systemResetCallback); + stream.setLocalName(FIRMATA_BLE_LOCAL_NAME); + + // set the BLE connection interval - this is the fastest interval you can read inputs + stream.setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); + // set how often the BLE TX buffer is flushed (if not full) + stream.setFlushInterval(FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL); + #ifdef IS_IGNORE_BLE_PINS for (byte i = 0; i < TOTAL_PINS; i++) { if (IS_IGNORE_BLE_PINS(i)) { diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index 906bf77a..412bb849 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -88,7 +88,6 @@ * Generic settings */ #if !defined(FIRMATA_BLE_MIN_INTERVAL) && !defined(FIRMATA_BLE_MAX_INTERVAL) -// BLE connection interval - this is the fastest interval you can read inputs. // These values apply to all devices using the Arduino BLEPeripheral library // with a Nordic nRF8001 or nRF51822. Both values must be between // 0x0006 (7.5ms) and 0x0c80 (4s). @@ -97,7 +96,6 @@ #endif #if !defined(FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL) -// How often the BLE TX buffer is flushed (if not full) #define FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL 30 // 30ms #endif diff --git a/utility/BLEStream.h b/utility/BLEStream.h index 9a0d61fd..56b36488 100644 --- a/utility/BLEStream.h +++ b/utility/BLEStream.h @@ -19,6 +19,9 @@ #define _MAX_ATTR_DATA_LEN_ BLE_ATTRIBUTE_MAX_VALUE_LENGTH #endif +#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 80 +#define BLESTREAM_MIN_FLUSH_INTERVAL 8 // minimum interval for flushing the TX buffer + // #define BLE_SERIAL_DEBUG class BLEStream : public BLEPeripheral, public Stream @@ -29,6 +32,7 @@ class BLEStream : public BLEPeripheral, public Stream void begin(...); bool poll(); void end(); + void setFlushInterval(int); virtual int available(void); virtual int peek(void); @@ -41,6 +45,7 @@ class BLEStream : public BLEPeripheral, public Stream private: bool _connected; unsigned long _flushed; + int _flushInterval; static BLEStream* _instance; size_t _rxHead; @@ -80,6 +85,7 @@ BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : this->_txCount = 0; this->_rxHead = this->_rxTail = 0; this->_flushed = 0; + this->_flushInterval = BLESTREAM_TXBUFFER_FLUSH_INTERVAL; BLEStream::_instance = this; addAttribute(this->_uartService); @@ -94,8 +100,6 @@ BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) : void BLEStream::begin(...) { - BLEPeripheral::setLocalName(FIRMATA_BLE_LOCAL_NAME); - BLEPeripheral::setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); BLEPeripheral::begin(); #ifdef BLE_SERIAL_DEBUG Serial.println(F("BLEStream::begin()")); @@ -106,7 +110,7 @@ bool BLEStream::poll() { // BLEPeripheral::poll is called each time connected() is called this->_connected = BLEPeripheral::connected(); - if (millis() > this->_flushed + FIRMATA_BLE_TXBUFFER_FLUSH_INTERVAL) { + if (millis() > this->_flushed + this->_flushInterval) { flush(); } return this->_connected; @@ -210,6 +214,13 @@ BLEStream::operator bool() return retval; } +void BLEStream::setFlushInterval(int interval) +{ + if (interval > BLESTREAM_MIN_FLUSH_INTERVAL) { + this->_flushInterval = interval; + } +} + void BLEStream::_received(const unsigned char* data, size_t size) { for (size_t i = 0; i < size; i++) { diff --git a/utility/BluefruitLE_SPI_Stream.h b/utility/BluefruitLE_SPI_Stream.h index 43f8f929..372e5aa9 100644 --- a/utility/BluefruitLE_SPI_Stream.h +++ b/utility/BluefruitLE_SPI_Stream.h @@ -16,6 +16,10 @@ class BluefruitLE_SPI_Stream : public Stream public: BluefruitLE_SPI_Stream(int8_t csPin, int8_t irqPin, int8_t rstPin); + void setLocalName(const char *localName); + void setConnectionInterval(unsigned short minConnInterval, unsigned short maxConnInterval); + void setFlushInterval(int flushInterval); + void begin(); bool poll(); void end(); @@ -33,6 +37,10 @@ class BluefruitLE_SPI_Stream : public Stream private: Adafruit_BluefruitLE_SPI ble; + String localName; + unsigned short minConnInterval; + unsigned short maxConnInterval; + uint8_t txBuffer[SDEP_MAX_PACKETSIZE]; size_t txCount; }; @@ -40,9 +48,27 @@ class BluefruitLE_SPI_Stream : public Stream BluefruitLE_SPI_Stream::BluefruitLE_SPI_Stream(int8_t csPin, int8_t irqPin, int8_t rstPin) : ble(csPin, irqPin, rstPin), + minConnInterval(0), + maxConnInterval(0), txCount(0) { } +void BluefruitLE_SPI_Stream::setLocalName(const char *localName) +{ + this->localName = localName; +} + +void BluefruitLE_SPI_Stream::setConnectionInterval(unsigned short minConnInterval, unsigned short maxConnInterval) +{ + this->minConnInterval = minConnInterval; + this->maxConnInterval = maxConnInterval; +} + +void BluefruitLE_SPI_Stream::setFlushInterval(int flushInterval) +{ + // Not used +} + void BluefruitLE_SPI_Stream::begin() { // Initialize the SPI interface @@ -58,15 +84,19 @@ void BluefruitLE_SPI_Stream::begin() ble.println("AT+HWMODELED=BLEUART"); // Set local name - ble.print("AT+GAPDEVNAME="); - ble.println(FIRMATA_BLE_LOCAL_NAME); + if (localName.length() > 0) { + ble.print("AT+GAPDEVNAME="); + ble.println(localName); + } // Set connection interval - ble.print("AT+GAPINTERVALS="); - ble.print(FIRMATA_BLE_MIN_INTERVAL); - ble.print(","); - ble.print(FIRMATA_BLE_MAX_INTERVAL); - ble.println(",,,"); + if (minConnInterval > 0 && maxConnInterval > 0) { + ble.print("AT+GAPINTERVALS="); + ble.print(minConnInterval); + ble.print(","); + ble.print(maxConnInterval); + ble.println(",,,"); + } // Disable real and simulated mode switch (i.e. "+++") command ble.println("AT+MODESWITCHEN=local,0"); From 00587f8756bca8f279d5914cc556827c63242925 Mon Sep 17 00:00:00 2001 From: Petros Angelatos Date: Fri, 13 Apr 2018 16:48:22 +0300 Subject: [PATCH 089/110] extend number of supported hardware serial ports to 6 Signed-off-by: Petros Angelatos --- utility/SerialFirmata.cpp | 12 ++++++++++++ utility/SerialFirmata.h | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/utility/SerialFirmata.cpp b/utility/SerialFirmata.cpp index b934f166..8b703e13 100644 --- a/utility/SerialFirmata.cpp +++ b/utility/SerialFirmata.cpp @@ -252,6 +252,18 @@ Stream* SerialFirmata::getPortFromId(byte portId) case HW_SERIAL3: return &Serial3; #endif +#if defined(PIN_SERIAL4_RX) + case HW_SERIAL4: + return &Serial4; +#endif +#if defined(PIN_SERIAL5_RX) + case HW_SERIAL5: + return &Serial5; +#endif +#if defined(PIN_SERIAL6_RX) + case HW_SERIAL6: + return &Serial6; +#endif #if defined(SoftwareSerial_h) case SW_SERIAL0: if (swSerial0 != NULL) { diff --git a/utility/SerialFirmata.h b/utility/SerialFirmata.h index 79915aaf..2319951b 100644 --- a/utility/SerialFirmata.h +++ b/utility/SerialFirmata.h @@ -37,6 +37,9 @@ #define HW_SERIAL1 0x01 #define HW_SERIAL2 0x02 #define HW_SERIAL3 0x03 +#define HW_SERIAL4 0x04 +#define HW_SERIAL5 0x05 +#define HW_SERIAL6 0x06 // extensible up to 0x07 #define SW_SERIAL0 0x08 @@ -56,6 +59,12 @@ #define RES_TX2 0x05 #define RES_RX3 0x06 #define RES_TX3 0x07 +#define RES_RX4 0x08 +#define RES_TX4 0x09 +#define RES_RX5 0x0a +#define RES_TX5 0x0b +#define RES_RX6 0x0c +#define RES_TX6 0x0d // Serial command bytes #define SERIAL_CONFIG 0x10 @@ -96,6 +105,18 @@ namespace { #if defined(PIN_SERIAL3_RX) if (pin == PIN_SERIAL3_RX) return RES_RX3; if (pin == PIN_SERIAL3_TX) return RES_TX3; + #endif + #if defined(PIN_SERIAL4_RX) + if (pin == PIN_SERIAL4_RX) return RES_RX4; + if (pin == PIN_SERIAL4_TX) return RES_TX4; + #endif + #if defined(PIN_SERIAL5_RX) + if (pin == PIN_SERIAL5_RX) return RES_RX5; + if (pin == PIN_SERIAL5_TX) return RES_TX5; + #endif + #if defined(PIN_SERIAL6_RX) + if (pin == PIN_SERIAL6_RX) return RES_RX6; + if (pin == PIN_SERIAL6_TX) return RES_TX6; #endif return 0; } @@ -128,6 +149,24 @@ namespace { pins.rx = PIN_SERIAL3_RX; pins.tx = PIN_SERIAL3_TX; break; + #endif + #if defined(PIN_SERIAL4_RX) + case HW_SERIAL4: + pins.rx = PIN_SERIAL4_RX; + pins.tx = PIN_SERIAL4_TX; + break; + #endif + #if defined(PIN_SERIAL5_RX) + case HW_SERIAL5: + pins.rx = PIN_SERIAL5_RX; + pins.tx = PIN_SERIAL5_TX; + break; + #endif + #if defined(PIN_SERIAL6_RX) + case HW_SERIAL6: + pins.rx = PIN_SERIAL6_RX; + pins.tx = PIN_SERIAL6_TX; + break; #endif default: pins.rx = 0; From 47fa25d51efb841ff8d8b85ed7ffc4945c5e1174 Mon Sep 17 00:00:00 2001 From: Petros Angelatos Date: Fri, 13 Apr 2018 16:50:08 +0300 Subject: [PATCH 090/110] boards: fix pin mapping for Teensy 3.5 and 3.6 Reference: https://www.pjrc.com/teensy/td_uart.html Signed-off-by: Petros Angelatos --- Boards.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Boards.h b/Boards.h index 69c12481..d8ef528f 100644 --- a/Boards.h +++ b/Boards.h @@ -403,11 +403,12 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_SERIAL2_TX 10 #define PIN_SERIAL3_RX 7 #define PIN_SERIAL3_TX 8 -// The following 2 UARTs are not yet available via SerialFirmata #define PIN_SERIAL4_RX 31 -#define PIN_SERIAL5_TX 32 -#define PIN_SERIAL6_RX 34 -#define PIN_SERIAL6_TX 33 +#define PIN_SERIAL4_TX 32 +#define PIN_SERIAL5_RX 34 +#define PIN_SERIAL5_TX 33 +#define PIN_SERIAL6_RX 47 +#define PIN_SERIAL6_TX 48 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 63) #define IS_PIN_ANALOG(p) (((p) >= 14 && (p) <= 23) || ((p) >= 31 && (p) <= 39) || ((p) >= 49 && (p) <= 50) || ((p) >= 64 && (p) <= 69)) #define IS_PIN_PWM(p) digitalPinHasPWM(p) From c669cc369c876803e05d7e174649d68b37f97b56 Mon Sep 17 00:00:00 2001 From: Petros Angelatos Date: Sun, 15 Apr 2018 20:08:16 +0300 Subject: [PATCH 091/110] boards: update IS_PIN_SERIAL for Teensy 3.5 & 3.6 Signed-off-by: Petros Angelatos --- Boards.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Boards.h b/Boards.h index d8ef528f..3ae0e2ff 100644 --- a/Boards.h +++ b/Boards.h @@ -414,7 +414,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_PWM(p) digitalPinHasPWM(p) #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19) -#define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1)) +#define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1) || ((p) > 30 && (p) < 35) || ((p) == 47 || (p) == 48)) #define PIN_TO_DIGITAL(p) (p) // A0-A9 = D14-D23; A12-A20 = D31-D39; A23-A24 = D49-D50; A10-A11 = D64-D65; A21-A22 = D66-D67; A25-A26 = D68-D69 #define PIN_TO_ANALOG(p) (((p) <= 23) ? (p) - 14 : (((p) <= 39) ? (p) - 19 : (((p) <= 50) ? (p) - 26 : (((p) <= 65) ? (p) - 55 : (((p) <= 67) ? (p) - 45 : (p) - 43))))) From d78cd6c4ab67c61ebf19da718b83cbdd8719db0a Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 15 Apr 2018 10:24:34 -0700 Subject: [PATCH 092/110] change last updated date --- Boards.h | 2 +- examples/StandardFirmataBLE/StandardFirmataBLE.ino | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Boards.h b/Boards.h index ae07eff5..ace8d975 100644 --- a/Boards.h +++ b/Boards.h @@ -10,7 +10,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated August 14th, 2017 + Last updated April 15th, 2018 */ #ifndef Firmata_Boards_h diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 65cf3cbd..7b17b891 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -20,7 +20,7 @@ See file LICENSE.txt for further informations on licensing terms. - Last updated August 17th, 2017 + Last updated April 15th, 2018 */ #include From 8cbe99be5890296d330b990f3ec078a4fba3a980 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Sun, 15 Apr 2018 10:29:02 -0700 Subject: [PATCH 093/110] bump bugfix version --- Firmata.cpp | 2 +- Firmata.h | 2 +- library.properties | 2 +- readme.md | 8 ++++---- release.sh | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Firmata.cpp b/Firmata.cpp index e35c3dcb..ee01f8f5 100644 --- a/Firmata.cpp +++ b/Firmata.cpp @@ -1,5 +1,5 @@ /* - Firmata.cpp - Firmata library v2.5.7 - 2017-08-19 + Firmata.cpp - Firmata library v2.5.8 - 2018-04-15 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved. diff --git a/Firmata.h b/Firmata.h index c07b38d3..fa0fa6c2 100644 --- a/Firmata.h +++ b/Firmata.h @@ -1,5 +1,5 @@ /* - Firmata.h - Firmata library v2.5.7 - 2017-08-19 + Firmata.h - Firmata library v2.5.8 - 2018-04-15 Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved. diff --git a/library.properties b/library.properties index 83431fc9..0dc9a348 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Firmata -version=2.5.7 +version=2.5.8 author=Firmata Developers maintainer=https://github.com/firmata/arduino sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino/Genuino boards. diff --git a/readme.md b/readme.md index 46692a5b..988edfd7 100644 --- a/readme.md +++ b/readme.md @@ -107,7 +107,7 @@ $ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Fir ## Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x) -Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.7) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. +Download the latest [release](https://github.com/firmata/arduino/releases/tag/2.5.8) (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform. *Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).* @@ -118,7 +118,7 @@ The Firmata library is contained within the Arduino package. 1. Navigate to the Arduino application 2. Right click on the application icon and select `Show Package Contents` 3. Navigate to: `/Contents/Resources/Java/libraries/` and replace the existing -`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.7) (note there is a different download +`Firmata` folder with latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.8) (note there is a different download for Arduino 1.0.x vs 1.6.x) 4. Restart the Arduino application and the latest version of Firmata will be available. @@ -128,7 +128,7 @@ will differ slightly: `Contents/Java/libraries/Firmata` (no Resources directory) ### Windows: 1. Navigate to `c:/Program\ Files/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.7) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.8) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. @@ -137,7 +137,7 @@ for Arduino 1.0.x vs 1.6.x). ### Linux: 1. Navigate to `~/arduino-1.x/libraries/` and replace the existing -`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.7) (note there is a different download +`Firmata` folder with the latest [Firmata release](https://github.com/firmata/arduino/releases/tag/2.5.8) (note there is a different download for Arduino 1.0.x vs 1.6.x). 2. Restart the Arduino application and the latest version of Firmata will be available. diff --git a/release.sh b/release.sh index 05cb74e4..0c47db8d 100644 --- a/release.sh +++ b/release.sh @@ -15,7 +15,7 @@ cd temp find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Arduino-1.0.x-Firmata-2.5.7.zip +mv ./temp/Firmata.zip Arduino-1.0.x-Firmata-2.5.8.zip #package for Arduino 1.6.x and 1.8.x cp library.properties temp/Firmata @@ -29,5 +29,5 @@ cd .. find . -name "*.DS_Store" -type f -delete zip -r Firmata.zip ./Firmata/ cd .. -mv ./temp/Firmata.zip Firmata-2.5.7.zip +mv ./temp/Firmata.zip Firmata-2.5.8.zip rm -r ./temp From f9d9ec420c659eed4ce251cd58b1cdc6ff9c508e Mon Sep 17 00:00:00 2001 From: Serge Stinckwich Date: Fri, 11 May 2018 18:50:01 +0700 Subject: [PATCH 094/110] Add Pharo support --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 988edfd7..042c28d2 100644 --- a/readme.md +++ b/readme.md @@ -59,6 +59,8 @@ Most of the time you will be interacting with Arduino with a client library on t * Flash/AS3 * [http://funnel.cc](http://funnel.cc) * [http://code.google.com/p/as3glue/](http://code.google.com/p/as3glue/) +* Pharo + * [https://github.com/pharo-iot/Firmata](https://github.com/pharo-iot/Firmata) * PHP * [https://github.com/ThomasWeinert/carica-firmata]() * [https://github.com/oasynnoum/phpmake_firmata](https://github.com/oasynnoum/phpmake_firmata) From b1428e2ecb363fe733803419ecf74ca938db2274 Mon Sep 17 00:00:00 2001 From: per1234 Date: Sun, 15 Jul 2018 01:54:07 -0700 Subject: [PATCH 095/110] Use a single tab field separator in keywords.txt Each field of keywords.txt is separated by a single true tab. When you use multiple tabs it causes the field to be interpreted as empty. On Arduino IDE 1.6.5 and newer an empty KEYWORD_TOKENTYPE causes the default editor.function.style coloration to be used (as with KEYWORD2, KEYWORD3, LITERAL2). On Arduino IDE 1.6.4 and older it causes the keyword to not be recognized for any special coloration. Reference: https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification#keywords --- keywords.txt | 110 +++++++++++++++++++++++++-------------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/keywords.txt b/keywords.txt index 5ab13d05..d11a5072 100644 --- a/keywords.txt +++ b/keywords.txt @@ -6,44 +6,44 @@ # Datatypes (KEYWORD1) ####################################### -Firmata KEYWORD1 Firmata -callbackFunction KEYWORD1 callbackFunction +Firmata KEYWORD1 Firmata +callbackFunction KEYWORD1 callbackFunction systemResetCallbackFunction KEYWORD1 systemResetCallbackFunction -stringCallbackFunction KEYWORD1 stringCallbackFunction -sysexCallbackFunction KEYWORD1 sysexCallbackFunction +stringCallbackFunction KEYWORD1 stringCallbackFunction +sysexCallbackFunction KEYWORD1 sysexCallbackFunction ####################################### # Methods and Functions (KEYWORD2) ####################################### -begin KEYWORD2 -printVersion KEYWORD2 -blinkVersion KEYWORD2 -printFirmwareVersion KEYWORD2 -setFirmwareVersion KEYWORD2 +begin KEYWORD2 +printVersion KEYWORD2 +blinkVersion KEYWORD2 +printFirmwareVersion KEYWORD2 +setFirmwareVersion KEYWORD2 setFirmwareNameAndVersion KEYWORD2 -available KEYWORD2 -processInput KEYWORD2 -isParsingMessage KEYWORD2 -parse KEYWORD2 -sendAnalog KEYWORD2 -sendDigital KEYWORD2 -sendDigitalPort KEYWORD2 -sendString KEYWORD2 -sendSysex KEYWORD2 -getPinMode KEYWORD2 -setPinMode KEYWORD2 -getPinState KEYWORD2 -setPinState KEYWORD2 -attach KEYWORD2 -detach KEYWORD2 -write KEYWORD2 +available KEYWORD2 +processInput KEYWORD2 +isParsingMessage KEYWORD2 +parse KEYWORD2 +sendAnalog KEYWORD2 +sendDigital KEYWORD2 +sendDigitalPort KEYWORD2 +sendString KEYWORD2 +sendSysex KEYWORD2 +getPinMode KEYWORD2 +setPinMode KEYWORD2 +getPinState KEYWORD2 +setPinState KEYWORD2 +attach KEYWORD2 +detach KEYWORD2 +write KEYWORD2 sendValueAsTwo7bitBytes KEYWORD2 -startSysex KEYWORD2 -endSysex KEYWORD2 -writePort KEYWORD2 -readPort KEYWORD2 -disableBlinkVersion KEYWORD2 +startSysex KEYWORD2 +endSysex KEYWORD2 +writePort KEYWORD2 +readPort KEYWORD2 +disableBlinkVersion KEYWORD2 ####################################### @@ -54,37 +54,37 @@ FIRMATA_MAJOR_VERSION LITERAL1 FIRMATA_MINOR_VERSION LITERAL1 FIRMATA_BUGFIX_VERSION LITERAL1 -MAX_DATA_BYTES LITERAL1 +MAX_DATA_BYTES LITERAL1 -DIGITAL_MESSAGE LITERAL1 -ANALOG_MESSAGE LITERAL1 -REPORT_ANALOG LITERAL1 -REPORT_DIGITAL LITERAL1 -REPORT_VERSION LITERAL1 -SET_PIN_MODE LITERAL1 +DIGITAL_MESSAGE LITERAL1 +ANALOG_MESSAGE LITERAL1 +REPORT_ANALOG LITERAL1 +REPORT_DIGITAL LITERAL1 +REPORT_VERSION LITERAL1 +SET_PIN_MODE LITERAL1 SET_DIGITAL_PIN_VALUE LITERAL1 -SYSTEM_RESET LITERAL1 -START_SYSEX LITERAL1 -END_SYSEX LITERAL1 -REPORT_FIRMWARE LITERAL1 -STRING_DATA LITERAL1 +SYSTEM_RESET LITERAL1 +START_SYSEX LITERAL1 +END_SYSEX LITERAL1 +REPORT_FIRMWARE LITERAL1 +STRING_DATA LITERAL1 -PIN_MODE_ANALOG LITERAL1 -PIN_MODE_PWM LITERAL1 -PIN_MODE_SERVO LITERAL1 -PIN_MODE_SHIFT LITERAL1 -PIN_MODE_I2C LITERAL1 +PIN_MODE_ANALOG LITERAL1 +PIN_MODE_PWM LITERAL1 +PIN_MODE_SERVO LITERAL1 +PIN_MODE_SHIFT LITERAL1 +PIN_MODE_I2C LITERAL1 PIN_MODE_ONEWIRE LITERAL1 PIN_MODE_STEPPER LITERAL1 PIN_MODE_ENCODER LITERAL1 -PIN_MODE_SERIAL LITERAL1 -PIN_MODE_PULLUP LITERAL1 -PIN_MODE_IGNORE LITERAL1 +PIN_MODE_SERIAL LITERAL1 +PIN_MODE_PULLUP LITERAL1 +PIN_MODE_IGNORE LITERAL1 -TOTAL_PINS LITERAL1 +TOTAL_PINS LITERAL1 TOTAL_ANALOG_PINS LITERAL1 TOTAL_DIGITAL_PINS LITERAL1 -TOTAL_PIN_MODES LITERAL1 -TOTAL_PORTS LITERAL1 -ANALOG_PORT LITERAL1 -MAX_SERVOS LITERAL1 +TOTAL_PIN_MODES LITERAL1 +TOTAL_PORTS LITERAL1 +ANALOG_PORT LITERAL1 +MAX_SERVOS LITERAL1 From 3d786388ad329fadacd52894e1faacd480d23800 Mon Sep 17 00:00:00 2001 From: per1234 Date: Sun, 9 Sep 2018 03:00:55 -0700 Subject: [PATCH 096/110] Remove invalid reference link from keywords.txt The third field of keywords.txt is used to provide Arduino Language/Libraries Reference links, which are accessed from the Arduino IDE by highlighting the keyword and then selecting "Find in Reference" from the Help or right click menu. Adding values to this field that do not match any existing reference pages results in a "Could not open the URL" error. Reference: https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification#keywordstxt-format --- keywords.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/keywords.txt b/keywords.txt index d11a5072..1e6dbc66 100644 --- a/keywords.txt +++ b/keywords.txt @@ -7,10 +7,10 @@ ####################################### Firmata KEYWORD1 Firmata -callbackFunction KEYWORD1 callbackFunction -systemResetCallbackFunction KEYWORD1 systemResetCallbackFunction -stringCallbackFunction KEYWORD1 stringCallbackFunction -sysexCallbackFunction KEYWORD1 sysexCallbackFunction +callbackFunction KEYWORD1 +systemResetCallbackFunction KEYWORD1 +stringCallbackFunction KEYWORD1 +sysexCallbackFunction KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) From f3fef2bc81f31c8fdb9041f7e3bb0fd9373bc060 Mon Sep 17 00:00:00 2001 From: Hannes Brandstaetter-Mueller Date: Tue, 30 Oct 2018 22:37:15 +0100 Subject: [PATCH 097/110] Support for Sanguino/Melzi, e.g. Creality Ender-3 --- Boards.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Boards.h b/Boards.h index ace8d975..997093b9 100644 --- a/Boards.h +++ b/Boards.h @@ -590,6 +590,25 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) ((p) - 2) +// Sanguino/Melzi, e.g. Creality Ender-3 +#elif defined(__AVR_ATmega1284P__) +#define TOTAL_ANALOG_PINS 8 +#define TOTAL_PINS 32 +#define VERSION_BLINK_PIN 13 +#define PIN_SERIAL1_RX 8 //PD0 +#define PIN_SERIAL1_TX 9 //PD1 +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p) ((p) >= 24 && (p) < TOTAL_PINS) +#define IS_PIN_PWM(p) ((p) == 3 || (p) == 4 || (p) == 6 || (p) == 7 || (p) == 12 || (p) == 13 || (p) == 14 || (p) == 15) +#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p) ((p) == 16 || (p) == 17) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == 8 || (p) == 9) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) (p) - 24 +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) + // Illuminato #elif defined(__AVR_ATmega645__) From 521bdc93d6fe53cf68cf01e428f23147c7ee7d0b Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 30 Oct 2018 10:22:06 +0100 Subject: [PATCH 098/110] Add support for UNO WiFi Rev2 (ATMega4809) --- Boards.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Boards.h b/Boards.h index ace8d975..3df81370 100644 --- a/Boards.h +++ b/Boards.h @@ -219,6 +219,24 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) #define PIN_TO_SERVO(p) ((p) - 2) +// Arduino UNO WiFi rev2 (ATMega 4809) +#elif defined(__AVR_ATmega4809__) +#define TOTAL_ANALOG_PINS 6 +#define TOTAL_PINS 20 // 14 digital + 6 analog + /* 3 SPI (unexported, on ISP header) */ +#define VERSION_BLINK_PIN 25 +#define PIN_SERIAL1_RX 0 +#define PIN_SERIAL1_TX 1 +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < TOTAL_PINS) +#define IS_PIN_PWM(p) digitalPinHasPWM(p) +#define IS_PIN_SERVO(p) (p) +#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) +#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) +#define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1) +#define PIN_TO_DIGITAL(p) (p) +#define PIN_TO_ANALOG(p) (p) - 14 +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) // Arduino DUE #elif defined(__SAM3X8E__) From f9c978d279ca01283121c6bf6b9b1db257fd6b23 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 8 Nov 2018 21:00:54 +0700 Subject: [PATCH 099/110] update TOTAL_PINS for nrf52840 (64 pins max) --- Boards.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Boards.h b/Boards.h index 4af8b405..d790205b 100644 --- a/Boards.h +++ b/Boards.h @@ -873,7 +873,7 @@ writePort(port, value, bitmask): Write an 8 bit port. // Adafruit Bluefruit nRF52 boards #elif defined(ARDUINO_NRF52_ADAFRUIT) #define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS -#define TOTAL_PINS 32 +#define TOTAL_PINS NUM_DIGITAL_PINS #define VERSION_BLINK_PIN LED_BUILTIN #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS) #define IS_PIN_ANALOG(p) ((p) == PIN_A0 || (p) == PIN_A1 || (p) == PIN_A2 || (p) == PIN_A3 || \ From b28dd5dcd494d37dd705f827f04a49beed37ae10 Mon Sep 17 00:00:00 2001 From: gdsports Date: Thu, 4 Apr 2019 02:53:42 -0700 Subject: [PATCH 100/110] Add support for Arduino MKR WiFi 1010 The board uses the U-Blox WiFi NINA chip which has an ESP32 inside running NINA firmware. The SAMD21 is connected to the U-Blox chip via SPI. The WiFININA library is used to communicate between the U-Blox chip and the SAMD21. Other boards use the same U-Blox chip such as the MKR Vidor 4000 and the Uno WiFi Rev2. Additional changes will be required to support those boards. --- Boards.h | 4 +-- .../StandardFirmataWiFi.ino | 3 ++ examples/StandardFirmataWiFi/wifiConfig.h | 35 +++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/Boards.h b/Boards.h index d790205b..730826f6 100644 --- a/Boards.h +++ b/Boards.h @@ -261,8 +261,8 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_SERVO(p) ((p) - 2) -// Arduino/Genuino MKR1000 -#elif defined(ARDUINO_SAMD_MKR1000) +// Arduino/Genuino MKR1000 or MKR1010 +#elif defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010) #define TOTAL_ANALOG_PINS 7 #define TOTAL_PINS 22 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 21) diff --git a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino index 4f7e4163..032357d5 100644 --- a/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino +++ b/examples/StandardFirmataWiFi/StandardFirmataWiFi.ino @@ -37,6 +37,7 @@ - Arduino WiFi Shield (or clone) - Arduino WiFi Shield 101 - Arduino MKR1000 board + - Arduino MKRWIFI1010 board - ESP8266 WiFi board compatible with ESP8266 Arduino core Follow the instructions in the wifiConfig.h file (wifiConfig.h tab in Arduino IDE) to @@ -929,6 +930,8 @@ void initTransport() DEBUG_PRINTLN( "using the ESP8266 WiFi library." ); #elif defined(HUZZAH_WIFI) DEBUG_PRINTLN( "using the HUZZAH WiFi library." ); +#elif defined(WIFI_NINA) + DEBUG_PRINTLN( "using the WiFi NINA library." ); //else should never happen here as error-checking in wifiConfig.h will catch this #endif //defined(WIFI_101) diff --git a/examples/StandardFirmataWiFi/wifiConfig.h b/examples/StandardFirmataWiFi/wifiConfig.h index bedc7447..6cdebc84 100644 --- a/examples/StandardFirmataWiFi/wifiConfig.h +++ b/examples/StandardFirmataWiFi/wifiConfig.h @@ -102,6 +102,41 @@ * For HUZZAH with ESP8266 use ESP8266_WIFI. */ +/* + * OPTION E: Configure for Arduino MKR WiFi 1010 and maybe other WiFiNINA boards. + * + * This will configure StandardFirmataWiFi to use the WiFiNINA library, which works with the + * boards that have the U-Blox NINA chip built in (such as the MKR1010). + * It is compatible with 802.11 2.4GHz B/G/N networks. + * + * If you are using the MKR1010 board, continue on to STEP 2. If you are using WiFiNINA add-on + * boards, follow the instructions below. + * + * To enable for WiFiNINA add-on boards, uncomment the #define WIFI_NINA below. + * TBD: Adafruit AirLyft boards are based on the WiFiNINA firmware so may work here. + * + * IMPORTANT: You must have the WiFI NINA library installed. To easily install this library, open + * the library manager via: Arduino IDE Menus: Sketch > Include Library > Manage Libraries > filter + * search for "WiFiNINA" > Select the result and click 'install' + */ +//#define WIFI_NINA + +//do not modify the following 15 lines +#if defined(ARDUINO_SAMD_MKRWIFI1010) && !defined(WIFI_NINA) +// automatically include if compiling for MRKWIFI1010 +#define WIFI_NINA +#endif +#ifdef WIFI_NINA +#include +#include "utility/WiFiClientStream.h" +#include "utility/WiFiServerStream.h" + #ifdef WIFI_LIB_INCLUDED + #define MULTIPLE_WIFI_LIB_INCLUDES + #else + #define WIFI_LIB_INCLUDED + #endif +#endif + //------------------------------ // TODO //------------------------------ From f22fe5403b59272ba528aaa8d06af643ec33a05a Mon Sep 17 00:00:00 2001 From: Christopher Stawarz Date: Wed, 24 Apr 2019 15:59:10 -0400 Subject: [PATCH 101/110] Adjusted Bluefruit LE connection intervals for better compatibility with Apple devices --- examples/StandardFirmataBLE/bleConfig.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index 412bb849..39b0b24d 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -67,16 +67,16 @@ * with the nRF51822 via SPI (e.g. Bluefruit LE SPI Friend, Bluefruit LE Shield), although * you may need to change the values of BLE_SPI_CS, BLE_SPI_IRQ, and/or BLE_SPI_RST below. * - * You will need to install a lightly-modified version of the Adafruit BluefruitLE nRF51 - * package, available at: - * https://github.com/cstawarz/Adafruit_BluefruitLE_nRF51/archive/firmata_fixes.zip + * You will need to install the latest version of the Adafruit BluefruitLE nRF51 package, + * available at: + * https://github.com/adafruit/Adafruit_BluefruitLE_nRF51/archive/master.zip */ //#define BLUEFRUIT_LE_SPI #ifdef BLUEFRUIT_LE_SPI // Both values must be between 10ms and 4s -#define FIRMATA_BLE_MIN_INTERVAL 10 // 10ms -#define FIRMATA_BLE_MAX_INTERVAL 20 // 20ms +#define FIRMATA_BLE_MIN_INTERVAL 15 // 15ms +#define FIRMATA_BLE_MAX_INTERVAL 30 // 30ms #define BLE_SPI_CS 8 #define BLE_SPI_IRQ 7 From ad2fd4ff97bd7170177072f1265b3272878db448 Mon Sep 17 00:00:00 2001 From: Timothy Claassens Date: Sat, 27 Apr 2019 21:12:49 +1200 Subject: [PATCH 102/110] Added a condition that adds the SoftwareSerial library for the ESP8266. --- utility/SerialFirmata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utility/SerialFirmata.h b/utility/SerialFirmata.h index 2319951b..365fde48 100644 --- a/utility/SerialFirmata.h +++ b/utility/SerialFirmata.h @@ -26,7 +26,7 @@ // SoftwareSerial is currently only supported for AVR-based boards and the Arduino 101. // Limited to Arduino 1.6.6 or higher because Arduino builder cannot find SoftwareSerial // prior to this release. -#if (ARDUINO > 10605) && (defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ARC32)) +#if (ARDUINO > 10605) && (defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ARC32) || defined(ESP8266)) #include #endif From 5f211573eda74786220c790066b3ac58edaf7965 Mon Sep 17 00:00:00 2001 From: Christopher Stawarz Date: Fri, 3 May 2019 16:01:41 -0400 Subject: [PATCH 103/110] Set Bluefruit LE advertising interval --- .../StandardFirmataBLE/StandardFirmataBLE.ino | 4 +++ examples/StandardFirmataBLE/bleConfig.h | 3 +++ utility/BluefruitLE_SPI_Stream.h | 26 +++++++++++++------ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/examples/StandardFirmataBLE/StandardFirmataBLE.ino b/examples/StandardFirmataBLE/StandardFirmataBLE.ino index 7b17b891..ebbe2efc 100755 --- a/examples/StandardFirmataBLE/StandardFirmataBLE.ino +++ b/examples/StandardFirmataBLE/StandardFirmataBLE.ino @@ -770,6 +770,10 @@ void setup() stream.setLocalName(FIRMATA_BLE_LOCAL_NAME); +#ifdef FIRMATA_BLE_ADVERTISING_INTERVAL + // set the BLE advertising interval + stream.setAdvertisingInterval(FIRMATA_BLE_ADVERTISING_INTERVAL); +#endif // set the BLE connection interval - this is the fastest interval you can read inputs stream.setConnectionInterval(FIRMATA_BLE_MIN_INTERVAL, FIRMATA_BLE_MAX_INTERVAL); // set how often the BLE TX buffer is flushed (if not full) diff --git a/examples/StandardFirmataBLE/bleConfig.h b/examples/StandardFirmataBLE/bleConfig.h index 39b0b24d..a783ce9b 100644 --- a/examples/StandardFirmataBLE/bleConfig.h +++ b/examples/StandardFirmataBLE/bleConfig.h @@ -74,6 +74,9 @@ //#define BLUEFRUIT_LE_SPI #ifdef BLUEFRUIT_LE_SPI +// Value must be between 20ms and 10.24s +#define FIRMATA_BLE_ADVERTISING_INTERVAL 20 // 20ms + // Both values must be between 10ms and 4s #define FIRMATA_BLE_MIN_INTERVAL 15 // 15ms #define FIRMATA_BLE_MAX_INTERVAL 30 // 30ms diff --git a/utility/BluefruitLE_SPI_Stream.h b/utility/BluefruitLE_SPI_Stream.h index 372e5aa9..42e982b2 100644 --- a/utility/BluefruitLE_SPI_Stream.h +++ b/utility/BluefruitLE_SPI_Stream.h @@ -17,6 +17,7 @@ class BluefruitLE_SPI_Stream : public Stream BluefruitLE_SPI_Stream(int8_t csPin, int8_t irqPin, int8_t rstPin); void setLocalName(const char *localName); + void setAdvertisingInterval(unsigned short advertisingInterval); void setConnectionInterval(unsigned short minConnInterval, unsigned short maxConnInterval); void setFlushInterval(int flushInterval); @@ -38,6 +39,7 @@ class BluefruitLE_SPI_Stream : public Stream Adafruit_BluefruitLE_SPI ble; String localName; + unsigned short advertisingInterval; unsigned short minConnInterval; unsigned short maxConnInterval; @@ -48,6 +50,7 @@ class BluefruitLE_SPI_Stream : public Stream BluefruitLE_SPI_Stream::BluefruitLE_SPI_Stream(int8_t csPin, int8_t irqPin, int8_t rstPin) : ble(csPin, irqPin, rstPin), + advertisingInterval(0), minConnInterval(0), maxConnInterval(0), txCount(0) @@ -58,6 +61,11 @@ void BluefruitLE_SPI_Stream::setLocalName(const char *localName) this->localName = localName; } +void BluefruitLE_SPI_Stream::setAdvertisingInterval(unsigned short advertisingInterval) +{ + this->advertisingInterval = advertisingInterval; +} + void BluefruitLE_SPI_Stream::setConnectionInterval(unsigned short minConnInterval, unsigned short maxConnInterval) { this->minConnInterval = minConnInterval; @@ -89,14 +97,16 @@ void BluefruitLE_SPI_Stream::begin() ble.println(localName); } - // Set connection interval - if (minConnInterval > 0 && maxConnInterval > 0) { - ble.print("AT+GAPINTERVALS="); - ble.print(minConnInterval); - ble.print(","); - ble.print(maxConnInterval); - ble.println(",,,"); - } + // Set connection and advertising intervals + ble.print("AT+GAPINTERVALS="); + if (minConnInterval > 0) ble.print(minConnInterval); + ble.print(","); + if (maxConnInterval > 0) ble.print(maxConnInterval); + ble.print(","); + if (advertisingInterval > 0) ble.print(advertisingInterval); + ble.print(",,"); // Always omit fast advertising timeout, hence two commas + if (advertisingInterval > 0) ble.print(advertisingInterval); + ble.println(); // Disable real and simulated mode switch (i.e. "+++") command ble.println("AT+MODESWITCHEN=local,0"); From 3f417c124e525aae1b5222b524e952a994671243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Jorge?= Date: Wed, 9 Oct 2019 22:24:30 -0500 Subject: [PATCH 104/110] Set up API docs using Doxygen --- docs/.nojekyll | 0 docs/Doxyfile | 2539 +++++++++++++++++ docs/html/_boards_8h_source.html | 1067 +++++++ docs/html/_firmata_8h_source.html | 284 ++ docs/html/_firmata_constants_8h_source.html | 174 ++ docs/html/_firmata_defines_8h_source.html | 360 +++ docs/html/_firmata_marshaller_8h_source.html | 176 ++ docs/html/_firmata_parser_8h_source.html | 189 ++ docs/html/annotated.html | 85 + docs/html/bc_s.png | Bin 0 -> 676 bytes docs/html/bdwn.png | Bin 0 -> 147 bytes docs/html/classes.html | 90 + ...lassfirmata_1_1_firmata_class-members.html | 121 + docs/html/classfirmata_1_1_firmata_class.html | 972 +++++++ ...irmata_1_1_firmata_marshaller-members.html | 107 + .../classfirmata_1_1_firmata_marshaller.html | 738 +++++ ...assfirmata_1_1_firmata_parser-members.html | 102 + .../html/classfirmata_1_1_firmata_parser.html | 552 ++++ docs/html/closed.png | Bin 0 -> 132 bytes docs/html/doc.png | Bin 0 -> 746 bytes docs/html/doxygen.css | 1766 ++++++++++++ docs/html/doxygen.png | Bin 0 -> 3779 bytes docs/html/dynsections.js | 120 + docs/html/files.html | 87 + docs/html/folderclosed.png | Bin 0 -> 616 bytes docs/html/folderopen.png | Bin 0 -> 597 bytes docs/html/functions.html | 262 ++ docs/html/functions_func.html | 262 ++ docs/html/index.html | 275 ++ docs/html/jquery.js | 35 + docs/html/md_readme.html | 275 ++ docs/html/menu.js | 50 + docs/html/menudata.js | 56 + docs/html/nav_f.png | Bin 0 -> 153 bytes docs/html/nav_g.png | Bin 0 -> 95 bytes docs/html/nav_h.png | Bin 0 -> 98 bytes docs/html/open.png | Bin 0 -> 123 bytes docs/html/pages.html | 82 + docs/html/search/all_0.html | 30 + docs/html/search/all_0.js | 5 + docs/html/search/all_1.html | 30 + docs/html/search/all_1.js | 5 + docs/html/search/all_2.html | 30 + docs/html/search/all_2.js | 5 + docs/html/search/all_3.html | 30 + docs/html/search/all_3.js | 5 + docs/html/search/all_4.html | 30 + docs/html/search/all_4.js | 7 + docs/html/search/all_5.html | 30 + docs/html/search/all_5.js | 5 + docs/html/search/all_6.html | 30 + docs/html/search/all_6.js | 4 + docs/html/search/all_7.html | 30 + docs/html/search/all_7.js | 7 + docs/html/search/all_8.html | 30 + docs/html/search/all_8.js | 5 + docs/html/search/all_9.html | 30 + docs/html/search/all_9.js | 7 + docs/html/search/all_a.html | 30 + docs/html/search/all_a.js | 22 + docs/html/search/all_b.html | 30 + docs/html/search/all_b.js | 4 + docs/html/search/classes_0.html | 30 + docs/html/search/classes_0.js | 6 + docs/html/search/close.png | Bin 0 -> 273 bytes docs/html/search/functions_0.html | 30 + docs/html/search/functions_0.js | 5 + docs/html/search/functions_1.html | 30 + docs/html/search/functions_1.js | 5 + docs/html/search/functions_2.html | 30 + docs/html/search/functions_2.js | 5 + docs/html/search/functions_3.html | 30 + docs/html/search/functions_3.js | 5 + docs/html/search/functions_4.html | 30 + docs/html/search/functions_4.js | 6 + docs/html/search/functions_5.html | 30 + docs/html/search/functions_5.js | 5 + docs/html/search/functions_6.html | 30 + docs/html/search/functions_6.js | 4 + docs/html/search/functions_7.html | 30 + docs/html/search/functions_7.js | 7 + docs/html/search/functions_8.html | 30 + docs/html/search/functions_8.js | 5 + docs/html/search/functions_9.html | 30 + docs/html/search/functions_9.js | 7 + docs/html/search/functions_a.html | 30 + docs/html/search/functions_a.js | 22 + docs/html/search/functions_b.html | 30 + docs/html/search/functions_b.js | 4 + docs/html/search/mag_sel.png | Bin 0 -> 465 bytes docs/html/search/nomatches.html | 12 + docs/html/search/pages_0.html | 30 + docs/html/search/pages_0.js | 4 + docs/html/search/search.css | 271 ++ docs/html/search/search.js | 814 ++++++ docs/html/search/search_l.png | Bin 0 -> 567 bytes docs/html/search/search_m.png | Bin 0 -> 158 bytes docs/html/search/search_r.png | Bin 0 -> 553 bytes docs/html/search/searchdata.js | 24 + docs/html/splitbar.png | Bin 0 -> 314 bytes docs/html/sync_off.png | Bin 0 -> 853 bytes docs/html/sync_on.png | Bin 0 -> 845 bytes docs/html/tab_a.png | Bin 0 -> 142 bytes docs/html/tab_b.png | Bin 0 -> 169 bytes docs/html/tab_h.png | Bin 0 -> 177 bytes docs/html/tab_s.png | Bin 0 -> 184 bytes docs/html/tabs.css | 1 + docs/index.html | 2 + 108 files changed, 12901 insertions(+) create mode 100644 docs/.nojekyll create mode 100644 docs/Doxyfile create mode 100644 docs/html/_boards_8h_source.html create mode 100644 docs/html/_firmata_8h_source.html create mode 100644 docs/html/_firmata_constants_8h_source.html create mode 100644 docs/html/_firmata_defines_8h_source.html create mode 100644 docs/html/_firmata_marshaller_8h_source.html create mode 100644 docs/html/_firmata_parser_8h_source.html create mode 100644 docs/html/annotated.html create mode 100644 docs/html/bc_s.png create mode 100644 docs/html/bdwn.png create mode 100644 docs/html/classes.html create mode 100644 docs/html/classfirmata_1_1_firmata_class-members.html create mode 100644 docs/html/classfirmata_1_1_firmata_class.html create mode 100644 docs/html/classfirmata_1_1_firmata_marshaller-members.html create mode 100644 docs/html/classfirmata_1_1_firmata_marshaller.html create mode 100644 docs/html/classfirmata_1_1_firmata_parser-members.html create mode 100644 docs/html/classfirmata_1_1_firmata_parser.html create mode 100644 docs/html/closed.png create mode 100644 docs/html/doc.png create mode 100644 docs/html/doxygen.css create mode 100644 docs/html/doxygen.png create mode 100644 docs/html/dynsections.js create mode 100644 docs/html/files.html create mode 100644 docs/html/folderclosed.png create mode 100644 docs/html/folderopen.png create mode 100644 docs/html/functions.html create mode 100644 docs/html/functions_func.html create mode 100644 docs/html/index.html create mode 100644 docs/html/jquery.js create mode 100644 docs/html/md_readme.html create mode 100644 docs/html/menu.js create mode 100644 docs/html/menudata.js create mode 100644 docs/html/nav_f.png create mode 100644 docs/html/nav_g.png create mode 100644 docs/html/nav_h.png create mode 100644 docs/html/open.png create mode 100644 docs/html/pages.html create mode 100644 docs/html/search/all_0.html create mode 100644 docs/html/search/all_0.js create mode 100644 docs/html/search/all_1.html create mode 100644 docs/html/search/all_1.js create mode 100644 docs/html/search/all_2.html create mode 100644 docs/html/search/all_2.js create mode 100644 docs/html/search/all_3.html create mode 100644 docs/html/search/all_3.js create mode 100644 docs/html/search/all_4.html create mode 100644 docs/html/search/all_4.js create mode 100644 docs/html/search/all_5.html create mode 100644 docs/html/search/all_5.js create mode 100644 docs/html/search/all_6.html create mode 100644 docs/html/search/all_6.js create mode 100644 docs/html/search/all_7.html create mode 100644 docs/html/search/all_7.js create mode 100644 docs/html/search/all_8.html create mode 100644 docs/html/search/all_8.js create mode 100644 docs/html/search/all_9.html create mode 100644 docs/html/search/all_9.js create mode 100644 docs/html/search/all_a.html create mode 100644 docs/html/search/all_a.js create mode 100644 docs/html/search/all_b.html create mode 100644 docs/html/search/all_b.js create mode 100644 docs/html/search/classes_0.html create mode 100644 docs/html/search/classes_0.js create mode 100644 docs/html/search/close.png create mode 100644 docs/html/search/functions_0.html create mode 100644 docs/html/search/functions_0.js create mode 100644 docs/html/search/functions_1.html create mode 100644 docs/html/search/functions_1.js create mode 100644 docs/html/search/functions_2.html create mode 100644 docs/html/search/functions_2.js create mode 100644 docs/html/search/functions_3.html create mode 100644 docs/html/search/functions_3.js create mode 100644 docs/html/search/functions_4.html create mode 100644 docs/html/search/functions_4.js create mode 100644 docs/html/search/functions_5.html create mode 100644 docs/html/search/functions_5.js create mode 100644 docs/html/search/functions_6.html create mode 100644 docs/html/search/functions_6.js create mode 100644 docs/html/search/functions_7.html create mode 100644 docs/html/search/functions_7.js create mode 100644 docs/html/search/functions_8.html create mode 100644 docs/html/search/functions_8.js create mode 100644 docs/html/search/functions_9.html create mode 100644 docs/html/search/functions_9.js create mode 100644 docs/html/search/functions_a.html create mode 100644 docs/html/search/functions_a.js create mode 100644 docs/html/search/functions_b.html create mode 100644 docs/html/search/functions_b.js create mode 100644 docs/html/search/mag_sel.png create mode 100644 docs/html/search/nomatches.html create mode 100644 docs/html/search/pages_0.html create mode 100644 docs/html/search/pages_0.js create mode 100644 docs/html/search/search.css create mode 100644 docs/html/search/search.js create mode 100644 docs/html/search/search_l.png create mode 100644 docs/html/search/search_m.png create mode 100644 docs/html/search/search_r.png create mode 100644 docs/html/search/searchdata.js create mode 100644 docs/html/splitbar.png create mode 100644 docs/html/sync_off.png create mode 100644 docs/html/sync_on.png create mode 100644 docs/html/tab_a.png create mode 100644 docs/html/tab_b.png create mode 100644 docs/html/tab_h.png create mode 100644 docs/html/tab_s.png create mode 100644 docs/html/tabs.css create mode 100644 docs/index.html diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/docs/Doxyfile b/docs/Doxyfile new file mode 100644 index 00000000..a420115e --- /dev/null +++ b/docs/Doxyfile @@ -0,0 +1,2539 @@ +# Doxyfile 1.8.16 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "Firmata firmware for Arduino" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Firmata is a protocol for communicating with microcontrollers from software on a host computer" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = . + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = ../ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is +# Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# (including Cygwin) ands Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ../ \ + ../readme.md + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = readme.md + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via Javascript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have Javascript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /
+
1 /*
+
2  Boards.h - Hardware Abstraction Layer for Firmata library
+
3  Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
+
4  Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved.
+
5 
+
6  This library is free software; you can redistribute it and/or
+
7  modify it under the terms of the GNU Lesser General Public
+
8  License as published by the Free Software Foundation; either
+
9  version 2.1 of the License, or (at your option) any later version.
+
10 
+
11  See file LICENSE.txt for further informations on licensing terms.
+
12 
+
13  Last updated April 15th, 2018
+
14 */
+
15 
+
16 #ifndef Firmata_Boards_h
+
17 #define Firmata_Boards_h
+
18 
+
19 #include <inttypes.h>
+
20 
+
21 #if defined(ARDUINO) && ARDUINO >= 100
+
22 #include "Arduino.h" // for digitalRead, digitalWrite, etc
+
23 #else
+
24 #include "WProgram.h"
+
25 #endif
+
26 
+
27 // Normally Servo.h must be included before Firmata.h (which then includes
+
28 // this file). If Servo.h wasn't included, this allows the code to still
+
29 // compile, but without support for any Servos. Hopefully that's what the
+
30 // user intended by not including Servo.h
+
31 #ifndef MAX_SERVOS
+
32 #define MAX_SERVOS 0
+
33 #endif
+
34 
+
35 /*
+
36  Firmata Hardware Abstraction Layer
+
37 
+
38 Firmata is built on top of the hardware abstraction functions of Arduino,
+
39 specifically digitalWrite, digitalRead, analogWrite, analogRead, and
+
40 pinMode. While these functions offer simple integer pin numbers, Firmata
+
41 needs more information than is provided by Arduino. This file provides
+
42 all other hardware specific details. To make Firmata support a new board,
+
43 only this file should require editing.
+
44 
+
45 The key concept is every "pin" implemented by Firmata may be mapped to
+
46 any pin as implemented by Arduino. Usually a simple 1-to-1 mapping is
+
47 best, but such mapping should not be assumed. This hardware abstraction
+
48 layer allows Firmata to implement any number of pins which map onto the
+
49 Arduino implemented pins in almost any arbitrary way.
+
50 
+
51 
+
52 General Constants:
+
53 
+
54 These constants provide basic information Firmata requires.
+
55 
+
56 TOTAL_PINS: The total number of pins Firmata implemented by Firmata.
+
57  Usually this will match the number of pins the Arduino functions
+
58  implement, including any pins pins capable of analog or digital.
+
59  However, Firmata may implement any number of pins. For example,
+
60  on Arduino Mini with 8 analog inputs, 6 of these may be used
+
61  for digital functions, and 2 are analog only. On such boards,
+
62  Firmata can implement more pins than Arduino's pinMode()
+
63  function, in order to accommodate those special pins. The
+
64  Firmata protocol supports a maximum of 128 pins, so this
+
65  constant must not exceed 128.
+
66 
+
67 TOTAL_ANALOG_PINS: The total number of analog input pins implemented.
+
68  The Firmata protocol allows up to 16 analog inputs, accessed
+
69  using offsets 0 to 15. Because Firmata presents the analog
+
70  inputs using different offsets than the actual pin numbers
+
71  (a legacy of Arduino's analogRead function, and the way the
+
72  analog input capable pins are physically labeled on all
+
73  Arduino boards), the total number of analog input signals
+
74  must be specified. 16 is the maximum.
+
75 
+
76 VERSION_BLINK_PIN: When Firmata starts up, it will blink the version
+
77  number. This constant is the Arduino pin number where a
+
78  LED is connected.
+
79 
+
80 
+
81 Pin Mapping Macros:
+
82 
+
83 These macros provide the mapping between pins as implemented by
+
84 Firmata protocol and the actual pin numbers used by the Arduino
+
85 functions. Even though such mappings are often simple, pin
+
86 numbers received by Firmata protocol should always be used as
+
87 input to these macros, and the result of the macro should be
+
88 used with with any Arduino function.
+
89 
+
90 When Firmata is extended to support a new pin mode or feature,
+
91 a pair of macros should be added and used for all hardware
+
92 access. For simple 1:1 mapping, these macros add no actual
+
93 overhead, yet their consistent use allows source code which
+
94 uses them consistently to be easily adapted to all other boards
+
95 with different requirements.
+
96 
+
97 IS_PIN_XXXX(pin): The IS_PIN macros resolve to true or non-zero
+
98  if a pin as implemented by Firmata corresponds to a pin
+
99  that actually implements the named feature.
+
100 
+
101 PIN_TO_XXXX(pin): The PIN_TO macros translate pin numbers as
+
102  implemented by Firmata to the pin numbers needed as inputs
+
103  to the Arduino functions. The corresponding IS_PIN macro
+
104  should always be tested before using a PIN_TO macro, so
+
105  these macros only need to handle valid Firmata pin
+
106  numbers for the named feature.
+
107 
+
108 
+
109 Port Access Inline Funtions:
+
110 
+
111 For efficiency, Firmata protocol provides access to digital
+
112 input and output pins grouped by 8 bit ports. When these
+
113 groups of 8 correspond to actual 8 bit ports as implemented
+
114 by the hardware, these inline functions can provide high
+
115 speed direct port access. Otherwise, a default implementation
+
116 using 8 calls to digitalWrite or digitalRead is used.
+
117 
+
118 When porting Firmata to a new board, it is recommended to
+
119 use the default functions first and focus only on the constants
+
120 and macros above. When those are working, if optimized port
+
121 access is desired, these inline functions may be extended.
+
122 The recommended approach defines a symbol indicating which
+
123 optimization to use, and then conditional complication is
+
124 used within these functions.
+
125 
+
126 readPort(port, bitmask): Read an 8 bit port, returning the value.
+
127  port: The port number, Firmata pins port*8 to port*8+7
+
128  bitmask: The actual pins to read, indicated by 1 bits.
+
129 
+
130 writePort(port, value, bitmask): Write an 8 bit port.
+
131  port: The port number, Firmata pins port*8 to port*8+7
+
132  value: The 8 bit value to write
+
133  bitmask: The actual pins to write, indicated by 1 bits.
+
134 */
+
135 
+
136 /*==============================================================================
+
137  * Board Specific Configuration
+
138  *============================================================================*/
+
139 
+
140 #ifndef digitalPinHasPWM
+
141 #define digitalPinHasPWM(p) IS_PIN_DIGITAL(p)
+
142 #endif
+
143 
+
144 // Arduino Duemilanove, Diecimila, and NG
+
145 #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
+
146 #if defined(NUM_ANALOG_INPUTS) && NUM_ANALOG_INPUTS == 6
+
147 #define TOTAL_ANALOG_PINS 6
+
148 #define TOTAL_PINS 20 // 14 digital + 6 analog
+
149 #else
+
150 #define TOTAL_ANALOG_PINS 8
+
151 #define TOTAL_PINS 22 // 14 digital + 8 analog
+
152 #endif
+
153 #define VERSION_BLINK_PIN 13
+
154 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19)
+
155 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS)
+
156 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
157 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS)
+
158 #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
+
159 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
160 #define PIN_TO_DIGITAL(p) (p)
+
161 #define PIN_TO_ANALOG(p) ((p) - 14)
+
162 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
163 #define PIN_TO_SERVO(p) ((p) - 2)
+
164 #define ARDUINO_PINOUT_OPTIMIZE 1
+
165 
+
166 
+
167 // Wiring (and board)
+
168 #elif defined(WIRING)
+
169 #define VERSION_BLINK_PIN WLED
+
170 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
+
171 #define IS_PIN_ANALOG(p) ((p) >= FIRST_ANALOG_PIN && (p) < (FIRST_ANALOG_PIN+TOTAL_ANALOG_PINS))
+
172 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
173 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
174 #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
+
175 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
176 #define PIN_TO_DIGITAL(p) (p)
+
177 #define PIN_TO_ANALOG(p) ((p) - FIRST_ANALOG_PIN)
+
178 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
179 #define PIN_TO_SERVO(p) (p)
+
180 
+
181 
+
182 // old Arduinos
+
183 #elif defined(__AVR_ATmega8__)
+
184 #define TOTAL_ANALOG_PINS 6
+
185 #define TOTAL_PINS 20 // 14 digital + 6 analog
+
186 #define VERSION_BLINK_PIN 13
+
187 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19)
+
188 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 19)
+
189 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
190 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS)
+
191 #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
+
192 #define PIN_TO_DIGITAL(p) (p)
+
193 #define PIN_TO_ANALOG(p) ((p) - 14)
+
194 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
195 #define PIN_TO_SERVO(p) ((p) - 2)
+
196 #define ARDUINO_PINOUT_OPTIMIZE 1
+
197 
+
198 
+
199 // Arduino Mega
+
200 #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+
201 #define TOTAL_ANALOG_PINS 16
+
202 #define TOTAL_PINS 70 // 54 digital + 16 analog
+
203 #define VERSION_BLINK_PIN 13
+
204 #define PIN_SERIAL1_RX 19
+
205 #define PIN_SERIAL1_TX 18
+
206 #define PIN_SERIAL2_RX 17
+
207 #define PIN_SERIAL2_TX 16
+
208 #define PIN_SERIAL3_RX 15
+
209 #define PIN_SERIAL3_TX 14
+
210 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
+
211 #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS)
+
212 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
213 #define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS)
+
214 #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21)
+
215 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
216 #define IS_PIN_SERIAL(p) ((p) > 13 && (p) < 20)
+
217 #define PIN_TO_DIGITAL(p) (p)
+
218 #define PIN_TO_ANALOG(p) ((p) - 54)
+
219 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
220 #define PIN_TO_SERVO(p) ((p) - 2)
+
221 
+
222 // Arduino UNO WiFi rev2 (ATMega 4809)
+
223 #elif defined(__AVR_ATmega4809__)
+
224 #define TOTAL_ANALOG_PINS 6
+
225 #define TOTAL_PINS 20 // 14 digital + 6 analog + /* 3 SPI (unexported, on ISP header) */
+
226 #define VERSION_BLINK_PIN 25
+
227 #define PIN_SERIAL1_RX 0
+
228 #define PIN_SERIAL1_TX 1
+
229 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
+
230 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < TOTAL_PINS)
+
231 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
232 #define IS_PIN_SERVO(p) (p)
+
233 #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
+
234 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
235 #define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1)
+
236 #define PIN_TO_DIGITAL(p) (p)
+
237 #define PIN_TO_ANALOG(p) (p) - 14
+
238 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
239 #define PIN_TO_SERVO(p) (p)
+
240 
+
241 // Arduino DUE
+
242 #elif defined(__SAM3X8E__)
+
243 #define TOTAL_ANALOG_PINS 12
+
244 #define TOTAL_PINS 66 // 54 digital + 12 analog
+
245 #define VERSION_BLINK_PIN 13
+
246 #define PIN_SERIAL1_RX 19
+
247 #define PIN_SERIAL1_TX 18
+
248 #define PIN_SERIAL2_RX 17
+
249 #define PIN_SERIAL2_TX 16
+
250 #define PIN_SERIAL3_RX 15
+
251 #define PIN_SERIAL3_TX 14
+
252 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
+
253 #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS)
+
254 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
255 #define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS)
+
256 #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) // 70 71
+
257 #define IS_PIN_SERIAL(p) ((p) > 13 && (p) < 20)
+
258 #define PIN_TO_DIGITAL(p) (p)
+
259 #define PIN_TO_ANALOG(p) ((p) - 54)
+
260 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
261 #define PIN_TO_SERVO(p) ((p) - 2)
+
262 
+
263 
+
264 // Arduino/Genuino MKR1000 or MKR1010
+
265 #elif defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010)
+
266 #define TOTAL_ANALOG_PINS 7
+
267 #define TOTAL_PINS 22 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog
+
268 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 21)
+
269 #define IS_PIN_ANALOG(p) ((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS)
+
270 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
271 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
+
272 #define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12
+
273 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
274 #define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14
+
275 #define PIN_TO_DIGITAL(p) (p)
+
276 #define PIN_TO_ANALOG(p) ((p) - 15)
+
277 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
278 #define PIN_TO_SERVO(p) (p) // deprecated since v2.4
+
279 
+
280 
+
281 // Arduino MKRZero
+
282 #elif defined(ARDUINO_SAMD_MKRZERO)
+
283 #define TOTAL_ANALOG_PINS 7
+
284 #define TOTAL_PINS 34 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog + 3 usb + 1 aref + 5 sd + 1 bottom pad + 1 led + 1 battery adc
+
285 #define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21) || (p) == 32)
+
286 #define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 33)
+
287 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
288 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
+
289 #define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12
+
290 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
291 #define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14
+
292 #define PIN_TO_DIGITAL(p) (p)
+
293 #define PIN_TO_ANALOG(p) ((p) - 15)
+
294 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
295 #define PIN_TO_SERVO(p) (p) // deprecated since v2.4
+
296 
+
297 // Arduino MKRFox1200
+
298 #elif defined(ARDUINO_SAMD_MKRFox1200)
+
299 #define TOTAL_ANALOG_PINS 7
+
300 #define TOTAL_PINS 33 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog + 3 usb + 1 aref + 5 sd + 1 bottom pad + 1 battery adc
+
301 #define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21))
+
302 #define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 32)
+
303 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
304 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
+
305 #define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12
+
306 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
307 #define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14
+
308 #define PIN_TO_DIGITAL(p) (p)
+
309 #define PIN_TO_ANALOG(p) ((p) - 15)
+
310 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
311 #define PIN_TO_SERVO(p) (p) // deprecated since v2.4
+
312 
+
313 // Arduino MKR WAN 1300
+
314 #elif defined(ARDUINO_SAMD_MKRWAN1300)
+
315 #define TOTAL_ANALOG_PINS 7
+
316 #define TOTAL_PINS 33
+
317 #define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21))
+
318 #define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 32)
+
319 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
320 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
+
321 #define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12
+
322 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
323 #define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14
+
324 #define PIN_TO_DIGITAL(p) (p)
+
325 #define PIN_TO_ANALOG(p) ((p) - 15)
+
326 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
327 #define PIN_TO_SERVO(p) (p) // deprecated since v2.4
+
328 
+
329 // Arduino MKR GSM 1400
+
330 #elif defined(ARDUINO_SAMD_MKRGSM1400)
+
331 #define TOTAL_ANALOG_PINS 7
+
332 #define TOTAL_PINS 33
+
333 #define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21))
+
334 #define IS_PIN_ANALOG(p) (((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS) || (p) == 32)
+
335 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
336 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
+
337 #define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12
+
338 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
339 #define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14
+
340 #define PIN_TO_DIGITAL(p) (p)
+
341 #define PIN_TO_ANALOG(p) ((p) - 15)
+
342 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
343 #define PIN_TO_SERVO(p) (p) // deprecated since v2.4
+
344 
+
345 // Arduino Zero
+
346 // Note this will work with an Arduino Zero Pro, but not with an Arduino M0 Pro
+
347 // Arduino M0 Pro does not properly map pins to the board labeled pin numbers
+
348 #elif defined(_VARIANT_ARDUINO_ZERO_)
+
349 #define TOTAL_ANALOG_PINS 6
+
350 #define TOTAL_PINS 25 // 14 digital + 6 analog + 2 i2c + 3 spi
+
351 #define TOTAL_PORTS 3 // set when TOTAL_PINS > num digitial I/O pins
+
352 #define VERSION_BLINK_PIN LED_BUILTIN
+
353 //#define PIN_SERIAL1_RX 0 // already defined in zero core variant.h
+
354 //#define PIN_SERIAL1_TX 1 // already defined in zero core variant.h
+
355 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 19)
+
356 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS)
+
357 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
358 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
+
359 #define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) // SDA = 20, SCL = 21
+
360 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) // SS = A2
+
361 #define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1)
+
362 #define PIN_TO_DIGITAL(p) (p)
+
363 #define PIN_TO_ANALOG(p) ((p) - 14)
+
364 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
365 #define PIN_TO_SERVO(p) (p) // deprecated since v2.4
+
366 
+
367 // Arduino Primo
+
368 #elif defined(ARDUINO_PRIMO)
+
369 #define TOTAL_ANALOG_PINS 6
+
370 #define TOTAL_PINS 22 //14 digital + 6 analog + 2 i2c
+
371 #define VERSION_BLINK_PIN LED_BUILTIN
+
372 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < 20)
+
373 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 20)
+
374 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
375 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS+2)
+
376 #define IS_PIN_I2C(p) ((p) == PIN_WIRE_SDA || (p) == PIN_WIRE_SCL) // SDA = 20, SCL = 21
+
377 #define IS_PIN_SPI(p) ((p) == SS || (p)== MOSI || (p) == MISO || (p == SCK)) // 10, 11, 12, 13
+
378 #define PIN_TO_DIGITAL(p) (p)
+
379 #define PIN_TO_ANALOG(p) ((p) - 14)
+
380 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
381 #define PIN_TO_SERVO(p) (p)
+
382 
+
383 // Arduino 101
+
384 #elif defined(_VARIANT_ARDUINO_101_X_)
+
385 #define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS
+
386 #define TOTAL_PINS NUM_DIGITAL_PINS // 15 digital (including ATN pin) + 6 analog
+
387 #define VERSION_BLINK_PIN LED_BUILTIN
+
388 #define PIN_SERIAL1_RX 0
+
389 #define PIN_SERIAL1_TX 1
+
390 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 20)
+
391 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS)
+
392 #define IS_PIN_PWM(p) digitalPinHasPWM(p) // 3, 5, 6, 9
+
393 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
+
394 #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) // SDA = 18, SCL = 19
+
395 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
396 #define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1)
+
397 #define PIN_TO_DIGITAL(p) (p)
+
398 #define PIN_TO_ANALOG(p) ((p) - 14)
+
399 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
400 #define PIN_TO_SERVO(p) (p) // deprecated since v2.4
+
401 
+
402 
+
403 // Teensy 1.0
+
404 #elif defined(__AVR_AT90USB162__)
+
405 #define TOTAL_ANALOG_PINS 0
+
406 #define TOTAL_PINS 21 // 21 digital + no analog
+
407 #define VERSION_BLINK_PIN 6
+
408 #define PIN_SERIAL1_RX 2
+
409 #define PIN_SERIAL1_TX 3
+
410 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
+
411 #define IS_PIN_ANALOG(p) (0)
+
412 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
413 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
414 #define IS_PIN_I2C(p) (0)
+
415 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
416 #define IS_PIN_SERIAL(p) ((p) == 2 || (p) == 3)
+
417 #define PIN_TO_DIGITAL(p) (p)
+
418 #define PIN_TO_ANALOG(p) (0)
+
419 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
420 #define PIN_TO_SERVO(p) (p)
+
421 
+
422 
+
423 // Teensy 2.0
+
424 #elif defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY)
+
425 #define TOTAL_ANALOG_PINS 12
+
426 #define TOTAL_PINS 25 // 11 digital + 12 analog
+
427 #define VERSION_BLINK_PIN 11
+
428 #define PIN_SERIAL1_RX 7
+
429 #define PIN_SERIAL1_TX 8
+
430 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
+
431 #define IS_PIN_ANALOG(p) ((p) >= 11 && (p) <= 22)
+
432 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
433 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
434 #define IS_PIN_I2C(p) ((p) == 5 || (p) == 6)
+
435 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
436 #define IS_PIN_SERIAL(p) ((p) == 7 || (p) == 8)
+
437 #define PIN_TO_DIGITAL(p) (p)
+
438 #define PIN_TO_ANALOG(p) (((p) < 22) ? 21 - (p) : 11)
+
439 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
440 #define PIN_TO_SERVO(p) (p)
+
441 
+
442 
+
443 // Teensy 3.5 and 3.6
+
444 // reference: https://github.com/PaulStoffregen/cores/blob/master/teensy3/pins_arduino.h
+
445 #elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
+
446 #define TOTAL_ANALOG_PINS 27 // 3.5 has 27 and 3.6 has 25
+
447 #define TOTAL_PINS 70 // 43 digital + 21 analog-digital + 6 analog (64-69)
+
448 #define VERSION_BLINK_PIN 13
+
449 #define PIN_SERIAL1_RX 0
+
450 #define PIN_SERIAL1_TX 1
+
451 #define PIN_SERIAL2_RX 9
+
452 #define PIN_SERIAL2_TX 10
+
453 #define PIN_SERIAL3_RX 7
+
454 #define PIN_SERIAL3_TX 8
+
455 #define PIN_SERIAL4_RX 31
+
456 #define PIN_SERIAL4_TX 32
+
457 #define PIN_SERIAL5_RX 34
+
458 #define PIN_SERIAL5_TX 33
+
459 #define PIN_SERIAL6_RX 47
+
460 #define PIN_SERIAL6_TX 48
+
461 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 63)
+
462 #define IS_PIN_ANALOG(p) (((p) >= 14 && (p) <= 23) || ((p) >= 31 && (p) <= 39) || ((p) >= 49 && (p) <= 50) || ((p) >= 64 && (p) <= 69))
+
463 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
464 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
465 #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
+
466 #define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1) || ((p) > 30 && (p) < 35) || ((p) == 47 || (p) == 48))
+
467 #define PIN_TO_DIGITAL(p) (p)
+
468 // A0-A9 = D14-D23; A12-A20 = D31-D39; A23-A24 = D49-D50; A10-A11 = D64-D65; A21-A22 = D66-D67; A25-A26 = D68-D69
+
469 #define PIN_TO_ANALOG(p) (((p) <= 23) ? (p) - 14 : (((p) <= 39) ? (p) - 19 : (((p) <= 50) ? (p) - 26 : (((p) <= 65) ? (p) - 55 : (((p) <= 67) ? (p) - 45 : (p) - 43)))))
+
470 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
471 #define PIN_TO_SERVO(p) (p)
+
472 
+
473 
+
474 // Teensy 3.0, 3.1 and 3.2
+
475 #elif defined(__MK20DX128__) || defined(__MK20DX256__)
+
476 #define TOTAL_ANALOG_PINS 14
+
477 #define TOTAL_PINS 38 // 24 digital + 10 analog-digital + 4 analog
+
478 #define VERSION_BLINK_PIN 13
+
479 #define PIN_SERIAL1_RX 0
+
480 #define PIN_SERIAL1_TX 1
+
481 #define PIN_SERIAL2_RX 9
+
482 #define PIN_SERIAL2_TX 10
+
483 #define PIN_SERIAL3_RX 7
+
484 #define PIN_SERIAL3_TX 8
+
485 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 33)
+
486 #define IS_PIN_ANALOG(p) (((p) >= 14 && (p) <= 23) || ((p) >= 34 && (p) <= 38))
+
487 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
488 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
489 #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
+
490 #define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1))
+
491 #define PIN_TO_DIGITAL(p) (p)
+
492 #define PIN_TO_ANALOG(p) (((p) <= 23) ? (p) - 14 : (p) - 24)
+
493 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
494 #define PIN_TO_SERVO(p) (p)
+
495 
+
496 
+
497 // Teensy-LC
+
498 #elif defined(__MKL26Z64__)
+
499 #define TOTAL_ANALOG_PINS 13
+
500 #define TOTAL_PINS 27 // 27 digital + 13 analog-digital
+
501 #define VERSION_BLINK_PIN 13
+
502 #define PIN_SERIAL1_RX 0
+
503 #define PIN_SERIAL1_TX 1
+
504 #define PIN_SERIAL2_RX 9
+
505 #define PIN_SERIAL2_TX 10
+
506 #define PIN_SERIAL3_RX 7
+
507 #define PIN_SERIAL3_TX 8
+
508 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 26)
+
509 #define IS_PIN_ANALOG(p) ((p) >= 14)
+
510 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
511 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
512 #define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
+
513 #define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1))
+
514 #define PIN_TO_DIGITAL(p) (p)
+
515 #define PIN_TO_ANALOG(p) ((p) - 14)
+
516 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
517 #define PIN_TO_SERVO(p) (p)
+
518 
+
519 
+
520 // Teensy++ 1.0 and 2.0
+
521 #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
+
522 #define TOTAL_ANALOG_PINS 8
+
523 #define TOTAL_PINS 46 // 38 digital + 8 analog
+
524 #define VERSION_BLINK_PIN 6
+
525 #define PIN_SERIAL1_RX 2
+
526 #define PIN_SERIAL1_TX 3
+
527 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
+
528 #define IS_PIN_ANALOG(p) ((p) >= 38 && (p) < TOTAL_PINS)
+
529 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
530 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
531 #define IS_PIN_I2C(p) ((p) == 0 || (p) == 1)
+
532 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
533 #define IS_PIN_SERIAL(p) ((p) == 2 || (p) == 3)
+
534 #define PIN_TO_DIGITAL(p) (p)
+
535 #define PIN_TO_ANALOG(p) ((p) - 38)
+
536 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
537 #define PIN_TO_SERVO(p) (p)
+
538 
+
539 
+
540 // Leonardo
+
541 #elif defined(__AVR_ATmega32U4__)
+
542 #define TOTAL_ANALOG_PINS 12
+
543 #define TOTAL_PINS 30 // 14 digital + 12 analog + 4 SPI (D14-D17 on ISP header)
+
544 #define VERSION_BLINK_PIN 13
+
545 #define PIN_SERIAL1_RX 0
+
546 #define PIN_SERIAL1_TX 1
+
547 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
+
548 #define IS_PIN_ANALOG(p) ((p) >= 18 && (p) < TOTAL_PINS)
+
549 #define IS_PIN_PWM(p) ((p) == 3 || (p) == 5 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 11 || (p) == 13)
+
550 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
551 #define IS_PIN_I2C(p) ((p) == 2 || (p) == 3)
+
552 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
553 #define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1)
+
554 #define PIN_TO_DIGITAL(p) (p)
+
555 #define PIN_TO_ANALOG(p) (p) - 18
+
556 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
557 #define PIN_TO_SERVO(p) (p)
+
558 
+
559 
+
560 // Intel Galileo Board (gen 1 and 2) and Intel Edison
+
561 #elif defined(ARDUINO_LINUX)
+
562 #define TOTAL_ANALOG_PINS 6
+
563 #define TOTAL_PINS 20 // 14 digital + 6 analog
+
564 #define VERSION_BLINK_PIN 13
+
565 #define PIN_SERIAL1_RX 0
+
566 #define PIN_SERIAL1_TX 1
+
567 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19)
+
568 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 19)
+
569 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
570 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS)
+
571 #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
+
572 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
573 #define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1)
+
574 #define PIN_TO_DIGITAL(p) (p)
+
575 #define PIN_TO_ANALOG(p) ((p) - 14)
+
576 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
577 #define PIN_TO_SERVO(p) ((p) - 2)
+
578 
+
579 
+
580 // RedBearLab BLE Nano with factory switch settings (S1 - S10)
+
581 #elif defined(BLE_NANO)
+
582 #define TOTAL_ANALOG_PINS 6
+
583 #define TOTAL_PINS 15 // 9 digital + 3 analog
+
584 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 14)
+
585 #define IS_PIN_ANALOG(p) ((p) == 8 || (p) == 9 || (p) == 10 || (p) == 11 || (p) == 12 || (p) == 14) //A0~A5
+
586 #define IS_PIN_PWM(p) ((p) == 3 || (p) == 5 || (p) == 6)
+
587 #define IS_PIN_SERVO(p) ((p) >= 2 && (p) <= 7)
+
588 #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
+
589 #define IS_PIN_SPI(p) ((p) == CS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
590 #define PIN_TO_DIGITAL(p) (p)
+
591 #define PIN_TO_ANALOG(p) ((p) - 8)
+
592 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
593 #define PIN_TO_SERVO(p) (p)
+
594 
+
595 
+
596 // Sanguino
+
597 #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
+
598 #define TOTAL_ANALOG_PINS 8
+
599 #define TOTAL_PINS 32 // 24 digital + 8 analog
+
600 #define VERSION_BLINK_PIN 0
+
601 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
+
602 #define IS_PIN_ANALOG(p) ((p) >= 24 && (p) < TOTAL_PINS)
+
603 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
604 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
605 #define IS_PIN_I2C(p) ((p) == 16 || (p) == 17)
+
606 #define PIN_TO_DIGITAL(p) (p)
+
607 #define PIN_TO_ANALOG(p) ((p) - 24)
+
608 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
609 #define PIN_TO_SERVO(p) ((p) - 2)
+
610 
+
611 // Sanguino/Melzi, e.g. Creality Ender-3
+
612 #elif defined(__AVR_ATmega1284P__)
+
613 #define TOTAL_ANALOG_PINS 8
+
614 #define TOTAL_PINS 32
+
615 #define VERSION_BLINK_PIN 13
+
616 #define PIN_SERIAL1_RX 8 //PD0
+
617 #define PIN_SERIAL1_TX 9 //PD1
+
618 #define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
+
619 #define IS_PIN_ANALOG(p) ((p) >= 24 && (p) < TOTAL_PINS)
+
620 #define IS_PIN_PWM(p) ((p) == 3 || (p) == 4 || (p) == 6 || (p) == 7 || (p) == 12 || (p) == 13 || (p) == 14 || (p) == 15)
+
621 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
622 #define IS_PIN_I2C(p) ((p) == 16 || (p) == 17)
+
623 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
624 #define IS_PIN_SERIAL(p) ((p) == 8 || (p) == 9)
+
625 #define PIN_TO_DIGITAL(p) (p)
+
626 #define PIN_TO_ANALOG(p) (p) - 24
+
627 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
628 #define PIN_TO_SERVO(p) (p)
+
629 
+
630 
+
631 // Illuminato
+
632 #elif defined(__AVR_ATmega645__)
+
633 #define TOTAL_ANALOG_PINS 6
+
634 #define TOTAL_PINS 42 // 36 digital + 6 analog
+
635 #define VERSION_BLINK_PIN 13
+
636 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
+
637 #define IS_PIN_ANALOG(p) ((p) >= 36 && (p) < TOTAL_PINS)
+
638 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
639 #define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
+
640 #define IS_PIN_I2C(p) ((p) == 4 || (p) == 5)
+
641 #define PIN_TO_DIGITAL(p) (p)
+
642 #define PIN_TO_ANALOG(p) ((p) - 36)
+
643 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
644 #define PIN_TO_SERVO(p) ((p) - 2)
+
645 
+
646 
+
647 // Pic32 chipKIT FubarinoSD
+
648 #elif defined(_BOARD_FUBARINO_SD_)
+
649 #define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 15
+
650 #define TOTAL_PINS NUM_DIGITAL_PINS // 45, All pins can be digital
+
651 #define MAX_SERVOS NUM_DIGITAL_PINS
+
652 #define VERSION_BLINK_PIN PIN_LED1
+
653 #define IS_PIN_DIGITAL(p) 1
+
654 #define IS_PIN_ANALOG(p) ((p) >= 30 && (p) <= 44)
+
655 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
656 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
657 #define IS_PIN_I2C(p) ((p) == 1 || (p) == 2)
+
658 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
659 #define PIN_TO_DIGITAL(p) (p)
+
660 #define PIN_TO_ANALOG(p) (14 - (p - 30))
+
661 #define PIN_TO_PWM(p) (p)
+
662 #define PIN_TO_SERVO(p) (p)
+
663 
+
664 
+
665 // Pic32 chipKIT FubarinoMini
+
666 // Note, FubarinoMini analog pin 20 will not function in Firmata as analog input due to limitation in analog mapping
+
667 #elif defined(_BOARD_FUBARINO_MINI_)
+
668 #define TOTAL_ANALOG_PINS 14 // We have to fake this because of the poor analog pin mapping planning in FubarinoMini
+
669 #define TOTAL_PINS NUM_DIGITAL_PINS // 33
+
670 #define MAX_SERVOS NUM_DIGITAL_PINS
+
671 #define VERSION_BLINK_PIN PIN_LED1
+
672 #define IS_PIN_DIGITAL(p) ((p) != 14 && (p) != 15 && (p) != 31 && (p) != 32)
+
673 #define IS_PIN_ANALOG(p) ((p) == 0 || ((p) >= 3 && (p) <= 13))
+
674 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
675 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
676 #define IS_PIN_I2C(p) ((p) == 25 || (p) == 26)
+
677 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
678 #define PIN_TO_DIGITAL(p) (p)
+
679 #define PIN_TO_ANALOG(p) (p)
+
680 #define PIN_TO_PWM(p) (p)
+
681 #define PIN_TO_SERVO(p) (p)
+
682 
+
683 
+
684 // Pic32 chipKIT UNO32
+
685 #elif defined(_BOARD_UNO_) && defined(__PIC32) // NOTE: no _BOARD_UNO32_ to use
+
686 #define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 12
+
687 #define TOTAL_PINS NUM_DIGITAL_PINS // 47 All pins can be digital
+
688 #define MAX_SERVOS NUM_DIGITAL_PINS // All pins can be servo with SoftPWMservo
+
689 #define VERSION_BLINK_PIN PIN_LED1
+
690 #define IS_PIN_DIGITAL(p) ((p) >= 2)
+
691 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25)
+
692 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
693 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
694 #define IS_PIN_I2C(p) ((p) == 45 || (p) == 46)
+
695 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
696 #define PIN_TO_DIGITAL(p) (p)
+
697 #define PIN_TO_ANALOG(p) ((p) - 14)
+
698 #define PIN_TO_PWM(p) (p)
+
699 #define PIN_TO_SERVO(p) (p)
+
700 
+
701 
+
702 // Pic32 chipKIT DP32
+
703 #elif defined(_BOARD_DP32_)
+
704 #define TOTAL_ANALOG_PINS 15 // Really only has 9, but have to override because of mistake in variant file
+
705 #define TOTAL_PINS NUM_DIGITAL_PINS // 19
+
706 #define MAX_SERVOS NUM_DIGITAL_PINS // All pins can be servo with SoftPWMservo
+
707 #define VERSION_BLINK_PIN PIN_LED1
+
708 #define IS_PIN_DIGITAL(p) (((p) != 1) && ((p) != 4) && ((p) != 5) && ((p) != 15) && ((p) != 16))
+
709 #define IS_PIN_ANALOG(p) ((p) >= 6 && (p) <= 14)
+
710 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
711 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
712 #define IS_PIN_I2C(p) ((p) == 2 || (p) == 3)
+
713 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
714 #define PIN_TO_DIGITAL(p) (p)
+
715 #define PIN_TO_ANALOG(p) (p)
+
716 #define PIN_TO_PWM(p) (p)
+
717 #define PIN_TO_SERVO(p) (p)
+
718 
+
719 
+
720 // Pic32 chipKIT uC32
+
721 #elif defined(_BOARD_UC32_)
+
722 #define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 12
+
723 #define TOTAL_PINS NUM_DIGITAL_PINS // 47 All pins can be digital
+
724 #define MAX_SERVOS NUM_DIGITAL_PINS // All pins can be servo with SoftPWMservo
+
725 #define VERSION_BLINK_PIN PIN_LED1
+
726 #define IS_PIN_DIGITAL(p) ((p) >= 2)
+
727 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25)
+
728 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
729 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
730 #define IS_PIN_I2C(p) ((p) == 45 || (p) == 46)
+
731 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
732 #define PIN_TO_DIGITAL(p) (p)
+
733 #define PIN_TO_ANALOG(p) ((p) - 14)
+
734 #define PIN_TO_PWM(p) (p)
+
735 #define PIN_TO_SERVO(p) (p)
+
736 
+
737 
+
738 // Pic32 chipKIT WF32
+
739 #elif defined(_BOARD_WF32_)
+
740 #define TOTAL_ANALOG_PINS NUM_ANALOG_PINS
+
741 #define TOTAL_PINS NUM_DIGITAL_PINS
+
742 #define MAX_SERVOS NUM_DIGITAL_PINS
+
743 #define VERSION_BLINK_PIN PIN_LED1
+
744 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 49) // Accounts for SD and WiFi dedicated pins
+
745 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25)
+
746 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
747 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
748 #define IS_PIN_I2C(p) ((p) == 34 || (p) == 35)
+
749 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
750 #define PIN_TO_DIGITAL(p) (p)
+
751 #define PIN_TO_ANALOG(p) ((p) - 14)
+
752 #define PIN_TO_PWM(p) (p)
+
753 #define PIN_TO_SERVO(p) (p)
+
754 
+
755 
+
756 // Pic32 chipKIT WiFire
+
757 #elif defined(_BOARD_WIFIRE_)
+
758 #define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 14
+
759 #define TOTAL_PINS NUM_DIGITAL_PINS // 71
+
760 #define MAX_SERVOS NUM_DIGITAL_PINS
+
761 #define VERSION_BLINK_PIN PIN_LED1
+
762 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 47) // Accounts for SD and WiFi dedicated pins
+
763 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25)
+
764 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
765 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
766 #define IS_PIN_I2C(p) ((p) == 34 || (p) == 35)
+
767 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
768 #define PIN_TO_DIGITAL(p) (p)
+
769 #define PIN_TO_ANALOG(p) ((p) <= 25 ? ((p) - 14) : (p) - 36)
+
770 #define PIN_TO_PWM(p) (p)
+
771 #define PIN_TO_SERVO(p) (p)
+
772 
+
773 
+
774 // Pic32 chipKIT MAX32
+
775 #elif defined(_BOARD_MEGA_) && defined(__PIC32) // NOTE: no _BOARD_MAX32_ to use
+
776 #define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 16
+
777 #define TOTAL_PINS NUM_DIGITAL_PINS // 87
+
778 #define MAX_SERVOS NUM_DIGITAL_PINS
+
779 #define VERSION_BLINK_PIN PIN_LED1
+
780 #define IS_PIN_DIGITAL(p) ((p) >= 2)
+
781 #define IS_PIN_ANALOG(p) ((p) >= 54 && (p) <= 69)
+
782 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
783 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
784 #define IS_PIN_I2C(p) ((p) == 34 || (p) == 35)
+
785 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
786 #define PIN_TO_DIGITAL(p) (p)
+
787 #define PIN_TO_ANALOG(p) ((p) - 54)
+
788 #define PIN_TO_PWM(p) (p)
+
789 #define PIN_TO_SERVO(p) (p)
+
790 
+
791 
+
792 // Pic32 chipKIT Pi
+
793 #elif defined(_BOARD_CHIPKIT_PI_)
+
794 #define TOTAL_ANALOG_PINS 16
+
795 #define TOTAL_PINS NUM_DIGITAL_PINS // 19
+
796 #define MAX_SERVOS NUM_DIGITAL_PINS
+
797 #define VERSION_BLINK_PIN PIN_LED1
+
798 #define IS_PIN_DIGITAL(p) (((p) >= 2) && ((p) <= 3) || (((p) >= 8) && ((p) <= 13)) || (((p) >= 14) && ((p) <= 17)))
+
799 #define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 17)
+
800 #define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
+
801 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
802 #define IS_PIN_I2C(p) ((p) == 16 || (p) == 17)
+
803 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
804 #define PIN_TO_DIGITAL(p) (p)
+
805 #define PIN_TO_ANALOG(p) ((p) <= 15 ? (p) - 14 : (p) - 12)
+
806 //#define PIN_TO_ANALOG(p) (((p) <= 16) ? ((p) - 14) : ((p) - 16))
+
807 #define PIN_TO_PWM(p) (p)
+
808 #define PIN_TO_SERVO(p) (p)
+
809 
+
810 // Pinoccio Scout
+
811 // Note: digital pins 9-16 are usable but not labeled on the board numerically.
+
812 // SS=9, MOSI=10, MISO=11, SCK=12, RX1=13, TX1=14, SCL=15, SDA=16
+
813 #elif defined(ARDUINO_PINOCCIO)
+
814 #define TOTAL_ANALOG_PINS 8
+
815 #define TOTAL_PINS NUM_DIGITAL_PINS // 32
+
816 #define VERSION_BLINK_PIN 23
+
817 #define PIN_SERIAL1_RX 13
+
818 #define PIN_SERIAL1_TX 14
+
819 #define IS_PIN_DIGITAL(p) (((p) >= 2) && ((p) <= 16)) || (((p) >= 24) && ((p) <= 31))
+
820 #define IS_PIN_ANALOG(p) ((p) >= 24 && (p) <= 31)
+
821 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
822 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
823 #define IS_PIN_I2C(p) ((p) == SCL || (p) == SDA)
+
824 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
825 #define IS_PIN_SERIAL(p) ((p) == 13 || (p) == 14)
+
826 #define PIN_TO_DIGITAL(p) (p)
+
827 #define PIN_TO_ANALOG(p) ((p) - 24)
+
828 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
829 #define PIN_TO_SERVO(p) ((p) - 2)
+
830 
+
831 // ESP8266
+
832 // note: boot mode GPIOs 0, 2 and 15 can be used as outputs, GPIOs 6-11 are in use for flash IO
+
833 #elif defined(ESP8266)
+
834 #define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS
+
835 #define TOTAL_PINS A0 + NUM_ANALOG_INPUTS
+
836 #define PIN_SERIAL_RX 3
+
837 #define PIN_SERIAL_TX 1
+
838 #define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 5) || ((p) >= 12 && (p) < A0))
+
839 #define IS_PIN_ANALOG(p) ((p) >= A0 && (p) < A0 + NUM_ANALOG_INPUTS)
+
840 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
841 #define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS)
+
842 #define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
+
843 #define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
+
844 #define IS_PIN_INTERRUPT(p) (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT)
+
845 #define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL_RX || (p) == PIN_SERIAL_TX)
+
846 #define PIN_TO_DIGITAL(p) (p)
+
847 #define PIN_TO_ANALOG(p) ((p) - A0)
+
848 #define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
+
849 #define PIN_TO_SERVO(p) (p)
+
850 #define DEFAULT_PWM_RESOLUTION 10
+
851 
+
852 // STM32 based boards
+
853 #elif defined(ARDUINO_ARCH_STM32)
+
854 #define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS
+
855 #define TOTAL_PINS NUM_DIGITAL_PINS
+
856 #define TOTAL_PORTS MAX_NB_PORT
+
857 #define VERSION_BLINK_PIN LED_BUILTIN
+
858 // PIN_SERIALY_RX/TX defined in the variant.h
+
859 #define IS_PIN_DIGITAL(p) (digitalPinIsValid(p) && !pinIsSerial(p))
+
860 #define IS_PIN_ANALOG(p) ((p >= A0) && (p < (A0 + TOTAL_ANALOG_PINS)) && !pinIsSerial(p))
+
861 #define IS_PIN_PWM(p) (IS_PIN_DIGITAL(p) && digitalPinHasPWM(p))
+
862 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
863 #define IS_PIN_I2C(p) (IS_PIN_DIGITAL(p) && digitalPinHasI2C(p))
+
864 #define IS_PIN_SPI(p) (IS_PIN_DIGITAL(p) && digitalPinHasSPI(p))
+
865 #define IS_PIN_INTERRUPT(p) (IS_PIN_DIGITAL(p) && (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT)))
+
866 #define IS_PIN_SERIAL(p) (digitalPinHasSerial(p) && !pinIsSerial(p))
+
867 #define PIN_TO_DIGITAL(p) (p)
+
868 #define PIN_TO_ANALOG(p) (p-A0)
+
869 #define PIN_TO_PWM(p) (p)
+
870 #define PIN_TO_SERVO(p) (p)
+
871 #define DEFAULT_PWM_RESOLUTION PWM_RESOLUTION
+
872 
+
873 // Adafruit Bluefruit nRF52 boards
+
874 #elif defined(ARDUINO_NRF52_ADAFRUIT)
+
875 #define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS
+
876 #define TOTAL_PINS NUM_DIGITAL_PINS
+
877 #define VERSION_BLINK_PIN LED_BUILTIN
+
878 #define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
+
879 #define IS_PIN_ANALOG(p) ((p) == PIN_A0 || (p) == PIN_A1 || (p) == PIN_A2 || (p) == PIN_A3 || \
+
880  (p) == PIN_A4 || (p) == PIN_A5 || (p) == PIN_A6 || (p) == PIN_A7)
+
881 #define IS_PIN_PWM(p) digitalPinHasPWM(p)
+
882 #define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
+
883 #define IS_PIN_I2C(p) ((p) == PIN_WIRE_SDA || (p) == PIN_WIRE_SCL)
+
884 #define IS_PIN_SPI(p) ((p) == SS || (p)== MOSI || (p) == MISO || (p == SCK))
+
885 #define PIN_TO_DIGITAL(p) (p)
+
886 #define PIN_TO_ANALOG(p) ( ((p) == PIN_A0) ? 0 : ((p) == PIN_A1) ? 1 : ((p) == PIN_A2) ? 2 : ((p) == PIN_A3) ? 3 : \
+
887  ((p) == PIN_A4) ? 4 : ((p) == PIN_A5) ? 5 : ((p) == PIN_A6) ? 6 : ((p) == PIN_A7) ? 7 : (127))
+
888 #define PIN_TO_PWM(p) (p)
+
889 #define PIN_TO_SERVO(p) (p)
+
890 
+
891 // anything else
+
892 #else
+
893 #error "Please edit Boards.h with a hardware abstraction for this board"
+
894 #endif
+
895 
+
896 // as long this is not defined for all boards:
+
897 #ifndef IS_PIN_SPI
+
898 #define IS_PIN_SPI(p) 0
+
899 #endif
+
900 
+
901 #ifndef IS_PIN_SERIAL
+
902 #define IS_PIN_SERIAL(p) 0
+
903 #endif
+
904 
+
905 #ifndef DEFAULT_PWM_RESOLUTION
+
906 #define DEFAULT_PWM_RESOLUTION 8
+
907 #endif
+
908 
+
909 /*==============================================================================
+
910  * readPort() - Read an 8 bit port
+
911  *============================================================================*/
+
912 
+
913 static inline unsigned char readPort(byte, byte) __attribute__((always_inline, unused));
+
914 static inline unsigned char readPort(byte port, byte bitmask)
+
915 {
+
916 #if defined(ARDUINO_PINOUT_OPTIMIZE)
+
917  if (port == 0) return (PIND & 0xFC) & bitmask; // ignore Rx/Tx 0/1
+
918  if (port == 1) return ((PINB & 0x3F) | ((PINC & 0x03) << 6)) & bitmask;
+
919  if (port == 2) return ((PINC & 0x3C) >> 2) & bitmask;
+
920  return 0;
+
921 #else
+
922  unsigned char out = 0, pin = port * 8;
+
923  if (IS_PIN_DIGITAL(pin + 0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(pin + 0))) out |= 0x01;
+
924  if (IS_PIN_DIGITAL(pin + 1) && (bitmask & 0x02) && digitalRead(PIN_TO_DIGITAL(pin + 1))) out |= 0x02;
+
925  if (IS_PIN_DIGITAL(pin + 2) && (bitmask & 0x04) && digitalRead(PIN_TO_DIGITAL(pin + 2))) out |= 0x04;
+
926  if (IS_PIN_DIGITAL(pin + 3) && (bitmask & 0x08) && digitalRead(PIN_TO_DIGITAL(pin + 3))) out |= 0x08;
+
927  if (IS_PIN_DIGITAL(pin + 4) && (bitmask & 0x10) && digitalRead(PIN_TO_DIGITAL(pin + 4))) out |= 0x10;
+
928  if (IS_PIN_DIGITAL(pin + 5) && (bitmask & 0x20) && digitalRead(PIN_TO_DIGITAL(pin + 5))) out |= 0x20;
+
929  if (IS_PIN_DIGITAL(pin + 6) && (bitmask & 0x40) && digitalRead(PIN_TO_DIGITAL(pin + 6))) out |= 0x40;
+
930  if (IS_PIN_DIGITAL(pin + 7) && (bitmask & 0x80) && digitalRead(PIN_TO_DIGITAL(pin + 7))) out |= 0x80;
+
931  return out;
+
932 #endif
+
933 }
+
934 
+
935 /*==============================================================================
+
936  * writePort() - Write an 8 bit port, only touch pins specified by a bitmask
+
937  *============================================================================*/
+
938 
+
939 static inline unsigned char writePort(byte, byte, byte) __attribute__((always_inline, unused));
+
940 static inline unsigned char writePort(byte port, byte value, byte bitmask)
+
941 {
+
942 #if defined(ARDUINO_PINOUT_OPTIMIZE)
+
943  if (port == 0) {
+
944  bitmask = bitmask & 0xFC; // do not touch Tx & Rx pins
+
945  byte valD = value & bitmask;
+
946  byte maskD = ~bitmask;
+
947  cli();
+
948  PORTD = (PORTD & maskD) | valD;
+
949  sei();
+
950  } else if (port == 1) {
+
951  byte valB = (value & bitmask) & 0x3F;
+
952  byte valC = (value & bitmask) >> 6;
+
953  byte maskB = ~(bitmask & 0x3F);
+
954  byte maskC = ~((bitmask & 0xC0) >> 6);
+
955  cli();
+
956  PORTB = (PORTB & maskB) | valB;
+
957  PORTC = (PORTC & maskC) | valC;
+
958  sei();
+
959  } else if (port == 2) {
+
960  bitmask = bitmask & 0x0F;
+
961  byte valC = (value & bitmask) << 2;
+
962  byte maskC = ~(bitmask << 2);
+
963  cli();
+
964  PORTC = (PORTC & maskC) | valC;
+
965  sei();
+
966  }
+
967  return 1;
+
968 #else
+
969  byte pin = port * 8;
+
970  if ((bitmask & 0x01)) digitalWrite(PIN_TO_DIGITAL(pin + 0), (value & 0x01));
+
971  if ((bitmask & 0x02)) digitalWrite(PIN_TO_DIGITAL(pin + 1), (value & 0x02));
+
972  if ((bitmask & 0x04)) digitalWrite(PIN_TO_DIGITAL(pin + 2), (value & 0x04));
+
973  if ((bitmask & 0x08)) digitalWrite(PIN_TO_DIGITAL(pin + 3), (value & 0x08));
+
974  if ((bitmask & 0x10)) digitalWrite(PIN_TO_DIGITAL(pin + 4), (value & 0x10));
+
975  if ((bitmask & 0x20)) digitalWrite(PIN_TO_DIGITAL(pin + 5), (value & 0x20));
+
976  if ((bitmask & 0x40)) digitalWrite(PIN_TO_DIGITAL(pin + 6), (value & 0x40));
+
977  if ((bitmask & 0x80)) digitalWrite(PIN_TO_DIGITAL(pin + 7), (value & 0x80));
+
978  return 1;
+
979 #endif
+
980 }
+
981 
+
982 
+
983 
+
984 
+
985 #ifndef TOTAL_PORTS
+
986 #define TOTAL_PORTS ((TOTAL_PINS + 7) / 8)
+
987 #endif
+
988 
+
989 
+
990 #endif /* Firmata_Boards_h */
+
+ + + + diff --git a/docs/html/_firmata_8h_source.html b/docs/html/_firmata_8h_source.html new file mode 100644 index 00000000..7556f5fe --- /dev/null +++ b/docs/html/_firmata_8h_source.html @@ -0,0 +1,284 @@ + + + + + + + +Firmata firmware for Arduino: Firmata.h Source File + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Firmata.h
+
+
+
1 /*
+
2  Firmata.h - Firmata library v2.5.8 - 2018-04-15
+
3  Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
+
4  Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved.
+
5 
+
6  This library is free software; you can redistribute it and/or
+
7  modify it under the terms of the GNU Lesser General Public
+
8  License as published by the Free Software Foundation; either
+
9  version 2.1 of the License, or (at your option) any later version.
+
10 
+
11  See file LICENSE.txt for further informations on licensing terms.
+
12 */
+
13 
+
14 #ifndef Firmata_h
+
15 #define Firmata_h
+
16 
+
17 #include "Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */
+
18 #include "FirmataDefines.h"
+
19 #include "FirmataMarshaller.h"
+
20 #include "FirmataParser.h"
+
21 
+
22 /* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for
+
23  * the protocol version and the firmware version.
+
24  */
+
25 #define FIRMATA_MAJOR_VERSION 2 // same as FIRMATA_PROTOCOL_MAJOR_VERSION
+
26 #define FIRMATA_MINOR_VERSION 5 // same as FIRMATA_PROTOCOL_MINOR_VERSION
+
27 #define FIRMATA_BUGFIX_VERSION 1 // same as FIRMATA_PROTOCOL_BUGFIX_VERSION
+
28 
+
29 // extended command set using sysex (0-127/0x00-0x7F)
+
30 /* 0x00-0x0F reserved for user-defined commands */
+
31 // these are DEPRECATED to make the naming more consistent
+
32 #define FIRMATA_STRING 0x71 // same as STRING_DATA
+
33 #define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST
+
34 #define SYSEX_I2C_REPLY 0x77 // same as I2C_REPLY
+
35 #define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL
+
36 
+
37 // pin modes
+
38 //#define INPUT 0x00 // defined in Arduino.h
+
39 //#define OUTPUT 0x01 // defined in Arduino.h
+
40 // DEPRECATED as of Firmata v2.5
+
41 #define ANALOG 0x02 // same as PIN_MODE_ANALOG
+
42 #define PWM 0x03 // same as PIN_MODE_PWM
+
43 #define SERVO 0x04 // same as PIN_MODE_SERVO
+
44 #define SHIFT 0x05 // same as PIN_MODE_SHIFT
+
45 #define I2C 0x06 // same as PIN_MODE_I2C
+
46 #define ONEWIRE 0x07 // same as PIN_MODE_ONEWIRE
+
47 #define STEPPER 0x08 // same as PIN_MODE_STEPPER
+
48 #define ENCODER 0x09 // same as PIN_MODE_ENCODER
+
49 #define IGNORE 0x7F // same as PIN_MODE_IGNORE
+
50 
+
51 namespace firmata {
+
52 
+
53 // TODO make it a subclass of a generic Serial/Stream base class
+ +
55 {
+
56  public:
+
57  typedef void (*callbackFunction)(uint8_t, int);
+
58  typedef void (*systemCallbackFunction)(void);
+
59  typedef void (*stringCallbackFunction)(char *);
+
60  typedef void (*sysexCallbackFunction)(uint8_t command, uint8_t argc, uint8_t *argv);
+
61 
+
62  FirmataClass();
+
63 
+
64  /* Arduino constructors */
+
65  void begin();
+
66  void begin(long);
+
67  void begin(Stream &s);
+
68 
+
69  /* querying functions */
+
70  void printVersion(void);
+
71  void blinkVersion(void);
+
72  void printFirmwareVersion(void);
+
73 
+
74  //void setFirmwareVersion(byte major, byte minor); // see macro below
+
75  void setFirmwareNameAndVersion(const char *name, byte major, byte minor);
+
76  void disableBlinkVersion();
+
77 
+
78  /* serial receive handling */
+
79  int available(void);
+
80  void processInput(void);
+
81  void parse(unsigned char value);
+
82  boolean isParsingMessage(void);
+
83 
+
84  /* serial send handling */
+
85  void sendAnalog(byte pin, int value);
+
86  void sendDigital(byte pin, int value); // TODO implement this
+
87  void sendDigitalPort(byte portNumber, int portData);
+
88  void sendString(const char *string);
+
89  void sendString(byte command, const char *string);
+
90  void sendSysex(byte command, byte bytec, byte *bytev);
+
91  void write(byte c);
+
92 
+
93  /* attach & detach callback functions to messages */
+
94  void attach(uint8_t command, callbackFunction newFunction);
+
95  void attach(uint8_t command, systemCallbackFunction newFunction);
+
96  void attach(uint8_t command, stringCallbackFunction newFunction);
+
97  void attach(uint8_t command, sysexCallbackFunction newFunction);
+
98  void detach(uint8_t command);
+
99 
+
100  /* access pin state and config */
+
101  byte getPinMode(byte pin);
+
102  void setPinMode(byte pin, byte config);
+
103 
+
104  /* access pin state */
+
105  int getPinState(byte pin);
+
106  void setPinState(byte pin, int state);
+
107 
+
108  /* utility methods */
+
109  void sendValueAsTwo7bitBytes(int value);
+
110  void startSysex(void);
+
111  void endSysex(void);
+
112 
+
113  private:
+
114  uint8_t parserBuffer[MAX_DATA_BYTES];
+
115  FirmataMarshaller marshaller;
+
116  FirmataParser parser;
+
117  Stream *FirmataStream;
+
118 
+
119  /* firmware name and version */
+
120  byte firmwareVersionCount;
+
121  byte *firmwareVersionVector;
+
122 
+
123  /* pin configuration */
+
124  byte pinConfig[TOTAL_PINS];
+
125  int pinState[TOTAL_PINS];
+
126 
+
127  boolean blinkVersionDisabled;
+
128 
+
129  /* private methods ------------------------------ */
+
130  void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval);
+
131  friend void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const;
+
132 
+
133  /* callback functions */
+
134  static callbackFunction currentAnalogCallback;
+
135  static callbackFunction currentDigitalCallback;
+
136  static callbackFunction currentPinModeCallback;
+
137  static callbackFunction currentPinValueCallback;
+
138  static callbackFunction currentReportAnalogCallback;
+
139  static callbackFunction currentReportDigitalCallback;
+
140  static stringCallbackFunction currentStringCallback;
+
141  static sysexCallbackFunction currentSysexCallback;
+
142  static systemCallbackFunction currentSystemResetCallback;
+
143 
+
144  /* static callbacks */
+
145  inline static void staticAnalogCallback (void *, uint8_t command, uint16_t value) { if ( currentAnalogCallback ) { currentAnalogCallback(command,(int)value); } }
+
146  inline static void staticDigitalCallback (void *, uint8_t command, uint16_t value) { if ( currentDigitalCallback ) { currentDigitalCallback(command, (int)value); } }
+
147  inline static void staticPinModeCallback (void *, uint8_t command, uint16_t value) { if ( currentPinModeCallback ) { currentPinModeCallback(command, (int)value); } }
+
148  inline static void staticPinValueCallback (void *, uint8_t command, uint16_t value) { if ( currentPinValueCallback ) { currentPinValueCallback(command, (int)value); } }
+
149  inline static void staticReportAnalogCallback (void *, uint8_t command, uint16_t value) { if ( currentReportAnalogCallback ) { currentReportAnalogCallback(command, (int)value); } }
+
150  inline static void staticReportDigitalCallback (void *, uint8_t command, uint16_t value) { if ( currentReportDigitalCallback ) { currentReportDigitalCallback(command, (int)value); } }
+
151  inline static void staticStringCallback (void *, const char * c_str) { if ( currentStringCallback ) { currentStringCallback((char *)c_str); } }
+
152  inline static void staticSysexCallback (void *, uint8_t command, size_t argc, uint8_t *argv) { if ( currentSysexCallback ) { currentSysexCallback(command, (uint8_t)argc, argv); } }
+
153  inline static void staticReportFirmwareCallback (void * context, size_t, size_t, const char *) { if ( context ) { ((FirmataClass *)context)->printFirmwareVersion(); } }
+
154  inline static void staticReportVersionCallback (void * context) { if ( context ) { ((FirmataClass *)context)->printVersion(); } }
+
155  inline static void staticSystemResetCallback (void *) { if ( currentSystemResetCallback ) { currentSystemResetCallback(); } }
+
156 };
+
157 
+
158 } // namespace firmata
+
159 
+
160 extern "C" {
+
161  // callback function types
+
162  typedef firmata::FirmataClass::callbackFunction callbackFunction;
+
163  typedef firmata::FirmataClass::systemCallbackFunction systemCallbackFunction;
+
164  typedef firmata::FirmataClass::stringCallbackFunction stringCallbackFunction;
+
165  typedef firmata::FirmataClass::sysexCallbackFunction sysexCallbackFunction;
+
166 }
+
167 
+
168 extern firmata::FirmataClass Firmata;
+
169 
+
170 /*==============================================================================
+
171  * MACROS
+
172  *============================================================================*/
+
173 
+
174 /* shortcut for setFirmwareNameAndVersion() that uses __FILE__ to set the
+
175  * firmware name. It needs to be a macro so that __FILE__ is included in the
+
176  * firmware source file rather than the library source file.
+
177  */
+
178 #define setFirmwareVersion(x, y) setFirmwareNameAndVersion(__FILE__, x, y)
+
179 
+
180 #endif /* Firmata_h */
+
+
void processInput(void)
Definition: Firmata.cpp:252
+
void setPinMode(byte pin, byte config)
Definition: Firmata.cpp:486
+
boolean isParsingMessage(void)
Definition: Firmata.cpp:272
+
void sendString(const char *string)
Definition: Firmata.cpp:363
+
void write(byte c)
Definition: Firmata.cpp:373
+
void printFirmwareVersion(void)
Definition: Firmata.cpp:187
+
void setPinState(byte pin, int state)
Definition: Firmata.cpp:509
+
int getPinState(byte pin)
Definition: Firmata.cpp:498
+
int available(void)
Definition: Firmata.cpp:244
+
byte getPinMode(byte pin)
Definition: Firmata.cpp:474
+
void printVersion(void)
Definition: Firmata.cpp:147
+
void setFirmwareNameAndVersion(const char *name, byte major, byte minor)
Definition: Firmata.cpp:201
+
void sendAnalog(byte pin, int value)
Definition: Firmata.cpp:289
+
Definition: FirmataParser.h:27
+
void endSysex(void)
Definition: Firmata.cpp:67
+
void blinkVersion(void)
Definition: Firmata.cpp:159
+
void sendSysex(byte command, byte bytec, byte *bytev)
Definition: Firmata.cpp:342
+
void detach(uint8_t command)
Definition: Firmata.cpp:452
+
FirmataClass()
Definition: Firmata.cpp:80
+
void disableBlinkVersion()
Definition: Firmata.cpp:177
+
void parse(unsigned char value)
Definition: Firmata.cpp:264
+
Definition: Firmata.h:54
+
void sendDigitalPort(byte portNumber, int portData)
Definition: Firmata.cpp:330
+
void startSysex(void)
Definition: Firmata.cpp:59
+
Definition: FirmataMarshaller.h:29
+
void sendValueAsTwo7bitBytes(int value)
Definition: Firmata.cpp:51
+
void begin()
Definition: Firmata.cpp:109
+ + + + diff --git a/docs/html/_firmata_constants_8h_source.html b/docs/html/_firmata_constants_8h_source.html new file mode 100644 index 00000000..a5f23ead --- /dev/null +++ b/docs/html/_firmata_constants_8h_source.html @@ -0,0 +1,174 @@ + + + + + + + +Firmata firmware for Arduino: FirmataConstants.h Source File + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
FirmataConstants.h
+
+
+
1 /*
+
2  FirmataConstants.h
+
3  Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
+
4  Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved.
+
5 
+
6  This library is free software; you can redistribute it and/or
+
7  modify it under the terms of the GNU Lesser General Public
+
8  License as published by the Free Software Foundation; either
+
9  version 2.1 of the License, or (at your option) any later version.
+
10 
+
11  See file LICENSE.txt for further informations on licensing terms.
+
12 */
+
13 
+
14 #ifndef FirmataConstants_h
+
15 #define FirmataConstants_h
+
16 
+
17 namespace firmata {
+
18 /* Version numbers for the Firmata library.
+
19  * The firmware version will not always equal the protocol version going forward.
+
20  * Query using the REPORT_FIRMWARE message.
+
21  */
+
22 static const int FIRMWARE_MAJOR_VERSION = 2;
+
23 static const int FIRMWARE_MINOR_VERSION = 5;
+
24 static const int FIRMWARE_BUGFIX_VERSION = 7;
+
25 
+
26 /* Version numbers for the protocol. The protocol is still changing, so these
+
27  * version numbers are important.
+
28  * Query using the REPORT_VERSION message.
+
29  */
+
30 static const int PROTOCOL_MAJOR_VERSION = 2; // for non-compatible changes
+
31 static const int PROTOCOL_MINOR_VERSION = 5; // for backwards compatible changes
+
32 static const int PROTOCOL_BUGFIX_VERSION = 1; // for bugfix releases
+
33 
+
34 static const int MAX_DATA_BYTES = 64; // max number of data bytes in incoming messages
+
35 
+
36 // message command bytes (128-255/0x80-0xFF)
+
37 
+
38 static const int DIGITAL_MESSAGE = 0x90; // send data for a digital port (collection of 8 pins)
+
39 static const int ANALOG_MESSAGE = 0xE0; // send data for an analog pin (or PWM)
+
40 static const int REPORT_ANALOG = 0xC0; // enable analog input by pin #
+
41 static const int REPORT_DIGITAL = 0xD0; // enable digital input by port pair
+
42 //
+
43 static const int SET_PIN_MODE = 0xF4; // set a pin to INPUT/OUTPUT/PWM/etc
+
44 static const int SET_DIGITAL_PIN_VALUE = 0xF5; // set value of an individual digital pin
+
45 //
+
46 static const int REPORT_VERSION = 0xF9; // report protocol version
+
47 static const int SYSTEM_RESET = 0xFF; // reset from MIDI
+
48 //
+
49 static const int START_SYSEX = 0xF0; // start a MIDI Sysex message
+
50 static const int END_SYSEX = 0xF7; // end a MIDI Sysex message
+
51 
+
52 // extended command set using sysex (0-127/0x00-0x7F)
+
53 /* 0x00-0x0F reserved for user-defined commands */
+
54 
+
55 static const int SERIAL_DATA = 0x60; // communicate with serial devices, including other boards
+
56 static const int ENCODER_DATA = 0x61; // reply with encoders current positions
+
57 static const int SERVO_CONFIG = 0x70; // set max angle, minPulse, maxPulse, freq
+
58 static const int STRING_DATA = 0x71; // a string message with 14-bits per char
+
59 static const int STEPPER_DATA = 0x72; // control a stepper motor
+
60 static const int ONEWIRE_DATA = 0x73; // send an OneWire read/write/reset/select/skip/search request
+
61 static const int SHIFT_DATA = 0x75; // a bitstream to/from a shift register
+
62 static const int I2C_REQUEST = 0x76; // send an I2C read/write request
+
63 static const int I2C_REPLY = 0x77; // a reply to an I2C read request
+
64 static const int I2C_CONFIG = 0x78; // config I2C settings such as delay times and power pins
+
65 static const int REPORT_FIRMWARE = 0x79; // report name and version of the firmware
+
66 static const int EXTENDED_ANALOG = 0x6F; // analog write (PWM, Servo, etc) to any pin
+
67 static const int PIN_STATE_QUERY = 0x6D; // ask for a pin's current mode and value
+
68 static const int PIN_STATE_RESPONSE = 0x6E; // reply with pin's current mode and value
+
69 static const int CAPABILITY_QUERY = 0x6B; // ask for supported modes and resolution of all pins
+
70 static const int CAPABILITY_RESPONSE = 0x6C; // reply with supported modes and resolution
+
71 static const int ANALOG_MAPPING_QUERY = 0x69; // ask for mapping of analog to pin numbers
+
72 static const int ANALOG_MAPPING_RESPONSE = 0x6A; // reply with mapping info
+
73 static const int SAMPLING_INTERVAL = 0x7A; // set the poll rate of the main loop
+
74 static const int SCHEDULER_DATA = 0x7B; // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler
+
75 static const int SYSEX_NON_REALTIME = 0x7E; // MIDI Reserved for non-realtime messages
+
76 static const int SYSEX_REALTIME = 0x7F; // MIDI Reserved for realtime messages
+
77 
+
78 // pin modes
+
79 static const int PIN_MODE_INPUT = 0x00; // same as INPUT defined in Arduino.h
+
80 static const int PIN_MODE_OUTPUT = 0x01; // same as OUTPUT defined in Arduino.h
+
81 static const int PIN_MODE_ANALOG = 0x02; // analog pin in analogInput mode
+
82 static const int PIN_MODE_PWM = 0x03; // digital pin in PWM output mode
+
83 static const int PIN_MODE_SERVO = 0x04; // digital pin in Servo output mode
+
84 static const int PIN_MODE_SHIFT = 0x05; // shiftIn/shiftOut mode
+
85 static const int PIN_MODE_I2C = 0x06; // pin included in I2C setup
+
86 static const int PIN_MODE_ONEWIRE = 0x07; // pin configured for 1-wire
+
87 static const int PIN_MODE_STEPPER = 0x08; // pin configured for stepper motor
+
88 static const int PIN_MODE_ENCODER = 0x09; // pin configured for rotary encoders
+
89 static const int PIN_MODE_SERIAL = 0x0A; // pin configured for serial communication
+
90 static const int PIN_MODE_PULLUP = 0x0B; // enable internal pull-up resistor for pin
+
91 static const int PIN_MODE_IGNORE = 0x7F; // pin configured to be ignored by digitalWrite and capabilityResponse
+
92 
+
93 static const int TOTAL_PIN_MODES = 13;
+
94 
+
95 } // namespace firmata
+
96 
+
97 #endif // FirmataConstants_h
+
+ + + + diff --git a/docs/html/_firmata_defines_8h_source.html b/docs/html/_firmata_defines_8h_source.html new file mode 100644 index 00000000..5dd9dc98 --- /dev/null +++ b/docs/html/_firmata_defines_8h_source.html @@ -0,0 +1,360 @@ + + + + + + + +Firmata firmware for Arduino: FirmataDefines.h Source File + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
FirmataDefines.h
+
+
+
1 /*
+
2  FirmataDefines.h
+
3  Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
+
4  Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved.
+
5 
+
6  This library is free software; you can redistribute it and/or
+
7  modify it under the terms of the GNU Lesser General Public
+
8  License as published by the Free Software Foundation; either
+
9  version 2.1 of the License, or (at your option) any later version.
+
10 
+
11  See file LICENSE.txt for further informations on licensing terms.
+
12 */
+
13 
+
14 #ifndef FirmataDefines_h
+
15 #define FirmataDefines_h
+
16 
+
17 #include "FirmataConstants.h"
+
18 
+
19 /* Version numbers for the Firmata library.
+
20  * The firmware version will not always equal the protocol version going forward.
+
21  * Query using the REPORT_FIRMWARE message.
+
22  */
+
23 #define FIRMATA_FIRMWARE_MAJOR_VERSION firmata::FIRMWARE_MAJOR_VERSION
+
24 #define FIRMATA_FIRMWARE_MINOR_VERSION firmata::FIRMWARE_MINOR_VERSION
+
25 #define FIRMATA_FIRMWARE_BUGFIX_VERSION firmata::FIRMWARE_BUGFIX_VERSION
+
26 
+
27 /* Version numbers for the protocol. The protocol is still changing, so these
+
28  * version numbers are important.
+
29  * Query using the REPORT_VERSION message.
+
30  */
+
31 #define FIRMATA_PROTOCOL_MAJOR_VERSION firmata::PROTOCOL_MAJOR_VERSION // for non-compatible changes
+
32 #define FIRMATA_PROTOCOL_MINOR_VERSION firmata::PROTOCOL_MINOR_VERSION // for backwards compatible changes
+
33 #define FIRMATA_PROTOCOL_BUGFIX_VERSION firmata::PROTOCOL_BUGFIX_VERSION // for bugfix releases
+
34 
+
35 #ifdef MAX_DATA_BYTES
+
36 #undef MAX_DATA_BYTES
+
37 #endif
+
38 #define MAX_DATA_BYTES firmata::MAX_DATA_BYTES // max number of data bytes in incoming messages
+
39 
+
40 // message command bytes (128-255/0x80-0xFF)
+
41 
+
42 #ifdef DIGITAL_MESSAGE
+
43 #undef DIGITAL_MESSAGE
+
44 #endif
+
45 #define DIGITAL_MESSAGE firmata::DIGITAL_MESSAGE // send data for a digital port (collection of 8 pins)
+
46 
+
47 #ifdef ANALOG_MESSAGE
+
48 #undef ANALOG_MESSAGE
+
49 #endif
+
50 #define ANALOG_MESSAGE firmata::ANALOG_MESSAGE // send data for an analog pin (or PWM)
+
51 
+
52 #ifdef REPORT_ANALOG
+
53 #undef REPORT_ANALOG
+
54 #endif
+
55 #define REPORT_ANALOG firmata::REPORT_ANALOG // enable analog input by pin #
+
56 
+
57 #ifdef REPORT_DIGITAL
+
58 #undef REPORT_DIGITAL
+
59 #endif
+
60 #define REPORT_DIGITAL firmata::REPORT_DIGITAL // enable digital input by port pair
+
61 
+
62 //
+
63 
+
64 #ifdef SET_PIN_MODE
+
65 #undef SET_PIN_MODE
+
66 #endif
+
67 #define SET_PIN_MODE firmata::SET_PIN_MODE // set a pin to INPUT/OUTPUT/PWM/etc
+
68 
+
69 #ifdef SET_DIGITAL_PIN_VALUE
+
70 #undef SET_DIGITAL_PIN_VALUE
+
71 #endif
+
72 #define SET_DIGITAL_PIN_VALUE firmata::SET_DIGITAL_PIN_VALUE // set value of an individual digital pin
+
73 
+
74 //
+
75 
+
76 #ifdef REPORT_VERSION
+
77 #undef REPORT_VERSION
+
78 #endif
+
79 #define REPORT_VERSION firmata::REPORT_VERSION // report protocol version
+
80 
+
81 #ifdef SYSTEM_RESET
+
82 #undef SYSTEM_RESET
+
83 #endif
+
84 #define SYSTEM_RESET firmata::SYSTEM_RESET // reset from MIDI
+
85 
+
86 //
+
87 
+
88 #ifdef START_SYSEX
+
89 #undef START_SYSEX
+
90 #endif
+
91 #define START_SYSEX firmata::START_SYSEX // start a MIDI Sysex message
+
92 
+
93 #ifdef END_SYSEX
+
94 #undef END_SYSEX
+
95 #endif
+
96 #define END_SYSEX firmata::END_SYSEX // end a MIDI Sysex message
+
97 
+
98 // extended command set using sysex (0-127/0x00-0x7F)
+
99 /* 0x00-0x0F reserved for user-defined commands */
+
100 
+
101 #ifdef SERIAL_MESSAGE
+
102 #undef SERIAL_MESSAGE
+
103 #endif
+
104 #define SERIAL_MESSAGE firmata::SERIAL_DATA // communicate with serial devices, including other boards
+
105 
+
106 #ifdef ENCODER_DATA
+
107 #undef ENCODER_DATA
+
108 #endif
+
109 #define ENCODER_DATA firmata::ENCODER_DATA // reply with encoders current positions
+
110 
+
111 #ifdef SERVO_CONFIG
+
112 #undef SERVO_CONFIG
+
113 #endif
+
114 #define SERVO_CONFIG firmata::SERVO_CONFIG // set max angle, minPulse, maxPulse, freq
+
115 
+
116 #ifdef STRING_DATA
+
117 #undef STRING_DATA
+
118 #endif
+
119 #define STRING_DATA firmata::STRING_DATA // a string message with 14-bits per char
+
120 
+
121 #ifdef STEPPER_DATA
+
122 #undef STEPPER_DATA
+
123 #endif
+
124 #define STEPPER_DATA firmata::STEPPER_DATA // control a stepper motor
+
125 
+
126 #ifdef ONEWIRE_DATA
+
127 #undef ONEWIRE_DATA
+
128 #endif
+
129 #define ONEWIRE_DATA firmata::ONEWIRE_DATA // send an OneWire read/write/reset/select/skip/search request
+
130 
+
131 #ifdef SHIFT_DATA
+
132 #undef SHIFT_DATA
+
133 #endif
+
134 #define SHIFT_DATA firmata::SHIFT_DATA // a bitstream to/from a shift register
+
135 
+
136 #ifdef I2C_REQUEST
+
137 #undef I2C_REQUEST
+
138 #endif
+
139 #define I2C_REQUEST firmata::I2C_REQUEST // send an I2C read/write request
+
140 
+
141 #ifdef I2C_REPLY
+
142 #undef I2C_REPLY
+
143 #endif
+
144 #define I2C_REPLY firmata::I2C_REPLY // a reply to an I2C read request
+
145 
+
146 #ifdef I2C_CONFIG
+
147 #undef I2C_CONFIG
+
148 #endif
+
149 #define I2C_CONFIG firmata::I2C_CONFIG // config I2C settings such as delay times and power pins
+
150 
+
151 #ifdef REPORT_FIRMWARE
+
152 #undef REPORT_FIRMWARE
+
153 #endif
+
154 #define REPORT_FIRMWARE firmata::REPORT_FIRMWARE // report name and version of the firmware
+
155 
+
156 #ifdef EXTENDED_ANALOG
+
157 #undef EXTENDED_ANALOG
+
158 #endif
+
159 #define EXTENDED_ANALOG firmata::EXTENDED_ANALOG // analog write (PWM, Servo, etc) to any pin
+
160 
+
161 #ifdef PIN_STATE_QUERY
+
162 #undef PIN_STATE_QUERY
+
163 #endif
+
164 #define PIN_STATE_QUERY firmata::PIN_STATE_QUERY // ask for a pin's current mode and value
+
165 
+
166 #ifdef PIN_STATE_RESPONSE
+
167 #undef PIN_STATE_RESPONSE
+
168 #endif
+
169 #define PIN_STATE_RESPONSE firmata::PIN_STATE_RESPONSE // reply with pin's current mode and value
+
170 
+
171 #ifdef CAPABILITY_QUERY
+
172 #undef CAPABILITY_QUERY
+
173 #endif
+
174 #define CAPABILITY_QUERY firmata::CAPABILITY_QUERY // ask for supported modes and resolution of all pins
+
175 
+
176 #ifdef CAPABILITY_RESPONSE
+
177 #undef CAPABILITY_RESPONSE
+
178 #endif
+
179 #define CAPABILITY_RESPONSE firmata::CAPABILITY_RESPONSE // reply with supported modes and resolution
+
180 
+
181 #ifdef ANALOG_MAPPING_QUERY
+
182 #undef ANALOG_MAPPING_QUERY
+
183 #endif
+
184 #define ANALOG_MAPPING_QUERY firmata::ANALOG_MAPPING_QUERY // ask for mapping of analog to pin numbers
+
185 
+
186 #ifdef ANALOG_MAPPING_RESPONSE
+
187 #undef ANALOG_MAPPING_RESPONSE
+
188 #endif
+
189 #define ANALOG_MAPPING_RESPONSE firmata::ANALOG_MAPPING_RESPONSE // reply with mapping info
+
190 
+
191 #ifdef SAMPLING_INTERVAL
+
192 #undef SAMPLING_INTERVAL
+
193 #endif
+
194 #define SAMPLING_INTERVAL firmata::SAMPLING_INTERVAL // set the poll rate of the main loop
+
195 
+
196 #ifdef SCHEDULER_DATA
+
197 #undef SCHEDULER_DATA
+
198 #endif
+
199 #define SCHEDULER_DATA firmata::SCHEDULER_DATA // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler
+
200 
+
201 #ifdef SYSEX_NON_REALTIME
+
202 #undef SYSEX_NON_REALTIME
+
203 #endif
+
204 #define SYSEX_NON_REALTIME firmata::SYSEX_NON_REALTIME // MIDI Reserved for non-realtime messages
+
205 
+
206 #ifdef SYSEX_REALTIME
+
207 #undef SYSEX_REALTIME
+
208 #endif
+
209 #define SYSEX_REALTIME firmata::SYSEX_REALTIME // MIDI Reserved for realtime messages
+
210 
+
211 // pin modes
+
212 
+
213 #ifdef PIN_MODE_INPUT
+
214 #undef PIN_MODE_INPUT
+
215 #endif
+
216 #define PIN_MODE_INPUT firmata::PIN_MODE_INPUT // same as INPUT defined in Arduino.h
+
217 
+
218 #ifdef PIN_MODE_OUTPUT
+
219 #undef PIN_MODE_OUTPUT
+
220 #endif
+
221 #define PIN_MODE_OUTPUT firmata::PIN_MODE_OUTPUT // same as OUTPUT defined in Arduino.h
+
222 
+
223 #ifdef PIN_MODE_ANALOG
+
224 #undef PIN_MODE_ANALOG
+
225 #endif
+
226 #define PIN_MODE_ANALOG firmata::PIN_MODE_ANALOG // analog pin in analogInput mode
+
227 
+
228 #ifdef PIN_MODE_PWM
+
229 #undef PIN_MODE_PWM
+
230 #endif
+
231 #define PIN_MODE_PWM firmata::PIN_MODE_PWM // digital pin in PWM output mode
+
232 
+
233 #ifdef PIN_MODE_SERVO
+
234 #undef PIN_MODE_SERVO
+
235 #endif
+
236 #define PIN_MODE_SERVO firmata::PIN_MODE_SERVO // digital pin in Servo output mode
+
237 
+
238 #ifdef PIN_MODE_SHIFT
+
239 #undef PIN_MODE_SHIFT
+
240 #endif
+
241 #define PIN_MODE_SHIFT firmata::PIN_MODE_SHIFT // shiftIn/shiftOut mode
+
242 
+
243 #ifdef PIN_MODE_I2C
+
244 #undef PIN_MODE_I2C
+
245 #endif
+
246 #define PIN_MODE_I2C firmata::PIN_MODE_I2C // pin included in I2C setup
+
247 
+
248 #ifdef PIN_MODE_ONEWIRE
+
249 #undef PIN_MODE_ONEWIRE
+
250 #endif
+
251 #define PIN_MODE_ONEWIRE firmata::PIN_MODE_ONEWIRE // pin configured for 1-wire
+
252 
+
253 #ifdef PIN_MODE_STEPPER
+
254 #undef PIN_MODE_STEPPER
+
255 #endif
+
256 #define PIN_MODE_STEPPER firmata::PIN_MODE_STEPPER // pin configured for stepper motor
+
257 
+
258 #ifdef PIN_MODE_ENCODER
+
259 #undef PIN_MODE_ENCODER
+
260 #endif
+
261 #define PIN_MODE_ENCODER firmata::PIN_MODE_ENCODER // pin configured for rotary encoders
+
262 
+
263 #ifdef PIN_MODE_SERIAL
+
264 #undef PIN_MODE_SERIAL
+
265 #endif
+
266 #define PIN_MODE_SERIAL firmata::PIN_MODE_SERIAL // pin configured for serial communication
+
267 
+
268 #ifdef PIN_MODE_PULLUP
+
269 #undef PIN_MODE_PULLUP
+
270 #endif
+
271 #define PIN_MODE_PULLUP firmata::PIN_MODE_PULLUP // enable internal pull-up resistor for pin
+
272 
+
273 #ifdef PIN_MODE_IGNORE
+
274 #undef PIN_MODE_IGNORE
+
275 #endif
+
276 #define PIN_MODE_IGNORE firmata::PIN_MODE_IGNORE // pin configured to be ignored by digitalWrite and capabilityResponse
+
277 
+
278 #ifdef TOTAL_PIN_MODES
+
279 #undef TOTAL_PIN_MODES
+
280 #endif
+
281 #define TOTAL_PIN_MODES firmata::TOTAL_PIN_MODES
+
282 
+
283 #endif // FirmataConstants_h
+
+ + + + diff --git a/docs/html/_firmata_marshaller_8h_source.html b/docs/html/_firmata_marshaller_8h_source.html new file mode 100644 index 00000000..e2b2b7be --- /dev/null +++ b/docs/html/_firmata_marshaller_8h_source.html @@ -0,0 +1,176 @@ + + + + + + + +Firmata firmware for Arduino: FirmataMarshaller.h Source File + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
FirmataMarshaller.h
+
+
+
1 /*
+
2  FirmataMarshaller.h
+
3  Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
+
4  Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved.
+
5 
+
6  This library is free software; you can redistribute it and/or
+
7  modify it under the terms of the GNU Lesser General Public
+
8  License as published by the Free Software Foundation; either
+
9  version 2.1 of the License, or (at your option) any later version.
+
10 
+
11  See file LICENSE.txt for further informations on licensing terms.
+
12 */
+
13 
+
14 #ifndef FirmataMarshaller_h
+
15 #define FirmataMarshaller_h
+
16 
+
17 #if defined(__cplusplus) && !defined(ARDUINO)
+
18  #include <cstddef>
+
19  #include <cstdint>
+
20 #else
+
21  #include <stddef.h>
+
22  #include <stdint.h>
+
23 #endif
+
24 
+
25 #include <Stream.h>
+
26 
+
27 namespace firmata {
+
28 
+ +
30 {
+
31  friend class FirmataClass;
+
32 
+
33  public:
+
34  /* constructors */
+ +
36 
+
37  /* public methods */
+
38  void begin(Stream &s);
+
39  void end();
+
40 
+
41  /* serial send handling */
+
42  void queryFirmwareVersion(void) const;
+
43  void queryVersion(void) const;
+
44  void reportAnalogDisable(uint8_t pin) const;
+
45  void reportAnalogEnable(uint8_t pin) const;
+
46  void reportDigitalPortDisable(uint8_t portNumber) const;
+
47  void reportDigitalPortEnable(uint8_t portNumber) const;
+
48  void sendAnalog(uint8_t pin, uint16_t value) const;
+
49  void sendAnalogMappingQuery(void) const;
+
50  void sendCapabilityQuery(void) const;
+
51  void sendDigital(uint8_t pin, uint8_t value) const;
+
52  void sendDigitalPort(uint8_t portNumber, uint16_t portData) const;
+
53  void sendFirmwareVersion(uint8_t major, uint8_t minor, size_t bytec, uint8_t *bytev) const;
+
54  void sendVersion(uint8_t major, uint8_t minor) const;
+
55  void sendPinMode(uint8_t pin, uint8_t config) const;
+
56  void sendPinStateQuery(uint8_t pin) const;
+
57  void sendString(const char *string) const;
+
58  void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) const;
+
59  void setSamplingInterval(uint16_t interval_ms) const;
+
60  void systemReset(void) const;
+
61 
+
62  private:
+
63  /* utility methods */
+
64  void reportAnalog(uint8_t pin, bool stream_enable) const;
+
65  void reportDigitalPort(uint8_t portNumber, bool stream_enable) const;
+
66  void sendExtendedAnalog(uint8_t pin, size_t bytec, uint8_t * bytev) const;
+
67  void encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const;
+
68 
+
69  Stream * FirmataStream;
+
70 };
+
71 
+
72 } // namespace firmata
+
73 
+
74 #endif /* FirmataMarshaller_h */
+
75 
+
+
void reportDigitalPortEnable(uint8_t portNumber) const
Definition: FirmataMarshaller.cpp:230
+
void queryFirmwareVersion(void) const
Definition: FirmataMarshaller.cpp:165
+
void reportDigitalPortDisable(uint8_t portNumber) const
Definition: FirmataMarshaller.cpp:217
+
FirmataMarshaller()
Definition: FirmataMarshaller.cpp:129
+
void sendAnalogMappingQuery(void) const
Definition: FirmataMarshaller.cpp:262
+
void sendString(const char *string) const
Definition: FirmataMarshaller.cpp:405
+
void reportAnalogDisable(uint8_t pin) const
Definition: FirmataMarshaller.cpp:191
+
void begin(Stream &s)
Definition: FirmataMarshaller.cpp:145
+
void sendCapabilityQuery(void) const
Definition: FirmataMarshaller.cpp:273
+
void systemReset(void) const
Definition: FirmataMarshaller.cpp:426
+
void reportAnalogEnable(uint8_t pin) const
Definition: FirmataMarshaller.cpp:204
+
void sendPinStateQuery(uint8_t pin) const
Definition: FirmataMarshaller.cpp:371
+
void end()
Definition: FirmataMarshaller.cpp:153
+
void sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) const
Definition: FirmataMarshaller.cpp:388
+
void sendFirmwareVersion(uint8_t major, uint8_t minor, size_t bytec, uint8_t *bytev) const
Definition: FirmataMarshaller.cpp:319
+
void sendDigital(uint8_t pin, uint8_t value) const
Definition: FirmataMarshaller.cpp:284
+
void queryVersion(void) const
Definition: FirmataMarshaller.cpp:177
+
void sendDigitalPort(uint8_t portNumber, uint16_t portData) const
Definition: FirmataMarshaller.cpp:302
+
Definition: Firmata.h:54
+
void sendVersion(uint8_t major, uint8_t minor) const
Definition: FirmataMarshaller.cpp:339
+
Definition: FirmataMarshaller.h:29
+
void sendAnalog(uint8_t pin, uint16_t value) const
Definition: FirmataMarshaller.cpp:245
+
void setSamplingInterval(uint16_t interval_ms) const
Definition: FirmataMarshaller.cpp:416
+
void sendPinMode(uint8_t pin, uint8_t config) const
Definition: FirmataMarshaller.cpp:355
+ + + + diff --git a/docs/html/_firmata_parser_8h_source.html b/docs/html/_firmata_parser_8h_source.html new file mode 100644 index 00000000..6db4f216 --- /dev/null +++ b/docs/html/_firmata_parser_8h_source.html @@ -0,0 +1,189 @@ + + + + + + + +Firmata firmware for Arduino: FirmataParser.h Source File + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
FirmataParser.h
+
+
+
1 /*
+
2  FirmataParser.h
+
3  Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
+
4  Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved.
+
5 
+
6  This library is free software; you can redistribute it and/or
+
7  modify it under the terms of the GNU Lesser General Public
+
8  License as published by the Free Software Foundation; either
+
9  version 2.1 of the License, or (at your option) any later version.
+
10 
+
11  See file LICENSE.txt for further informations on licensing terms.
+
12 */
+
13 
+
14 #ifndef FirmataParser_h
+
15 #define FirmataParser_h
+
16 
+
17 #if defined(__cplusplus) && !defined(ARDUINO)
+
18  #include <cstddef>
+
19  #include <cstdint>
+
20 #else
+
21  #include <stddef.h>
+
22  #include <stdint.h>
+
23 #endif
+
24 
+
25 namespace firmata {
+
26 
+ +
28 {
+
29  public:
+
30  /* callback function types */
+
31  typedef void (*callbackFunction)(void * context, uint8_t command, uint16_t value);
+
32  typedef void (*dataBufferOverflowCallbackFunction)(void * context);
+
33  typedef void (*stringCallbackFunction)(void * context, const char * c_str);
+
34  typedef void (*sysexCallbackFunction)(void * context, uint8_t command, size_t argc, uint8_t * argv);
+
35  typedef void (*systemCallbackFunction)(void * context);
+
36  typedef void (*versionCallbackFunction)(void * context, size_t sv_major, size_t sv_minor, const char * firmware);
+
37 
+
38  FirmataParser(uint8_t * dataBuffer = (uint8_t *)NULL, size_t dataBufferSize = 0);
+
39 
+
40  /* serial receive handling */
+
41  void parse(uint8_t value);
+
42  bool isParsingMessage(void) const;
+
43  int setDataBufferOfSize(uint8_t * dataBuffer, size_t dataBufferSize);
+
44 
+
45  /* attach & detach callback functions to messages */
+
46  void attach(uint8_t command, callbackFunction newFunction, void * context = NULL);
+
47  void attach(dataBufferOverflowCallbackFunction newFunction, void * context = NULL);
+
48  void attach(uint8_t command, stringCallbackFunction newFunction, void * context = NULL);
+
49  void attach(uint8_t command, sysexCallbackFunction newFunction, void * context = NULL);
+
50  void attach(uint8_t command, systemCallbackFunction newFunction, void * context = NULL);
+
51  void attach(uint8_t command, versionCallbackFunction newFunction, void * context = NULL);
+
52  void detach(uint8_t command);
+
53  void detach(dataBufferOverflowCallbackFunction);
+
54 
+
55  private:
+
56  /* input message handling */
+
57  bool allowBufferUpdate;
+
58  uint8_t * dataBuffer; // multi-byte data
+
59  size_t dataBufferSize;
+
60  uint8_t executeMultiByteCommand; // execute this after getting multi-byte data
+
61  uint8_t multiByteChannel; // channel data for multiByteCommands
+
62  size_t waitForData; // this flag says the next serial input will be data
+
63 
+
64  /* sysex */
+
65  bool parsingSysex;
+
66  size_t sysexBytesRead;
+
67 
+
68  /* callback context */
+
69  void * currentAnalogCallbackContext;
+
70  void * currentDigitalCallbackContext;
+
71  void * currentReportAnalogCallbackContext;
+
72  void * currentReportDigitalCallbackContext;
+
73  void * currentPinModeCallbackContext;
+
74  void * currentPinValueCallbackContext;
+
75  void * currentReportFirmwareCallbackContext;
+
76  void * currentReportVersionCallbackContext;
+
77  void * currentDataBufferOverflowCallbackContext;
+
78  void * currentStringCallbackContext;
+
79  void * currentSysexCallbackContext;
+
80  void * currentSystemResetCallbackContext;
+
81 
+
82  /* callback functions */
+
83  callbackFunction currentAnalogCallback;
+
84  callbackFunction currentDigitalCallback;
+
85  callbackFunction currentReportAnalogCallback;
+
86  callbackFunction currentReportDigitalCallback;
+
87  callbackFunction currentPinModeCallback;
+
88  callbackFunction currentPinValueCallback;
+
89  dataBufferOverflowCallbackFunction currentDataBufferOverflowCallback;
+
90  stringCallbackFunction currentStringCallback;
+
91  sysexCallbackFunction currentSysexCallback;
+
92  versionCallbackFunction currentReportFirmwareCallback;
+
93  systemCallbackFunction currentReportVersionCallback;
+
94  systemCallbackFunction currentSystemResetCallback;
+
95 
+
96  /* private methods ------------------------------ */
+
97  bool bufferDataAtPosition(const uint8_t data, const size_t pos);
+
98  size_t decodeByteStream(size_t bytec, uint8_t * bytev);
+
99  void processSysexMessage(void);
+
100  void systemReset(void);
+
101 };
+
102 
+
103 } // firmata
+
104 
+
105 #endif /* FirmataParser_h */
+
+
bool isParsingMessage(void) const
Definition: FirmataParser.cpp:176
+
FirmataParser(uint8_t *dataBuffer=(uint8_t *) NULL, size_t dataBufferSize=0)
Definition: FirmataParser.cpp:33
+
Definition: FirmataParser.h:27
+
void attach(uint8_t command, callbackFunction newFunction, void *context=NULL)
Definition: FirmataParser.cpp:216
+
void detach(uint8_t command)
Definition: FirmataParser.cpp:337
+
int setDataBufferOfSize(uint8_t *dataBuffer, size_t dataBufferSize)
Definition: FirmataParser.cpp:189
+
void parse(uint8_t value)
Definition: FirmataParser.cpp:81
+ + + + diff --git a/docs/html/annotated.html b/docs/html/annotated.html new file mode 100644 index 00000000..5a2b37a1 --- /dev/null +++ b/docs/html/annotated.html @@ -0,0 +1,85 @@ + + + + + + + +Firmata firmware for Arduino: Class List + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Class List
+
+
+
Here are the classes, structs, unions and interfaces with brief descriptions:
+
[detail level 12]
+ + + + +
 Nfirmata
 CFirmataClass
 CFirmataMarshaller
 CFirmataParser
+
+
+ + + + diff --git a/docs/html/bc_s.png b/docs/html/bc_s.png new file mode 100644 index 0000000000000000000000000000000000000000..224b29aa9847d5a4b3902efd602b7ddf7d33e6c2 GIT binary patch literal 676 zcmV;V0$crwP)y__>=_9%My z{n931IS})GlGUF8K#6VIbs%684A^L3@%PlP2>_sk`UWPq@f;rU*V%rPy_ekbhXT&s z(GN{DxFv}*vZp`F>S!r||M`I*nOwwKX+BC~3P5N3-)Y{65c;ywYiAh-1*hZcToLHK ztpl1xomJ+Yb}K(cfbJr2=GNOnT!UFA7Vy~fBz8?J>XHsbZoDad^8PxfSa0GDgENZS zuLCEqzb*xWX2CG*b&5IiO#NzrW*;`VC9455M`o1NBh+(k8~`XCEEoC1Ybwf;vr4K3 zg|EB<07?SOqHp9DhLpS&bzgo70I+ghB_#)K7H%AMU3v}xuyQq9&Bm~++VYhF09a+U zl7>n7Jjm$K#b*FONz~fj;I->Bf;ule1prFN9FovcDGBkpg>)O*-}eLnC{6oZHZ$o% zXKW$;0_{8hxHQ>l;_*HATI(`7t#^{$(zLe}h*mqwOc*nRY9=?Sx4OOeVIfI|0V(V2 zBrW#G7Ss9wvzr@>H*`r>zE z+e8bOBgqIgldUJlG(YUDviMB`9+DH8n-s9SXRLyJHO1!=wY^79WYZMTa(wiZ!zP66 zA~!21vmF3H2{ngD;+`6j#~6j;$*f*G_2ZD1E;9(yaw7d-QnSCpK(cR1zU3qU0000< KMNUMnLSTYoA~SLT literal 0 HcmV?d00001 diff --git a/docs/html/bdwn.png b/docs/html/bdwn.png new file mode 100644 index 0000000000000000000000000000000000000000..940a0b950443a0bb1b216ac03c45b8a16c955452 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)H!3HEvS)PKZC{Gv1kP61Pb5HX&C2wk~_T + + + + + + +Firmata firmware for Arduino: Class Index + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Class Index
+
+
+ + + + + + + + + + +
  f  
+
FirmataMarshaller (firmata)   FirmataParser (firmata)   
FirmataClass (firmata)   
+ +
+ + + + diff --git a/docs/html/classfirmata_1_1_firmata_class-members.html b/docs/html/classfirmata_1_1_firmata_class-members.html new file mode 100644 index 00000000..5663db31 --- /dev/null +++ b/docs/html/classfirmata_1_1_firmata_class-members.html @@ -0,0 +1,121 @@ + + + + + + + +Firmata firmware for Arduino: Member List + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
firmata::FirmataClass Member List
+
+
+ +

This is the complete list of members for firmata::FirmataClass, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
attach(uint8_t command, callbackFunction newFunction) (defined in firmata::FirmataClass)firmata::FirmataClass
attach(uint8_t command, systemCallbackFunction newFunction)firmata::FirmataClass
attach(uint8_t command, stringCallbackFunction newFunction)firmata::FirmataClass
attach(uint8_t command, sysexCallbackFunction newFunction)firmata::FirmataClass
available(void)firmata::FirmataClass
begin()firmata::FirmataClass
begin(long)firmata::FirmataClass
begin(Stream &s)firmata::FirmataClass
blinkVersion(void)firmata::FirmataClass
callbackFunction typedef (defined in firmata::FirmataClass)firmata::FirmataClass
detach(uint8_t command)firmata::FirmataClass
disableBlinkVersion()firmata::FirmataClass
endSysex(void)firmata::FirmataClass
FirmataClass()firmata::FirmataClass
FirmataMarshaller::encodeByteStream (defined in firmata::FirmataClass)firmata::FirmataClassfriend
getPinMode(byte pin)firmata::FirmataClass
getPinState(byte pin)firmata::FirmataClass
isParsingMessage(void)firmata::FirmataClass
parse(unsigned char value)firmata::FirmataClass
printFirmwareVersion(void)firmata::FirmataClass
printVersion(void)firmata::FirmataClass
processInput(void)firmata::FirmataClass
sendAnalog(byte pin, int value)firmata::FirmataClass
sendDigital(byte pin, int value) (defined in firmata::FirmataClass)firmata::FirmataClass
sendDigitalPort(byte portNumber, int portData)firmata::FirmataClass
sendString(const char *string)firmata::FirmataClass
sendString(byte command, const char *string)firmata::FirmataClass
sendSysex(byte command, byte bytec, byte *bytev)firmata::FirmataClass
sendValueAsTwo7bitBytes(int value)firmata::FirmataClass
setFirmwareNameAndVersion(const char *name, byte major, byte minor)firmata::FirmataClass
setPinMode(byte pin, byte config)firmata::FirmataClass
setPinState(byte pin, int state)firmata::FirmataClass
startSysex(void)firmata::FirmataClass
stringCallbackFunction typedef (defined in firmata::FirmataClass)firmata::FirmataClass
sysexCallbackFunction typedef (defined in firmata::FirmataClass)firmata::FirmataClass
systemCallbackFunction typedef (defined in firmata::FirmataClass)firmata::FirmataClass
write(byte c)firmata::FirmataClass
+ + + + diff --git a/docs/html/classfirmata_1_1_firmata_class.html b/docs/html/classfirmata_1_1_firmata_class.html new file mode 100644 index 00000000..6d0a5a55 --- /dev/null +++ b/docs/html/classfirmata_1_1_firmata_class.html @@ -0,0 +1,972 @@ + + + + + + + +Firmata firmware for Arduino: firmata::FirmataClass Class Reference + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
firmata::FirmataClass Class Reference
+
+
+ + + + + + + + + + +

+Public Types

+typedef void(* callbackFunction) (uint8_t, int)
 
+typedef void(* systemCallbackFunction) (void)
 
+typedef void(* stringCallbackFunction) (char *)
 
+typedef void(* sysexCallbackFunction) (uint8_t command, uint8_t argc, uint8_t *argv)
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

 FirmataClass ()
 
void begin ()
 
void begin (long)
 
void begin (Stream &s)
 
void printVersion (void)
 
void blinkVersion (void)
 
void printFirmwareVersion (void)
 
void setFirmwareNameAndVersion (const char *name, byte major, byte minor)
 
void disableBlinkVersion ()
 
int available (void)
 
void processInput (void)
 
void parse (unsigned char value)
 
boolean isParsingMessage (void)
 
void sendAnalog (byte pin, int value)
 
+void sendDigital (byte pin, int value)
 
void sendDigitalPort (byte portNumber, int portData)
 
void sendString (const char *string)
 
void sendString (byte command, const char *string)
 
void sendSysex (byte command, byte bytec, byte *bytev)
 
void write (byte c)
 
+void attach (uint8_t command, callbackFunction newFunction)
 
void attach (uint8_t command, systemCallbackFunction newFunction)
 
void attach (uint8_t command, stringCallbackFunction newFunction)
 
void attach (uint8_t command, sysexCallbackFunction newFunction)
 
void detach (uint8_t command)
 
byte getPinMode (byte pin)
 
void setPinMode (byte pin, byte config)
 
int getPinState (byte pin)
 
void setPinState (byte pin, int state)
 
void sendValueAsTwo7bitBytes (int value)
 
void startSysex (void)
 
void endSysex (void)
 
+ + + +

+Friends

+void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t *bytev, size_t max_bytes=0) const
 
+

Constructor & Destructor Documentation

+ +

◆ FirmataClass()

+ +
+
+ + + + + + + +
FirmataClass::FirmataClass ()
+
+

The Firmata class. An instance named "Firmata" is created automatically for the user.

+ +
+
+

Member Function Documentation

+ +

◆ attach() [1/3]

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::attach (uint8_t command,
stringCallbackFunction newFunction 
)
+
+

Attach a callback function for the STRING_DATA command.

Parameters
+ + + +
commandMust be set to STRING_DATA or it will be ignored.
newFunctionA reference to the string callback function to attach.
+
+
+ +
+
+ +

◆ attach() [2/3]

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::attach (uint8_t command,
sysexCallbackFunction newFunction 
)
+
+

Attach a generic sysex callback function to sysex command.

Parameters
+ + + +
commandThe ID of the command to attach a callback function to.
newFunctionA reference to the sysex callback function to attach.
+
+
+ +
+
+ +

◆ attach() [3/3]

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::attach (uint8_t command,
systemCallbackFunction newFunction 
)
+
+

Attach a callback function for the SYSTEM_RESET command.

Parameters
+ + + +
commandMust be set to SYSTEM_RESET or it will be ignored.
newFunctionA reference to the system reset callback function to attach.
+
+
+ +
+
+ +

◆ available()

+ +
+
+ + + + + + + + +
int FirmataClass::available (void )
+
+

A wrapper for Stream::available()

Returns
The number of bytes remaining in the input stream buffer.
+ +
+
+ +

◆ begin() [1/3]

+ +
+
+ + + + + + + + +
void FirmataClass::begin (void )
+
+

Initialize the default Serial transport at the default baud of 57600.

+ +
+
+ +

◆ begin() [2/3]

+ +
+
+ + + + + + + + +
void FirmataClass::begin (long speed)
+
+

Initialize the default Serial transport and override the default baud. Sends the protocol version to the host application followed by the firmware version and name. blinkVersion is also called. To skip the call to blinkVersion, call Firmata.disableBlinkVersion() before calling Firmata.begin(baud).

Parameters
+ + +
speedThe baud to use. 57600 baud is the default value.
+
+
+ +
+
+ +

◆ begin() [3/3]

+ +
+
+ + + + + + + + +
void FirmataClass::begin (Stream & s)
+
+

Reassign the Firmata stream transport.

Parameters
+ + +
sA reference to the Stream transport object. This can be any type of transport that implements the Stream interface. Some examples include Ethernet, WiFi and other UARTs on the board (Serial1, Serial2, etc).
+
+
+ +
+
+ +

◆ blinkVersion()

+ +
+
+ + + + + + + + +
void FirmataClass::blinkVersion (void )
+
+

Blink the Firmata protocol version to the onboard LEDs (if the board has an onboard LED). If VERSION_BLINK_PIN is not defined in Boards.h for a particular board, then this method does nothing. The first series of flashes indicates the firmware major version (2 flashes = 2). The second series of flashes indicates the firmware minor version (5 flashes = 5).

+ +
+
+ +

◆ detach()

+ +
+
+ + + + + + + + +
void FirmataClass::detach (uint8_t command)
+
+

Detach a callback function for a specified command (such as SYSTEM_RESET, STRING_DATA, ANALOG_MESSAGE, DIGITAL_MESSAGE, etc).

Parameters
+ + +
commandThe ID of the command to detatch the callback function from.
+
+
+ +
+
+ +

◆ disableBlinkVersion()

+ +
+
+ + + + + + + +
void FirmataClass::disableBlinkVersion ()
+
+

Provides a means to disable the version blink sequence on the onboard LED, trimming startup time by a couple of seconds. Call this before Firmata.begin(). It only applies when using the default Serial transport.

+ +
+
+ +

◆ endSysex()

+ +
+
+ + + + + + + + +
void FirmataClass::endSysex (void )
+
+

A helper method to write the end of a Sysex message transmission.

+ +
+
+ +

◆ getPinMode()

+ +
+
+ + + + + + + + +
byte FirmataClass::getPinMode (byte pin)
+
+
Parameters
+ + +
pinThe pin to get the configuration of.
+
+
+
Returns
The configuration of the specified pin.
+ +
+
+ +

◆ getPinState()

+ +
+
+ + + + + + + + +
int FirmataClass::getPinState (byte pin)
+
+
Parameters
+ + +
pinThe pin to get the state of.
+
+
+
Returns
The state of the specified pin.
+ +
+
+ +

◆ isParsingMessage()

+ +
+
+ + + + + + + + +
boolean FirmataClass::isParsingMessage (void )
+
+
Returns
Returns true if the parser is actively parsing data.
+ +
+
+ +

◆ parse()

+ +
+
+ + + + + + + + +
void FirmataClass::parse (unsigned char value)
+
+

Parse data from the input stream.

Parameters
+ + +
inputDataA single byte to be added to the parser.
+
+
+ +
+
+ +

◆ printFirmwareVersion()

+ +
+
+ + + + + + + + +
void FirmataClass::printFirmwareVersion (void )
+
+

Sends the firmware name and version to the Firmata host application. The major and minor version numbers are the first 2 bytes in the message. The following bytes are the characters of the firmware name.

+ +
+
+ +

◆ printVersion()

+ +
+
+ + + + + + + + +
void FirmataClass::printVersion (void )
+
+

Send the Firmata protocol version to the Firmata host application.

+ +
+
+ +

◆ processInput()

+ +
+
+ + + + + + + + +
void FirmataClass::processInput (void )
+
+

Read a single int from the input stream. If the value is not = -1, pass it on to parse(byte)

+ +
+
+ +

◆ sendAnalog()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::sendAnalog (byte pin,
int value 
)
+
+

Send an analog message to the Firmata host application. The range of pins is limited to [0..15] when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG message.

Parameters
+ + + +
pinThe analog pin to send the value of (limited to pins 0 - 15).
valueThe value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc). The maximum value is 14-bits (16384).
+
+
+ +
+
+ +

◆ sendDigitalPort()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::sendDigitalPort (byte portNumber,
int portData 
)
+
+

Send an 8-bit port in a single digital message (protocol v2 and later). Send 14-bits in a single digital message (protocol v1).

Parameters
+ + + +
portNumberThe port number to send. Note that this is not the same as a "port" on the physical microcontroller. Ports are defined in order per every 8 pins in ascending order of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc.
portDataThe value of the port. The value of each pin in the port is represented by a bit.
+
+
+ +
+
+ +

◆ sendString() [1/2]

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::sendString (byte command,
const char * string 
)
+
+

Send a string to the Firmata host application.

Parameters
+ + + +
commandMust be STRING_DATA
stringA pointer to the char string
+
+
+ +
+
+ +

◆ sendString() [2/2]

+ +
+
+ + + + + + + + +
void FirmataClass::sendString (const char * string)
+
+

Send a string to the Firmata host application.

Parameters
+ + +
stringA pointer to the char string
+
+
+ +
+
+ +

◆ sendSysex()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataClass::sendSysex (byte command,
byte bytec,
byte * bytev 
)
+
+

Send a sysex message where all values after the command byte are packet as 2 7-bit bytes (this is not always the case so this function is not always used to send sysex messages).

Parameters
+ + + + +
commandThe sysex command byte.
bytecThe number of data bytes in the message (excludes start, command and end bytes).
bytevA pointer to the array of data bytes to send in the message.
+
+
+ +
+
+ +

◆ sendValueAsTwo7bitBytes()

+ +
+
+ + + + + + + + +
void FirmataClass::sendValueAsTwo7bitBytes (int value)
+
+

Split a 16-bit byte into two 7-bit values and write each value.

Parameters
+ + +
valueThe 16-bit value to be split and written separately.
+
+
+ +
+
+ +

◆ setFirmwareNameAndVersion()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataClass::setFirmwareNameAndVersion (const char * name,
byte major,
byte minor 
)
+
+

Sets the name and version of the firmware. This is not the same version as the Firmata protocol (although at times the firmware version and protocol version may be the same number).

Parameters
+ + + + +
nameA pointer to the name char array
majorThe major version number
minorThe minor version number
+
+
+ +
+
+ +

◆ setPinMode()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::setPinMode (byte pin,
byte config 
)
+
+

Set the pin mode/configuration. The pin configuration (or mode) in Firmata represents the current function of the pin. Examples are digital input or output, analog input, pwm, i2c, serial (uart), etc.

Parameters
+ + + +
pinThe pin to configure.
configThe configuration value for the specified pin.
+
+
+ +
+
+ +

◆ setPinState()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataClass::setPinState (byte pin,
int state 
)
+
+

Set the pin state. The pin state of an output pin is the pin value. The state of an input pin is 0, unless the pin has it's internal pull up resistor enabled, then the value is 1.

Parameters
+ + + +
pinThe pin to set the state of
stateSet the state of the specified pin
+
+
+ +
+
+ +

◆ startSysex()

+ +
+
+ + + + + + + + +
void FirmataClass::startSysex (void )
+
+

A helper method to write the beginning of a Sysex message transmission.

+ +
+
+ +

◆ write()

+ +
+
+ + + + + + + + +
void FirmataClass::write (byte c)
+
+

A wrapper for Stream::available(). Write a single byte to the output stream.

Parameters
+ + +
cThe byte to be written.
+
+
+ +
+
+
The documentation for this class was generated from the following files: +
+ + + + diff --git a/docs/html/classfirmata_1_1_firmata_marshaller-members.html b/docs/html/classfirmata_1_1_firmata_marshaller-members.html new file mode 100644 index 00000000..7ffe8cae --- /dev/null +++ b/docs/html/classfirmata_1_1_firmata_marshaller-members.html @@ -0,0 +1,107 @@ + + + + + + + +Firmata firmware for Arduino: Member List + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
firmata::FirmataMarshaller Member List
+
+
+ +

This is the complete list of members for firmata::FirmataMarshaller, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + +
begin(Stream &s)firmata::FirmataMarshaller
end()firmata::FirmataMarshaller
FirmataClass (defined in firmata::FirmataMarshaller)firmata::FirmataMarshallerfriend
FirmataMarshaller()firmata::FirmataMarshaller
queryFirmwareVersion(void) constfirmata::FirmataMarshaller
queryVersion(void) constfirmata::FirmataMarshaller
reportAnalogDisable(uint8_t pin) constfirmata::FirmataMarshaller
reportAnalogEnable(uint8_t pin) constfirmata::FirmataMarshaller
reportDigitalPortDisable(uint8_t portNumber) constfirmata::FirmataMarshaller
reportDigitalPortEnable(uint8_t portNumber) constfirmata::FirmataMarshaller
sendAnalog(uint8_t pin, uint16_t value) constfirmata::FirmataMarshaller
sendAnalogMappingQuery(void) constfirmata::FirmataMarshaller
sendCapabilityQuery(void) constfirmata::FirmataMarshaller
sendDigital(uint8_t pin, uint8_t value) constfirmata::FirmataMarshaller
sendDigitalPort(uint8_t portNumber, uint16_t portData) constfirmata::FirmataMarshaller
sendFirmwareVersion(uint8_t major, uint8_t minor, size_t bytec, uint8_t *bytev) constfirmata::FirmataMarshaller
sendPinMode(uint8_t pin, uint8_t config) constfirmata::FirmataMarshaller
sendPinStateQuery(uint8_t pin) constfirmata::FirmataMarshaller
sendString(const char *string) constfirmata::FirmataMarshaller
sendSysex(uint8_t command, size_t bytec, uint8_t *bytev) constfirmata::FirmataMarshaller
sendVersion(uint8_t major, uint8_t minor) constfirmata::FirmataMarshaller
setSamplingInterval(uint16_t interval_ms) constfirmata::FirmataMarshaller
systemReset(void) constfirmata::FirmataMarshaller
+ + + + diff --git a/docs/html/classfirmata_1_1_firmata_marshaller.html b/docs/html/classfirmata_1_1_firmata_marshaller.html new file mode 100644 index 00000000..7eb6ec8e --- /dev/null +++ b/docs/html/classfirmata_1_1_firmata_marshaller.html @@ -0,0 +1,738 @@ + + + + + + + +Firmata firmware for Arduino: firmata::FirmataMarshaller Class Reference + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
firmata::FirmataMarshaller Class Reference
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

 FirmataMarshaller ()
 
void begin (Stream &s)
 
void end ()
 
void queryFirmwareVersion (void) const
 
void queryVersion (void) const
 
void reportAnalogDisable (uint8_t pin) const
 
void reportAnalogEnable (uint8_t pin) const
 
void reportDigitalPortDisable (uint8_t portNumber) const
 
void reportDigitalPortEnable (uint8_t portNumber) const
 
void sendAnalog (uint8_t pin, uint16_t value) const
 
void sendAnalogMappingQuery (void) const
 
void sendCapabilityQuery (void) const
 
void sendDigital (uint8_t pin, uint8_t value) const
 
void sendDigitalPort (uint8_t portNumber, uint16_t portData) const
 
void sendFirmwareVersion (uint8_t major, uint8_t minor, size_t bytec, uint8_t *bytev) const
 
void sendVersion (uint8_t major, uint8_t minor) const
 
void sendPinMode (uint8_t pin, uint8_t config) const
 
void sendPinStateQuery (uint8_t pin) const
 
void sendString (const char *string) const
 
void sendSysex (uint8_t command, size_t bytec, uint8_t *bytev) const
 
void setSamplingInterval (uint16_t interval_ms) const
 
void systemReset (void) const
 
+ + + +

+Friends

+class FirmataClass
 
+

Constructor & Destructor Documentation

+ +

◆ FirmataMarshaller()

+ +
+
+ + + + + + + +
FirmataMarshaller::FirmataMarshaller ()
+
+

The FirmataMarshaller class.

+ +
+
+

Member Function Documentation

+ +

◆ begin()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::begin (Stream & s)
+
+

Reassign the Firmata stream transport.

Parameters
+ + +
sA reference to the Stream transport object. This can be any type of transport that implements the Stream interface. Some examples include Ethernet, WiFi and other UARTs on the board (Serial1, Serial2, etc).
+
+
+ +
+
+ +

◆ end()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::end (void )
+
+

Closes the FirmataMarshaller stream by setting its stream reference to (Stream *)NULL

+ +
+
+ +

◆ queryFirmwareVersion()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::queryFirmwareVersion (void ) const
+
+

Query the target's firmware name and version

+ +
+
+ +

◆ queryVersion()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::queryVersion (void ) const
+
+

Query the target's Firmata protocol version

+ +
+
+ +

◆ reportAnalogDisable()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::reportAnalogDisable (uint8_t pin) const
+
+

Halt the stream of analog readings from the Firmata host application. The range of pins is limited to [0..15] when using the REPORT_ANALOG. The maximum result of the REPORT_ANALOG is limited to 14 bits (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG message.

Parameters
+ + +
pinThe analog pin for which to request the value (limited to pins 0 - 15).
+
+
+ +
+
+ +

◆ reportAnalogEnable()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::reportAnalogEnable (uint8_t pin) const
+
+

Request a stream of analog readings from the Firmata host application. The range of pins is limited to [0..15] when using the REPORT_ANALOG. The maximum result of the REPORT_ANALOG is limited to 14 bits (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG message.

Parameters
+ + +
pinThe analog pin for which to request the value (limited to pins 0 - 15).
+
+
+ +
+
+ +

◆ reportDigitalPortDisable()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::reportDigitalPortDisable (uint8_t portNumber) const
+
+

Halt an 8-bit port stream from the Firmata host application (protocol v2 and later). Send 14-bits in a single digital message (protocol v1).

Parameters
+ + +
portNumberThe port number for which to request the value. Note that this is not the same as a "port" on the physical microcontroller. Ports are defined in order per every 8 pins in ascending order of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc.
+
+
+ +
+
+ +

◆ reportDigitalPortEnable()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::reportDigitalPortEnable (uint8_t portNumber) const
+
+

Request an 8-bit port stream from the Firmata host application (protocol v2 and later). Send 14-bits in a single digital message (protocol v1).

Parameters
+ + +
portNumberThe port number for which to request the value. Note that this is not the same as a "port" on the physical microcontroller. Ports are defined in order per every 8 pins in ascending order of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc.
+
+
+ +
+
+ +

◆ sendAnalog()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataMarshaller::sendAnalog (uint8_t pin,
uint16_t value 
) const
+
+

Send an analog message to the Firmata host application. The range of pins is limited to [0..15] when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG message.

Parameters
+ + + +
pinThe analog pin to which the value is sent.
valueThe value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc).
+
+
+
Note
The maximum value is 14-bits (16384).
+ +
+
+ +

◆ sendAnalogMappingQuery()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::sendAnalogMappingQuery (void ) const
+
+

Send an analog mapping query to the Firmata host application. The resulting sysex message will have an ANALOG_MAPPING_RESPONSE command byte, followed by a list of pins [0-n]; where each pin will specify its corresponding analog pin number or 0x7F (127) if not applicable.

+ +
+
+ +

◆ sendCapabilityQuery()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::sendCapabilityQuery (void ) const
+
+

Send a capability query to the Firmata host application. The resulting sysex message will have a CAPABILITY_RESPONSE command byte, followed by a list of byte tuples (mode and mode resolution) for each pin; where each pin list is terminated by 0x7F (127).

+ +
+
+ +

◆ sendDigital()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataMarshaller::sendDigital (uint8_t pin,
uint8_t value 
) const
+
+

Send a single digital pin value to the Firmata host application.

Parameters
+ + + +
pinThe digital pin to send the value of.
valueThe value of the pin.
+
+
+ +
+
+ +

◆ sendDigitalPort()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataMarshaller::sendDigitalPort (uint8_t portNumber,
uint16_t portData 
) const
+
+

Send an 8-bit port in a single digital message (protocol v2 and later). Send 14-bits in a single digital message (protocol v1).

Parameters
+ + + +
portNumberThe port number to send. Note that this is not the same as a "port" on the physical microcontroller. Ports are defined in order per every 8 pins in ascending order of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc.
portDataThe value of the port. The value of each pin in the port is represented by a bit.
+
+
+ +
+
+ +

◆ sendFirmwareVersion()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataMarshaller::sendFirmwareVersion (uint8_t major,
uint8_t minor,
size_t bytec,
uint8_t * bytev 
) const
+
+

Sends the firmware name and version to the Firmata host application.

Parameters
+ + + + + +
majorThe major verison number
minorThe minor version number
bytecThe length of the firmware name
bytevThe firmware name array
+
+
+ +
+
+ +

◆ sendPinMode()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataMarshaller::sendPinMode (uint8_t pin,
uint8_t config 
) const
+
+

Send the pin mode/configuration. The pin configuration (or mode) in Firmata represents the current function of the pin. Examples are digital input or output, analog input, pwm, i2c, serial (uart), etc.

Parameters
+ + + +
pinThe pin to configure.
configThe configuration value for the specified pin.
+
+
+ +
+
+ +

◆ sendPinStateQuery()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::sendPinStateQuery (uint8_t pin) const
+
+

Send a pin state query to the Firmata host application. The resulting sysex message will have a PIN_STATE_RESPONSE command byte, followed by the pin number, the pin mode and a stream of bits to indicate any data written to the pin (pin state).

Parameters
+ + +
pinThe pin to query
+
+
+
Note
The pin state is any data written to the pin (i.e. pin state != pin value)
+ +
+
+ +

◆ sendString()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::sendString (const char * string) const
+
+

Send a string to the Firmata host application.

Parameters
+ + +
stringA pointer to the char string
+
+
+ +
+
+ +

◆ sendSysex()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataMarshaller::sendSysex (uint8_t command,
size_t bytec,
uint8_t * bytev 
) const
+
+

Send a sysex message where all values after the command byte are packet as 2 7-bit bytes (this is not always the case so this function is not always used to send sysex messages).

Parameters
+ + + + +
commandThe sysex command byte.
bytecThe number of data bytes in the message (excludes start, command and end bytes).
bytevA pointer to the array of data bytes to send in the message.
+
+
+ +
+
+ +

◆ sendVersion()

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataMarshaller::sendVersion (uint8_t major,
uint8_t minor 
) const
+
+

Send the Firmata protocol version to the Firmata host application.

Parameters
+ + + +
majorThe major verison number
minorThe minor version number
+
+
+ +
+
+ +

◆ setSamplingInterval()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::setSamplingInterval (uint16_t interval_ms) const
+
+

The sampling interval sets how often analog data and i2c data is reported to the client.

Parameters
+ + +
interval_msThe interval (in milliseconds) at which to sample
+
+
+
Note
The default sampling interval is 19ms
+ +
+
+ +

◆ systemReset()

+ +
+
+ + + + + + + + +
void FirmataMarshaller::systemReset (void ) const
+
+

Perform a software reset on the target. For example, StandardFirmata.ino will initialize everything to a known state and reset the parsing buffer.

+ +
+
+
The documentation for this class was generated from the following files: +
+ + + + diff --git a/docs/html/classfirmata_1_1_firmata_parser-members.html b/docs/html/classfirmata_1_1_firmata_parser-members.html new file mode 100644 index 00000000..52385b64 --- /dev/null +++ b/docs/html/classfirmata_1_1_firmata_parser-members.html @@ -0,0 +1,102 @@ + + + + + + + +Firmata firmware for Arduino: Member List + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
firmata::FirmataParser Member List
+
+
+ +

This is the complete list of members for firmata::FirmataParser, including all inherited members.

+ + + + + + + + + + + + + + + + + + + +
attach(uint8_t command, callbackFunction newFunction, void *context=NULL)firmata::FirmataParser
attach(dataBufferOverflowCallbackFunction newFunction, void *context=NULL)firmata::FirmataParser
attach(uint8_t command, stringCallbackFunction newFunction, void *context=NULL)firmata::FirmataParser
attach(uint8_t command, sysexCallbackFunction newFunction, void *context=NULL)firmata::FirmataParser
attach(uint8_t command, systemCallbackFunction newFunction, void *context=NULL)firmata::FirmataParser
attach(uint8_t command, versionCallbackFunction newFunction, void *context=NULL)firmata::FirmataParser
callbackFunction typedef (defined in firmata::FirmataParser)firmata::FirmataParser
dataBufferOverflowCallbackFunction typedef (defined in firmata::FirmataParser)firmata::FirmataParser
detach(uint8_t command)firmata::FirmataParser
detach(dataBufferOverflowCallbackFunction)firmata::FirmataParser
FirmataParser(uint8_t *dataBuffer=(uint8_t *) NULL, size_t dataBufferSize=0)firmata::FirmataParser
isParsingMessage(void) constfirmata::FirmataParser
parse(uint8_t value)firmata::FirmataParser
setDataBufferOfSize(uint8_t *dataBuffer, size_t dataBufferSize)firmata::FirmataParser
stringCallbackFunction typedef (defined in firmata::FirmataParser)firmata::FirmataParser
sysexCallbackFunction typedef (defined in firmata::FirmataParser)firmata::FirmataParser
systemCallbackFunction typedef (defined in firmata::FirmataParser)firmata::FirmataParser
versionCallbackFunction typedef (defined in firmata::FirmataParser)firmata::FirmataParser
+ + + + diff --git a/docs/html/classfirmata_1_1_firmata_parser.html b/docs/html/classfirmata_1_1_firmata_parser.html new file mode 100644 index 00000000..adcbc363 --- /dev/null +++ b/docs/html/classfirmata_1_1_firmata_parser.html @@ -0,0 +1,552 @@ + + + + + + + +Firmata firmware for Arduino: firmata::FirmataParser Class Reference + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+ +
+
firmata::FirmataParser Class Reference
+
+
+ + + + + + + + + + + + + + +

+Public Types

+typedef void(* callbackFunction) (void *context, uint8_t command, uint16_t value)
 
+typedef void(* dataBufferOverflowCallbackFunction) (void *context)
 
+typedef void(* stringCallbackFunction) (void *context, const char *c_str)
 
+typedef void(* sysexCallbackFunction) (void *context, uint8_t command, size_t argc, uint8_t *argv)
 
+typedef void(* systemCallbackFunction) (void *context)
 
+typedef void(* versionCallbackFunction) (void *context, size_t sv_major, size_t sv_minor, const char *firmware)
 
+ + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

 FirmataParser (uint8_t *dataBuffer=(uint8_t *) NULL, size_t dataBufferSize=0)
 
void parse (uint8_t value)
 
bool isParsingMessage (void) const
 
int setDataBufferOfSize (uint8_t *dataBuffer, size_t dataBufferSize)
 
void attach (uint8_t command, callbackFunction newFunction, void *context=NULL)
 
void attach (dataBufferOverflowCallbackFunction newFunction, void *context=NULL)
 
void attach (uint8_t command, stringCallbackFunction newFunction, void *context=NULL)
 
void attach (uint8_t command, sysexCallbackFunction newFunction, void *context=NULL)
 
void attach (uint8_t command, systemCallbackFunction newFunction, void *context=NULL)
 
void attach (uint8_t command, versionCallbackFunction newFunction, void *context=NULL)
 
void detach (uint8_t command)
 
void detach (dataBufferOverflowCallbackFunction)
 
+

Constructor & Destructor Documentation

+ +

◆ FirmataParser()

+ +
+
+ + + + + + + + + + + + + + + + + + +
FirmataParser::FirmataParser (uint8_t * dataBuffer = (uint8_t *)NULL,
size_t dataBufferSize = 0 
)
+
+

The FirmataParser class.

Parameters
+ + + +
dataBufferA pointer to an external buffer used to store parsed data
dataBufferSizeThe size of the external buffer
+
+
+ +
+
+

Member Function Documentation

+ +

◆ attach() [1/6]

+ +
+
+ + + + + + + + + + + + + + + + + + +
void FirmataParser::attach (dataBufferOverflowCallbackFunction newFunction,
void * context = NULL 
)
+
+

Attach a buffer overflow callback

Parameters
+ + + +
newFunctionA reference to the buffer overflow callback function to attach.
contextAn optional context to be provided to the callback function (NULL by default).
+
+
+
Note
The context parameter is provided so you can pass a parameter, by reference, to your callback function.
+ +
+
+ +

◆ attach() [2/6]

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataParser::attach (uint8_t command,
callbackFunction newFunction,
void * context = NULL 
)
+
+

Attach a generic sysex callback function to a command (options are: ANALOG_MESSAGE, DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE).

Parameters
+ + + + +
commandThe ID of the command to attach a callback function to.
newFunctionA reference to the callback function to attach.
contextAn optional context to be provided to the callback function (NULL by default).
+
+
+
Note
The context parameter is provided so you can pass a parameter, by reference, to your callback function.
+ +
+
+ +

◆ attach() [3/6]

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataParser::attach (uint8_t command,
stringCallbackFunction newFunction,
void * context = NULL 
)
+
+

Attach a callback function for the STRING_DATA command.

Parameters
+ + + + +
commandMust be set to STRING_DATA or it will be ignored.
newFunctionA reference to the string callback function to attach.
contextAn optional context to be provided to the callback function (NULL by default).
+
+
+
Note
The context parameter is provided so you can pass a parameter, by reference, to your callback function.
+ +
+
+ +

◆ attach() [4/6]

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataParser::attach (uint8_t command,
sysexCallbackFunction newFunction,
void * context = NULL 
)
+
+

Attach a generic sysex callback function to sysex command.

Parameters
+ + + + +
commandThe ID of the command to attach a callback function to.
newFunctionA reference to the sysex callback function to attach.
contextAn optional context to be provided to the callback function (NULL by default).
+
+
+
Note
The context parameter is provided so you can pass a parameter, by reference, to your callback function.
+ +
+
+ +

◆ attach() [5/6]

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataParser::attach (uint8_t command,
systemCallbackFunction newFunction,
void * context = NULL 
)
+
+

Attach a system callback function (supported options are: SYSTEM_RESET, REPORT_VERSION).

Parameters
+ + + + +
commandThe ID of the command to attach a callback function to.
newFunctionA reference to the callback function to attach.
contextAn optional context to be provided to the callback function (NULL by default).
+
+
+
Note
The context parameter is provided so you can pass a parameter, by reference, to your callback function.
+ +
+
+ +

◆ attach() [6/6]

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void FirmataParser::attach (uint8_t command,
versionCallbackFunction newFunction,
void * context = NULL 
)
+
+

Attach a version callback function (supported option: REPORT_FIRMWARE).

Parameters
+ + + + +
commandThe ID of the command to attach a callback function to.
newFunctionA reference to the callback function to attach.
contextAn optional context to be provided to the callback function (NULL by default).
+
+
+
Note
The context parameter is provided so you can pass a parameter, by reference, to your callback function.
+ +
+
+ +

◆ detach() [1/2]

+ +
+
+ + + + + + + + +
void FirmataParser::detach (dataBufferOverflowCallbackFunction )
+
+

Detach the buffer overflow callback

Parameters
+ + +
<unused>Any pointer of type dataBufferOverflowCallbackFunction.
+
+
+ +
+
+ +

◆ detach() [2/2]

+ +
+
+ + + + + + + + +
void FirmataParser::detach (uint8_t command)
+
+

Detach a callback function for a specified command (such as SYSTEM_RESET, STRING_DATA, ANALOG_MESSAGE, DIGITAL_MESSAGE, etc).

Parameters
+ + +
commandThe ID of the command to detatch the callback function from.
+
+
+ +
+
+ +

◆ isParsingMessage()

+ +
+
+ + + + + + + + +
bool FirmataParser::isParsingMessage (void ) const
+
+
Returns
Returns true if the parser is actively parsing data.
+ +
+
+ +

◆ parse()

+ +
+
+ + + + + + + + +
void FirmataParser::parse (uint8_t inputData)
+
+

Parse data from the input stream.

Parameters
+ + +
inputDataA single byte to be added to the parser.
+
+
+ +
+
+ +

◆ setDataBufferOfSize()

+ +
+
+ + + + + + + + + + + + + + + + + + +
int FirmataParser::setDataBufferOfSize (uint8_t * dataBuffer,
size_t dataBufferSize 
)
+
+

Provides a mechanism to either set or update the working buffer of the parser. The method will be enabled when no buffer has been provided, or an overflow condition exists.

Parameters
+ + + +
dataBufferA pointer to an external buffer used to store parsed data
dataBufferSizeThe size of the external buffer
+
+
+ +
+
+
The documentation for this class was generated from the following files: +
+ + + + diff --git a/docs/html/closed.png b/docs/html/closed.png new file mode 100644 index 0000000000000000000000000000000000000000..98cc2c909da37a6df914fbf67780eebd99c597f5 GIT binary patch literal 132 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{V-kvUwAr*{o@8{^CZMh(5KoB^r_<4^zF@3)Cp&&t3hdujKf f*?bjBoY!V+E))@{xMcbjXe@)LtDnm{r-UW|*e5JT literal 0 HcmV?d00001 diff --git a/docs/html/doc.png b/docs/html/doc.png new file mode 100644 index 0000000000000000000000000000000000000000..17edabff95f7b8da13c9516a04efe05493c29501 GIT binary patch literal 746 zcmV7=@pnbNXRFEm&G8P!&WHG=d)>K?YZ1bzou)2{$)) zumDct!>4SyxL;zgaG>wy`^Hv*+}0kUfCrz~BCOViSb$_*&;{TGGn2^x9K*!Sf0=lV zpP=7O;GA0*Jm*tTYj$IoXvimpnV4S1Z5f$p*f$Db2iq2zrVGQUz~yq`ahn7ck(|CE z7Gz;%OP~J6)tEZWDzjhL9h2hdfoU2)Nd%T<5Kt;Y0XLt&<@6pQx!nw*5`@bq#?l*?3z{Hlzoc=Pr>oB5(9i6~_&-}A(4{Q$>c>%rV&E|a(r&;?i5cQB=} zYSDU5nXG)NS4HEs0it2AHe2>shCyr7`6@4*6{r@8fXRbTA?=IFVWAQJL&H5H{)DpM#{W(GL+Idzf^)uRV@oB8u$ z8v{MfJbTiiRg4bza<41NAzrl{=3fl_D+$t+^!xlQ8S}{UtY`e z;;&9UhyZqQRN%2pot{*Ei0*4~hSF_3AH2@fKU!$NSflS>{@tZpDT4`M2WRTTVH+D? z)GFlEGGHe?koB}i|1w45!BF}N_q&^HJ&-tyR{(afC6H7|aml|tBBbv}55C5DNP8p3 z)~jLEO4Z&2hZmP^i-e%(@d!(E|KRafiU8Q5u(wU((j8un3OR*Hvj+t literal 0 HcmV?d00001 diff --git a/docs/html/doxygen.css b/docs/html/doxygen.css new file mode 100644 index 00000000..5bc13aac --- /dev/null +++ b/docs/html/doxygen.css @@ -0,0 +1,1766 @@ +/* The standard CSS for doxygen 1.8.16 */ + +body, table, div, p, dl { + font: 400 14px/22px Roboto,sans-serif; +} + +p.reference, p.definition { + font: 400 14px/22px Roboto,sans-serif; +} + +/* @group Heading Levels */ + +h1.groupheader { + font-size: 150%; +} + +.title { + font: 400 14px/28px Roboto,sans-serif; + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2.groupheader { + border-bottom: 1px solid #879ECB; + color: #354C7B; + font-size: 150%; + font-weight: normal; + margin-top: 1.75em; + padding-top: 8px; + padding-bottom: 4px; + width: 100%; +} + +h3.groupheader { + font-size: 100%; +} + +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px cyan; +} + +dt { + font-weight: bold; +} + +ul.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; + column-count: 3; +} + +p.startli, p.startdd { + margin-top: 2px; +} + +p.starttd { + margin-top: 0px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +p.interli { +} + +p.interdd { +} + +p.intertd { +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #FFFFFF; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #FFFFFF; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited, a.line, a.line:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +ul { + overflow: hidden; /*Fixed: list item bullets overlap floating elements*/ +} + +#side-nav ul { + overflow: visible; /* reset ul rule for scroll bar in GENERATE_TREEVIEW window */ +} + +#main-nav ul { + overflow: visible; /* reset ul rule for the navigation bar drop down lists */ +} + +.fragment { + text-align: left; + direction: ltr; + overflow-x: auto; /*Fixed: fragment lines overlap floating elements*/ + overflow-y: hidden; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; + font-family: monospace, fixed; + font-size: 105%; +} + +div.fragment { + padding: 0 0 1px 0; /*Fixed: last line underline overlap border*/ + margin: 4px 8px 4px 2px; + background-color: #FBFCFD; + border: 1px solid #C4CFE5; +} + +div.line { + font-family: monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line:after { + content:"\000A"; + white-space: pre; +} + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; +} + + +span.lineno { + padding-right: 4px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; +} +span.lineno a { + background-color: #D8D8D8; +} + +span.lineno a:hover { + background-color: #C8C8C8; +} + +.lineno { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +div.ah, span.ah { + background-color: black; + font-weight: bold; + color: #FFFFFF; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000 110%); +} + +div.classindex ul { + list-style: none; + padding-left: 0; +} + +div.classindex span.ai { + display: inline-block; +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 12px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl, img.inline { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F7F8FB; + border-left: 2px solid #9CAFD4; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +blockquote.DocNodeRTL { + border-left: 0; + border-right: 2px solid #9CAFD4; + margin: 0 4px 0 24px; + padding: 0 16px 0 12px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.memberdecls td, .fieldtable tr { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: cyan; + box-shadow: 0 0 15px cyan; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memSeparator { + border-bottom: 1px solid #DEE4F0; + line-height: 1px; + margin: 0px; + padding: 0px; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; + font-size: 80%; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtitle { + padding: 8px; + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + margin-bottom: -1px; + background-image: url('nav_f.png'); + background-repeat: repeat-x; + background-color: #E2E8F2; + line-height: 1.25; + font-weight: 300; + float:left; +} + +.permalink +{ + font-size: 65%; + display: inline-block; + vertical-align: middle; +} + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px cyan; +} + +.memname { + font-weight: 400; + margin-left: 6px; +} + +.memname td { + vertical-align: bottom; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + background-color: #DFE5F1; + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 4px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 4px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 4px; + +} + +.overload { + font-family: "courier new",courier,monospace; + font-size: 65%; +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 10px 2px 10px; + background-color: #FBFCFD; + border-top-width: 0; + background-image:url('nav_g.png'); + background-repeat:repeat-x; + background-color: #FFFFFF; + /* opera specific markup */ + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} +.paramname code { + line-height: 14px; +} + +.params, .retval, .exception, .tparams { + margin-left: 0px; + padding-left: 0px; +} + +.params .paramname, .retval .paramname, .tparams .paramname, .exception .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype, .tparams .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir, .tparams .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + +table.mlabels { + border-spacing: 0px; +} + +td.mlabels-left { + width: 100%; + padding: 0px; +} + +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} + +span.mlabels { + margin-left: 8px; +} + +span.mlabel { + background-color: #728DC1; + border-top:1px solid #5373B4; + border-left:1px solid #5373B4; + border-right:1px solid #C4CFE5; + border-bottom:1px solid #C4CFE5; + text-shadow: none; + color: white; + margin-right: 4px; + padding: 2px 3px; + border-radius: 3px; + font-size: 7pt; + white-space: nowrap; + vertical-align: middle; +} + + + +/* @end */ + +/* these are for tree view inside a (index) page */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid #9CAFD4; + border-bottom: 1px solid #9CAFD4; + width: 100%; +} + +.directory table { + border-collapse:collapse; +} + +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; +} + +.directory td.entry { + white-space: nowrap; + padding-right: 6px; + padding-top: 3px; +} + +.directory td.entry a { + outline:none; +} + +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.even { + padding-left: 6px; + background-color: #F7F8FB; +} + +.directory img { + vertical-align: -30%; +} + +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; +} + +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #3D578C; +} + +.arrow { + color: #9CAFD4; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + font-size: 80%; + display: inline-block; + width: 16px; + height: 22px; +} + +.icon { + font-family: Arial, Helvetica; + font-weight: bold; + font-size: 12px; + height: 14px; + width: 16px; + display: inline-block; + background-color: #728DC1; + color: white; + text-align: center; + border-radius: 4px; + margin-left: 2px; + margin-right: 2px; +} + +.icona { + width: 24px; + height: 22px; + display: inline-block; +} + +.iconfopen { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderopen.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.iconfclosed { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderclosed.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.icondoc { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('doc.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +table.directory { + font: 400 14px Roboto,sans-serif; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable caption { + caption-side: top; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + /*width: 100%;*/ + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fieldname { + padding-top: 3px; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + /*width: 100%;*/ +} + +.fieldtable td.fielddoc p:first-child { + margin-top: 0px; +} + +.fieldtable td.fielddoc p:last-child { + margin-bottom: 2px; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + font-weight: 400; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + background-position: 0 -5px; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; + color: #283A5D; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +table.classindex +{ + margin: 10px; + white-space: nowrap; + margin-left: 3%; + margin-right: 3%; + width: 94%; + border: 0; + border-spacing: 0; + padding: 0; +} + +div.ingroups +{ + font-size: 8pt; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 10px; +} + +.PageDocRTL-title div.headertitle { + text-align: right; + direction: rtl; +} + +dl { + padding: 0 0 0 0; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug, dl.examples */ +dl.section { + margin-left: 0px; + padding-left: 0px; +} + +dl.section.DocNodeRTL { + margin-right: 0px; + padding-right: 0px; +} + +dl.note { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #D0C000; +} + +dl.note.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #D0C000; +} + +dl.warning, dl.attention { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #FF0000; +} + +dl.warning.DocNodeRTL, dl.attention.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #00D000; +} + +dl.pre.DocNodeRTL, dl.post.DocNodeRTL, dl.invariant.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #00D000; +} + +dl.deprecated { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #505050; +} + +dl.deprecated.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #505050; +} + +dl.todo { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #00C0E0; +} + +dl.todo.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #00C0E0; +} + +dl.test { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #3030E0; +} + +dl.test.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #3030E0; +} + +dl.bug { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #C08050; +} + +dl.bug.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectalign +{ + vertical-align: middle; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.plantumlgraph +{ + text-align: center; +} + +.diagraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F4F6FA; + border: 1px solid #D8DFEE; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 8px 10px 10px; + width: 200px; +} + +.PageDocRTL-title div.toc { + float: left !important; + text-align: right; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +.PageDocRTL-title div.toc li { + background-position-x: right !important; + padding-left: 0 !important; + padding-right: 10px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #4665A2; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +.PageDocRTL-title div.toc li.level1 { + margin-left: 0 !important; + margin-right: 0; +} + +.PageDocRTL-title div.toc li.level2 { + margin-left: 0 !important; + margin-right: 15px; +} + +.PageDocRTL-title div.toc li.level3 { + margin-left: 0 !important; + margin-right: 30px; +} + +.PageDocRTL-title div.toc li.level4 { + margin-left: 0 !important; + margin-right: 45px; +} + +.inherit_header { + font-weight: bold; + color: gray; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +/* tooltip related style info */ + +.ttc { + position: absolute; + display: none; +} + +#powerTip { + cursor: default; + white-space: nowrap; + background-color: white; + border: 1px solid gray; + border-radius: 4px 4px 4px 4px; + box-shadow: 1px 1px 7px gray; + display: none; + font-size: smaller; + max-width: 80%; + opacity: 0.9; + padding: 1ex 1em 1em; + position: absolute; + z-index: 2147483647; +} + +#powerTip div.ttdoc { + color: grey; + font-style: italic; +} + +#powerTip div.ttname a { + font-weight: bold; +} + +#powerTip div.ttname { + font-weight: bold; +} + +#powerTip div.ttdeci { + color: #006318; +} + +#powerTip div { + margin: 0px; + padding: 0px; + font: 12px/16px Roboto,sans-serif; +} + +#powerTip:before, #powerTip:after { + content: ""; + position: absolute; + margin: 0px; +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.s:after, #powerTip.s:before, +#powerTip.w:after, #powerTip.w:before, +#powerTip.e:after, #powerTip.e:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.nw:after, #powerTip.nw:before, +#powerTip.sw:after, #powerTip.sw:before { + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; +} + +#powerTip.n:after, #powerTip.s:after, +#powerTip.w:after, #powerTip.e:after, +#powerTip.nw:after, #powerTip.ne:after, +#powerTip.sw:after, #powerTip.se:after { + border-color: rgba(255, 255, 255, 0); +} + +#powerTip.n:before, #powerTip.s:before, +#powerTip.w:before, #powerTip.e:before, +#powerTip.nw:before, #powerTip.ne:before, +#powerTip.sw:before, #powerTip.se:before { + border-color: rgba(128, 128, 128, 0); +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.nw:after, #powerTip.nw:before { + top: 100%; +} + +#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { + border-top-color: #FFFFFF; + border-width: 10px; + margin: 0px -10px; +} +#powerTip.n:before { + border-top-color: #808080; + border-width: 11px; + margin: 0px -11px; +} +#powerTip.n:after, #powerTip.n:before { + left: 50%; +} + +#powerTip.nw:after, #powerTip.nw:before { + right: 14px; +} + +#powerTip.ne:after, #powerTip.ne:before { + left: 14px; +} + +#powerTip.s:after, #powerTip.s:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.sw:after, #powerTip.sw:before { + bottom: 100%; +} + +#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { + border-bottom-color: #FFFFFF; + border-width: 10px; + margin: 0px -10px; +} + +#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { + border-bottom-color: #808080; + border-width: 11px; + margin: 0px -11px; +} + +#powerTip.s:after, #powerTip.s:before { + left: 50%; +} + +#powerTip.sw:after, #powerTip.sw:before { + right: 14px; +} + +#powerTip.se:after, #powerTip.se:before { + left: 14px; +} + +#powerTip.e:after, #powerTip.e:before { + left: 100%; +} +#powerTip.e:after { + border-left-color: #FFFFFF; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.e:before { + border-left-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +#powerTip.w:after, #powerTip.w:before { + right: 100%; +} +#powerTip.w:after { + border-right-color: #FFFFFF; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.w:before { + border-right-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } +} + +/* @group Markdown */ + +/* +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.markdownTableHead tr { +} + +table.markdownTableBodyLeft td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +th.markdownTableHeadLeft th.markdownTableHeadRight th.markdownTableHeadCenter th.markdownTableHeadNone { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft { + text-align: left +} + +th.markdownTableHeadRight { + text-align: right +} + +th.markdownTableHeadCenter { + text-align: center +} +*/ + +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.markdownTable tr { +} + +th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft, td.markdownTableBodyLeft { + text-align: left +} + +th.markdownTableHeadRight, td.markdownTableBodyRight { + text-align: right +} + +th.markdownTableHeadCenter, td.markdownTableBodyCenter { + text-align: center +} + +.DocNodeRTL { + text-align: right; + direction: rtl; +} + +.DocNodeLTR { + text-align: left; + direction: ltr; +} + +table.DocNodeRTL { + width: auto; + margin-right: 0; + margin-left: auto; +} + +table.DocNodeLTR { + width: auto; + margin-right: auto; + margin-left: 0; +} + +tt, code, kbd, samp +{ + display: inline-block; + direction:ltr; +} +/* @end */ + +u { + text-decoration: underline; +} + diff --git a/docs/html/doxygen.png b/docs/html/doxygen.png new file mode 100644 index 0000000000000000000000000000000000000000..3ff17d807fd8aa003bed8bb2a69e8f0909592fd1 GIT binary patch literal 3779 zcmV;!4m|ORP)tMIv#Q0*~7*`IBSO7_x;@a8#Zk6_PeKR_s92J&)(m+);m9Iz3blw)z#Gi zP!9lj4$%+*>Hz@HCmM9L9|8c+0u=!H$O3?R0Kgx|#WP<6fKfC8fM-CQZT|_r@`>VO zX^Hgb|9cJqpdJA5$MCEK`F_2@2Y@s>^+;pF`~jdI0Pvr|vl4`=C)EH@1IFe7pdJ8F zH(qGi004~QnF)Ggga~8v08kGAs2hKTATxr7pwfNk|4#_AaT>w8P6TV+R2kbS$v==} zAjf`s0g#V8lB+b3)5oEI*q+{Yt$MZDruD2^;$+(_%Qn+%v0X-bJO=;@kiJ^ygLBnC z?1OVv_%aex1M@jKU|Z~$eI?PoF4Vj>fDzyo zAiLfpXY*a^Sj-S5D0S3@#V$sRW)g)_1e#$%8xdM>Jm7?!h zu0P2X=xoN>^!4DoPRgph2(2va07yfpXF+WH7EOg1GY%Zn z7~1A<(z7Q$ktEXhW_?GMpHp9l_UL18F3KOsxu81pqoBiNbFSGsof-W z6~eloMoz=4?OOnl2J268x5rOY`dCk0us(uS#Ud4yqOr@?=Q57a}tit|BhY>}~frH1sP`ScHS_d)oqH^lYy zZ%VP`#10MlE~P?cE(%(#(AUSv_T{+;t@$U}El}(1ig`vZo`Rm;+5&(AYzJ^Ae=h2X z@Re%vHwZU>|f0NI&%$*4eJweC5OROQrpPMA@*w|o z()A==l}(@bv^&>H1Ob3C=<^|hob?0+xJ?QQ3-ueQC}zy&JQNib!OqSO@-=>XzxlSF zAZ^U*1l6EEmg3r};_HY>&Jo_{dOPEFTWPmt=U&F#+0(O59^UIlHbNX+eF8UzyDR*T z(=5X$VF3!gm@RooS-&iiUYGG^`hMR(07zr_xP`d!^BH?uD>Phl8Rdifx3Af^Zr`Ku ztL+~HkVeL#bJ)7;`=>;{KNRvjmc}1}c58Sr#Treq=4{xo!ATy|c>iRSp4`dzMMVd@ zL8?uwXDY}Wqgh4mH`|$BTXpUIu6A1-cSq%hJw;@^Zr8TP=GMh*p(m(tN7@!^D~sl$ zz^tf4II4|};+irE$Fnm4NTc5%p{PRA`%}Zk`CE5?#h3|xcyQsS#iONZ z6H(@^i9td!$z~bZiJLTax$o>r(p}3o@< zyD7%(>ZYvy=6$U3e!F{Z`uSaYy`xQyl?b{}eg|G3&fz*`QH@mDUn)1%#5u`0m$%D} z?;tZ0u(mWeMV0QtzjgN!lT*pNRj;6510Wwx?Yi_=tYw|J#7@(Xe7ifDzXuK;JB;QO z#bg~K$cgm$@{QiL_3yr}y&~wuv=P=#O&Tj=Sr)aCUlYmZMcw?)T?c%0rUe1cS+o!qs_ zQ6Gp)-{)V!;=q}llyK3|^WeLKyjf%y;xHku;9(vM!j|~<7w1c*Mk-;P{T&yG) z@C-8E?QPynNQ<8f01D`2qexcVEIOU?y}MG)TAE6&VT5`rK8s(4PE;uQ92LTXUQ<>^ ztyQ@=@kRdh@ebUG^Z6NWWIL;_IGJ2ST>$t!$m$qvtj0Qmw8moN6GUV^!QKNK zHBXCtUH8)RY9++gH_TUV4^=-j$t}dD3qsN7GclJ^Zc&(j6&a_!$jCf}%c5ey`pm~1)@{yI3 zTdWyB+*X{JFw#z;PwRr5evb2!ueWF;v`B0HoUu4-(~aL=z;OXUUEtG`_$)Oxw6FKg zEzY`CyKaSBK3xt#8gA|r_|Kehn_HYVBMpEwbn9-fI*!u*eTA1ef8Mkl1=!jV4oYwWYM}i`A>_F4nhmlCIC6WLa zY%;4&@AlnaG11ejl61Jev21|r*m+?Kru3;1tFDl}#!OzUp6c>go4{C|^erwpG*&h6bspUPJag}oOkN2912Y3I?(eRc@U9>z#HPBHC?nps7H5!zP``90!Q1n80jo+B3TWXp!8Pe zwuKuLLI6l3Gv@+QH*Y}2wPLPQ1^EZhT#+Ed8q8Wo z1pTmIBxv14-{l&QVKxAyQF#8Q@NeJwWdKk>?cpiJLkJr+aZ!Me+Cfp!?FWSRf^j2k z73BRR{WSKaMkJ>1Nbx5dan5hg^_}O{Tj6u%iV%#QGz0Q@j{R^Ik)Z*+(YvY2ziBG)?AmJa|JV%4UT$k`hcOg5r9R?5>?o~JzK zJCrj&{i#hG>N7!B4kNX(%igb%kDj0fOQThC-8mtfap82PNRXr1D>lbgg)dYTQ(kbx z`Ee5kXG~Bh+BHQBf|kJEy6(ga%WfhvdQNDuOfQoe377l#ht&DrMGeIsI5C<&ai zWG$|hop2@@q5YDa)_-A?B02W;#fH!%k`daQLEItaJJ8Yf1L%8x;kg?)k)00P-lH+w z)5$QNV6r2$YtnV(4o=0^3{kmaXn*Dm0F*fU(@o)yVVjk|ln8ea6BMy%vZAhW9|wvA z8RoDkVoMEz1d>|5(k0Nw>22ZT){V<3$^C-cN+|~hKt2)){+l-?3m@-$c?-dlzQ)q- zZ)j%n^gerV{|+t}9m1_&&Ly!9$rtG4XX|WQ8`xYzGC~U@nYh~g(z9)bdAl#xH)xd5a=@|qql z|FzEil{P5(@gy!4ek05i$>`E^G~{;pnf6ftpLh$h#W?^#4UkPfa;;?bsIe&kz!+40 zI|6`F2n020)-r`pFaZ38F!S-lJM-o&inOw|66=GMeP@xQU5ghQH{~5Uh~TMTd;I9` z>YhVB`e^EVj*S7JF39ZgNf}A-0DwOcTT63ydN$I3b?yBQtUI*_fae~kPvzoD$zjX3 zoqBe#>12im4WzZ=f^4+u=!lA|#r%1`WB0-6*3BL#at`47#ebPpR|D1b)3BjT34nYY z%Ds%d?5$|{LgOIaRO{{oC&RK`O91$fqwM0(C_TALcozu*fWHb%%q&p-q{_8*2Zsi^ zh1ZCnr^UYa;4vQEtHk{~zi>wwMC5o{S=$P0X681y`SXwFH?Ewn{x-MOZynmc)JT5v zuHLwh;tLfxRrr%|k370}GofLl7thg>ACWWY&msqaVu&ry+`7+Ss>NL^%T1|z{IGMA zW-SKl=V-^{(f!Kf^#3(|T2W47d(%JVCI4JgRrT1pNz>+ietmFToNv^`gzC@&O-)+i zPQ~RwK8%C_vf%;%e>NyTp~dM5;!C|N0Q^6|CEb7Bw=Vz~$1#FA;Z*?mKSC)Hl-20s t8QyHj(g6VK0RYbl8UjE)0O0w=e*@m04r>stuEhWV002ovPDHLkV1hl;dM*F} literal 0 HcmV?d00001 diff --git a/docs/html/dynsections.js b/docs/html/dynsections.js new file mode 100644 index 00000000..ea0a7b39 --- /dev/null +++ b/docs/html/dynsections.js @@ -0,0 +1,120 @@ +/* + @licstart The following is the entire license notice for the + JavaScript code in this file. + + Copyright (C) 1997-2017 by Dimitri van Heesch + + 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 2 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + @licend The above is the entire license notice + for the JavaScript code in this file + */ +function toggleVisibility(linkObj) +{ + var base = $(linkObj).attr('id'); + var summary = $('#'+base+'-summary'); + var content = $('#'+base+'-content'); + var trigger = $('#'+base+'-trigger'); + var src=$(trigger).attr('src'); + if (content.is(':visible')===true) { + content.hide(); + summary.show(); + $(linkObj).addClass('closed').removeClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-8)+'closed.png'); + } else { + content.show(); + summary.hide(); + $(linkObj).removeClass('closed').addClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-10)+'open.png'); + } + return false; +} + +function updateStripes() +{ + $('table.directory tr'). + removeClass('even').filter(':visible:even').addClass('even'); +} + +function toggleLevel(level) +{ + $('table.directory tr').each(function() { + var l = this.id.split('_').length-1; + var i = $('#img'+this.id.substring(3)); + var a = $('#arr'+this.id.substring(3)); + if (l + + + + + + +Firmata firmware for Arduino: File List + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
File List
+
+
+
Here is a list of all documented files with brief descriptions:
+ + + + + + + +
 Boards.h
 Firmata.h
 FirmataConstants.h
 FirmataDefines.h
 FirmataMarshaller.h
 FirmataParser.h
+
+
+ + + + diff --git a/docs/html/folderclosed.png b/docs/html/folderclosed.png new file mode 100644 index 0000000000000000000000000000000000000000..bb8ab35edce8e97554e360005ee9fc5bffb36e66 GIT binary patch literal 616 zcmV-u0+;=XP)a9#ETzayK)T~Jw&MMH>OIr#&;dC}is*2Mqdf&akCc=O@`qC+4i z5Iu3w#1M@KqXCz8TIZd1wli&kkl2HVcAiZ8PUn5z_kG@-y;?yK06=cA0U%H0PH+kU zl6dp}OR(|r8-RG+YLu`zbI}5TlOU6ToR41{9=uz^?dGTNL;wIMf|V3`d1Wj3y!#6` zBLZ?xpKR~^2x}?~zA(_NUu3IaDB$tKma*XUdOZN~c=dLt_h_k!dbxm_*ibDM zlFX`g{k$X}yIe%$N)cn1LNu=q9_CS)*>A zsX_mM4L@`(cSNQKMFc$RtYbx{79#j-J7hk*>*+ZZhM4Hw?I?rsXCi#mRWJ=-0LGV5a-WR0Qgt<|Nqf)C-@80`5gIz45^_20000IqP)X=#(TiCT&PiIIVc55T}TU}EUh*{q$|`3@{d>{Tc9Bo>e= zfmF3!f>fbI9#GoEHh0f`i5)wkLpva0ztf%HpZneK?w-7AK@b4Itw{y|Zd3k!fH?q2 zlhckHd_V2M_X7+)U&_Xcfvtw60l;--DgZmLSw-Y?S>)zIqMyJ1#FwLU*%bl38ok+! zh78H87n`ZTS;uhzAR$M`zZ`bVhq=+%u9^$5jDplgxd44}9;IRqUH1YHH|@6oFe%z( zo4)_>E$F&^P-f(#)>(TrnbE>Pefs9~@iN=|)Rz|V`sGfHNrJ)0gJb8xx+SBmRf@1l zvuzt=vGfI)<-F9!o&3l?>9~0QbUDT(wFdnQPv%xdD)m*g%!20>Bc9iYmGAp<9YAa( z0QgYgTWqf1qN++Gqp z8@AYPTB3E|6s=WLG?xw0tm|U!o=&zd+H0oRYE;Dbx+Na9s^STqX|Gnq%H8s(nGDGJ j8vwW|`Ts`)fSK|Kx=IK@RG@g200000NkvXXu0mjfauFEA literal 0 HcmV?d00001 diff --git a/docs/html/functions.html b/docs/html/functions.html new file mode 100644 index 00000000..452a8a22 --- /dev/null +++ b/docs/html/functions.html @@ -0,0 +1,262 @@ + + + + + + + +Firmata firmware for Arduino: Class Members + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- a -

+ + +

- b -

+ + +

- d -

+ + +

- e -

+ + +

- f -

+ + +

- g -

+ + +

- i -

+ + +

- p -

+ + +

- q -

+ + +

- r -

+ + +

- s -

+ + +

- w -

+
+ + + + diff --git a/docs/html/functions_func.html b/docs/html/functions_func.html new file mode 100644 index 00000000..ad7b87be --- /dev/null +++ b/docs/html/functions_func.html @@ -0,0 +1,262 @@ + + + + + + + +Firmata firmware for Arduino: Class Members - Functions + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+  + +

- a -

+ + +

- b -

+ + +

- d -

+ + +

- e -

+ + +

- f -

+ + +

- g -

+ + +

- i -

+ + +

- p -

+ + +

- q -

+ + +

- r -

+ + +

- s -

+ + +

- w -

+
+ + + + diff --git a/docs/html/index.html b/docs/html/index.html new file mode 100644 index 00000000..d07b9ead --- /dev/null +++ b/docs/html/index.html @@ -0,0 +1,275 @@ + + + + + + + +Firmata firmware for Arduino: Firmata + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + +
+ +
+
+ + +
+ +
+ +
+
+
Firmata
+
+
+

Gitter

+

Firmata is a protocol for communicating with microcontrollers from software on a host computer. The protocol can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The Arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. If you would like to contribute to Firmata, please see the Contributing section below.

+

+Contents

+ +

+Usage

+

There are two main models of usage of Firmata. In one model, the author of the Arduino sketch uses the various methods provided by the Firmata library to selectively send and receive data between the Arduino device and the software running on the host computer. For example, a user can send analog data to the host using Firmata.sendAnalog(analogPin, analogRead(analogPin)) or send data packed in a string using Firmata.sendString(stringToSend). See File -> Examples -> Firmata -> AnalogFirmata & EchoString respectively for examples.

+

The second and more common model is to load a general purpose sketch called StandardFirmata (or one of the variants such as StandardFirmataPlus or StandardFirmataEthernet depending on your needs) on the Arduino board and then use the host computer exclusively to interact with the Arduino board. StandardFirmata is located in the Arduino IDE in File -> Examples -> Firmata.

+

+Firmata Client Libraries

+

Most of the time you will be interacting with Arduino with a client library on the host computers. Several Firmata client libraries have been implemented in a variety of popular programming languages:

+ +

Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details.

+

+Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher

+

If you want to update to the latest stable version:

+
    +
  1. Open the Arduino IDE and navigate to: Sketch > Include Library > Manage Libraries
  2. +
  3. Filter by "Firmata" and click on the "Firmata by Firmata Developers" item in the list of results.
  4. +
  5. Click the Select version dropdown and select the most recent version (note you can also install previous versions)
  6. +
  7. Click Install.
  8. +
+

+Cloning Firmata

+

If you are contributing to Firmata or otherwise need a version newer than the latest tagged release, you can clone Firmata directly to your Arduino/libraries/ directory (where 3rd party libraries are installed). This only works for Arduino 1.6.4 and higher, for older versions you need to clone into the Arduino application directory (see section below titled "Using the Source code rather than release archive"). Be sure to change the name to Firmata as follows:

+
$ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Firmata
+

Update path above if you're using Windows or Linux or changed the default Arduino directory on OS X

+

+Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x)

+

Download the latest release (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform.

+

Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).

+

+Mac OSX:

+

The Firmata library is contained within the Arduino package.

+
    +
  1. Navigate to the Arduino application
  2. +
  3. Right click on the application icon and select Show Package Contents
  4. +
  5. Navigate to: /Contents/Resources/Java/libraries/ and replace the existing Firmata folder with latest Firmata release (note there is a different download for Arduino 1.0.x vs 1.6.x)
  6. +
  7. Restart the Arduino application and the latest version of Firmata will be available.
  8. +
+

If you are using the Java 7 version of Arduino 1.5.7 or higher, the file path will differ slightly: Contents/Java/libraries/Firmata (no Resources directory).

+

+Windows:

+
    +
  1. Navigate to c:/Program\ Files/arduino-1.x/libraries/ and replace the existing Firmata folder with the latest Firmata release (note there is a different download for Arduino 1.0.x vs 1.6.x).
  2. +
  3. Restart the Arduino application and the latest version of Firmata will be available.
  4. +
+

Update the path and Arduino version as necessary

+

+Linux:

+
    +
  1. Navigate to ~/arduino-1.x/libraries/ and replace the existing Firmata folder with the latest Firmata release (note there is a different download for Arduino 1.0.x vs 1.6.x).
  2. +
  3. Restart the Arduino application and the latest version of Firmata will be available.
  4. +
+

Update the path and Arduino version as necessary

+

+Using the Source code rather than release archive (only for versions older than Arduino 1.6.3)

+

It is recommended you update to Arduino 1.6.4 or higher if possible, that way you can clone directly into the external Arduino/libraries/ directory which persists between Arduino application updates. Otherwise you will need to move your clone each time you update to a newer version of the Arduino IDE.

+

If you're stuck with an older version of the IDE, then follow these keep reading otherwise jump up to the "Cloning Firmata section above".

+

Clone this repo directly into the core Arduino application libraries directory. If you are using Arduino 1.5.x or <= 1.6.3, the repo directory structure will not match the Arduino library format, however it should still compile as long as you are using Arduino 1.5.7 or higher.

+

You will first need to remove the existing Firmata library, then clone firmata/arduino into an empty Firmata directory:

+
$ rm -r /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata
+
$ git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata
+

Update paths if you're using Windows or Linux

+

To generate properly formatted versions of Firmata (for Arduino 1.0.x and Arduino 1.6.x), run the release.sh script.

+

+Contributing

+

If you discover a bug or would like to propose a new feature, please open a new issue. Due to the limited memory of standard Arduino boards we cannot add every requested feature to StandardFirmata. Requests to add new features to StandardFirmata will be evaluated by the Firmata developers. However it is still possible to add new features to other Firmata implementations (Firmata is a protocol whereas StandardFirmata is just one of many possible implementations).

+

To contribute, fork this repository and create a new topic branch for the bug, feature or other existing issue you are addressing. Submit the pull request against the master branch.

+

If you would like to contribute but don't have a specific bugfix or new feature to contribute, you can take on an existing issue, see issues labeled "pull-request-encouraged". Add a comment to the issue to express your intent to begin work and/or to get any additional information about the issue.

+

You must thoroughly test your contributed code. In your pull request, describe tests performed to ensure that no existing code is broken and that any changes maintain backwards compatibility with the existing api. Test on multiple Arduino board variants if possible. We hope to enable some form of automated (or at least semi-automated) testing in the future, but for now any tests will need to be executed manually by the contributor and reviewers.

+

Use Artistic Style (astyle) to format your code. Set the following rules for the astyle formatter:

+
style = ""
+
indent-spaces = 2
+
indent-classes = true
+
indent-switches = true
+
indent-cases = true
+
indent-col1-comments = true
+
pad-oper = true
+
pad-header = true
+
keep-one-line-statements = true
+

If you happen to use Sublime Text, this astyle plugin is helpful. Set the above rules in the user settings file.

+
+
+ + + + diff --git a/docs/html/jquery.js b/docs/html/jquery.js new file mode 100644 index 00000000..103c32d7 --- /dev/null +++ b/docs/html/jquery.js @@ -0,0 +1,35 @@ +/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0a;a++)for(i in o[a])n=o[a][i],o[a].hasOwnProperty(i)&&void 0!==n&&(e[i]=t.isPlainObject(n)?t.isPlainObject(e[i])?t.widget.extend({},e[i],n):t.widget.extend({},n):n);return e},t.widget.bridge=function(e,i){var n=i.prototype.widgetFullName||e;t.fn[e]=function(o){var a="string"==typeof o,r=s.call(arguments,1),h=this;return a?this.length||"instance"!==o?this.each(function(){var i,s=t.data(this,n);return"instance"===o?(h=s,!1):s?t.isFunction(s[o])&&"_"!==o.charAt(0)?(i=s[o].apply(s,r),i!==s&&void 0!==i?(h=i&&i.jquery?h.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+o+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+o+"'")}):h=void 0:(r.length&&(o=t.widget.extend.apply(null,[o].concat(r))),this.each(function(){var e=t.data(this,n);e?(e.option(o||{}),e._init&&e._init()):t.data(this,n,new i(o,this))})),h}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{classes:{},disabled:!1,create:null},_createWidget:function(e,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),this.classesElementLookup={},s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){var e=this;this._destroy(),t.each(this.classesElementLookup,function(t,i){e._removeClass(i,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,o,a=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(a={},s=e.split("."),e=s.shift(),s.length){for(n=a[e]=t.widget.extend({},this.options[e]),o=0;s.length-1>o;o++)n[s[o]]=n[s[o]]||{},n=n[s[o]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];a[e]=i}return this._setOptions(a),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(e){var i,s,n;for(i in e)n=this.classesElementLookup[i],e[i]!==this.options.classes[i]&&n&&n.length&&(s=t(n.get()),this._removeClass(n,i),s.addClass(this._classes({element:s,keys:i,classes:e,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(e){function i(i,o){var a,r;for(r=0;i.length>r;r++)a=n.classesElementLookup[i[r]]||t(),a=e.add?t(t.unique(a.get().concat(e.element.get()))):t(a.not(e.element).get()),n.classesElementLookup[i[r]]=a,s.push(i[r]),o&&e.classes[i[r]]&&s.push(e.classes[i[r]])}var s=[],n=this;return e=t.extend({element:this.element,classes:this.options.classes||{}},e),this._on(e.element,{remove:"_untrackClassesElement"}),e.keys&&i(e.keys.match(/\S+/g)||[],!0),e.extra&&i(e.extra.match(/\S+/g)||[]),s.join(" ")},_untrackClassesElement:function(e){var i=this;t.each(i.classesElementLookup,function(s,n){-1!==t.inArray(e.target,n)&&(i.classesElementLookup[s]=t(n.not(e.target).get()))})},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,s){s="boolean"==typeof s?s:i;var n="string"==typeof t||null===t,o={extra:n?e:i,keys:n?t:e,element:n?this.element:t,add:s};return o.element.toggleClass(this._classes(o),s),this},_on:function(e,i,s){var n,o=this;"boolean"!=typeof e&&(s=i,i=e,e=!1),s?(i=n=t(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),t.each(s,function(s,a){function r(){return e||o.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof a?o[a]:a).apply(o,arguments):void 0}"string"!=typeof a&&(r.guid=a.guid=a.guid||r.guid||t.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+o.eventNamespace,c=h[2];c?n.on(l,c,r):i.on(l,r)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.off(i).off(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){this._addClass(t(e.currentTarget),null,"ui-state-hover")},mouseleave:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){this._addClass(t(e.currentTarget),null,"ui-state-focus")},focusout:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}}),t.widget,function(){function e(t,e,i){return[parseFloat(t[0])*(u.test(t[0])?e/100:1),parseFloat(t[1])*(u.test(t[1])?i/100:1)]}function i(e,i){return parseInt(t.css(e,i),10)||0}function s(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}var n,o=Math.max,a=Math.abs,r=/left|center|right/,h=/top|center|bottom/,l=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,u=/%$/,d=t.fn.position;t.position={scrollbarWidth:function(){if(void 0!==n)return n;var e,i,s=t("
"),o=s.children()[0];return t("body").append(s),e=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,e===i&&(i=s[0].clientWidth),s.remove(),n=e-i},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.widthi?"left":e>0?"right":"center",vertical:0>r?"top":s>0?"bottom":"middle"};l>p&&p>a(e+i)&&(u.horizontal="center"),c>f&&f>a(s+r)&&(u.vertical="middle"),u.important=o(a(e),a(i))>o(a(s),a(r))?"horizontal":"vertical",n.using.call(this,t,u)}),h.offset(t.extend(D,{using:r}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-a-n;e.collisionWidth>a?h>0&&0>=l?(i=t.left+h+e.collisionWidth-a-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+a-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-a-n;e.collisionHeight>a?h>0&&0>=l?(i=t.top+h+e.collisionHeight-a-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+a-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,r=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-r-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-r-o,(0>i||a(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>a(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,r=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-r-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,m=-2*e.offset[1];0>c?(s=t.top+p+f+m+e.collisionHeight-r-o,(0>s||a(c)>s)&&(t.top+=p+f+m)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+m-h,(i>0||u>a(i))&&(t.top+=p+f+m))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}}}(),t.ui.position,t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])}}),t.fn.extend({disableSelection:function(){var t="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.on(t+".ui-disableSelection",function(t){t.preventDefault()})}}(),enableSelection:function(){return this.off(".ui-disableSelection")}}),t.ui.focusable=function(i,s){var n,o,a,r,h,l=i.nodeName.toLowerCase();return"area"===l?(n=i.parentNode,o=n.name,i.href&&o&&"map"===n.nodeName.toLowerCase()?(a=t("img[usemap='#"+o+"']"),a.length>0&&a.is(":visible")):!1):(/^(input|select|textarea|button|object)$/.test(l)?(r=!i.disabled,r&&(h=t(i).closest("fieldset")[0],h&&(r=!h.disabled))):r="a"===l?i.href||s:s,r&&t(i).is(":visible")&&e(t(i)))},t.extend(t.expr[":"],{focusable:function(e){return t.ui.focusable(e,null!=t.attr(e,"tabindex"))}}),t.ui.focusable,t.fn.form=function(){return"string"==typeof this[0].form?this.closest("form"):t(this[0].form)},t.ui.formResetMixin={_formResetHandler:function(){var e=t(this);setTimeout(function(){var i=e.data("ui-form-reset-instances");t.each(i,function(){this.refresh()})})},_bindFormResetHandler:function(){if(this.form=this.element.form(),this.form.length){var t=this.form.data("ui-form-reset-instances")||[];t.length||this.form.on("reset.ui-form-reset",this._formResetHandler),t.push(this),this.form.data("ui-form-reset-instances",t)}},_unbindFormResetHandler:function(){if(this.form.length){var e=this.form.data("ui-form-reset-instances");e.splice(t.inArray(this,e),1),e.length?this.form.data("ui-form-reset-instances",e):this.form.removeData("ui-form-reset-instances").off("reset.ui-form-reset")}}},"1.7"===t.fn.jquery.substring(0,3)&&(t.each(["Width","Height"],function(e,i){function s(e,i,s,o){return t.each(n,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),o&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],o=i.toLowerCase(),a={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+i]=function(e){return void 0===e?a["inner"+i].call(this):this.each(function(){t(this).css(o,s(this,e)+"px")})},t.fn["outer"+i]=function(e,n){return"number"!=typeof e?a["outer"+i].call(this,e):this.each(function(){t(this).css(o,s(this,e,!0,n)+"px")})}}),t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.ui.keyCode={BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38},t.ui.escapeSelector=function(){var t=/([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;return function(e){return e.replace(t,"\\$1")}}(),t.fn.labels=function(){var e,i,s,n,o;return this[0].labels&&this[0].labels.length?this.pushStack(this[0].labels):(n=this.eq(0).parents("label"),s=this.attr("id"),s&&(e=this.eq(0).parents().last(),o=e.add(e.length?e.siblings():this.siblings()),i="label[for='"+t.ui.escapeSelector(s)+"']",n=n.add(o.find(i).addBack(i))),this.pushStack(n))},t.fn.scrollParent=function(e){var i=this.css("position"),s="absolute"===i,n=e?/(auto|scroll|hidden)/:/(auto|scroll)/,o=this.parents().filter(function(){var e=t(this);return s&&"static"===e.css("position")?!1:n.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==i&&o.length?o:t(this[0].ownerDocument||document)},t.extend(t.expr[":"],{tabbable:function(e){var i=t.attr(e,"tabindex"),s=null!=i;return(!s||i>=0)&&t.ui.focusable(e,s)}}),t.fn.extend({uniqueId:function(){var t=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++t)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&t(this).removeAttr("id")})}}),t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());var n=!1;t(document).on("mouseup",function(){n=!1}),t.widget("ui.mouse",{version:"1.12.1",options:{cancel:"input, textarea, button, select, option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.on("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).on("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.off("."+this.widgetName),this._mouseMoveDelegate&&this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!n){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,s=1===e.which,o="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return s&&!o&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.on("mousemove."+this.widgetName,this._mouseMoveDelegate).on("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),n=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)if(e.originalEvent.altKey||e.originalEvent.ctrlKey||e.originalEvent.metaKey||e.originalEvent.shiftKey)this.ignoreMissingWhich=!0;else if(!this.ignoreMissingWhich)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),this._mouseDelayTimer&&(clearTimeout(this._mouseDelayTimer),delete this._mouseDelayTimer),this.ignoreMissingWhich=!1,n=!1,e.preventDefault()},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),t.ui.plugin={add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;o.length>n;n++)t.options[o[n][0]]&&o[n][1].apply(t.element,i)}},t.widget("ui.resizable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,classes:{"ui-resizable-se":"ui-icon ui-icon-gripsmall-diagonal-se"},containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(t){return parseFloat(t)||0},_isNumber:function(t){return!isNaN(parseFloat(t))},_hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)},_create:function(){var e,i=this.options,s=this;this._addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!i.aspectRatio,aspectRatio:i.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:i.helper||i.ghost||i.animate?i.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(t("
").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,e={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(e),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(e),this._proportionallyResize()),this._setupHandles(),i.autoHide&&t(this.element).on("mouseenter",function(){i.disabled||(s._removeClass("ui-resizable-autohide"),s._handles.show())}).on("mouseleave",function(){i.disabled||s.resizing||(s._addClass("ui-resizable-autohide"),s._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeData("resizable").removeData("ui-resizable").off(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;default:}},_setupHandles:function(){var e,i,s,n,o,a=this.options,r=this;if(this.handles=a.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=t(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),s=this.handles.split(","),this.handles={},i=0;s.length>i;i++)e=t.trim(s[i]),n="ui-resizable-"+e,o=t("
"),this._addClass(o,"ui-resizable-handle "+n),o.css({zIndex:a.zIndex}),this.handles[e]=".ui-resizable-"+e,this.element.append(o);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=t(this.handles[i]),this._on(this.handles[i],{mousedown:r._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){r.resizing||(this.className&&(o=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),r.axis=o&&o[1]?o[1]:"se")}),a.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._handles.remove()},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(e){var i,s,n,o=this.options,a=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),o.containment&&(i+=t(o.containment).scrollLeft()||0,s+=t(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:a.width(),height:a.height()},this.originalSize=this._helper?{width:a.outerWidth(),height:a.outerHeight()}:{width:a.width(),height:a.height()},this.sizeDiff={width:a.outerWidth()-a.width(),height:a.outerHeight()-a.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:e.pageX,top:e.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===n?this.axis+"-resize":n),this._addClass("ui-resizable-resizing"),this._propagate("start",e),!0},_mouseDrag:function(e){var i,s,n=this.originalMousePosition,o=this.axis,a=e.pageX-n.left||0,r=e.pageY-n.top||0,h=this._change[o];return this._updatePrevProperties(),h?(i=h.apply(this,[e,a,r]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",e,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseFloat(c.element.css("left"))+(c.position.left-c.originalPosition.left)||null,h=parseFloat(c.element.css("top"))+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s,n,o,a=this.options;o={minWidth:this._isNumber(a.minWidth)?a.minWidth:0,maxWidth:this._isNumber(a.maxWidth)?a.maxWidth:1/0,minHeight:this._isNumber(a.minHeight)?a.minHeight:0,maxHeight:this._isNumber(a.maxHeight)?a.maxHeight:1/0},(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,s=o.minWidth/this.aspectRatio,i=o.maxHeight*this.aspectRatio,n=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),s>o.minHeight&&(o.minHeight=s),o.maxWidth>i&&(o.maxWidth=i),o.maxHeight>n&&(o.maxHeight=n)),this._vBoundaries=o},_updateCache:function(t){this.offset=this.helper.offset(),this._isNumber(t.left)&&(this.position.left=t.left),this._isNumber(t.top)&&(this.position.top=t.top),this._isNumber(t.height)&&(this.size.height=t.height),this._isNumber(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,i=this.size,s=this.axis;return this._isNumber(t.height)?t.width=t.height*this.aspectRatio:this._isNumber(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===s&&(t.left=e.left+(i.width-t.width),t.top=null),"nw"===s&&(t.top=e.top+(i.height-t.height),t.left=e.left+(i.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,i=this.axis,s=this._isNumber(t.width)&&e.maxWidth&&e.maxWidtht.width,a=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,r=this.originalPosition.left+this.originalSize.width,h=this.originalPosition.top+this.originalSize.height,l=/sw|nw|w/.test(i),c=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),a&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=r-e.minWidth),s&&l&&(t.left=r-e.maxWidth),a&&c&&(t.top=h-e.minHeight),n&&c&&(t.top=h-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];4>e;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;this._proportionallyResizeElements.length>e;e++)t=this._proportionallyResizeElements[e],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(t)),t.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("
"),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element +},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,c=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var e,i,s,n,o,a,r,h=t(this).resizable("instance"),l=h.options,c=h.element,u=l.containment,d=u instanceof t?u.get(0):/parent/.test(u)?c.parent().get(0):u;d&&(h.containerElement=t(d),/document/.test(u)||u===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(e=t(d),i=[],t(["Top","Right","Left","Bottom"]).each(function(t,s){i[t]=h._num(e.css("padding"+s))}),h.containerOffset=e.offset(),h.containerPosition=e.position(),h.containerSize={height:e.innerHeight()-i[3],width:e.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,o=h.containerSize.width,a=h._hasScroll(d,"left")?d.scrollWidth:o,r=h._hasScroll(d)?d.scrollHeight:n,h.parentData={element:d,left:s.left,top:s.top,width:a,height:r}))},resize:function(e){var i,s,n,o,a=t(this).resizable("instance"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement,p=!0;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio,p=!1),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio,p=!1),a.position.top=a._helper?h.top:0),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o?(a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top):(a.offset.left=a.element.offset().left,a.offset.top=a.element.offset().top),i=Math.abs(a.sizeDiff.width+(a._helper?a.offset.left-u.left:a.offset.left-h.left)),s=Math.abs(a.sizeDiff.height+(a._helper?a.offset.top-u.top:a.offset.top-h.top)),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio,p=!1)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio,p=!1)),p||(a.position.left=a.prevPosition.left,a.position.top=a.prevPosition.top,a.size.width=a.prevSize.width,a.size.height=a.prevSize.height)},stop:function(){var e=t(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).resizable("instance"),i=e.options;t(i.alsoResize).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseFloat(e.width()),height:parseFloat(e.height()),left:parseFloat(e.css("left")),top:parseFloat(e.css("top"))})})},resize:function(e,i){var s=t(this).resizable("instance"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0};t(n.alsoResize).each(function(){var e=t(this),s=t(this).data("ui-resizable-alsoresize"),n={},o=e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(o,function(t,e){var i=(s[e]||0)+(r[e]||0);i&&i>=0&&(n[e]=i||null)}),e.css(n)})},stop:function(){t(this).removeData("ui-resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).resizable("instance"),i=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:i.height,width:i.width,margin:0,left:0,top:0}),e._addClass(e.ghost,"ui-resizable-ghost"),t.uiBackCompat!==!1&&"string"==typeof e.options.ghost&&e.ghost.addClass(this.options.ghost),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).resizable("instance");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).resizable("instance");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e,i=t(this).resizable("instance"),s=i.options,n=i.size,o=i.originalSize,a=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,c=h[1]||1,u=Math.round((n.width-o.width)/l)*l,d=Math.round((n.height-o.height)/c)*c,p=o.width+u,f=o.height+d,m=s.maxWidth&&p>s.maxWidth,g=s.maxHeight&&f>s.maxHeight,_=s.minWidth&&s.minWidth>p,v=s.minHeight&&s.minHeight>f;s.grid=h,_&&(p+=l),v&&(f+=c),m&&(p-=l),g&&(f-=c),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=a.top-d):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=a.left-u):((0>=f-c||0>=p-l)&&(e=i._getPaddingPlusBorderDimensions(this)),f-c>0?(i.size.height=f,i.position.top=a.top-d):(f=c-e.height,i.size.height=f,i.position.top=a.top+o.height-f),p-l>0?(i.size.width=p,i.position.left=a.left-u):(p=l-e.width,i.size.width=p,i.position.left=a.left+o.width-p))}}),t.ui.resizable});/** + * Copyright (c) 2007 Ariel Flesler - aflesler ○ gmail • com | https://github.com/flesler + * Licensed under MIT + * @author Ariel Flesler + * @version 2.1.2 + */ +;(function(f){"use strict";"function"===typeof define&&define.amd?define(["jquery"],f):"undefined"!==typeof module&&module.exports?module.exports=f(require("jquery")):f(jQuery)})(function($){"use strict";function n(a){return!a.nodeName||-1!==$.inArray(a.nodeName.toLowerCase(),["iframe","#document","html","body"])}function h(a){return $.isFunction(a)||$.isPlainObject(a)?a:{top:a,left:a}}var p=$.scrollTo=function(a,d,b){return $(window).scrollTo(a,d,b)};p.defaults={axis:"xy",duration:0,limit:!0};$.fn.scrollTo=function(a,d,b){"object"=== typeof d&&(b=d,d=0);"function"===typeof b&&(b={onAfter:b});"max"===a&&(a=9E9);b=$.extend({},p.defaults,b);d=d||b.duration;var u=b.queue&&1=f[g]?0:Math.min(f[g],n));!a&&1-1){targetElements.on(evt+EVENT_NAMESPACE,function elementToggle(event){$.powerTip.toggle(this,event)})}else{targetElements.on(evt+EVENT_NAMESPACE,function elementOpen(event){$.powerTip.show(this,event)})}});$.each(options.closeEvents,function(idx,evt){if($.inArray(evt,options.openEvents)<0){targetElements.on(evt+EVENT_NAMESPACE,function elementClose(event){$.powerTip.hide(this,!isMouseEvent(event))})}});targetElements.on("keydown"+EVENT_NAMESPACE,function elementKeyDown(event){if(event.keyCode===27){$.powerTip.hide(this,true)}})}return targetElements};$.fn.powerTip.defaults={fadeInTime:200,fadeOutTime:100,followMouse:false,popupId:"powerTip",popupClass:null,intentSensitivity:7,intentPollInterval:100,closeDelay:100,placement:"n",smartPlacement:false,offset:10,mouseOnToPopup:false,manual:false,openEvents:["mouseenter","focus"],closeEvents:["mouseleave","blur"]};$.fn.powerTip.smartPlacementLists={n:["n","ne","nw","s"],e:["e","ne","se","w","nw","sw","n","s","e"],s:["s","se","sw","n"],w:["w","nw","sw","e","ne","se","n","s","w"],nw:["nw","w","sw","n","s","se","nw"],ne:["ne","e","se","n","s","sw","ne"],sw:["sw","w","nw","s","n","ne","sw"],se:["se","e","ne","s","n","nw","se"],"nw-alt":["nw-alt","n","ne-alt","sw-alt","s","se-alt","w","e"],"ne-alt":["ne-alt","n","nw-alt","se-alt","s","sw-alt","e","w"],"sw-alt":["sw-alt","s","se-alt","nw-alt","n","ne-alt","w","e"],"se-alt":["se-alt","s","sw-alt","ne-alt","n","nw-alt","e","w"]};$.powerTip={show:function apiShowTip(element,event){if(isMouseEvent(event)){trackMouse(event);session.previousX=event.pageX;session.previousY=event.pageY;$(element).data(DATA_DISPLAYCONTROLLER).show()}else{$(element).first().data(DATA_DISPLAYCONTROLLER).show(true,true)}return element},reposition:function apiResetPosition(element){$(element).first().data(DATA_DISPLAYCONTROLLER).resetPosition();return element},hide:function apiCloseTip(element,immediate){var displayController;immediate=element?immediate:true;if(element){displayController=$(element).first().data(DATA_DISPLAYCONTROLLER)}else if(session.activeHover){displayController=session.activeHover.data(DATA_DISPLAYCONTROLLER)}if(displayController){displayController.hide(immediate)}return element},toggle:function apiToggle(element,event){if(session.activeHover&&session.activeHover.is(element)){$.powerTip.hide(element,!isMouseEvent(event))}else{$.powerTip.show(element,event)}return element}};$.powerTip.showTip=$.powerTip.show;$.powerTip.closeTip=$.powerTip.hide;function CSSCoordinates(){var me=this;me.top="auto";me.left="auto";me.right="auto";me.bottom="auto";me.set=function(property,value){if($.isNumeric(value)){me[property]=Math.round(value)}}}function DisplayController(element,options,tipController){var hoverTimer=null,myCloseDelay=null;function openTooltip(immediate,forceOpen){cancelTimer();if(!element.data(DATA_HASACTIVEHOVER)){if(!immediate){session.tipOpenImminent=true;hoverTimer=setTimeout(function intentDelay(){hoverTimer=null;checkForIntent()},options.intentPollInterval)}else{if(forceOpen){element.data(DATA_FORCEDOPEN,true)}closeAnyDelayed();tipController.showTip(element)}}else{cancelClose()}}function closeTooltip(disableDelay){if(myCloseDelay){myCloseDelay=session.closeDelayTimeout=clearTimeout(myCloseDelay);session.delayInProgress=false}cancelTimer();session.tipOpenImminent=false;if(element.data(DATA_HASACTIVEHOVER)){element.data(DATA_FORCEDOPEN,false);if(!disableDelay){session.delayInProgress=true;session.closeDelayTimeout=setTimeout(function closeDelay(){session.closeDelayTimeout=null;tipController.hideTip(element);session.delayInProgress=false;myCloseDelay=null},options.closeDelay);myCloseDelay=session.closeDelayTimeout}else{tipController.hideTip(element)}}}function checkForIntent(){var xDifference=Math.abs(session.previousX-session.currentX),yDifference=Math.abs(session.previousY-session.currentY),totalDifference=xDifference+yDifference;if(totalDifference",{id:options.popupId});if($body.length===0){$body=$("body")}$body.append(tipElement);session.tooltips=session.tooltips?session.tooltips.add(tipElement):tipElement}if(options.followMouse){if(!tipElement.data(DATA_HASMOUSEMOVE)){$document.on("mousemove"+EVENT_NAMESPACE,positionTipOnCursor);$window.on("scroll"+EVENT_NAMESPACE,positionTipOnCursor);tipElement.data(DATA_HASMOUSEMOVE,true)}}function beginShowTip(element){element.data(DATA_HASACTIVEHOVER,true);tipElement.queue(function queueTipInit(next){showTip(element);next()})}function showTip(element){var tipContent;if(!element.data(DATA_HASACTIVEHOVER)){return}if(session.isTipOpen){if(!session.isClosing){hideTip(session.activeHover)}tipElement.delay(100).queue(function queueTipAgain(next){showTip(element);next()});return}element.trigger("powerTipPreRender");tipContent=getTooltipContent(element);if(tipContent){tipElement.empty().append(tipContent)}else{return}element.trigger("powerTipRender");session.activeHover=element;session.isTipOpen=true;tipElement.data(DATA_MOUSEONTOTIP,options.mouseOnToPopup);tipElement.addClass(options.popupClass);if(!options.followMouse||element.data(DATA_FORCEDOPEN)){positionTipOnElement(element);session.isFixedTipOpen=true}else{positionTipOnCursor()}if(!element.data(DATA_FORCEDOPEN)&&!options.followMouse){$document.on("click"+EVENT_NAMESPACE,function documentClick(event){var target=event.target;if(target!==element[0]){if(options.mouseOnToPopup){if(target!==tipElement[0]&&!$.contains(tipElement[0],target)){$.powerTip.hide()}}else{$.powerTip.hide()}}})}if(options.mouseOnToPopup&&!options.manual){tipElement.on("mouseenter"+EVENT_NAMESPACE,function tipMouseEnter(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).cancel()}});tipElement.on("mouseleave"+EVENT_NAMESPACE,function tipMouseLeave(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).hide()}})}tipElement.fadeIn(options.fadeInTime,function fadeInCallback(){if(!session.desyncTimeout){session.desyncTimeout=setInterval(closeDesyncedTip,500)}element.trigger("powerTipOpen")})}function hideTip(element){session.isClosing=true;session.isTipOpen=false;session.desyncTimeout=clearInterval(session.desyncTimeout);element.data(DATA_HASACTIVEHOVER,false);element.data(DATA_FORCEDOPEN,false);$document.off("click"+EVENT_NAMESPACE);tipElement.off(EVENT_NAMESPACE);tipElement.fadeOut(options.fadeOutTime,function fadeOutCallback(){var coords=new CSSCoordinates;session.activeHover=null;session.isClosing=false;session.isFixedTipOpen=false;tipElement.removeClass();coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset);tipElement.css(coords);element.trigger("powerTipClose")})}function positionTipOnCursor(){var tipWidth,tipHeight,coords,collisions,collisionCount;if(!session.isFixedTipOpen&&(session.isTipOpen||session.tipOpenImminent&&tipElement.data(DATA_HASMOUSEMOVE))){tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=new CSSCoordinates;coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset);collisions=getViewportCollisions(coords,tipWidth,tipHeight);if(collisions!==Collision.none){collisionCount=countFlags(collisions);if(collisionCount===1){if(collisions===Collision.right){coords.set("left",session.scrollLeft+session.windowWidth-tipWidth)}else if(collisions===Collision.bottom){coords.set("top",session.scrollTop+session.windowHeight-tipHeight)}}else{coords.set("left",session.currentX-tipWidth-options.offset);coords.set("top",session.currentY-tipHeight-options.offset)}}tipElement.css(coords)}}function positionTipOnElement(element){var priorityList,finalPlacement;if(options.smartPlacement||options.followMouse&&element.data(DATA_FORCEDOPEN)){priorityList=$.fn.powerTip.smartPlacementLists[options.placement];$.each(priorityList,function(idx,pos){var collisions=getViewportCollisions(placeTooltip(element,pos),tipElement.outerWidth(),tipElement.outerHeight());finalPlacement=pos;return collisions!==Collision.none})}else{placeTooltip(element,options.placement);finalPlacement=options.placement}tipElement.removeClass("w nw sw e ne se n s w se-alt sw-alt ne-alt nw-alt");tipElement.addClass(finalPlacement)}function placeTooltip(element,placement){var iterationCount=0,tipWidth,tipHeight,coords=new CSSCoordinates;coords.set("top",0);coords.set("left",0);tipElement.css(coords);do{tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=placementCalculator.compute(element,placement,tipWidth,tipHeight,options.offset);tipElement.css(coords)}while(++iterationCount<=5&&(tipWidth!==tipElement.outerWidth()||tipHeight!==tipElement.outerHeight()));return coords}function closeDesyncedTip(){var isDesynced=false,hasDesyncableCloseEvent=$.grep(["mouseleave","mouseout","blur","focusout"],function(eventType){return $.inArray(eventType,options.closeEvents)!==-1}).length>0;if(session.isTipOpen&&!session.isClosing&&!session.delayInProgress&&hasDesyncableCloseEvent){if(session.activeHover.data(DATA_HASACTIVEHOVER)===false||session.activeHover.is(":disabled")){isDesynced=true}else if(!isMouseOver(session.activeHover)&&!session.activeHover.is(":focus")&&!session.activeHover.data(DATA_FORCEDOPEN)){if(tipElement.data(DATA_MOUSEONTOTIP)){if(!isMouseOver(tipElement)){isDesynced=true}}else{isDesynced=true}}if(isDesynced){hideTip(session.activeHover)}}}this.showTip=beginShowTip;this.hideTip=hideTip;this.resetPosition=positionTipOnElement}function isSvgElement(element){return Boolean(window.SVGElement&&element[0]instanceof SVGElement)}function isMouseEvent(event){return Boolean(event&&$.inArray(event.type,MOUSE_EVENTS)>-1&&typeof event.pageX==="number")}function initTracking(){if(!session.mouseTrackingActive){session.mouseTrackingActive=true;getViewportDimensions();$(getViewportDimensions);$document.on("mousemove"+EVENT_NAMESPACE,trackMouse);$window.on("resize"+EVENT_NAMESPACE,trackResize);$window.on("scroll"+EVENT_NAMESPACE,trackScroll)}}function getViewportDimensions(){session.scrollLeft=$window.scrollLeft();session.scrollTop=$window.scrollTop();session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackResize(){session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackScroll(){var x=$window.scrollLeft(),y=$window.scrollTop();if(x!==session.scrollLeft){session.currentX+=x-session.scrollLeft;session.scrollLeft=x}if(y!==session.scrollTop){session.currentY+=y-session.scrollTop;session.scrollTop=y}}function trackMouse(event){session.currentX=event.pageX;session.currentY=event.pageY}function isMouseOver(element){var elementPosition=element.offset(),elementBox=element[0].getBoundingClientRect(),elementWidth=elementBox.right-elementBox.left,elementHeight=elementBox.bottom-elementBox.top;return session.currentX>=elementPosition.left&&session.currentX<=elementPosition.left+elementWidth&&session.currentY>=elementPosition.top&&session.currentY<=elementPosition.top+elementHeight}function getTooltipContent(element){var tipText=element.data(DATA_POWERTIP),tipObject=element.data(DATA_POWERTIPJQ),tipTarget=element.data(DATA_POWERTIPTARGET),targetElement,content;if(tipText){if($.isFunction(tipText)){tipText=tipText.call(element[0])}content=tipText}else if(tipObject){if($.isFunction(tipObject)){tipObject=tipObject.call(element[0])}if(tipObject.length>0){content=tipObject.clone(true,true)}}else if(tipTarget){targetElement=$("#"+tipTarget);if(targetElement.length>0){content=targetElement.html()}}return content}function getViewportCollisions(coords,elementWidth,elementHeight){var viewportTop=session.scrollTop,viewportLeft=session.scrollLeft,viewportBottom=viewportTop+session.windowHeight,viewportRight=viewportLeft+session.windowWidth,collisions=Collision.none;if(coords.topviewportBottom||Math.abs(coords.bottom-session.windowHeight)>viewportBottom){collisions|=Collision.bottom}if(coords.leftviewportRight){collisions|=Collision.left}if(coords.left+elementWidth>viewportRight||coords.right1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);/*! SmartMenus jQuery Plugin - v1.1.0 - September 17, 2017 + * http://www.smartmenus.org/ + * Copyright Vasil Dinkov, Vadikom Web Ltd. http://vadikom.com; Licensed MIT */(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof module&&"object"==typeof module.exports?module.exports=t(require("jquery")):t(jQuery)})(function($){function initMouseDetection(t){var e=".smartmenus_mouse";if(mouseDetectionEnabled||t)mouseDetectionEnabled&&t&&($(document).off(e),mouseDetectionEnabled=!1);else{var i=!0,s=null,o={mousemove:function(t){var e={x:t.pageX,y:t.pageY,timeStamp:(new Date).getTime()};if(s){var o=Math.abs(s.x-e.x),a=Math.abs(s.y-e.y);if((o>0||a>0)&&2>=o&&2>=a&&300>=e.timeStamp-s.timeStamp&&(mouse=!0,i)){var n=$(t.target).closest("a");n.is("a")&&$.each(menuTrees,function(){return $.contains(this.$root[0],n[0])?(this.itemEnter({currentTarget:n[0]}),!1):void 0}),i=!1}}s=e}};o[touchEvents?"touchstart":"pointerover pointermove pointerout MSPointerOver MSPointerMove MSPointerOut"]=function(t){isTouchEvent(t.originalEvent)&&(mouse=!1)},$(document).on(getEventsNS(o,e)),mouseDetectionEnabled=!0}}function isTouchEvent(t){return!/^(4|mouse)$/.test(t.pointerType)}function getEventsNS(t,e){e||(e="");var i={};for(var s in t)i[s.split(" ").join(e+" ")+e]=t[s];return i}var menuTrees=[],mouse=!1,touchEvents="ontouchstart"in window,mouseDetectionEnabled=!1,requestAnimationFrame=window.requestAnimationFrame||function(t){return setTimeout(t,1e3/60)},cancelAnimationFrame=window.cancelAnimationFrame||function(t){clearTimeout(t)},canAnimate=!!$.fn.animate;return $.SmartMenus=function(t,e){this.$root=$(t),this.opts=e,this.rootId="",this.accessIdPrefix="",this.$subArrow=null,this.activatedItems=[],this.visibleSubMenus=[],this.showTimeout=0,this.hideTimeout=0,this.scrollTimeout=0,this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.idInc=0,this.$firstLink=null,this.$firstSub=null,this.disabled=!1,this.$disableOverlay=null,this.$touchScrollingSub=null,this.cssTransforms3d="perspective"in t.style||"webkitPerspective"in t.style,this.wasCollapsible=!1,this.init()},$.extend($.SmartMenus,{hideAll:function(){$.each(menuTrees,function(){this.menuHideAll()})},destroy:function(){for(;menuTrees.length;)menuTrees[0].destroy();initMouseDetection(!0)},prototype:{init:function(t){var e=this;if(!t){menuTrees.push(this),this.rootId=((new Date).getTime()+Math.random()+"").replace(/\D/g,""),this.accessIdPrefix="sm-"+this.rootId+"-",this.$root.hasClass("sm-rtl")&&(this.opts.rightToLeftSubMenus=!0);var i=".smartmenus";this.$root.data("smartmenus",this).attr("data-smartmenus-id",this.rootId).dataSM("level",1).on(getEventsNS({"mouseover focusin":$.proxy(this.rootOver,this),"mouseout focusout":$.proxy(this.rootOut,this),keydown:$.proxy(this.rootKeyDown,this)},i)).on(getEventsNS({mouseenter:$.proxy(this.itemEnter,this),mouseleave:$.proxy(this.itemLeave,this),mousedown:$.proxy(this.itemDown,this),focus:$.proxy(this.itemFocus,this),blur:$.proxy(this.itemBlur,this),click:$.proxy(this.itemClick,this)},i),"a"),i+=this.rootId,this.opts.hideOnClick&&$(document).on(getEventsNS({touchstart:$.proxy(this.docTouchStart,this),touchmove:$.proxy(this.docTouchMove,this),touchend:$.proxy(this.docTouchEnd,this),click:$.proxy(this.docClick,this)},i)),$(window).on(getEventsNS({"resize orientationchange":$.proxy(this.winResize,this)},i)),this.opts.subIndicators&&(this.$subArrow=$("").addClass("sub-arrow"),this.opts.subIndicatorsText&&this.$subArrow.html(this.opts.subIndicatorsText)),initMouseDetection()}if(this.$firstSub=this.$root.find("ul").each(function(){e.menuInit($(this))}).eq(0),this.$firstLink=this.$root.find("a").eq(0),this.opts.markCurrentItem){var s=/(index|default)\.[^#\?\/]*/i,o=/#.*/,a=window.location.href.replace(s,""),n=a.replace(o,"");this.$root.find("a").each(function(){var t=this.href.replace(s,""),i=$(this);(t==a||t==n)&&(i.addClass("current"),e.opts.markCurrentTree&&i.parentsUntil("[data-smartmenus-id]","ul").each(function(){$(this).dataSM("parent-a").addClass("current")}))})}this.wasCollapsible=this.isCollapsible()},destroy:function(t){if(!t){var e=".smartmenus";this.$root.removeData("smartmenus").removeAttr("data-smartmenus-id").removeDataSM("level").off(e),e+=this.rootId,$(document).off(e),$(window).off(e),this.opts.subIndicators&&(this.$subArrow=null)}this.menuHideAll();var i=this;this.$root.find("ul").each(function(){var t=$(this);t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.dataSM("shown-before")&&((i.opts.subMenusMinWidth||i.opts.subMenusMaxWidth)&&t.css({width:"",minWidth:"",maxWidth:""}).removeClass("sm-nowrap"),t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.css({zIndex:"",top:"",left:"",marginLeft:"",marginTop:"",display:""})),0==(t.attr("id")||"").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeDataSM("in-mega").removeDataSM("shown-before").removeDataSM("scroll-arrows").removeDataSM("parent-a").removeDataSM("level").removeDataSM("beforefirstshowfired").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeAttr("aria-expanded"),this.$root.find("a.has-submenu").each(function(){var t=$(this);0==t.attr("id").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeClass("has-submenu").removeDataSM("sub").removeAttr("aria-haspopup").removeAttr("aria-controls").removeAttr("aria-expanded").closest("li").removeDataSM("sub"),this.opts.subIndicators&&this.$root.find("span.sub-arrow").remove(),this.opts.markCurrentItem&&this.$root.find("a.current").removeClass("current"),t||(this.$root=null,this.$firstLink=null,this.$firstSub=null,this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),menuTrees.splice($.inArray(this,menuTrees),1))},disable:function(t){if(!this.disabled){if(this.menuHideAll(),!t&&!this.opts.isPopup&&this.$root.is(":visible")){var e=this.$root.offset();this.$disableOverlay=$('
').css({position:"absolute",top:e.top,left:e.left,width:this.$root.outerWidth(),height:this.$root.outerHeight(),zIndex:this.getStartZIndex(!0),opacity:0}).appendTo(document.body)}this.disabled=!0}},docClick:function(t){return this.$touchScrollingSub?(this.$touchScrollingSub=null,void 0):((this.visibleSubMenus.length&&!$.contains(this.$root[0],t.target)||$(t.target).closest("a").length)&&this.menuHideAll(),void 0)},docTouchEnd:function(){if(this.lastTouch){if(!(!this.visibleSubMenus.length||void 0!==this.lastTouch.x2&&this.lastTouch.x1!=this.lastTouch.x2||void 0!==this.lastTouch.y2&&this.lastTouch.y1!=this.lastTouch.y2||this.lastTouch.target&&$.contains(this.$root[0],this.lastTouch.target))){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var t=this;this.hideTimeout=setTimeout(function(){t.menuHideAll()},350)}this.lastTouch=null}},docTouchMove:function(t){if(this.lastTouch){var e=t.originalEvent.touches[0];this.lastTouch.x2=e.pageX,this.lastTouch.y2=e.pageY}},docTouchStart:function(t){var e=t.originalEvent.touches[0];this.lastTouch={x1:e.pageX,y1:e.pageY,target:e.target}},enable:function(){this.disabled&&(this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),this.disabled=!1)},getClosestMenu:function(t){for(var e=$(t).closest("ul");e.dataSM("in-mega");)e=e.parent().closest("ul");return e[0]||null},getHeight:function(t){return this.getOffset(t,!0)},getOffset:function(t,e){var i;"none"==t.css("display")&&(i={position:t[0].style.position,visibility:t[0].style.visibility},t.css({position:"absolute",visibility:"hidden"}).show());var s=t[0].getBoundingClientRect&&t[0].getBoundingClientRect(),o=s&&(e?s.height||s.bottom-s.top:s.width||s.right-s.left);return o||0===o||(o=e?t[0].offsetHeight:t[0].offsetWidth),i&&t.hide().css(i),o},getStartZIndex:function(t){var e=parseInt(this[t?"$root":"$firstSub"].css("z-index"));return!t&&isNaN(e)&&(e=parseInt(this.$root.css("z-index"))),isNaN(e)?1:e},getTouchPoint:function(t){return t.touches&&t.touches[0]||t.changedTouches&&t.changedTouches[0]||t},getViewport:function(t){var e=t?"Height":"Width",i=document.documentElement["client"+e],s=window["inner"+e];return s&&(i=Math.min(i,s)),i},getViewportHeight:function(){return this.getViewport(!0)},getViewportWidth:function(){return this.getViewport()},getWidth:function(t){return this.getOffset(t)},handleEvents:function(){return!this.disabled&&this.isCSSOn()},handleItemEvents:function(t){return this.handleEvents()&&!this.isLinkInMegaMenu(t)},isCollapsible:function(){return"static"==this.$firstSub.css("position")},isCSSOn:function(){return"inline"!=this.$firstLink.css("display")},isFixed:function(){var t="fixed"==this.$root.css("position");return t||this.$root.parentsUntil("body").each(function(){return"fixed"==$(this).css("position")?(t=!0,!1):void 0}),t},isLinkInMegaMenu:function(t){return $(this.getClosestMenu(t[0])).hasClass("mega-menu")},isTouchMode:function(){return!mouse||this.opts.noMouseOver||this.isCollapsible()},itemActivate:function(t,e){var i=t.closest("ul"),s=i.dataSM("level");if(s>1&&(!this.activatedItems[s-2]||this.activatedItems[s-2][0]!=i.dataSM("parent-a")[0])){var o=this;$(i.parentsUntil("[data-smartmenus-id]","ul").get().reverse()).add(i).each(function(){o.itemActivate($(this).dataSM("parent-a"))})}if((!this.isCollapsible()||e)&&this.menuHideSubMenus(this.activatedItems[s-1]&&this.activatedItems[s-1][0]==t[0]?s:s-1),this.activatedItems[s-1]=t,this.$root.triggerHandler("activate.smapi",t[0])!==!1){var a=t.dataSM("sub");a&&(this.isTouchMode()||!this.opts.showOnClick||this.clickActivated)&&this.menuShow(a)}},itemBlur:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&this.$root.triggerHandler("blur.smapi",e[0])},itemClick:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(this.$touchScrollingSub&&this.$touchScrollingSub[0]==e.closest("ul")[0])return this.$touchScrollingSub=null,t.stopPropagation(),!1;if(this.$root.triggerHandler("click.smapi",e[0])===!1)return!1;var i=$(t.target).is(".sub-arrow"),s=e.dataSM("sub"),o=s?2==s.dataSM("level"):!1,a=this.isCollapsible(),n=/toggle$/.test(this.opts.collapsibleBehavior),r=/link$/.test(this.opts.collapsibleBehavior),h=/^accordion/.test(this.opts.collapsibleBehavior);if(s&&!s.is(":visible")){if((!r||!a||i)&&(this.opts.showOnClick&&o&&(this.clickActivated=!0),this.itemActivate(e,h),s.is(":visible")))return this.focusActivated=!0,!1}else if(a&&(n||i))return this.itemActivate(e,h),this.menuHide(s),n&&(this.focusActivated=!1),!1;return this.opts.showOnClick&&o||e.hasClass("disabled")||this.$root.triggerHandler("select.smapi",e[0])===!1?!1:void 0}},itemDown:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&e.dataSM("mousedown",!0)},itemEnter:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(!this.isTouchMode()){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);var i=this;this.showTimeout=setTimeout(function(){i.itemActivate(e)},this.opts.showOnClick&&1==e.closest("ul").dataSM("level")?1:this.opts.showTimeout)}this.$root.triggerHandler("mouseenter.smapi",e[0])}},itemFocus:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(!this.focusActivated||this.isTouchMode()&&e.dataSM("mousedown")||this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0]==e[0]||this.itemActivate(e,!0),this.$root.triggerHandler("focus.smapi",e[0]))},itemLeave:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(this.isTouchMode()||(e[0].blur(),this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0)),e.removeDataSM("mousedown"),this.$root.triggerHandler("mouseleave.smapi",e[0]))},menuHide:function(t){if(this.$root.triggerHandler("beforehide.smapi",t[0])!==!1&&(canAnimate&&t.stop(!0,!0),"none"!=t.css("display"))){var e=function(){t.css("z-index","")};this.isCollapsible()?canAnimate&&this.opts.collapsibleHideFunction?this.opts.collapsibleHideFunction.call(this,t,e):t.hide(this.opts.collapsibleHideDuration,e):canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,t,e):t.hide(this.opts.hideDuration,e),t.dataSM("scroll")&&(this.menuScrollStop(t),t.css({"touch-action":"","-ms-touch-action":"","-webkit-transform":"",transform:""}).off(".smartmenus_scroll").removeDataSM("scroll").dataSM("scroll-arrows").hide()),t.dataSM("parent-a").removeClass("highlighted").attr("aria-expanded","false"),t.attr({"aria-expanded":"false","aria-hidden":"true"});var i=t.dataSM("level");this.activatedItems.splice(i-1,1),this.visibleSubMenus.splice($.inArray(t,this.visibleSubMenus),1),this.$root.triggerHandler("hide.smapi",t[0])}},menuHideAll:function(){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);for(var t=this.opts.isPopup?1:0,e=this.visibleSubMenus.length-1;e>=t;e--)this.menuHide(this.visibleSubMenus[e]);this.opts.isPopup&&(canAnimate&&this.$root.stop(!0,!0),this.$root.is(":visible")&&(canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,this.$root):this.$root.hide(this.opts.hideDuration))),this.activatedItems=[],this.visibleSubMenus=[],this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.$root.triggerHandler("hideAll.smapi")},menuHideSubMenus:function(t){for(var e=this.activatedItems.length-1;e>=t;e--){var i=this.activatedItems[e].dataSM("sub");i&&this.menuHide(i)}},menuInit:function(t){if(!t.dataSM("in-mega")){t.hasClass("mega-menu")&&t.find("ul").dataSM("in-mega",!0);for(var e=2,i=t[0];(i=i.parentNode.parentNode)!=this.$root[0];)e++;var s=t.prevAll("a").eq(-1);s.length||(s=t.prevAll().find("a").eq(-1)),s.addClass("has-submenu").dataSM("sub",t),t.dataSM("parent-a",s).dataSM("level",e).parent().dataSM("sub",t);var o=s.attr("id")||this.accessIdPrefix+ ++this.idInc,a=t.attr("id")||this.accessIdPrefix+ ++this.idInc;s.attr({id:o,"aria-haspopup":"true","aria-controls":a,"aria-expanded":"false"}),t.attr({id:a,role:"group","aria-hidden":"true","aria-labelledby":o,"aria-expanded":"false"}),this.opts.subIndicators&&s[this.opts.subIndicatorsPos](this.$subArrow.clone())}},menuPosition:function(t){var e,i,s=t.dataSM("parent-a"),o=s.closest("li"),a=o.parent(),n=t.dataSM("level"),r=this.getWidth(t),h=this.getHeight(t),u=s.offset(),l=u.left,c=u.top,d=this.getWidth(s),m=this.getHeight(s),p=$(window),f=p.scrollLeft(),v=p.scrollTop(),b=this.getViewportWidth(),S=this.getViewportHeight(),g=a.parent().is("[data-sm-horizontal-sub]")||2==n&&!a.hasClass("sm-vertical"),M=this.opts.rightToLeftSubMenus&&!o.is("[data-sm-reverse]")||!this.opts.rightToLeftSubMenus&&o.is("[data-sm-reverse]"),w=2==n?this.opts.mainMenuSubOffsetX:this.opts.subMenusSubOffsetX,T=2==n?this.opts.mainMenuSubOffsetY:this.opts.subMenusSubOffsetY;if(g?(e=M?d-r-w:w,i=this.opts.bottomToTopSubMenus?-h-T:m+T):(e=M?w-r:d-w,i=this.opts.bottomToTopSubMenus?m-T-h:T),this.opts.keepInViewport){var y=l+e,I=c+i;if(M&&f>y?e=g?f-y+e:d-w:!M&&y+r>f+b&&(e=g?f+b-r-y+e:w-r),g||(S>h&&I+h>v+S?i+=v+S-h-I:(h>=S||v>I)&&(i+=v-I)),g&&(I+h>v+S+.49||v>I)||!g&&h>S+.49){var x=this;t.dataSM("scroll-arrows")||t.dataSM("scroll-arrows",$([$('')[0],$('')[0]]).on({mouseenter:function(){t.dataSM("scroll").up=$(this).hasClass("scroll-up"),x.menuScroll(t)},mouseleave:function(e){x.menuScrollStop(t),x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(t){t.preventDefault()}}).insertAfter(t));var A=".smartmenus_scroll";if(t.dataSM("scroll",{y:this.cssTransforms3d?0:i-m,step:1,itemH:m,subH:h,arrowDownH:this.getHeight(t.dataSM("scroll-arrows").eq(1))}).on(getEventsNS({mouseover:function(e){x.menuScrollOver(t,e)},mouseout:function(e){x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(e){x.menuScrollMousewheel(t,e)}},A)).dataSM("scroll-arrows").css({top:"auto",left:"0",marginLeft:e+(parseInt(t.css("border-left-width"))||0),width:r-(parseInt(t.css("border-left-width"))||0)-(parseInt(t.css("border-right-width"))||0),zIndex:t.css("z-index")}).eq(g&&this.opts.bottomToTopSubMenus?0:1).show(),this.isFixed()){var C={};C[touchEvents?"touchstart touchmove touchend":"pointerdown pointermove pointerup MSPointerDown MSPointerMove MSPointerUp"]=function(e){x.menuScrollTouch(t,e)},t.css({"touch-action":"none","-ms-touch-action":"none"}).on(getEventsNS(C,A))}}}t.css({top:"auto",left:"0",marginLeft:e,marginTop:i-m})},menuScroll:function(t,e,i){var s,o=t.dataSM("scroll"),a=t.dataSM("scroll-arrows"),n=o.up?o.upEnd:o.downEnd;if(!e&&o.momentum){if(o.momentum*=.92,s=o.momentum,.5>s)return this.menuScrollStop(t),void 0}else s=i||(e||!this.opts.scrollAccelerate?this.opts.scrollStep:Math.floor(o.step));var r=t.dataSM("level");if(this.activatedItems[r-1]&&this.activatedItems[r-1].dataSM("sub")&&this.activatedItems[r-1].dataSM("sub").is(":visible")&&this.menuHideSubMenus(r-1),o.y=o.up&&o.y>=n||!o.up&&n>=o.y?o.y:Math.abs(n-o.y)>s?o.y+(o.up?s:-s):n,t.css(this.cssTransforms3d?{"-webkit-transform":"translate3d(0, "+o.y+"px, 0)",transform:"translate3d(0, "+o.y+"px, 0)"}:{marginTop:o.y}),mouse&&(o.up&&o.y>o.downEnd||!o.up&&o.y0;t.dataSM("scroll-arrows").eq(i?0:1).is(":visible")&&(t.dataSM("scroll").up=i,this.menuScroll(t,!0))}e.preventDefault()},menuScrollOut:function(t,e){mouse&&(/^scroll-(up|down)/.test((e.relatedTarget||"").className)||(t[0]==e.relatedTarget||$.contains(t[0],e.relatedTarget))&&this.getClosestMenu(e.relatedTarget)==t[0]||t.dataSM("scroll-arrows").css("visibility","hidden"))},menuScrollOver:function(t,e){if(mouse&&!/^scroll-(up|down)/.test(e.target.className)&&this.getClosestMenu(e.target)==t[0]){this.menuScrollRefreshData(t);var i=t.dataSM("scroll"),s=$(window).scrollTop()-t.dataSM("parent-a").offset().top-i.itemH;t.dataSM("scroll-arrows").eq(0).css("margin-top",s).end().eq(1).css("margin-top",s+this.getViewportHeight()-i.arrowDownH).end().css("visibility","visible")}},menuScrollRefreshData:function(t){var e=t.dataSM("scroll"),i=$(window).scrollTop()-t.dataSM("parent-a").offset().top-e.itemH;this.cssTransforms3d&&(i=-(parseFloat(t.css("margin-top"))-i)),$.extend(e,{upEnd:i,downEnd:i+this.getViewportHeight()-e.subH})},menuScrollStop:function(t){return this.scrollTimeout?(cancelAnimationFrame(this.scrollTimeout),this.scrollTimeout=0,t.dataSM("scroll").step=1,!0):void 0},menuScrollTouch:function(t,e){if(e=e.originalEvent,isTouchEvent(e)){var i=this.getTouchPoint(e);if(this.getClosestMenu(i.target)==t[0]){var s=t.dataSM("scroll");if(/(start|down)$/i.test(e.type))this.menuScrollStop(t)?(e.preventDefault(),this.$touchScrollingSub=t):this.$touchScrollingSub=null,this.menuScrollRefreshData(t),$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp});else if(/move$/i.test(e.type)){var o=void 0!==s.touchY?s.touchY:s.touchStartY;if(void 0!==o&&o!=i.pageY){this.$touchScrollingSub=t;var a=i.pageY>o;void 0!==s.up&&s.up!=a&&$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp}),$.extend(s,{up:a,touchY:i.pageY}),this.menuScroll(t,!0,Math.abs(i.pageY-o))}e.preventDefault()}else void 0!==s.touchY&&((s.momentum=15*Math.pow(Math.abs(i.pageY-s.touchStartY)/(e.timeStamp-s.touchStartTime),2))&&(this.menuScrollStop(t),this.menuScroll(t),e.preventDefault()),delete s.touchY)}}},menuShow:function(t){if((t.dataSM("beforefirstshowfired")||(t.dataSM("beforefirstshowfired",!0),this.$root.triggerHandler("beforefirstshow.smapi",t[0])!==!1))&&this.$root.triggerHandler("beforeshow.smapi",t[0])!==!1&&(t.dataSM("shown-before",!0),canAnimate&&t.stop(!0,!0),!t.is(":visible"))){var e=t.dataSM("parent-a"),i=this.isCollapsible();if((this.opts.keepHighlighted||i)&&e.addClass("highlighted"),i)t.removeClass("sm-nowrap").css({zIndex:"",width:"auto",minWidth:"",maxWidth:"",top:"",left:"",marginLeft:"",marginTop:""});else{if(t.css("z-index",this.zIndexInc=(this.zIndexInc||this.getStartZIndex())+1),(this.opts.subMenusMinWidth||this.opts.subMenusMaxWidth)&&(t.css({width:"auto",minWidth:"",maxWidth:""}).addClass("sm-nowrap"),this.opts.subMenusMinWidth&&t.css("min-width",this.opts.subMenusMinWidth),this.opts.subMenusMaxWidth)){var s=this.getWidth(t);t.css("max-width",this.opts.subMenusMaxWidth),s>this.getWidth(t)&&t.removeClass("sm-nowrap").css("width",this.opts.subMenusMaxWidth)}this.menuPosition(t)}var o=function(){t.css("overflow","")};i?canAnimate&&this.opts.collapsibleShowFunction?this.opts.collapsibleShowFunction.call(this,t,o):t.show(this.opts.collapsibleShowDuration,o):canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,t,o):t.show(this.opts.showDuration,o),e.attr("aria-expanded","true"),t.attr({"aria-expanded":"true","aria-hidden":"false"}),this.visibleSubMenus.push(t),this.$root.triggerHandler("show.smapi",t[0])}},popupHide:function(t){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},t?1:this.opts.hideTimeout)},popupShow:function(t,e){if(!this.opts.isPopup)return alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'),void 0;if(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),this.$root.dataSM("shown-before",!0),canAnimate&&this.$root.stop(!0,!0),!this.$root.is(":visible")){this.$root.css({left:t,top:e});var i=this,s=function(){i.$root.css("overflow","")};canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,this.$root,s):this.$root.show(this.opts.showDuration,s),this.visibleSubMenus[0]=this.$root}},refresh:function(){this.destroy(!0),this.init(!0)},rootKeyDown:function(t){if(this.handleEvents())switch(t.keyCode){case 27:var e=this.activatedItems[0];if(e){this.menuHideAll(),e[0].focus();var i=e.dataSM("sub");i&&this.menuHide(i)}break;case 32:var s=$(t.target);if(s.is("a")&&this.handleItemEvents(s)){var i=s.dataSM("sub");i&&!i.is(":visible")&&(this.itemClick({currentTarget:t.target}),t.preventDefault())}}},rootOut:function(t){if(this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),!this.opts.showOnClick||!this.opts.hideOnClick)){var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},this.opts.hideTimeout)}},rootOver:function(t){this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0)},winResize:function(t){if(this.handleEvents()){if(!("onorientationchange"in window)||"orientationchange"==t.type){var e=this.isCollapsible();this.wasCollapsible&&e||(this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0].blur(),this.menuHideAll()),this.wasCollapsible=e}}else if(this.$disableOverlay){var i=this.$root.offset();this.$disableOverlay.css({top:i.top,left:i.left,width:this.$root.outerWidth(),height:this.$root.outerHeight()})}}}}),$.fn.dataSM=function(t,e){return e?this.data(t+"_smartmenus",e):this.data(t+"_smartmenus")},$.fn.removeDataSM=function(t){return this.removeData(t+"_smartmenus")},$.fn.smartmenus=function(options){if("string"==typeof options){var args=arguments,method=options;return Array.prototype.shift.call(args),this.each(function(){var t=$(this).data("smartmenus");t&&t[method]&&t[method].apply(t,args)})}return this.each(function(){var dataOpts=$(this).data("sm-options")||null;if(dataOpts)try{dataOpts=eval("("+dataOpts+")")}catch(e){dataOpts=null,alert('ERROR\n\nSmartMenus jQuery init:\nInvalid "data-sm-options" attribute value syntax.')}new $.SmartMenus(this,$.extend({},$.fn.smartmenus.defaults,options,dataOpts))})},$.fn.smartmenus.defaults={isPopup:!1,mainMenuSubOffsetX:0,mainMenuSubOffsetY:0,subMenusSubOffsetX:0,subMenusSubOffsetY:0,subMenusMinWidth:"10em",subMenusMaxWidth:"20em",subIndicators:!0,subIndicatorsPos:"append",subIndicatorsText:"",scrollStep:30,scrollAccelerate:!0,showTimeout:250,hideTimeout:500,showDuration:0,showFunction:null,hideDuration:0,hideFunction:function(t,e){t.fadeOut(200,e)},collapsibleShowDuration:0,collapsibleShowFunction:function(t,e){t.slideDown(200,e)},collapsibleHideDuration:0,collapsibleHideFunction:function(t,e){t.slideUp(200,e)},showOnClick:!1,hideOnClick:!0,noMouseOver:!1,keepInViewport:!0,keepHighlighted:!0,markCurrentItem:!1,markCurrentTree:!0,rightToLeftSubMenus:!1,bottomToTopSubMenus:!1,collapsibleBehavior:"default"},$}); \ No newline at end of file diff --git a/docs/html/md_readme.html b/docs/html/md_readme.html new file mode 100644 index 00000000..c4979525 --- /dev/null +++ b/docs/html/md_readme.html @@ -0,0 +1,275 @@ + + + + + + + +Firmata firmware for Arduino: Firmata + + + + + + + + + +
+
+ + + + + + +
+
Firmata firmware for Arduino +
+
Firmata is a protocol for communicating with microcontrollers from software on a host computer
+
+
+ + + + + + + + +
+
+ + +
+ +
+ +
+
+
+
Firmata
+
+
+

Gitter

+

Firmata is a protocol for communicating with microcontrollers from software on a host computer. The protocol can be implemented in firmware on any microcontroller architecture as well as software on any host computer software package. The Arduino repository described here is a Firmata library for Arduino and Arduino-compatible devices. If you would like to contribute to Firmata, please see the Contributing section below.

+

+Contents

+ +

+Usage

+

There are two main models of usage of Firmata. In one model, the author of the Arduino sketch uses the various methods provided by the Firmata library to selectively send and receive data between the Arduino device and the software running on the host computer. For example, a user can send analog data to the host using Firmata.sendAnalog(analogPin, analogRead(analogPin)) or send data packed in a string using Firmata.sendString(stringToSend). See File -> Examples -> Firmata -> AnalogFirmata & EchoString respectively for examples.

+

The second and more common model is to load a general purpose sketch called StandardFirmata (or one of the variants such as StandardFirmataPlus or StandardFirmataEthernet depending on your needs) on the Arduino board and then use the host computer exclusively to interact with the Arduino board. StandardFirmata is located in the Arduino IDE in File -> Examples -> Firmata.

+

+Firmata Client Libraries

+

Most of the time you will be interacting with Arduino with a client library on the host computers. Several Firmata client libraries have been implemented in a variety of popular programming languages:

+ +

Note: The above libraries may support various versions of the Firmata protocol and therefore may not support all features of the latest Firmata spec nor all Arduino and Arduino-compatible boards. Refer to the respective projects for details.

+

+Updating Firmata in the Arduino IDE - Arduino 1.6.4 and higher

+

If you want to update to the latest stable version:

+
    +
  1. Open the Arduino IDE and navigate to: Sketch > Include Library > Manage Libraries
  2. +
  3. Filter by "Firmata" and click on the "Firmata by Firmata Developers" item in the list of results.
  4. +
  5. Click the Select version dropdown and select the most recent version (note you can also install previous versions)
  6. +
  7. Click Install.
  8. +
+

+Cloning Firmata

+

If you are contributing to Firmata or otherwise need a version newer than the latest tagged release, you can clone Firmata directly to your Arduino/libraries/ directory (where 3rd party libraries are installed). This only works for Arduino 1.6.4 and higher, for older versions you need to clone into the Arduino application directory (see section below titled "Using the Source code rather than release archive"). Be sure to change the name to Firmata as follows:

+
$ git clone git@github.com:firmata/arduino.git ~/Documents/Arduino/libraries/Firmata
+

Update path above if you're using Windows or Linux or changed the default Arduino directory on OS X

+

+Updating Firmata in the Arduino IDE - older versions (<= 1.6.3 or 1.0.x)

+

Download the latest release (for Arduino 1.0.x or Arduino 1.5.6 or higher) and replace the existing Firmata folder in your Arduino application. See the instructions below for your platform.

+

Note that Arduino 1.5.0 - 1.5.5 are not supported. Please use Arduino 1.5.6 or higher (or Arduino 1.0.5 or 1.0.6).

+

+Mac OSX:

+

The Firmata library is contained within the Arduino package.

+
    +
  1. Navigate to the Arduino application
  2. +
  3. Right click on the application icon and select Show Package Contents
  4. +
  5. Navigate to: /Contents/Resources/Java/libraries/ and replace the existing Firmata folder with latest Firmata release (note there is a different download for Arduino 1.0.x vs 1.6.x)
  6. +
  7. Restart the Arduino application and the latest version of Firmata will be available.
  8. +
+

If you are using the Java 7 version of Arduino 1.5.7 or higher, the file path will differ slightly: Contents/Java/libraries/Firmata (no Resources directory).

+

+Windows:

+
    +
  1. Navigate to c:/Program\ Files/arduino-1.x/libraries/ and replace the existing Firmata folder with the latest Firmata release (note there is a different download for Arduino 1.0.x vs 1.6.x).
  2. +
  3. Restart the Arduino application and the latest version of Firmata will be available.
  4. +
+

Update the path and Arduino version as necessary

+

+Linux:

+
    +
  1. Navigate to ~/arduino-1.x/libraries/ and replace the existing Firmata folder with the latest Firmata release (note there is a different download for Arduino 1.0.x vs 1.6.x).
  2. +
  3. Restart the Arduino application and the latest version of Firmata will be available.
  4. +
+

Update the path and Arduino version as necessary

+

+Using the Source code rather than release archive (only for versions older than Arduino 1.6.3)

+

It is recommended you update to Arduino 1.6.4 or higher if possible, that way you can clone directly into the external Arduino/libraries/ directory which persists between Arduino application updates. Otherwise you will need to move your clone each time you update to a newer version of the Arduino IDE.

+

If you're stuck with an older version of the IDE, then follow these keep reading otherwise jump up to the "Cloning Firmata section above".

+

Clone this repo directly into the core Arduino application libraries directory. If you are using Arduino 1.5.x or <= 1.6.3, the repo directory structure will not match the Arduino library format, however it should still compile as long as you are using Arduino 1.5.7 or higher.

+

You will first need to remove the existing Firmata library, then clone firmata/arduino into an empty Firmata directory:

+
$ rm -r /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata
+
$ git clone git@github.com:firmata/arduino.git /Applications/Arduino.app/Contents/Resources/Java/libraries/Firmata
+

Update paths if you're using Windows or Linux

+

To generate properly formatted versions of Firmata (for Arduino 1.0.x and Arduino 1.6.x), run the release.sh script.

+

+Contributing

+

If you discover a bug or would like to propose a new feature, please open a new issue. Due to the limited memory of standard Arduino boards we cannot add every requested feature to StandardFirmata. Requests to add new features to StandardFirmata will be evaluated by the Firmata developers. However it is still possible to add new features to other Firmata implementations (Firmata is a protocol whereas StandardFirmata is just one of many possible implementations).

+

To contribute, fork this repository and create a new topic branch for the bug, feature or other existing issue you are addressing. Submit the pull request against the master branch.

+

If you would like to contribute but don't have a specific bugfix or new feature to contribute, you can take on an existing issue, see issues labeled "pull-request-encouraged". Add a comment to the issue to express your intent to begin work and/or to get any additional information about the issue.

+

You must thoroughly test your contributed code. In your pull request, describe tests performed to ensure that no existing code is broken and that any changes maintain backwards compatibility with the existing api. Test on multiple Arduino board variants if possible. We hope to enable some form of automated (or at least semi-automated) testing in the future, but for now any tests will need to be executed manually by the contributor and reviewers.

+

Use Artistic Style (astyle) to format your code. Set the following rules for the astyle formatter:

+
style = ""
+
indent-spaces = 2
+
indent-classes = true
+
indent-switches = true
+
indent-cases = true
+
indent-col1-comments = true
+
pad-oper = true
+
pad-header = true
+
keep-one-line-statements = true
+

If you happen to use Sublime Text, this astyle plugin is helpful. Set the above rules in the user settings file.

+
+
+ + + + diff --git a/docs/html/menu.js b/docs/html/menu.js new file mode 100644 index 00000000..433c15b8 --- /dev/null +++ b/docs/html/menu.js @@ -0,0 +1,50 @@ +/* + @licstart The following is the entire license notice for the + JavaScript code in this file. + + Copyright (C) 1997-2017 by Dimitri van Heesch + + 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 2 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + @licend The above is the entire license notice + for the JavaScript code in this file + */ +function initMenu(relPath,searchEnabled,serverSide,searchPage,search) { + function makeTree(data,relPath) { + var result=''; + if ('children' in data) { + result+=''; + } + return result; + } + + $('#main-nav').append(makeTree(menudata,relPath)); + $('#main-nav').children(':first').addClass('sm sm-dox').attr('id','main-menu'); + if (searchEnabled) { + if (serverSide) { + $('#main-menu').append('
  • '); + } else { + $('#main-menu').append('
  • '); + } + } + $('#main-menu').smartmenus(); +} +/* @license-end */ diff --git a/docs/html/menudata.js b/docs/html/menudata.js new file mode 100644 index 00000000..dc5f7896 --- /dev/null +++ b/docs/html/menudata.js @@ -0,0 +1,56 @@ +/* +@licstart The following is the entire license notice for the +JavaScript code in this file. + +Copyright (C) 1997-2019 by Dimitri van Heesch + +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., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +@licend The above is the entire license notice +for the JavaScript code in this file +*/ +var menudata={children:[ +{text:"Main Page",url:"index.html"}, +{text:"Classes",url:"annotated.html",children:[ +{text:"Class List",url:"annotated.html"}, +{text:"Class Index",url:"classes.html"}, +{text:"Class Members",url:"functions.html",children:[ +{text:"All",url:"functions.html",children:[ +{text:"a",url:"functions.html#index_a"}, +{text:"b",url:"functions.html#index_b"}, +{text:"d",url:"functions.html#index_d"}, +{text:"e",url:"functions.html#index_e"}, +{text:"f",url:"functions.html#index_f"}, +{text:"g",url:"functions.html#index_g"}, +{text:"i",url:"functions.html#index_i"}, +{text:"p",url:"functions.html#index_p"}, +{text:"q",url:"functions.html#index_q"}, +{text:"r",url:"functions.html#index_r"}, +{text:"s",url:"functions.html#index_s"}, +{text:"w",url:"functions.html#index_w"}]}, +{text:"Functions",url:"functions_func.html",children:[ +{text:"a",url:"functions_func.html#index_a"}, +{text:"b",url:"functions_func.html#index_b"}, +{text:"d",url:"functions_func.html#index_d"}, +{text:"e",url:"functions_func.html#index_e"}, +{text:"f",url:"functions_func.html#index_f"}, +{text:"g",url:"functions_func.html#index_g"}, +{text:"i",url:"functions_func.html#index_i"}, +{text:"p",url:"functions_func.html#index_p"}, +{text:"q",url:"functions_func.html#index_q"}, +{text:"r",url:"functions_func.html#index_r"}, +{text:"s",url:"functions_func.html#index_s"}, +{text:"w",url:"functions_func.html#index_w"}]}]}]}, +{text:"Files",url:"files.html",children:[ +{text:"File List",url:"files.html"}]}]} diff --git a/docs/html/nav_f.png b/docs/html/nav_f.png new file mode 100644 index 0000000000000000000000000000000000000000..72a58a529ed3a9ed6aa0c51a79cf207e026deee2 GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^j6iI`!2~2XGqLUlQVE_ejv*C{Z|{2ZH7M}7UYxc) zn!W8uqtnIQ>_z8U literal 0 HcmV?d00001 diff --git a/docs/html/nav_g.png b/docs/html/nav_g.png new file mode 100644 index 0000000000000000000000000000000000000000..2093a237a94f6c83e19ec6e5fd42f7ddabdafa81 GIT binary patch literal 95 zcmeAS@N?(olHy`uVBq!ia0vp^j6lrB!3HFm1ilyoDK$?Q$B+ufw|5PB85lU25BhtE tr?otc=hd~V+ws&_A@j8Fiv!KF$B+ufw|5=67#uj90@pIL wZ=Q8~_Ju`#59=RjDrmm`tMD@M=!-l18IR?&vFVdQ&MBb@0HFXL1|%O$WD@{VPM$7~Ar*{o?;hlAFyLXmaDC0y znK1_#cQqJWPES%4Uujug^TE?jMft$}Eq^WaR~)%f)vSNs&gek&x%A9X9sM + + + + + + +Firmata firmware for Arduino: Related Pages + + + + + + + + + +
    +
    + + + + + + +
    +
    Firmata firmware for Arduino +
    +
    Firmata is a protocol for communicating with microcontrollers from software on a host computer
    +
    +
    + + + + + + + +
    + +
    +
    + + +
    + +
    + +
    +
    +
    Related Pages
    +
    +
    +
    Here is a list of all related documentation pages:
    + + +
     Firmata
    +
    +
    + + + + diff --git a/docs/html/search/all_0.html b/docs/html/search/all_0.html new file mode 100644 index 00000000..a52d5f05 --- /dev/null +++ b/docs/html/search/all_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_0.js b/docs/html/search/all_0.js new file mode 100644 index 00000000..b0514350 --- /dev/null +++ b/docs/html/search/all_0.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['attach_0',['attach',['../classfirmata_1_1_firmata_class.html#adc3db897058f33e902097ce89bb01bb3',1,'firmata::FirmataClass::attach(uint8_t command, systemCallbackFunction newFunction)'],['../classfirmata_1_1_firmata_class.html#a074887a70f9aca0c0aae7e9bdc103f77',1,'firmata::FirmataClass::attach(uint8_t command, stringCallbackFunction newFunction)'],['../classfirmata_1_1_firmata_class.html#a78e360c0c8d70cffeb9c935fdec23f77',1,'firmata::FirmataClass::attach(uint8_t command, sysexCallbackFunction newFunction)'],['../classfirmata_1_1_firmata_parser.html#a2a472a925ed7e626ed36dee94ceae45e',1,'firmata::FirmataParser::attach(uint8_t command, callbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#ae176414892a2d240b921c2b8037a8ade',1,'firmata::FirmataParser::attach(dataBufferOverflowCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#a239b37e09dea042d229fc2171d3a1979',1,'firmata::FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#aaa1d755b20b21e528bfa62d6a7c2dc0f',1,'firmata::FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#affc821e7742d889965e61b248c204842',1,'firmata::FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#a876105f2203f5e8f1fb06c8236a96933',1,'firmata::FirmataParser::attach(uint8_t command, versionCallbackFunction newFunction, void *context=NULL)']]], + ['available_1',['available',['../classfirmata_1_1_firmata_class.html#a119734b867186567c1cd011e52e59d2d',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/all_1.html b/docs/html/search/all_1.html new file mode 100644 index 00000000..0fcb7040 --- /dev/null +++ b/docs/html/search/all_1.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_1.js b/docs/html/search/all_1.js new file mode 100644 index 00000000..bda5c136 --- /dev/null +++ b/docs/html/search/all_1.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['begin_2',['begin',['../classfirmata_1_1_firmata_class.html#a2fddcc643892bec2f4aa7aef6dba70eb',1,'firmata::FirmataClass::begin()'],['../classfirmata_1_1_firmata_class.html#ab0b7b837d2c32b4ce79e62895ced2731',1,'firmata::FirmataClass::begin(long)'],['../classfirmata_1_1_firmata_class.html#a0c7b0e10168e3c5dc6442d77c65a156e',1,'firmata::FirmataClass::begin(Stream &s)'],['../classfirmata_1_1_firmata_marshaller.html#a5be18ca3658875dbe5580c2254071c76',1,'firmata::FirmataMarshaller::begin()']]], + ['blinkversion_3',['blinkVersion',['../classfirmata_1_1_firmata_class.html#a9421550f2501fc1df60fd174b154e606',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/all_2.html b/docs/html/search/all_2.html new file mode 100644 index 00000000..19c530f2 --- /dev/null +++ b/docs/html/search/all_2.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_2.js b/docs/html/search/all_2.js new file mode 100644 index 00000000..eb289a71 --- /dev/null +++ b/docs/html/search/all_2.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['detach_4',['detach',['../classfirmata_1_1_firmata_class.html#a5db0faee74b9291d1b783d2dde0929d1',1,'firmata::FirmataClass::detach()'],['../classfirmata_1_1_firmata_parser.html#a7cd707386c0807bee733a3e27d161c7d',1,'firmata::FirmataParser::detach(uint8_t command)'],['../classfirmata_1_1_firmata_parser.html#a280ac17e428f8374afd30bce75e9a861',1,'firmata::FirmataParser::detach(dataBufferOverflowCallbackFunction)']]], + ['disableblinkversion_5',['disableBlinkVersion',['../classfirmata_1_1_firmata_class.html#a5ddba465c3772f841828ef82c79d4307',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/all_3.html b/docs/html/search/all_3.html new file mode 100644 index 00000000..1ae887fc --- /dev/null +++ b/docs/html/search/all_3.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_3.js b/docs/html/search/all_3.js new file mode 100644 index 00000000..f78f16bd --- /dev/null +++ b/docs/html/search/all_3.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['end_6',['end',['../classfirmata_1_1_firmata_marshaller.html#ab856434fc577b1e069cba51c39daf1de',1,'firmata::FirmataMarshaller']]], + ['endsysex_7',['endSysex',['../classfirmata_1_1_firmata_class.html#a9bb68afbb1d37a7990f59a1d419e64c9',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/all_4.html b/docs/html/search/all_4.html new file mode 100644 index 00000000..14c90ef5 --- /dev/null +++ b/docs/html/search/all_4.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_4.js b/docs/html/search/all_4.js new file mode 100644 index 00000000..5ebeac62 --- /dev/null +++ b/docs/html/search/all_4.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['firmataclass_8',['FirmataClass',['../classfirmata_1_1_firmata_class.html',1,'firmata::FirmataClass'],['../classfirmata_1_1_firmata_class.html#a75b035ab8d96d87d28deeb87badfe11a',1,'firmata::FirmataClass::FirmataClass()']]], + ['firmatamarshaller_9',['FirmataMarshaller',['../classfirmata_1_1_firmata_marshaller.html',1,'firmata::FirmataMarshaller'],['../classfirmata_1_1_firmata_marshaller.html#ad1a42532bdf77088c47c1a62f5a03829',1,'firmata::FirmataMarshaller::FirmataMarshaller()']]], + ['firmataparser_10',['FirmataParser',['../classfirmata_1_1_firmata_parser.html',1,'firmata::FirmataParser'],['../classfirmata_1_1_firmata_parser.html#ac8c388b593a00e88856646712beae68b',1,'firmata::FirmataParser::FirmataParser()']]], + ['firmata_11',['Firmata',['../index.html',1,'']]] +]; diff --git a/docs/html/search/all_5.html b/docs/html/search/all_5.html new file mode 100644 index 00000000..60fa53e9 --- /dev/null +++ b/docs/html/search/all_5.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_5.js b/docs/html/search/all_5.js new file mode 100644 index 00000000..3a076e7b --- /dev/null +++ b/docs/html/search/all_5.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['getpinmode_12',['getPinMode',['../classfirmata_1_1_firmata_class.html#a0c434227456ce2ba97b3b1142c329f96',1,'firmata::FirmataClass']]], + ['getpinstate_13',['getPinState',['../classfirmata_1_1_firmata_class.html#acf5d4f460b9a2298653d4a71de918dfe',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/all_6.html b/docs/html/search/all_6.html new file mode 100644 index 00000000..71803631 --- /dev/null +++ b/docs/html/search/all_6.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_6.js b/docs/html/search/all_6.js new file mode 100644 index 00000000..da4c8abb --- /dev/null +++ b/docs/html/search/all_6.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['isparsingmessage_14',['isParsingMessage',['../classfirmata_1_1_firmata_class.html#a58e9d787957c3085f22d33b59b1f6ea6',1,'firmata::FirmataClass::isParsingMessage()'],['../classfirmata_1_1_firmata_parser.html#a67902b70695eaf0cf8f7b06175ca3902',1,'firmata::FirmataParser::isParsingMessage()']]] +]; diff --git a/docs/html/search/all_7.html b/docs/html/search/all_7.html new file mode 100644 index 00000000..ee6d2e4a --- /dev/null +++ b/docs/html/search/all_7.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_7.js b/docs/html/search/all_7.js new file mode 100644 index 00000000..923c587c --- /dev/null +++ b/docs/html/search/all_7.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['parse_15',['parse',['../classfirmata_1_1_firmata_class.html#aaeaac8b1f8facf070615b0035120c432',1,'firmata::FirmataClass::parse()'],['../classfirmata_1_1_firmata_parser.html#a754c97b890b7fd66c8d953a3e615acbf',1,'firmata::FirmataParser::parse()']]], + ['printfirmwareversion_16',['printFirmwareVersion',['../classfirmata_1_1_firmata_class.html#abe49261eab0bd4892a09fa8b8980b11a',1,'firmata::FirmataClass']]], + ['printversion_17',['printVersion',['../classfirmata_1_1_firmata_class.html#abd8a0370db6d9e923e7e3d5836e78d7a',1,'firmata::FirmataClass']]], + ['processinput_18',['processInput',['../classfirmata_1_1_firmata_class.html#aa698f5f5a234173d5eebb54831350676',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/all_8.html b/docs/html/search/all_8.html new file mode 100644 index 00000000..7829aa40 --- /dev/null +++ b/docs/html/search/all_8.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_8.js b/docs/html/search/all_8.js new file mode 100644 index 00000000..518d5d64 --- /dev/null +++ b/docs/html/search/all_8.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['queryfirmwareversion_19',['queryFirmwareVersion',['../classfirmata_1_1_firmata_marshaller.html#af954bcf09b77458b3c4f032897d14697',1,'firmata::FirmataMarshaller']]], + ['queryversion_20',['queryVersion',['../classfirmata_1_1_firmata_marshaller.html#a488fbbd372c894ec78ebb99e0faf5167',1,'firmata::FirmataMarshaller']]] +]; diff --git a/docs/html/search/all_9.html b/docs/html/search/all_9.html new file mode 100644 index 00000000..e4242c71 --- /dev/null +++ b/docs/html/search/all_9.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_9.js b/docs/html/search/all_9.js new file mode 100644 index 00000000..0c28921f --- /dev/null +++ b/docs/html/search/all_9.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['reportanalogdisable_21',['reportAnalogDisable',['../classfirmata_1_1_firmata_marshaller.html#a2668d1332704bbf9938f386e247a8f30',1,'firmata::FirmataMarshaller']]], + ['reportanalogenable_22',['reportAnalogEnable',['../classfirmata_1_1_firmata_marshaller.html#a67b3db7232143acf63bd48b765fcc4db',1,'firmata::FirmataMarshaller']]], + ['reportdigitalportdisable_23',['reportDigitalPortDisable',['../classfirmata_1_1_firmata_marshaller.html#aa00582e6e014605a65a8953f8275a5ad',1,'firmata::FirmataMarshaller']]], + ['reportdigitalportenable_24',['reportDigitalPortEnable',['../classfirmata_1_1_firmata_marshaller.html#a608c28cdc966c33d0cc2239d9465ef7c',1,'firmata::FirmataMarshaller']]] +]; diff --git a/docs/html/search/all_a.html b/docs/html/search/all_a.html new file mode 100644 index 00000000..47a4a78d --- /dev/null +++ b/docs/html/search/all_a.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_a.js b/docs/html/search/all_a.js new file mode 100644 index 00000000..6768baad --- /dev/null +++ b/docs/html/search/all_a.js @@ -0,0 +1,22 @@ +var searchData= +[ + ['sendanalog_25',['sendAnalog',['../classfirmata_1_1_firmata_class.html#ae14e1d8d9bd72068f6e8ca07721e8dda',1,'firmata::FirmataClass::sendAnalog()'],['../classfirmata_1_1_firmata_marshaller.html#a4d9f2d3bb058237404dfe433cfe7571a',1,'firmata::FirmataMarshaller::sendAnalog()']]], + ['sendanalogmappingquery_26',['sendAnalogMappingQuery',['../classfirmata_1_1_firmata_marshaller.html#a1c987a534cc8dd197eb2f2a728bdacb3',1,'firmata::FirmataMarshaller']]], + ['sendcapabilityquery_27',['sendCapabilityQuery',['../classfirmata_1_1_firmata_marshaller.html#a1f1c5ce29ba4488306c9a1e3f158b781',1,'firmata::FirmataMarshaller']]], + ['senddigital_28',['sendDigital',['../classfirmata_1_1_firmata_marshaller.html#a2d90627f0543b6298be71f7d903399b3',1,'firmata::FirmataMarshaller']]], + ['senddigitalport_29',['sendDigitalPort',['../classfirmata_1_1_firmata_class.html#a799b91e5a888dd21b066a2020d8e2b68',1,'firmata::FirmataClass::sendDigitalPort()'],['../classfirmata_1_1_firmata_marshaller.html#a346dcb4487a51efaa95de42d292ad951',1,'firmata::FirmataMarshaller::sendDigitalPort()']]], + ['sendfirmwareversion_30',['sendFirmwareVersion',['../classfirmata_1_1_firmata_marshaller.html#aed71d62cc41f2e0bf3f161894b91be7c',1,'firmata::FirmataMarshaller']]], + ['sendpinmode_31',['sendPinMode',['../classfirmata_1_1_firmata_marshaller.html#a36b6cc103609d900cce36149a239f221',1,'firmata::FirmataMarshaller']]], + ['sendpinstatequery_32',['sendPinStateQuery',['../classfirmata_1_1_firmata_marshaller.html#afc378ab4a39c843d4419acdee944972b',1,'firmata::FirmataMarshaller']]], + ['sendstring_33',['sendString',['../classfirmata_1_1_firmata_class.html#abe11f621154afd308926129de349fc6e',1,'firmata::FirmataClass::sendString(const char *string)'],['../classfirmata_1_1_firmata_class.html#ab139c0d784e69003c88eb5be8807dcdf',1,'firmata::FirmataClass::sendString(byte command, const char *string)'],['../classfirmata_1_1_firmata_marshaller.html#a483ac2dea885ab3472dc38b99bfdec2f',1,'firmata::FirmataMarshaller::sendString()']]], + ['sendsysex_34',['sendSysex',['../classfirmata_1_1_firmata_class.html#a81e2de5b37eb2372c8a3d9a43d5eb0cc',1,'firmata::FirmataClass::sendSysex()'],['../classfirmata_1_1_firmata_marshaller.html#ade4f4592877ec0b9f8d6c74e909bad8e',1,'firmata::FirmataMarshaller::sendSysex()']]], + ['sendvalueastwo7bitbytes_35',['sendValueAsTwo7bitBytes',['../classfirmata_1_1_firmata_class.html#a770e43f26f18204e43acebf9202a6d39',1,'firmata::FirmataClass']]], + ['sendversion_36',['sendVersion',['../classfirmata_1_1_firmata_marshaller.html#a95d58949e32ad285088705dbe5680b29',1,'firmata::FirmataMarshaller']]], + ['setdatabufferofsize_37',['setDataBufferOfSize',['../classfirmata_1_1_firmata_parser.html#a8fbe143ddb428a97c00a15993c31a516',1,'firmata::FirmataParser']]], + ['setfirmwarenameandversion_38',['setFirmwareNameAndVersion',['../classfirmata_1_1_firmata_class.html#ab7aa66b528027566c15b7d64c8cd0f89',1,'firmata::FirmataClass']]], + ['setpinmode_39',['setPinMode',['../classfirmata_1_1_firmata_class.html#a32c41dd94c1d23aa0e6d3d1dbe5c0c04',1,'firmata::FirmataClass']]], + ['setpinstate_40',['setPinState',['../classfirmata_1_1_firmata_class.html#aa9f98ba5069823b4c1d08db9f8999ba8',1,'firmata::FirmataClass']]], + ['setsamplinginterval_41',['setSamplingInterval',['../classfirmata_1_1_firmata_marshaller.html#abb8f4c79dd8a0dbee3f5e04c587ae20c',1,'firmata::FirmataMarshaller']]], + ['startsysex_42',['startSysex',['../classfirmata_1_1_firmata_class.html#a3cc7ea1af348bca3ea0bd570314cada3',1,'firmata::FirmataClass']]], + ['systemreset_43',['systemReset',['../classfirmata_1_1_firmata_marshaller.html#a3a585937f94b1f9e51797e5950a33206',1,'firmata::FirmataMarshaller']]] +]; diff --git a/docs/html/search/all_b.html b/docs/html/search/all_b.html new file mode 100644 index 00000000..1320a43f --- /dev/null +++ b/docs/html/search/all_b.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/all_b.js b/docs/html/search/all_b.js new file mode 100644 index 00000000..18c55ecd --- /dev/null +++ b/docs/html/search/all_b.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['write_44',['write',['../classfirmata_1_1_firmata_class.html#ae8f29a829e17379602fcb9fd6a497807',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/classes_0.html b/docs/html/search/classes_0.html new file mode 100644 index 00000000..d585e6a9 --- /dev/null +++ b/docs/html/search/classes_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/classes_0.js b/docs/html/search/classes_0.js new file mode 100644 index 00000000..48d27db1 --- /dev/null +++ b/docs/html/search/classes_0.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['firmataclass_45',['FirmataClass',['../classfirmata_1_1_firmata_class.html',1,'firmata']]], + ['firmatamarshaller_46',['FirmataMarshaller',['../classfirmata_1_1_firmata_marshaller.html',1,'firmata']]], + ['firmataparser_47',['FirmataParser',['../classfirmata_1_1_firmata_parser.html',1,'firmata']]] +]; diff --git a/docs/html/search/close.png b/docs/html/search/close.png new file mode 100644 index 0000000000000000000000000000000000000000..9342d3dfeea7b7c4ee610987e717804b5a42ceb9 GIT binary patch literal 273 zcmV+s0q*{ZP)4(RlMby96)VwnbG{ zbe&}^BDn7x>$<{ck4zAK-=nT;=hHG)kmplIF${xqm8db3oX6wT3bvp`TE@m0cg;b) zBuSL}5?N7O(iZLdAlz@)b)Rd~DnSsSX&P5qC`XwuFwcAYLC+d2>+1(8on;wpt8QIC X2MT$R4iQDd00000NkvXXu0mjfia~GN literal 0 HcmV?d00001 diff --git a/docs/html/search/functions_0.html b/docs/html/search/functions_0.html new file mode 100644 index 00000000..8a729f78 --- /dev/null +++ b/docs/html/search/functions_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_0.js b/docs/html/search/functions_0.js new file mode 100644 index 00000000..8ab9073e --- /dev/null +++ b/docs/html/search/functions_0.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['attach_48',['attach',['../classfirmata_1_1_firmata_class.html#adc3db897058f33e902097ce89bb01bb3',1,'firmata::FirmataClass::attach(uint8_t command, systemCallbackFunction newFunction)'],['../classfirmata_1_1_firmata_class.html#a074887a70f9aca0c0aae7e9bdc103f77',1,'firmata::FirmataClass::attach(uint8_t command, stringCallbackFunction newFunction)'],['../classfirmata_1_1_firmata_class.html#a78e360c0c8d70cffeb9c935fdec23f77',1,'firmata::FirmataClass::attach(uint8_t command, sysexCallbackFunction newFunction)'],['../classfirmata_1_1_firmata_parser.html#a2a472a925ed7e626ed36dee94ceae45e',1,'firmata::FirmataParser::attach(uint8_t command, callbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#ae176414892a2d240b921c2b8037a8ade',1,'firmata::FirmataParser::attach(dataBufferOverflowCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#a239b37e09dea042d229fc2171d3a1979',1,'firmata::FirmataParser::attach(uint8_t command, stringCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#aaa1d755b20b21e528bfa62d6a7c2dc0f',1,'firmata::FirmataParser::attach(uint8_t command, sysexCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#affc821e7742d889965e61b248c204842',1,'firmata::FirmataParser::attach(uint8_t command, systemCallbackFunction newFunction, void *context=NULL)'],['../classfirmata_1_1_firmata_parser.html#a876105f2203f5e8f1fb06c8236a96933',1,'firmata::FirmataParser::attach(uint8_t command, versionCallbackFunction newFunction, void *context=NULL)']]], + ['available_49',['available',['../classfirmata_1_1_firmata_class.html#a119734b867186567c1cd011e52e59d2d',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/functions_1.html b/docs/html/search/functions_1.html new file mode 100644 index 00000000..d4929aaf --- /dev/null +++ b/docs/html/search/functions_1.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_1.js b/docs/html/search/functions_1.js new file mode 100644 index 00000000..8e87ba1e --- /dev/null +++ b/docs/html/search/functions_1.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['begin_50',['begin',['../classfirmata_1_1_firmata_class.html#a2fddcc643892bec2f4aa7aef6dba70eb',1,'firmata::FirmataClass::begin()'],['../classfirmata_1_1_firmata_class.html#ab0b7b837d2c32b4ce79e62895ced2731',1,'firmata::FirmataClass::begin(long)'],['../classfirmata_1_1_firmata_class.html#a0c7b0e10168e3c5dc6442d77c65a156e',1,'firmata::FirmataClass::begin(Stream &s)'],['../classfirmata_1_1_firmata_marshaller.html#a5be18ca3658875dbe5580c2254071c76',1,'firmata::FirmataMarshaller::begin()']]], + ['blinkversion_51',['blinkVersion',['../classfirmata_1_1_firmata_class.html#a9421550f2501fc1df60fd174b154e606',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/functions_2.html b/docs/html/search/functions_2.html new file mode 100644 index 00000000..07e3fdad --- /dev/null +++ b/docs/html/search/functions_2.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_2.js b/docs/html/search/functions_2.js new file mode 100644 index 00000000..63c6a6d0 --- /dev/null +++ b/docs/html/search/functions_2.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['detach_52',['detach',['../classfirmata_1_1_firmata_class.html#a5db0faee74b9291d1b783d2dde0929d1',1,'firmata::FirmataClass::detach()'],['../classfirmata_1_1_firmata_parser.html#a7cd707386c0807bee733a3e27d161c7d',1,'firmata::FirmataParser::detach(uint8_t command)'],['../classfirmata_1_1_firmata_parser.html#a280ac17e428f8374afd30bce75e9a861',1,'firmata::FirmataParser::detach(dataBufferOverflowCallbackFunction)']]], + ['disableblinkversion_53',['disableBlinkVersion',['../classfirmata_1_1_firmata_class.html#a5ddba465c3772f841828ef82c79d4307',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/functions_3.html b/docs/html/search/functions_3.html new file mode 100644 index 00000000..40bd389e --- /dev/null +++ b/docs/html/search/functions_3.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_3.js b/docs/html/search/functions_3.js new file mode 100644 index 00000000..d019efe2 --- /dev/null +++ b/docs/html/search/functions_3.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['end_54',['end',['../classfirmata_1_1_firmata_marshaller.html#ab856434fc577b1e069cba51c39daf1de',1,'firmata::FirmataMarshaller']]], + ['endsysex_55',['endSysex',['../classfirmata_1_1_firmata_class.html#a9bb68afbb1d37a7990f59a1d419e64c9',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/functions_4.html b/docs/html/search/functions_4.html new file mode 100644 index 00000000..8a4df4cd --- /dev/null +++ b/docs/html/search/functions_4.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_4.js b/docs/html/search/functions_4.js new file mode 100644 index 00000000..caec8006 --- /dev/null +++ b/docs/html/search/functions_4.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['firmataclass_56',['FirmataClass',['../classfirmata_1_1_firmata_class.html#a75b035ab8d96d87d28deeb87badfe11a',1,'firmata::FirmataClass']]], + ['firmatamarshaller_57',['FirmataMarshaller',['../classfirmata_1_1_firmata_marshaller.html#ad1a42532bdf77088c47c1a62f5a03829',1,'firmata::FirmataMarshaller']]], + ['firmataparser_58',['FirmataParser',['../classfirmata_1_1_firmata_parser.html#ac8c388b593a00e88856646712beae68b',1,'firmata::FirmataParser']]] +]; diff --git a/docs/html/search/functions_5.html b/docs/html/search/functions_5.html new file mode 100644 index 00000000..2b983b21 --- /dev/null +++ b/docs/html/search/functions_5.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_5.js b/docs/html/search/functions_5.js new file mode 100644 index 00000000..75d8c445 --- /dev/null +++ b/docs/html/search/functions_5.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['getpinmode_59',['getPinMode',['../classfirmata_1_1_firmata_class.html#a0c434227456ce2ba97b3b1142c329f96',1,'firmata::FirmataClass']]], + ['getpinstate_60',['getPinState',['../classfirmata_1_1_firmata_class.html#acf5d4f460b9a2298653d4a71de918dfe',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/functions_6.html b/docs/html/search/functions_6.html new file mode 100644 index 00000000..f7d283d1 --- /dev/null +++ b/docs/html/search/functions_6.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_6.js b/docs/html/search/functions_6.js new file mode 100644 index 00000000..cfa73aeb --- /dev/null +++ b/docs/html/search/functions_6.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['isparsingmessage_61',['isParsingMessage',['../classfirmata_1_1_firmata_class.html#a58e9d787957c3085f22d33b59b1f6ea6',1,'firmata::FirmataClass::isParsingMessage()'],['../classfirmata_1_1_firmata_parser.html#a67902b70695eaf0cf8f7b06175ca3902',1,'firmata::FirmataParser::isParsingMessage()']]] +]; diff --git a/docs/html/search/functions_7.html b/docs/html/search/functions_7.html new file mode 100644 index 00000000..a74fe44a --- /dev/null +++ b/docs/html/search/functions_7.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_7.js b/docs/html/search/functions_7.js new file mode 100644 index 00000000..746df096 --- /dev/null +++ b/docs/html/search/functions_7.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['parse_62',['parse',['../classfirmata_1_1_firmata_class.html#aaeaac8b1f8facf070615b0035120c432',1,'firmata::FirmataClass::parse()'],['../classfirmata_1_1_firmata_parser.html#a754c97b890b7fd66c8d953a3e615acbf',1,'firmata::FirmataParser::parse()']]], + ['printfirmwareversion_63',['printFirmwareVersion',['../classfirmata_1_1_firmata_class.html#abe49261eab0bd4892a09fa8b8980b11a',1,'firmata::FirmataClass']]], + ['printversion_64',['printVersion',['../classfirmata_1_1_firmata_class.html#abd8a0370db6d9e923e7e3d5836e78d7a',1,'firmata::FirmataClass']]], + ['processinput_65',['processInput',['../classfirmata_1_1_firmata_class.html#aa698f5f5a234173d5eebb54831350676',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/functions_8.html b/docs/html/search/functions_8.html new file mode 100644 index 00000000..75fc0bea --- /dev/null +++ b/docs/html/search/functions_8.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_8.js b/docs/html/search/functions_8.js new file mode 100644 index 00000000..2d768241 --- /dev/null +++ b/docs/html/search/functions_8.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['queryfirmwareversion_66',['queryFirmwareVersion',['../classfirmata_1_1_firmata_marshaller.html#af954bcf09b77458b3c4f032897d14697',1,'firmata::FirmataMarshaller']]], + ['queryversion_67',['queryVersion',['../classfirmata_1_1_firmata_marshaller.html#a488fbbd372c894ec78ebb99e0faf5167',1,'firmata::FirmataMarshaller']]] +]; diff --git a/docs/html/search/functions_9.html b/docs/html/search/functions_9.html new file mode 100644 index 00000000..7541c9e3 --- /dev/null +++ b/docs/html/search/functions_9.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_9.js b/docs/html/search/functions_9.js new file mode 100644 index 00000000..56d890a8 --- /dev/null +++ b/docs/html/search/functions_9.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['reportanalogdisable_68',['reportAnalogDisable',['../classfirmata_1_1_firmata_marshaller.html#a2668d1332704bbf9938f386e247a8f30',1,'firmata::FirmataMarshaller']]], + ['reportanalogenable_69',['reportAnalogEnable',['../classfirmata_1_1_firmata_marshaller.html#a67b3db7232143acf63bd48b765fcc4db',1,'firmata::FirmataMarshaller']]], + ['reportdigitalportdisable_70',['reportDigitalPortDisable',['../classfirmata_1_1_firmata_marshaller.html#aa00582e6e014605a65a8953f8275a5ad',1,'firmata::FirmataMarshaller']]], + ['reportdigitalportenable_71',['reportDigitalPortEnable',['../classfirmata_1_1_firmata_marshaller.html#a608c28cdc966c33d0cc2239d9465ef7c',1,'firmata::FirmataMarshaller']]] +]; diff --git a/docs/html/search/functions_a.html b/docs/html/search/functions_a.html new file mode 100644 index 00000000..5a5be630 --- /dev/null +++ b/docs/html/search/functions_a.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_a.js b/docs/html/search/functions_a.js new file mode 100644 index 00000000..fca5da61 --- /dev/null +++ b/docs/html/search/functions_a.js @@ -0,0 +1,22 @@ +var searchData= +[ + ['sendanalog_72',['sendAnalog',['../classfirmata_1_1_firmata_class.html#ae14e1d8d9bd72068f6e8ca07721e8dda',1,'firmata::FirmataClass::sendAnalog()'],['../classfirmata_1_1_firmata_marshaller.html#a4d9f2d3bb058237404dfe433cfe7571a',1,'firmata::FirmataMarshaller::sendAnalog()']]], + ['sendanalogmappingquery_73',['sendAnalogMappingQuery',['../classfirmata_1_1_firmata_marshaller.html#a1c987a534cc8dd197eb2f2a728bdacb3',1,'firmata::FirmataMarshaller']]], + ['sendcapabilityquery_74',['sendCapabilityQuery',['../classfirmata_1_1_firmata_marshaller.html#a1f1c5ce29ba4488306c9a1e3f158b781',1,'firmata::FirmataMarshaller']]], + ['senddigital_75',['sendDigital',['../classfirmata_1_1_firmata_marshaller.html#a2d90627f0543b6298be71f7d903399b3',1,'firmata::FirmataMarshaller']]], + ['senddigitalport_76',['sendDigitalPort',['../classfirmata_1_1_firmata_class.html#a799b91e5a888dd21b066a2020d8e2b68',1,'firmata::FirmataClass::sendDigitalPort()'],['../classfirmata_1_1_firmata_marshaller.html#a346dcb4487a51efaa95de42d292ad951',1,'firmata::FirmataMarshaller::sendDigitalPort()']]], + ['sendfirmwareversion_77',['sendFirmwareVersion',['../classfirmata_1_1_firmata_marshaller.html#aed71d62cc41f2e0bf3f161894b91be7c',1,'firmata::FirmataMarshaller']]], + ['sendpinmode_78',['sendPinMode',['../classfirmata_1_1_firmata_marshaller.html#a36b6cc103609d900cce36149a239f221',1,'firmata::FirmataMarshaller']]], + ['sendpinstatequery_79',['sendPinStateQuery',['../classfirmata_1_1_firmata_marshaller.html#afc378ab4a39c843d4419acdee944972b',1,'firmata::FirmataMarshaller']]], + ['sendstring_80',['sendString',['../classfirmata_1_1_firmata_class.html#abe11f621154afd308926129de349fc6e',1,'firmata::FirmataClass::sendString(const char *string)'],['../classfirmata_1_1_firmata_class.html#ab139c0d784e69003c88eb5be8807dcdf',1,'firmata::FirmataClass::sendString(byte command, const char *string)'],['../classfirmata_1_1_firmata_marshaller.html#a483ac2dea885ab3472dc38b99bfdec2f',1,'firmata::FirmataMarshaller::sendString()']]], + ['sendsysex_81',['sendSysex',['../classfirmata_1_1_firmata_class.html#a81e2de5b37eb2372c8a3d9a43d5eb0cc',1,'firmata::FirmataClass::sendSysex()'],['../classfirmata_1_1_firmata_marshaller.html#ade4f4592877ec0b9f8d6c74e909bad8e',1,'firmata::FirmataMarshaller::sendSysex()']]], + ['sendvalueastwo7bitbytes_82',['sendValueAsTwo7bitBytes',['../classfirmata_1_1_firmata_class.html#a770e43f26f18204e43acebf9202a6d39',1,'firmata::FirmataClass']]], + ['sendversion_83',['sendVersion',['../classfirmata_1_1_firmata_marshaller.html#a95d58949e32ad285088705dbe5680b29',1,'firmata::FirmataMarshaller']]], + ['setdatabufferofsize_84',['setDataBufferOfSize',['../classfirmata_1_1_firmata_parser.html#a8fbe143ddb428a97c00a15993c31a516',1,'firmata::FirmataParser']]], + ['setfirmwarenameandversion_85',['setFirmwareNameAndVersion',['../classfirmata_1_1_firmata_class.html#ab7aa66b528027566c15b7d64c8cd0f89',1,'firmata::FirmataClass']]], + ['setpinmode_86',['setPinMode',['../classfirmata_1_1_firmata_class.html#a32c41dd94c1d23aa0e6d3d1dbe5c0c04',1,'firmata::FirmataClass']]], + ['setpinstate_87',['setPinState',['../classfirmata_1_1_firmata_class.html#aa9f98ba5069823b4c1d08db9f8999ba8',1,'firmata::FirmataClass']]], + ['setsamplinginterval_88',['setSamplingInterval',['../classfirmata_1_1_firmata_marshaller.html#abb8f4c79dd8a0dbee3f5e04c587ae20c',1,'firmata::FirmataMarshaller']]], + ['startsysex_89',['startSysex',['../classfirmata_1_1_firmata_class.html#a3cc7ea1af348bca3ea0bd570314cada3',1,'firmata::FirmataClass']]], + ['systemreset_90',['systemReset',['../classfirmata_1_1_firmata_marshaller.html#a3a585937f94b1f9e51797e5950a33206',1,'firmata::FirmataMarshaller']]] +]; diff --git a/docs/html/search/functions_b.html b/docs/html/search/functions_b.html new file mode 100644 index 00000000..fc2d5aa4 --- /dev/null +++ b/docs/html/search/functions_b.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/functions_b.js b/docs/html/search/functions_b.js new file mode 100644 index 00000000..4eaed0dc --- /dev/null +++ b/docs/html/search/functions_b.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['write_91',['write',['../classfirmata_1_1_firmata_class.html#ae8f29a829e17379602fcb9fd6a497807',1,'firmata::FirmataClass']]] +]; diff --git a/docs/html/search/mag_sel.png b/docs/html/search/mag_sel.png new file mode 100644 index 0000000000000000000000000000000000000000..39c0ed52a25dd9d080ee0d42ae6c6042bdfa04d7 GIT binary patch literal 465 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz6!2%?$TA$hhDVB6cUq=Rpjs4tz5?O(Kg=CK) zUj~NU84L`?eGCi_EEpJ?t}-xGu`@87+QPtK?83kxQ`TapwHK(CDaqU2h2ejD|C#+j z9%q3^WHAE+w=f7ZGR&GI0Tg5}@$_|Nf5gMiEhFgvHvB$N=!mC_V~EE2vzPXI9ZnEo zd+1zHor@dYLod2Y{ z@R$7$Z!PXTbY$|@#T!bMzm?`b<(R`cbw(gxJHzu zB$lLFB^RXvDF!10LknF)BV7aY5JN*NBMU1-b8Q0yD+2>vd*|CI8glbfGSez?Ylunu RoetE%;OXk;vd$@?2>>CYplSdB literal 0 HcmV?d00001 diff --git a/docs/html/search/nomatches.html b/docs/html/search/nomatches.html new file mode 100644 index 00000000..43773208 --- /dev/null +++ b/docs/html/search/nomatches.html @@ -0,0 +1,12 @@ + + + + + + + +
    +
    No Matches
    +
    + + diff --git a/docs/html/search/pages_0.html b/docs/html/search/pages_0.html new file mode 100644 index 00000000..32cbf498 --- /dev/null +++ b/docs/html/search/pages_0.html @@ -0,0 +1,30 @@ + + + + + + + + + +
    +
    Loading...
    +
    + +
    Searching...
    +
    No Matches
    + +
    + + diff --git a/docs/html/search/pages_0.js b/docs/html/search/pages_0.js new file mode 100644 index 00000000..a24cb5da --- /dev/null +++ b/docs/html/search/pages_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['firmata_92',['Firmata',['../index.html',1,'']]] +]; diff --git a/docs/html/search/search.css b/docs/html/search/search.css new file mode 100644 index 00000000..3cf9df94 --- /dev/null +++ b/docs/html/search/search.css @@ -0,0 +1,271 @@ +/*---------------- Search Box */ + +#FSearchBox { + float: left; +} + +#MSearchBox { + white-space : nowrap; + float: none; + margin-top: 8px; + right: 0px; + width: 170px; + height: 24px; + z-index: 102; +} + +#MSearchBox .left +{ + display:block; + position:absolute; + left:10px; + width:20px; + height:19px; + background:url('search_l.png') no-repeat; + background-position:right; +} + +#MSearchSelect { + display:block; + position:absolute; + width:20px; + height:19px; +} + +.left #MSearchSelect { + left:4px; +} + +.right #MSearchSelect { + right:5px; +} + +#MSearchField { + display:block; + position:absolute; + height:19px; + background:url('search_m.png') repeat-x; + border:none; + width:115px; + margin-left:20px; + padding-left:4px; + color: #909090; + outline: none; + font: 9pt Arial, Verdana, sans-serif; + -webkit-border-radius: 0px; +} + +#FSearchBox #MSearchField { + margin-left:15px; +} + +#MSearchBox .right { + display:block; + position:absolute; + right:10px; + top:8px; + width:20px; + height:19px; + background:url('search_r.png') no-repeat; + background-position:left; +} + +#MSearchClose { + display: none; + position: absolute; + top: 4px; + background : none; + border: none; + margin: 0px 4px 0px 0px; + padding: 0px 0px; + outline: none; +} + +.left #MSearchClose { + left: 6px; +} + +.right #MSearchClose { + right: 2px; +} + +.MSearchBoxActive #MSearchField { + color: #000000; +} + +/*---------------- Search filter selection */ + +#MSearchSelectWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid #90A5CE; + background-color: #F9FAFC; + z-index: 10001; + padding-top: 4px; + padding-bottom: 4px; + -moz-border-radius: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +.SelectItem { + font: 8pt Arial, Verdana, sans-serif; + padding-left: 2px; + padding-right: 12px; + border: 0px; +} + +span.SelectionMark { + margin-right: 4px; + font-family: monospace; + outline-style: none; + text-decoration: none; +} + +a.SelectItem { + display: block; + outline-style: none; + color: #000000; + text-decoration: none; + padding-left: 6px; + padding-right: 12px; +} + +a.SelectItem:focus, +a.SelectItem:active { + color: #000000; + outline-style: none; + text-decoration: none; +} + +a.SelectItem:hover { + color: #FFFFFF; + background-color: #3D578C; + outline-style: none; + text-decoration: none; + cursor: pointer; + display: block; +} + +/*---------------- Search results window */ + +iframe#MSearchResults { + width: 60ex; + height: 15em; +} + +#MSearchResultsWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid #000; + background-color: #EEF1F7; + z-index:10000; +} + +/* ----------------------------------- */ + + +#SRIndex { + clear:both; + padding-bottom: 15px; +} + +.SREntry { + font-size: 10pt; + padding-left: 1ex; +} + +.SRPage .SREntry { + font-size: 8pt; + padding: 1px 5px; +} + +body.SRPage { + margin: 5px 2px; +} + +.SRChildren { + padding-left: 3ex; padding-bottom: .5em +} + +.SRPage .SRChildren { + display: none; +} + +.SRSymbol { + font-weight: bold; + color: #425E97; + font-family: Arial, Verdana, sans-serif; + text-decoration: none; + outline: none; +} + +a.SRScope { + display: block; + color: #425E97; + font-family: Arial, Verdana, sans-serif; + text-decoration: none; + outline: none; +} + +a.SRSymbol:focus, a.SRSymbol:active, +a.SRScope:focus, a.SRScope:active { + text-decoration: underline; +} + +span.SRScope { + padding-left: 4px; +} + +.SRPage .SRStatus { + padding: 2px 5px; + font-size: 8pt; + font-style: italic; +} + +.SRResult { + display: none; +} + +DIV.searchresults { + margin-left: 10px; + margin-right: 10px; +} + +/*---------------- External search page results */ + +.searchresult { + background-color: #F0F3F8; +} + +.pages b { + color: white; + padding: 5px 5px 3px 5px; + background-image: url("../tab_a.png"); + background-repeat: repeat-x; + text-shadow: 0 1px 1px #000000; +} + +.pages { + line-height: 17px; + margin-left: 4px; + text-decoration: none; +} + +.hl { + font-weight: bold; +} + +#searchresults { + margin-bottom: 20px; +} + +.searchpages { + margin-top: 10px; +} + diff --git a/docs/html/search/search.js b/docs/html/search/search.js new file mode 100644 index 00000000..a554ab9c --- /dev/null +++ b/docs/html/search/search.js @@ -0,0 +1,814 @@ +/* + @licstart The following is the entire license notice for the + JavaScript code in this file. + + Copyright (C) 1997-2017 by Dimitri van Heesch + + 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 2 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + @licend The above is the entire license notice + for the JavaScript code in this file + */ +function convertToId(search) +{ + var result = ''; + for (i=0;i do a search + { + this.Search(); + } + } + + this.OnSearchSelectKey = function(evt) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==40 && this.searchIndex0) // Up + { + this.searchIndex--; + this.OnSelectItem(this.searchIndex); + } + else if (e.keyCode==13 || e.keyCode==27) + { + this.OnSelectItem(this.searchIndex); + this.CloseSelectionWindow(); + this.DOMSearchField().focus(); + } + return false; + } + + // --------- Actions + + // Closes the results window. + this.CloseResultsWindow = function() + { + this.DOMPopupSearchResultsWindow().style.display = 'none'; + this.DOMSearchClose().style.display = 'none'; + this.Activate(false); + } + + this.CloseSelectionWindow = function() + { + this.DOMSearchSelectWindow().style.display = 'none'; + } + + // Performs a search. + this.Search = function() + { + this.keyTimeout = 0; + + // strip leading whitespace + var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); + + var code = searchValue.toLowerCase().charCodeAt(0); + var idxChar = searchValue.substr(0, 1).toLowerCase(); + if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair + { + idxChar = searchValue.substr(0, 2); + } + + var resultsPage; + var resultsPageWithSearch; + var hasResultsPage; + + var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar); + if (idx!=-1) + { + var hexCode=idx.toString(16); + resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html'; + resultsPageWithSearch = resultsPage+'?'+escape(searchValue); + hasResultsPage = true; + } + else // nothing available for this search term + { + resultsPage = this.resultsPath + '/nomatches.html'; + resultsPageWithSearch = resultsPage; + hasResultsPage = false; + } + + window.frames.MSearchResults.location = resultsPageWithSearch; + var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); + + if (domPopupSearchResultsWindow.style.display!='block') + { + var domSearchBox = this.DOMSearchBox(); + this.DOMSearchClose().style.display = 'inline'; + if (this.insideFrame) + { + var domPopupSearchResults = this.DOMPopupSearchResults(); + domPopupSearchResultsWindow.style.position = 'relative'; + domPopupSearchResultsWindow.style.display = 'block'; + var width = document.body.clientWidth - 8; // the -8 is for IE :-( + domPopupSearchResultsWindow.style.width = width + 'px'; + domPopupSearchResults.style.width = width + 'px'; + } + else + { + var domPopupSearchResults = this.DOMPopupSearchResults(); + var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth; + var top = getYPos(domSearchBox) + 20; // domSearchBox.offsetHeight + 1; + domPopupSearchResultsWindow.style.display = 'block'; + left -= domPopupSearchResults.offsetWidth; + domPopupSearchResultsWindow.style.top = top + 'px'; + domPopupSearchResultsWindow.style.left = left + 'px'; + } + } + + this.lastSearchValue = searchValue; + this.lastResultsPage = resultsPage; + } + + // -------- Activation Functions + + // Activates or deactivates the search panel, resetting things to + // their default values if necessary. + this.Activate = function(isActive) + { + if (isActive || // open it + this.DOMPopupSearchResultsWindow().style.display == 'block' + ) + { + this.DOMSearchBox().className = 'MSearchBoxActive'; + + var searchField = this.DOMSearchField(); + + if (searchField.value == this.searchLabel) // clear "Search" term upon entry + { + searchField.value = ''; + this.searchActive = true; + } + } + else if (!isActive) // directly remove the panel + { + this.DOMSearchBox().className = 'MSearchBoxInactive'; + this.DOMSearchField().value = this.searchLabel; + this.searchActive = false; + this.lastSearchValue = '' + this.lastResultsPage = ''; + } + } +} + +// ----------------------------------------------------------------------- + +// The class that handles everything on the search results page. +function SearchResults(name) +{ + // The number of matches from the last run of . + this.lastMatchCount = 0; + this.lastKey = 0; + this.repeatOn = false; + + // Toggles the visibility of the passed element ID. + this.FindChildElement = function(id) + { + var parentElement = document.getElementById(id); + var element = parentElement.firstChild; + + while (element && element!=parentElement) + { + if (element.nodeName == 'DIV' && element.className == 'SRChildren') + { + return element; + } + + if (element.nodeName == 'DIV' && element.hasChildNodes()) + { + element = element.firstChild; + } + else if (element.nextSibling) + { + element = element.nextSibling; + } + else + { + do + { + element = element.parentNode; + } + while (element && element!=parentElement && !element.nextSibling); + + if (element && element!=parentElement) + { + element = element.nextSibling; + } + } + } + } + + this.Toggle = function(id) + { + var element = this.FindChildElement(id); + if (element) + { + if (element.style.display == 'block') + { + element.style.display = 'none'; + } + else + { + element.style.display = 'block'; + } + } + } + + // Searches for the passed string. If there is no parameter, + // it takes it from the URL query. + // + // Always returns true, since other documents may try to call it + // and that may or may not be possible. + this.Search = function(search) + { + if (!search) // get search word from URL + { + search = window.location.search; + search = search.substring(1); // Remove the leading '?' + search = unescape(search); + } + + search = search.replace(/^ +/, ""); // strip leading spaces + search = search.replace(/ +$/, ""); // strip trailing spaces + search = search.toLowerCase(); + search = convertToId(search); + + var resultRows = document.getElementsByTagName("div"); + var matches = 0; + + var i = 0; + while (i < resultRows.length) + { + var row = resultRows.item(i); + if (row.className == "SRResult") + { + var rowMatchName = row.id.toLowerCase(); + rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_' + + if (search.length<=rowMatchName.length && + rowMatchName.substr(0, search.length)==search) + { + row.style.display = 'block'; + matches++; + } + else + { + row.style.display = 'none'; + } + } + i++; + } + document.getElementById("Searching").style.display='none'; + if (matches == 0) // no results + { + document.getElementById("NoMatches").style.display='block'; + } + else // at least one result + { + document.getElementById("NoMatches").style.display='none'; + } + this.lastMatchCount = matches; + return true; + } + + // return the first item with index index or higher that is visible + this.NavNext = function(index) + { + var focusItem; + while (1) + { + var focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') + { + break; + } + else if (!focusItem) // last element + { + break; + } + focusItem=null; + index++; + } + return focusItem; + } + + this.NavPrev = function(index) + { + var focusItem; + while (1) + { + var focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') + { + break; + } + else if (!focusItem) // last element + { + break; + } + focusItem=null; + index--; + } + return focusItem; + } + + this.ProcessKeys = function(e) + { + if (e.type == "keydown") + { + this.repeatOn = false; + this.lastKey = e.keyCode; + } + else if (e.type == "keypress") + { + if (!this.repeatOn) + { + if (this.lastKey) this.repeatOn = true; + return false; // ignore first keypress after keydown + } + } + else if (e.type == "keyup") + { + this.lastKey = 0; + this.repeatOn = false; + } + return this.lastKey!=0; + } + + this.Nav = function(evt,itemIndex) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) // Up + { + var newIndex = itemIndex-1; + var focusItem = this.NavPrev(newIndex); + if (focusItem) + { + var child = this.FindChildElement(focusItem.parentNode.parentNode.id); + if (child && child.style.display == 'block') // children visible + { + var n=0; + var tmpElem; + while (1) // search for last child + { + tmpElem = document.getElementById('Item'+newIndex+'_c'+n); + if (tmpElem) + { + focusItem = tmpElem; + } + else // found it! + { + break; + } + n++; + } + } + } + if (focusItem) + { + focusItem.focus(); + } + else // return focus to search field + { + parent.document.getElementById("MSearchField").focus(); + } + } + else if (this.lastKey==40) // Down + { + var newIndex = itemIndex+1; + var focusItem; + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem && elem.style.display == 'block') // children visible + { + focusItem = document.getElementById('Item'+itemIndex+'_c0'); + } + if (!focusItem) focusItem = this.NavNext(newIndex); + if (focusItem) focusItem.focus(); + } + else if (this.lastKey==39) // Right + { + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'block'; + } + else if (this.lastKey==37) // Left + { + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'none'; + } + else if (this.lastKey==27) // Escape + { + parent.searchBox.CloseResultsWindow(); + parent.document.getElementById("MSearchField").focus(); + } + else if (this.lastKey==13) // Enter + { + return true; + } + return false; + } + + this.NavChild = function(evt,itemIndex,childIndex) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) // Up + { + if (childIndex>0) + { + var newIndex = childIndex-1; + document.getElementById('Item'+itemIndex+'_c'+newIndex).focus(); + } + else // already at first child, jump to parent + { + document.getElementById('Item'+itemIndex).focus(); + } + } + else if (this.lastKey==40) // Down + { + var newIndex = childIndex+1; + var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex); + if (!elem) // last child, jump to parent next parent + { + elem = this.NavNext(itemIndex+1); + } + if (elem) + { + elem.focus(); + } + } + else if (this.lastKey==27) // Escape + { + parent.searchBox.CloseResultsWindow(); + parent.document.getElementById("MSearchField").focus(); + } + else if (this.lastKey==13) // Enter + { + return true; + } + return false; + } +} + +function setKeyActions(elem,action) +{ + elem.setAttribute('onkeydown',action); + elem.setAttribute('onkeypress',action); + elem.setAttribute('onkeyup',action); +} + +function setClassAttr(elem,attr) +{ + elem.setAttribute('class',attr); + elem.setAttribute('className',attr); +} + +function createResults() +{ + var results = document.getElementById("SRResults"); + for (var e=0; e(R!W8j_r#qQ#gnr4kAxdU#F0+OBry$Z+ z_0PMi;P|#{d%mw(dnw=jM%@$onTJa%@6Nm3`;2S#nwtVFJI#`U@2Q@@JCCctagvF- z8H=anvo~dTmJ2YA%wA6IHRv%{vxvUm|R)kgZeo zmX%Zb;mpflGZdXCTAgit`||AFzkI#z&(3d4(htA?U2FOL4WF6wY&TB#n3n*I4+hl| z*NBpo#FA92vEu822WQ%mvv4FO#qs` BFGc_W literal 0 HcmV?d00001 diff --git a/docs/html/search/search_r.png b/docs/html/search/search_r.png new file mode 100644 index 0000000000000000000000000000000000000000..1af5d21ee13e070d7600f1c4657fde843b953a69 GIT binary patch literal 553 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9c!2%@BXHTsJQY`6?zK#qG8~eHcB(ehe3dtTp zz6=bxGZ+|(`xqD=STHa&U1eaXVrO7DwS|Gf*oA>XrmV$GYcEhOQT(QLuS{~ooZ2P@v=Xc@RKW@Irliv8_;wroU0*)0O?temdsA~70jrdux+`@W7 z-N(<(C)L?hOO?KV{>8(jC{hpKsws)#Fh zvsO>IB+gb@b+rGWaO&!a9Z{!U+fV*s7TS>fdt&j$L%^U@Epd$~Nl7e8wMs5Z1yT$~ z28I^8hDN#u<{^fLRz?<9hUVG^237_Jy7tbuQ8eV{r(~v8;?@w8^gA7>fx*+&&t;uc GLK6VEQpiUD literal 0 HcmV?d00001 diff --git a/docs/html/search/searchdata.js b/docs/html/search/searchdata.js new file mode 100644 index 00000000..d8fd087d --- /dev/null +++ b/docs/html/search/searchdata.js @@ -0,0 +1,24 @@ +var indexSectionsWithContent = +{ + 0: "abdefgipqrsw", + 1: "f", + 2: "abdefgipqrsw", + 3: "f" +}; + +var indexSectionNames = +{ + 0: "all", + 1: "classes", + 2: "functions", + 3: "pages" +}; + +var indexSectionLabels = +{ + 0: "All", + 1: "Classes", + 2: "Functions", + 3: "Pages" +}; + diff --git a/docs/html/splitbar.png b/docs/html/splitbar.png new file mode 100644 index 0000000000000000000000000000000000000000..fe895f2c58179b471a22d8320b39a4bd7312ec8e GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^Yzz!63>-{AmhX=Jf(#6djGiuzAr*{o?=JLmPLyc> z_*`QK&+BH@jWrYJ7>r6%keRM@)Qyv8R=enp0jiI>aWlGyB58O zFVR20d+y`K7vDw(hJF3;>dD*3-?v=<8M)@x|EEGLnJsniYK!2U1 Y!`|5biEc?d1`HDhPgg&ebxsLQ02F6;9RL6T literal 0 HcmV?d00001 diff --git a/docs/html/sync_off.png b/docs/html/sync_off.png new file mode 100644 index 0000000000000000000000000000000000000000..3b443fc62892114406e3d399421b2a881b897acc GIT binary patch literal 853 zcmV-b1FHOqP)oT|#XixUYy%lpuf3i8{fX!o zUyDD0jOrAiT^tq>fLSOOABs-#u{dV^F$b{L9&!2=9&RmV;;8s^x&UqB$PCj4FdKbh zoB1WTskPUPu05XzFbA}=KZ-GP1fPpAfSs>6AHb12UlR%-i&uOlTpFNS7{jm@mkU1V zh`nrXr~+^lsV-s1dkZOaI|kYyVj3WBpPCY{n~yd%u%e+d=f%`N0FItMPtdgBb@py; zq@v6NVArhyTC7)ULw-Jy8y42S1~4n(3LkrW8mW(F-4oXUP3E`e#g**YyqI7h-J2zK zK{m9##m4ri!7N>CqQqCcnI3hqo1I;Yh&QLNY4T`*ptiQGozK>FF$!$+84Z`xwmeMh zJ0WT+OH$WYFALEaGj2_l+#DC3t7_S`vHpSivNeFbP6+r50cO8iu)`7i%Z4BTPh@_m3Tk!nAm^)5Bqnr%Ov|Baunj#&RPtRuK& z4RGz|D5HNrW83-#ydk}tVKJrNmyYt-sTxLGlJY5nc&Re zU4SgHNPx8~Yxwr$bsju?4q&%T1874xxzq+_%?h8_ofw~(bld=o3iC)LUNR*BY%c0y zWd_jX{Y8`l%z+ol1$@Qa?Cy!(0CVIEeYpKZ`(9{z>3$CIe;pJDQk$m3p}$>xBm4lb zKo{4S)`wdU9Ba9jJbVJ0C=SOefZe%d$8=2r={nu<_^a3~>c#t_U6dye5)JrR(_a^E f@}b6j1K9lwFJq@>o)+Ry00000NkvXXu0mjfWa5j* literal 0 HcmV?d00001 diff --git a/docs/html/sync_on.png b/docs/html/sync_on.png new file mode 100644 index 0000000000000000000000000000000000000000..e08320fb64e6fa33b573005ed6d8fe294e19db76 GIT binary patch literal 845 zcmV-T1G4;yP)Y;xxyHF2B5Wzm| zOOGupOTn@c(JmBOl)e;XMNnZuiTJP>rM8<|Q`7I_))aP?*T)ow&n59{}X4$3Goat zgjs?*aasfbrokzG5cT4K=uG`E14xZl@z)F={P0Y^?$4t z>v!teRnNZym<6h{7sLyF1V0HsfEl+l6TrZpsfr1}luH~F7L}ktXu|*uVX^RG$L0`K zWs3j|0tIvVe(N%_?2{(iCPFGf#B6Hjy6o&}D$A%W%jfO8_W%ZO#-mh}EM$LMn7joJ z05dHr!5Y92g+31l<%i1(=L1a1pXX+OYnalY>31V4K}BjyRe3)9n#;-cCVRD_IG1fT zOKGeNY8q;TL@K{dj@D^scf&VCs*-Jb>8b>|`b*osv52-!A?BpbYtTQBns5EAU**$m zSnVSm(teh>tQi*S*A>#ySc=n;`BHz`DuG4&g4Kf8lLhca+zvZ7t7RflD6-i-mcK=M z!=^P$*u2)bkY5asG4gsss!Hn%u~>}kIW`vMs%lJLH+u*9<4PaV_c6U`KqWXQH%+Nu zTv41O(^ZVi@qhjQdG!fbZw&y+2o!iYymO^?ud3{P*HdoX83YV*Uu_HB=?U&W9%AU# z80}k1SS-CXTU7dcQlsm<^oYLxVSseqY6NO}dc`Nj?8vrhNuCdm@^{a3AQ_>6myOj+ z`1RsLUXF|dm|3k7s2jD(B{rzE>WI2scH8i1;=O5Cc9xB3^aJk%fQjqsu+kH#0=_5a z0nCE8@dbQa-|YIuUVvG0L_IwHMEhOj$Mj4Uq05 X8=0q~qBNan00000NkvXXu0mjfptF>5 literal 0 HcmV?d00001 diff --git a/docs/html/tab_a.png b/docs/html/tab_a.png new file mode 100644 index 0000000000000000000000000000000000000000..3b725c41c5a527a3a3e40097077d0e206a681247 GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QlXwMjv*C{Z|8b*H5dputLHD# z=<0|*y7z(Vor?d;H&?EG&cXR}?!j-Lm&u1OOI7AIF5&c)RFE;&p0MYK>*Kl@eiymD r@|NpwKX@^z+;{u_Z~trSBfrMKa%3`zocFjEXaR$#tDnm{r-UW|TZ1%4 literal 0 HcmV?d00001 diff --git a/docs/html/tab_b.png b/docs/html/tab_b.png new file mode 100644 index 0000000000000000000000000000000000000000..e2b4a8638cb3496a016eaed9e16ffc12846dea18 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^j6kfy!2~3aiye;!QU#tajv*C{Z}0l@H7kg?K0Lnr z!j&C6_(~HV9oQ0Pa6x{-v0AGV_E?vLn=ZI-;YrdjIl`U`uzuDWSP?o#Dmo{%SgM#oan kX~E1%D-|#H#QbHoIja2U-MgvsK&LQxy85}Sb4q9e0Efg%P5=M^ literal 0 HcmV?d00001 diff --git a/docs/html/tabs.css b/docs/html/tabs.css new file mode 100644 index 00000000..85a0cd5b --- /dev/null +++ b/docs/html/tabs.css @@ -0,0 +1 @@ +.sm{position:relative;z-index:9999}.sm,.sm ul,.sm li{display:block;list-style:none;margin:0;padding:0;line-height:normal;direction:ltr;text-align:left;-webkit-tap-highlight-color:rgba(0,0,0,0)}.sm-rtl,.sm-rtl ul,.sm-rtl li{direction:rtl;text-align:right}.sm>li>h1,.sm>li>h2,.sm>li>h3,.sm>li>h4,.sm>li>h5,.sm>li>h6{margin:0;padding:0}.sm ul{display:none}.sm li,.sm a{position:relative}.sm a{display:block}.sm a.disabled{cursor:not-allowed}.sm:after{content:"\00a0";display:block;height:0;font:0/0 serif;clear:both;visibility:hidden;overflow:hidden}.sm,.sm *,.sm *:before,.sm *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sm-dox{background-image:url("tab_b.png")}.sm-dox a,.sm-dox a:focus,.sm-dox a:hover,.sm-dox a:active{padding:0 12px;padding-right:43px;font-family:"Lucida Grande","Geneva","Helvetica",Arial,sans-serif;font-size:13px;font-weight:bold;line-height:36px;text-decoration:none;text-shadow:0 1px 1px rgba(255,255,255,0.9);color:#283a5d;outline:0}.sm-dox a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox a.current{color:#d23600}.sm-dox a.disabled{color:#bbb}.sm-dox a span.sub-arrow{position:absolute;top:50%;margin-top:-14px;left:auto;right:3px;width:28px;height:28px;overflow:hidden;font:bold 12px/28px monospace!important;text-align:center;text-shadow:none;background:rgba(255,255,255,0.5);-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox a.highlighted span.sub-arrow:before{display:block;content:'-'}.sm-dox>li:first-child>a,.sm-dox>li:first-child>:not(ul) a{-moz-border-radius:5px 5px 0 0;-webkit-border-radius:5px;border-radius:5px 5px 0 0}.sm-dox>li:last-child>a,.sm-dox>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul{-moz-border-radius:0 0 5px 5px;-webkit-border-radius:0;border-radius:0 0 5px 5px}.sm-dox>li:last-child>a.highlighted,.sm-dox>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox ul{background:rgba(162,162,162,0.1)}.sm-dox ul a,.sm-dox ul a:focus,.sm-dox ul a:hover,.sm-dox ul a:active{font-size:12px;border-left:8px solid transparent;line-height:36px;text-shadow:none;background-color:white;background-image:none}.sm-dox ul a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox ul ul a,.sm-dox ul ul a:hover,.sm-dox ul ul a:focus,.sm-dox ul ul a:active{border-left:16px solid transparent}.sm-dox ul ul ul a,.sm-dox ul ul ul a:hover,.sm-dox ul ul ul a:focus,.sm-dox ul ul ul a:active{border-left:24px solid transparent}.sm-dox ul ul ul ul a,.sm-dox ul ul ul ul a:hover,.sm-dox ul ul ul ul a:focus,.sm-dox ul ul ul ul a:active{border-left:32px solid transparent}.sm-dox ul ul ul ul ul a,.sm-dox ul ul ul ul ul a:hover,.sm-dox ul ul ul ul ul a:focus,.sm-dox ul ul ul ul ul a:active{border-left:40px solid transparent}@media(min-width:768px){.sm-dox ul{position:absolute;width:12em}.sm-dox li{float:left}.sm-dox.sm-rtl li{float:right}.sm-dox ul li,.sm-dox.sm-rtl ul li,.sm-dox.sm-vertical li{float:none}.sm-dox a{white-space:nowrap}.sm-dox ul a,.sm-dox.sm-vertical a{white-space:normal}.sm-dox .sm-nowrap>li>a,.sm-dox .sm-nowrap>li>:not(ul) a{white-space:nowrap}.sm-dox{padding:0 10px;background-image:url("tab_b.png");line-height:36px}.sm-dox a span.sub-arrow{top:50%;margin-top:-2px;right:12px;width:0;height:0;border-width:4px;border-style:solid dashed dashed dashed;border-color:#283a5d transparent transparent transparent;background:transparent;-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted{padding:0 12px;background-image:url("tab_s.png");background-repeat:no-repeat;background-position:right;-moz-border-radius:0!important;-webkit-border-radius:0;border-radius:0!important}.sm-dox a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox a:hover span.sub-arrow{border-color:white transparent transparent transparent}.sm-dox a.has-submenu{padding-right:24px}.sm-dox li{border-top:0}.sm-dox>li>ul:before,.sm-dox>li>ul:after{content:'';position:absolute;top:-18px;left:30px;width:0;height:0;overflow:hidden;border-width:9px;border-style:dashed dashed solid dashed;border-color:transparent transparent #bbb transparent}.sm-dox>li>ul:after{top:-16px;left:31px;border-width:8px;border-color:transparent transparent #fff transparent}.sm-dox ul{border:1px solid #bbb;padding:5px 0;background:#fff;-moz-border-radius:5px!important;-webkit-border-radius:5px;border-radius:5px!important;-moz-box-shadow:0 5px 9px rgba(0,0,0,0.2);-webkit-box-shadow:0 5px 9px rgba(0,0,0,0.2);box-shadow:0 5px 9px rgba(0,0,0,0.2)}.sm-dox ul a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-color:transparent transparent transparent #555;border-style:dashed dashed dashed solid}.sm-dox ul a,.sm-dox ul a:hover,.sm-dox ul a:focus,.sm-dox ul a:active,.sm-dox ul a.highlighted{color:#555;background-image:none;border:0!important;color:#555;background-image:none}.sm-dox ul a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox ul a:hover span.sub-arrow{border-color:transparent transparent transparent white}.sm-dox span.scroll-up,.sm-dox span.scroll-down{position:absolute;display:none;visibility:hidden;overflow:hidden;background:#fff;height:36px}.sm-dox span.scroll-up:hover,.sm-dox span.scroll-down:hover{background:#eee}.sm-dox span.scroll-up:hover span.scroll-up-arrow,.sm-dox span.scroll-up:hover span.scroll-down-arrow{border-color:transparent transparent #d23600 transparent}.sm-dox span.scroll-down:hover span.scroll-down-arrow{border-color:#d23600 transparent transparent transparent}.sm-dox span.scroll-up-arrow,.sm-dox span.scroll-down-arrow{position:absolute;top:0;left:50%;margin-left:-6px;width:0;height:0;overflow:hidden;border-width:6px;border-style:dashed dashed solid dashed;border-color:transparent transparent #555 transparent}.sm-dox span.scroll-down-arrow{top:8px;border-style:solid dashed dashed dashed;border-color:#555 transparent transparent transparent}.sm-dox.sm-rtl a.has-submenu{padding-right:12px;padding-left:24px}.sm-dox.sm-rtl a span.sub-arrow{right:auto;left:12px}.sm-dox.sm-rtl.sm-vertical a.has-submenu{padding:10px 20px}.sm-dox.sm-rtl.sm-vertical a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-rtl>li>ul:before{left:auto;right:30px}.sm-dox.sm-rtl>li>ul:after{left:auto;right:31px}.sm-dox.sm-rtl ul a.has-submenu{padding:10px 20px!important}.sm-dox.sm-rtl ul a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-vertical{padding:10px 0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox.sm-vertical a{padding:10px 20px}.sm-dox.sm-vertical a:hover,.sm-dox.sm-vertical a:focus,.sm-dox.sm-vertical a:active,.sm-dox.sm-vertical a.highlighted{background:#fff}.sm-dox.sm-vertical a.disabled{background-image:url("tab_b.png")}.sm-dox.sm-vertical a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-style:dashed dashed dashed solid;border-color:transparent transparent transparent #555}.sm-dox.sm-vertical>li>ul:before,.sm-dox.sm-vertical>li>ul:after{display:none}.sm-dox.sm-vertical ul a{padding:10px 20px}.sm-dox.sm-vertical ul a:hover,.sm-dox.sm-vertical ul a:focus,.sm-dox.sm-vertical ul a:active,.sm-dox.sm-vertical ul a.highlighted{background:#eee}.sm-dox.sm-vertical ul a.disabled{background:#fff}} \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..cfd32901 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,2 @@ + + From bdc289213cb61a47113abf6f281e9333c2e9d3f7 Mon Sep 17 00:00:00 2001 From: Jeff Hoefs Date: Fri, 11 Oct 2019 21:42:34 -0700 Subject: [PATCH 105/110] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 042c28d2..ed5d319f 100644 --- a/readme.md +++ b/readme.md @@ -19,7 +19,7 @@ Firmata is a protocol for communicating with microcontrollers from software on a ## Usage -There are two main models of usage of Firmata. In one model, the author of the Arduino sketch uses the various methods provided by the Firmata library to selectively send and receive data between the Arduino device and the software running on the host computer. For example, a user can send analog data to the host using ``` Firmata.sendAnalog(analogPin, analogRead(analogPin)) ``` or send data packed in a string using ``` Firmata.sendString(stringToSend) ```. See File -> Examples -> Firmata -> AnalogFirmata & EchoString respectively for examples. +There are two main models of usage of Firmata. In one model, the author of the Arduino sketch uses the various methods provided by the Firmata library to selectively send and receive data between the Arduino device and the software running on the host computer. For example, a user can send analog data to the host using ``` Firmata.sendAnalog(analogPin, analogRead(analogPin)) ``` or send data packed in a string using ``` Firmata.sendString(stringToSend) ```. See File -> Examples -> Firmata -> AnalogFirmata & EchoString respectively for examples. Browse the API documentation [here](https://firmata.github.io/arduino/html/index.html). The second and more common model is to load a general purpose sketch called StandardFirmata (or one of the variants such as StandardFirmataPlus or StandardFirmataEthernet depending on your needs) on the Arduino board and then use the host computer exclusively to interact with the Arduino board. StandardFirmata is located in the Arduino IDE in File -> Examples -> Firmata. From 663454a5f8db6fef9800b11bee4aceb10a0eb75c Mon Sep 17 00:00:00 2001 From: baggio63446333 <55774994+baggio63446333@users.noreply.github.com> Date: Sun, 20 Oct 2019 15:17:04 +0900 Subject: [PATCH 106/110] Add support for SPRESENSE board --- Boards.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Boards.h b/Boards.h index 730826f6..d9d2ae02 100644 --- a/Boards.h +++ b/Boards.h @@ -888,6 +888,23 @@ writePort(port, value, bitmask): Write an 8 bit port. #define PIN_TO_PWM(p) (p) #define PIN_TO_SERVO(p) (p) +// SPRESENSE +#elif defined(ARDUINO_ARCH_SPRESENSE) +#define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS +#define TOTAL_PINS NUM_DIGITAL_PINS + 4 + NUM_ANALOG_INPUTS // + 4 built-in led +#define VERSION_BLINK_PIN LED_BUILTIN +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < (NUM_DIGITAL_PINS + 4)) +#define IS_PIN_ANALOG(p) ((p) >= (TOTAL_PINS - NUM_ANALOG_INPUTS) && (p) < TOTAL_PINS) +#define IS_PIN_PWM(p) ((p) == 6 || (p) == 5 || (p) == 9 || (p) == 3) +#define IS_PIN_SERVO(p) ((p) < NUM_DIGITAL_PINS) +#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) +#define IS_PIN_SPI(p) ((p) == 10 || (p) == 11 || (p) == 12 || (p) == 13) +#define PIN_TO_DIGITAL(p) (((p) < NUM_DIGITAL_PINS) ? (p) : (_LED_PIN((p) - NUM_DIGITAL_PINS))) +#define PIN_TO_ANALOG(p) ((p) - (TOTAL_PINS - NUM_ANALOG_INPUTS)) +#define PIN_TO_PWM(p) (p) +#define PIN_TO_SERVO(p) (p) +#define analogRead(p) analogRead(_ANALOG_PIN(p)) // wrap function for analogRead() + // anything else #else #error "Please edit Boards.h with a hardware abstraction for this board" From a142327e5a1e1e3450b0774c93b7c642f827c60c Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Mon, 9 Dec 2019 09:28:05 +0100 Subject: [PATCH 107/110] Fix build issue with arm none eabi gcc v9.2.1 Firmata/Firmata.h:131:17: error: friend declaration of 'void encodeByteStream(size_t, uint8_t*, size_t) const' specifies default arguments and isn't a definition [-fpermissive] 131 | friend void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; | ^~~~~~~~~~~~~~~~~ Ref: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1263.html Fixes #437 Signed-off-by: Frederic Pillon --- Firmata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmata.h b/Firmata.h index fa0fa6c2..fb993d79 100644 --- a/Firmata.h +++ b/Firmata.h @@ -128,7 +128,7 @@ class FirmataClass /* private methods ------------------------------ */ void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval); - friend void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes = 0) const; + friend void FirmataMarshaller::encodeByteStream (size_t bytec, uint8_t * bytev, size_t max_bytes) const; /* callback functions */ static callbackFunction currentAnalogCallback; From 4d0742fc367eb8539957ae980ac12347896b7e7e Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Tue, 3 Dec 2019 08:44:58 +0100 Subject: [PATCH 108/110] [STM32] Define VERSION_BLINK_PIN only if LED_BUILTIN is defined Not all STM32 boards have a LED_BUILTIN. Signed-off-by: Frederic Pillon --- Boards.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Boards.h b/Boards.h index d9d2ae02..d00fb89e 100644 --- a/Boards.h +++ b/Boards.h @@ -854,7 +854,9 @@ writePort(port, value, bitmask): Write an 8 bit port. #define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS #define TOTAL_PINS NUM_DIGITAL_PINS #define TOTAL_PORTS MAX_NB_PORT +#ifdef LED_BUILTIN #define VERSION_BLINK_PIN LED_BUILTIN +#endif // PIN_SERIALY_RX/TX defined in the variant.h #define IS_PIN_DIGITAL(p) (digitalPinIsValid(p) && !pinIsSerial(p)) #define IS_PIN_ANALOG(p) ((p >= A0) && (p < (A0 + TOTAL_ANALOG_PINS)) && !pinIsSerial(p)) From 5d37416f89e31ff8e10a8a109924c2d7a1f985b1 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Tue, 3 Dec 2019 11:46:19 +0100 Subject: [PATCH 109/110] [STM32] Update analog macro Since STM32 core version 1.8.0, analog pins definition can be not contiguous Signed-off-by: Frederic Pillon --- Boards.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Boards.h b/Boards.h index d00fb89e..b6937545 100644 --- a/Boards.h +++ b/Boards.h @@ -859,15 +859,23 @@ writePort(port, value, bitmask): Write an 8 bit port. #endif // PIN_SERIALY_RX/TX defined in the variant.h #define IS_PIN_DIGITAL(p) (digitalPinIsValid(p) && !pinIsSerial(p)) +#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION <= 0x01080000) #define IS_PIN_ANALOG(p) ((p >= A0) && (p < (A0 + TOTAL_ANALOG_PINS)) && !pinIsSerial(p)) +#else +#define IS_PIN_ANALOG(p) (pinIsAnalogInput(p) && !pinIsSerial(p)) +#endif #define IS_PIN_PWM(p) (IS_PIN_DIGITAL(p) && digitalPinHasPWM(p)) -#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p) +#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p)) #define IS_PIN_I2C(p) (IS_PIN_DIGITAL(p) && digitalPinHasI2C(p)) #define IS_PIN_SPI(p) (IS_PIN_DIGITAL(p) && digitalPinHasSPI(p)) #define IS_PIN_INTERRUPT(p) (IS_PIN_DIGITAL(p) && (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT))) #define IS_PIN_SERIAL(p) (digitalPinHasSerial(p) && !pinIsSerial(p)) #define PIN_TO_DIGITAL(p) (p) +#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION <= 0x01080000) #define PIN_TO_ANALOG(p) (p-A0) +#else +#define PIN_TO_ANALOG(p) (digitalPinToAnalogInput(p)) +#endif #define PIN_TO_PWM(p) (p) #define PIN_TO_SERVO(p) (p) #define DEFAULT_PWM_RESOLUTION PWM_RESOLUTION From b102e745441bdeab51bbcd6202ca12598954ad17 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Mon, 20 Jan 2020 07:52:01 +0100 Subject: [PATCH 110/110] [STM32] Fix version checking Signed-off-by: Frederic Pillon --- Boards.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Boards.h b/Boards.h index b6937545..a56ed8d6 100644 --- a/Boards.h +++ b/Boards.h @@ -859,7 +859,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #endif // PIN_SERIALY_RX/TX defined in the variant.h #define IS_PIN_DIGITAL(p) (digitalPinIsValid(p) && !pinIsSerial(p)) -#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION <= 0x01080000) +#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION < 0x01080000) #define IS_PIN_ANALOG(p) ((p >= A0) && (p < (A0 + TOTAL_ANALOG_PINS)) && !pinIsSerial(p)) #else #define IS_PIN_ANALOG(p) (pinIsAnalogInput(p) && !pinIsSerial(p)) @@ -871,7 +871,7 @@ writePort(port, value, bitmask): Write an 8 bit port. #define IS_PIN_INTERRUPT(p) (IS_PIN_DIGITAL(p) && (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT))) #define IS_PIN_SERIAL(p) (digitalPinHasSerial(p) && !pinIsSerial(p)) #define PIN_TO_DIGITAL(p) (p) -#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION <= 0x01080000) +#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION < 0x01080000) #define PIN_TO_ANALOG(p) (p-A0) #else #define PIN_TO_ANALOG(p) (digitalPinToAnalogInput(p))