├── .github └── FUNDING.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── examples ├── App │ ├── OttoNinja_APP │ │ └── OttoNinja_APP.ino │ ├── OttoNinja_APP_OLED │ │ └── OttoNinja_APP_OLED.ino │ └── OttoNinja_App_matrix │ │ └── OttoNinja_App_matrix.ino ├── Humanoid │ ├── OttoNinjaHumanoid_Avoid │ │ └── OttoNinjaHumanoid_Avoid.ino │ └── OttoNinjaHumanoid_Demo │ │ └── OttoNinjaHumanoid_Demo.ino ├── LED matrix │ ├── OttoE_alleyes │ │ └── OttoE_alleyes.ino │ ├── OttoE_flappybird │ │ └── OttoE_flappybird.ino │ ├── OttoE_rolleyes │ │ └── OttoE_rolleyes.ino │ ├── OttoE_soundlevels │ │ └── OttoE_soundlevels.ino │ └── Snake8x8matrix │ │ ├── Snake8x8matrix.ino │ │ └── buttons.ino └── Starter │ └── OttoNinja_Theremin │ └── OttoNinja_Theremin.ino ├── keywords.txt ├── library.json ├── library.properties └── src ├── RemoteXY.h ├── RemoteXYApi.h ├── RemoteXYApiData.h ├── RemoteXYCloudServer.h ├── RemoteXYComm.h ├── RemoteXYComm_AT.h ├── RemoteXYComm_ESP8266.h ├── RemoteXYComm_Ethernet.h ├── RemoteXYComm_WiFi.h ├── RemoteXYConnection.h ├── RemoteXYConnectionCloud.h ├── RemoteXYConnectionServer.h ├── RemoteXYConnectionStream.h ├── RemoteXYDebugLog.h ├── RemoteXYFunc.h ├── RemoteXYStream.h ├── RemoteXYStream_BLEDevice.h ├── RemoteXYStream_BLEPeripheral.h ├── RemoteXYStream_BluetoothSerial.h ├── RemoteXYStream_CDCSerial.h ├── RemoteXYStream_HardSerial.h ├── RemoteXYStream_SoftSerial.h ├── RemoteXYThread.h ├── RemoteXYWire.h ├── RemoteXYWireCloud.h └── RemoteXYWireStream.h /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute to OttoDIY effectively? 2 | Otto Builders are the community of Otto DIY. 3 | 4 | ## 1. step one is become an Otto Builder 5 | 6 | Be a part of this friendly community of robot builders, teachers and makers! 7 | 8 | * [Group in Facebook](https://www.facebook.com/groups/ottodiy/) 9 | * [Like our Facebook page](https://www.facebook.com/ottodiy/) 10 | * [Subscribe to our YouTube channel](https://www.youtube.com/c/ottodiy?sub_confirmation=1) 11 | * [Follow us in Instagram](https://www.instagram.com/ottodiy/) 12 | * [and Twitter](https://twitter.com/ottodiy) 13 | 14 | Welcome to our Otto Builder community! 15 | 16 | ## 2. step two is to build your own Otto! 17 | Start with the basic if you are a beginner; Otto DIY can be made easily with [our Builder Kit (full with 3D printed parts)](https://ottodiy.ecwid.com/Otto-DIY-Builder-Kit-p135022769) or [Maker Kit (only electronics) if you have a 3D printer](https://ottodiy.ecwid.com/Otto-DIY-Maker-Kit-p135022782). 18 | 19 | Once you feel more confident you can [jump to any of our other Otto robots](https://ottodiy.ecwid.com/) with more advanced features and sensors. 20 | 21 | ## 3. step three Make your contribution 22 | 23 | If you noticed we have @divided our documenation in [Wikifactory](https://wikifactory.com/+OttoDIY/projects) and [Github](https://github.com/OttoDIY/), this is because one tool is good for hardware the other for merely software, we also find out that one is easier to use for our main community audience but feel free to use any you feel comfortable with, currently we need support with: 24 | 25 | * New Remixes or designs of similar robots you can just upload into Wikifactory Otto DIY projects [submit any creation you have made here](https://wikifactory.com/new-project) they help show the projects possibility and community collaboration. 26 | * Language [translations for our Otto Blockly](https://github.com/OttoDIY/blockly) with this more people will learn how to code. 27 | * In the same repository you can help us report issues or solve them or pull request other improvements. 28 | * Ideas or [improvements for our mobile App!](https://github.com/OttoDIY/OttoDIYApp) 29 | 30 | or just send us the files we will upload for you and give the appropriate credits to you. 31 | 32 | Happy to have you as a part of the Otto Community :) and thanks! 33 | 34 | ## 4. Share with #OttoDIY 35 | 36 | to have more visibility keep sharing with us in any of our social media, friends, family [#OttoDIY](https://twitter.com/search?q=%23OttoDIY&src=typd&lang=en) and make sure more Otto Builders do the same everywhere. We love to see Ottos around the world! 37 | help us please to spread the word in Maker Faires, maker spaces, hacker spaces, schools and so on, We are rewarding the best Otto builders with kits! 38 | 39 | [check our Forum for questions.](https://wikifactory.com/+OttoDIY/forum) 40 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Issue Template 2 | 3 | ## Explain the problem: 4 | 5 | *Is it a code issue? - make sure you are using the right libraries and Mblock or Arduino software, please post a screenshot. 6 | 7 | *Is it an electronic issue? - please post a complementary picture. 8 | 9 | *Is it a 3D print issue? - In the case of 3D print improvement please post in thingiverse. 10 | 11 | If solved please share the solution. 12 | 13 | Thanks #Ottobuilder 14 | 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Otto DIY 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Otto Ninja Robot Arduino Libraries 2 | 3 | [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) 4 | ![version](https://img.shields.io/badge/version-1.1-blue) 5 | 6 | This repository has the main [Otto Ninja robot](https://www.ottodiy.com/ninja) libraries for ESP compatible boards. 7 | 8 | ## Compatible Hardware 9 | 10 | - Designed to work with ESP8266 boards, but most of the code could be adapted to other microcontrollers. 11 | 12 | You will need to [add the ESP8266 to your Arduino IDE](https://randomnerdtutorials.com/how-to-install-esp8266-board-arduino-ide/) 13 | 14 | :star: Star us on GitHub; it helps! 15 | 16 | ## Installation: 17 | 18 | You will need the [Arduino IDE on your computer](https://www.arduino.cc/en/software) 19 | 20 | 1. [Download Otto Ninja libraries here](https://github.com/OttoDIY/OttoNinja/archive/master.zip) 21 | 2. Open the Arduino IDE and navigate to Sketch > Include Library > Add .ZIP Library... 22 | 3. Navigate to .zip file location that you just downloaded and open it. 23 | 4. You will see in the bottom black area a message that it has been installed.  24 | 5. To verify they are properly installed, go to Sketch > Include Library menu. You should now see the library at the bottom of the drop-down menu. 25 | 26 | ## Example: 27 | 28 | You can find codes in File > Examples > OttoNinja. 29 | 30 | *For more details or other ways to [install libraries, visit this link](https://www.arduino.cc/en/Guide/Libraries)  31 | 32 | *For the LED matrix, you will need the [Adafruit LED Backpack library and all the dependencies](https://github.com/adafruit/Adafruit_LED_Backpack/archive/refs/heads/master.zip) just do the exact same installation steps. 33 | 34 | *For the OLED display, you will need the [U8g2 libraries](https://github.com/olikraus/u8g2/archive/refs/heads/master.zip) 35 | 36 | ## Uploading: 37 | 38 | For the firmware code to remote control Ninja via the [Remote XY mobile App](https://remotexy.com), select NodeMCU 1.0 as the board. 39 | 40 | 1. Connect the ESP board using the USB cable to your computer. 41 | 42 | 2. [Upload this code](https://github.com/OttoDIY/OttoNinja/blob/master/examples/App/OttoNinja_APP/OttoNinja_APP.ino)  43 | 3. [Download the app to your phone](https://remotexy.com/en/download/) 44 | 4. Open the app and press + Add new device. 45 | 5. Select the WiFi point. 46 | 6. Select "OTTO NINJA" from the options. 47 | 7. The password is 12345678. 48 | 49 | (Make sure to have wifi disconnected from other networks) and power the robot with a battery all the time. 50 | 51 | ## How to Contribute: 52 | Contributing to this software is warmly welcomed. 53 | 1. Test it, and if you find any problems, then post an issue. 54 | 2. Help us solve the issues or other bugs. 55 | 3. Improve and optimize the current libraries. 56 | You can do this [basically by forking](https://help.github.com/en/articles/fork-a-repo), committing modifications, and then [pull a request](https://help.github.com/en/articles/about-pull-requests).  57 | 58 | Thanks for your contribution, and welcome to the [Otto DIY community](https://www.ottodiy.com/community) 59 | 60 | ## License: CC-BY-SA 61 | You can use all resources of Otto for free, but Otto DIY website must be included in any redistribution, and remixes must keep the CC-BY-SA license. In open source, the idea is that more people can have access; therefore, if you copy or remix Otto, you must also release it under the same open license, which means you must also release all files to the public. 62 | 63 | Creative Commons License
Otto DIY by [www.ottodiy.com](http://www.ottodiy.com) is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. 64 | 65 | Thanks to [Sebastian Coddington](https://github.com/SebastianCoddington) for this project. 66 | -------------------------------------------------------------------------------- /examples/App/OttoNinja_APP/OttoNinja_APP.ino: -------------------------------------------------------------------------------- 1 | // PINOUT FOR ESP8266 2 | 3 | // A0 = GPIO A0 TX = GPIO 1 4 | // D0 = GPIO 16 RX = GPIO 3 5 | // D5 = GPIO 14 D1 = GPIO 5 6 | // D6 = GPIO 12 D2 = GPIO 4 7 | // D7 = GPIO 13 D3 = GPIO 0 8 | // D8 = GPIO 15 D4 = GPIO 2 9 | // S3 = GPIO 9 10 | // SK = GPIO 10 11 | 12 | /* 13 | -- Remote Control Otto Ninja -- 14 | 15 | This source code of graphical user interface 16 | has been generated automatically by RemoteXY editor. 17 | To compile this code using RemoteXY library 2.4.3 or later version 18 | download by link http://remotexy.com/en/library/ 19 | To connect using RemoteXY mobile app by link http://remotexy.com/en/download/ 20 | - for ANDROID 4.5.1 or later version; 21 | - for iOS 1.4.1 or later version; 22 | 23 | This source code is free software; you can redistribute it and/or 24 | modify it under the terms of the GNU Lesser General Public 25 | License as published by the Free Software Foundation; either 26 | version 2.1 of the License, or (at your option) any later version. 27 | */ 28 | 29 | ////////////////////////////////////////////// 30 | // RemoteXY include library // 31 | ////////////////////////////////////////////// 32 | 33 | // RemoteXY select connection mode and include library 34 | #define REMOTEXY_MODE__ESP8266WIFI_LIB_POINT 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | // RemoteXY connection settings 42 | #define REMOTEXY_WIFI_SSID "OTTO NINJA" 43 | #define REMOTEXY_WIFI_PASSWORD "12345678" 44 | #define REMOTEXY_SERVER_PORT 6377 45 | 46 | // RemoteXY configurate 47 | #pragma pack(push, 1) 48 | uint8_t RemoteXY_CONF[] = 49 | { 255,6,0,0,0,66,0,13,8,0, 50 | 5,32,3,12,41,41,1,26,31,1, 51 | 3,79,16,16,12,1,31,82,240,159, 52 | 166,190,0,1,3,56,39,18,12,1, 53 | 31,240,159,146,191,0,1,3,79,39, 54 | 17,12,1,31,240,159,166,191,0,1, 55 | 3,56,16,17,12,1,31,76,240,159, 56 | 166,190,0 }; 57 | 58 | // this structure defines all the variables and events of your control interface 59 | struct { 60 | 61 | // input variables 62 | int8_t J_x; // =-100..100 x-coordinate joystick position 63 | int8_t J_y; // =-100..100 y-coordinate joystick position 64 | uint8_t button_B; // =1 if button pressed, else =0 65 | uint8_t button_X; // =1 if button pressed, else =0 66 | uint8_t button_Y; // =1 if button pressed, else =0 67 | uint8_t button_A; // =1 if button pressed, else =0 68 | 69 | // other variable 70 | uint8_t connect_flag; // =1 if wire connected, else =0 71 | 72 | } RemoteXY; 73 | #pragma pack(pop) 74 | 75 | ///////////////////////////////////////////// 76 | // END RemoteXY include // 77 | ///////////////////////////////////////////// 78 | 79 | //CALIBRATION SETTINGS: 80 | 81 | ////////// 2: 82 | 83 | // Left foot forward walking rotation Speed 84 | int LFFWRS= 20; // 0 = Slowest 90 = Fastest Default = 12 85 | 86 | // Right foot forward walking rotation Speed 87 | int RFFWRS= 20; // 0 = Slowest 90 = Fastest Default = 12 88 | 89 | ////////// 3: 90 | 91 | // Left foot Backward walking rotation Speed 92 | int LFBWRS= 20; // 0 = Slowest 90 = Fastest Default = 12 93 | 94 | // Right foot Backward walking rotation Speed 95 | int RFBWRS= 20; // 0 = Slowest 90 = Fastest Default = 12 96 | 97 | ////////// 4: 98 | 99 | // Left Leg standing Position 100 | int LA0= 60; // 0 = Full Tilt Right 180 = Full Tilt Left Default = 60 101 | 102 | // Right Leg standing position 103 | int RA0= 120; // 0 = Full Tilt Right 180 = Full Tilt Left Default = 120 104 | 105 | ////////// 5: 106 | 107 | // Left Leg tilt left walking position 108 | int LATL= 100; // 0 = Full Tilt Right 180 = Full Tilt Left Default BASIC = 85 Default HUMANOID = 80 109 | 110 | // Right Leg tilt left walking position 111 | int RATL= 175; // 0 = Full Tilt Right 180 = Full Tilt Left Default BASIC = 175 Default HUMANOID = 150 112 | 113 | // Left Leg tilt right walking position 114 | int LATR= 5; // 0 = Full Tilt Right 180 = Full Tilt Left Default BASIC = 5 Default HUMANOID = 30 115 | 116 | // Right Leg tilt right walking position 117 | int RATR= 80; // 0 = Full Tilt Right 180 = Full Tilt Left Default BASIC = 95 Default HUMANOID = 100 118 | 119 | ////////// 6: 120 | 121 | // Left Leg roll Position 122 | int LA1= 180; // 0 = Full Tilt Right 180 = Full Tilt Left Default = 170 123 | 124 | // Right Leg roll position 125 | int RA1= 0; // 0 = Full Tilt Right 180 = Full Tilt Left Default = 10 126 | 127 | 128 | //////////////////////////////////////// 129 | 130 | int currentmillis1 = 0; 131 | int currentmillis2 = 0; 132 | int currentmillis3 = 0; 133 | // Mode counter for biped/wheel mode 134 | int ModeCounter = 0; 135 | 136 | const uint8_t ServoLeftFootPin = 13; //D7 137 | const uint8_t ServoLeftLegPin = 15; //D8 138 | const uint8_t ServoRightFootPin = 0; //D3 139 | const uint8_t ServoRightLegPin = 2; //D4 140 | const uint8_t ServoLeftArmPin = 16; //D0 141 | const uint8_t ServoRightArmPin = 3; //RX 142 | const uint8_t ServoHeadPin = 1; //TX 143 | 144 | Servo myservoLeftFoot; 145 | Servo myservoLeftLeg; 146 | Servo myservoRightFoot; 147 | Servo myservoRightLeg; 148 | 149 | Servo myservoLeftArm; 150 | Servo myservoRightArm; 151 | Servo myservoHead; 152 | 153 | void setup() 154 | { 155 | 156 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 157 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 158 | myservoLeftLeg.attach(ServoLeftLegPin, 544, 2400); 159 | myservoRightLeg.attach(ServoRightLegPin, 544, 2400); 160 | 161 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 162 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 163 | 164 | myservoHead.attach(ServoHeadPin, 544, 2400); 165 | 166 | myservoHead.write(90); 167 | myservoLeftArm.write(90); 168 | myservoRightArm.write(90); 169 | delay(300); 170 | myservoLeftFoot.write(90); 171 | myservoRightFoot.write(90); 172 | myservoLeftLeg.write(60); 173 | myservoRightLeg.write(120); 174 | delay(300); 175 | myservoLeftArm.write(180); 176 | myservoRightArm.write(0); 177 | 178 | delay(500); 179 | 180 | myservoLeftFoot.detach(); 181 | myservoRightFoot.detach(); 182 | myservoLeftLeg.detach(); 183 | myservoRightLeg.detach(); 184 | 185 | myservoLeftArm.detach(); 186 | myservoRightArm.detach(); 187 | 188 | myservoHead.detach(); 189 | 190 | Serial.begin(250000); 191 | 192 | RemoteXY_Init (); 193 | } 194 | 195 | void loop() 196 | { 197 | RemoteXY_Handler (); 198 | 199 | if (RemoteXY.button_X == HIGH) 200 | { 201 | NinjaSetRoll(); 202 | ModeCounter = 1; 203 | } 204 | if (RemoteXY.button_Y == HIGH) 205 | { 206 | NinjaSetWalk(); 207 | ModeCounter = 0; 208 | } 209 | if (RemoteXY.button_A == HIGH) 210 | { 211 | NinjaLeftArm(); 212 | } 213 | 214 | if (RemoteXY.button_A == LOW) 215 | { 216 | NinjaLeftArmDown(); 217 | } 218 | 219 | if (RemoteXY.button_B == HIGH) 220 | { 221 | NinjaRightArm(); 222 | } 223 | 224 | if (RemoteXY.button_B == LOW) 225 | { 226 | NinjaRightArmDown(); 227 | } 228 | 229 | if (ModeCounter == 0) 230 | { 231 | if ((RemoteXY.J_x >= -10)&&(RemoteXY.J_x <= 10)&&(RemoteXY.J_y >= -10)&&(RemoteXY.J_y <= 10)) 232 | { 233 | NinjaWalkStop(); 234 | } 235 | 236 | if (RemoteXY.J_y > 0) 237 | { 238 | int lt= map(RemoteXY.J_x, 100, -100, 200, 700); 239 | int rt= map(RemoteXY.J_x, 100, -100, 700, 200); 240 | int Interval1 = 250; 241 | int Interval2 = 250 + rt; 242 | int Interval3 = 250 + rt + 250; 243 | int Interval4 = 250 + rt + 250 + lt; 244 | int Interval5 = 250 + rt + 250 + lt + 50; 245 | 246 | if(millis() > currentmillis1 + Interval5) 247 | { 248 | currentmillis1 = millis(); 249 | } 250 | 251 | 252 | if(millis() - currentmillis1 <= Interval1) 253 | { 254 | myservoLeftLeg.attach(ServoLeftLegPin, 544, 2400); 255 | myservoRightLeg.attach(ServoRightLegPin, 544, 2400); 256 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 257 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 258 | 259 | myservoLeftLeg.write(LATR); 260 | myservoRightLeg.write(RATR); 261 | } 262 | 263 | if((millis() - currentmillis1 >= Interval1)&&(millis() - currentmillis1 <= Interval2)) 264 | { 265 | myservoRightFoot.write(90-RFFWRS); 266 | 267 | } 268 | 269 | if((millis() - currentmillis1 >= Interval2)&&(millis() - currentmillis1 <= Interval3)) 270 | { 271 | myservoRightFoot.detach(); 272 | myservoLeftLeg.write(LATL); 273 | myservoRightLeg.write(RATL); 274 | } 275 | 276 | if((millis() - currentmillis1 >= Interval3)&&(millis() - currentmillis1 <= Interval4)) 277 | { 278 | myservoLeftFoot.write(90+LFFWRS); 279 | } 280 | 281 | if((millis() - currentmillis1 >= Interval4)&&(millis() - currentmillis1 <= Interval5)) 282 | { 283 | myservoLeftFoot.detach(); 284 | } 285 | } 286 | 287 | if (RemoteXY.J_y < 0) 288 | { 289 | 290 | int lt= map(RemoteXY.J_x, 100, -100, 200, 700); 291 | int rt= map(RemoteXY.J_x, 100, -100, 700, 200); 292 | int Interval1 = 250; 293 | int Interval2 = 250 + rt; 294 | int Interval3 = 250 + rt + 250; 295 | int Interval4 = 250 + rt + 250 + lt; 296 | int Interval5 = 250 + rt + 250 + lt + 50; 297 | 298 | if(millis() > currentmillis1 + Interval5) 299 | { 300 | currentmillis1 = millis(); 301 | } 302 | 303 | 304 | if(millis() - currentmillis1 <= Interval1) 305 | { 306 | myservoLeftLeg.attach(ServoLeftLegPin, 544, 2400); 307 | myservoRightLeg.attach(ServoRightLegPin, 544, 2400); 308 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 309 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 310 | 311 | myservoLeftLeg.write(LATR); 312 | myservoRightLeg.write(RATR); 313 | } 314 | 315 | if((millis() - currentmillis1 >= Interval1)&&(millis() - currentmillis1 <= Interval2)) 316 | { 317 | myservoRightFoot.write(90+RFBWRS); 318 | 319 | } 320 | 321 | if((millis() - currentmillis1 >= Interval2)&&(millis() - currentmillis1 <= Interval3)) 322 | { 323 | myservoRightFoot.detach(); 324 | myservoLeftLeg.write(LATL); 325 | myservoRightLeg.write(RATL); 326 | } 327 | 328 | if((millis() - currentmillis1 >= Interval3)&&(millis() - currentmillis1 <= Interval4)) 329 | { 330 | myservoLeftFoot.write(90-LFBWRS); 331 | } 332 | 333 | if((millis() - currentmillis1 >= Interval4)&&(millis() - currentmillis1 <= Interval5)) 334 | { 335 | myservoLeftFoot.detach(); 336 | } 337 | } 338 | } 339 | 340 | if (ModeCounter == 1) 341 | { 342 | if ((RemoteXY.J_x >= -10)&&(RemoteXY.J_x <= 10)&&(RemoteXY.J_y >= -10)&&(RemoteXY.J_y <= 10)) 343 | { 344 | NinjaRollStop(); 345 | } 346 | 347 | else 348 | { 349 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 350 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 351 | 352 | int LWS= map(RemoteXY.J_y, 100, -100, 135, 45); 353 | int RWS= map(RemoteXY.J_y, 100, -100, 45, 135); 354 | int LWD= map(RemoteXY.J_x, 100, -100, 45, 0); 355 | int RWD= map(RemoteXY.J_x, 100, -100, 0, -45); 356 | 357 | myservoLeftFoot.write(LWS+LWD); 358 | myservoRightFoot.write(RWS+RWD); 359 | } 360 | } 361 | 362 | Serial.print(" X: "); 363 | Serial.print(RemoteXY.J_x); 364 | Serial.print(" Y: "); 365 | Serial.print(RemoteXY.J_y); 366 | Serial.print(" MC: "); 367 | Serial.println(ModeCounter); 368 | } 369 | 370 | void NinjaStop() 371 | { 372 | myservoLeftFoot.detach(); 373 | myservoRightFoot.detach(); 374 | myservoLeftLeg.detach(); 375 | myservoRightLeg.detach(); 376 | } 377 | 378 | void NinjaSetWalk() 379 | { 380 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 381 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 382 | myservoLeftArm.write(90); 383 | myservoRightArm.write(90); 384 | delay(200); 385 | myservoLeftArm.detach(); 386 | myservoRightArm.detach(); 387 | myservoLeftLeg.attach(ServoLeftLegPin, 544, 2400); 388 | myservoRightLeg.attach(ServoRightLegPin, 544, 2400); 389 | myservoLeftLeg.write(LA0); 390 | myservoRightLeg.write(RA0); 391 | delay(300); 392 | myservoLeftLeg.detach(); 393 | myservoRightLeg.detach(); 394 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 395 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 396 | myservoLeftArm.write(180); 397 | myservoRightArm.write(0); 398 | delay(300); 399 | myservoLeftArm.detach(); 400 | myservoRightArm.detach(); 401 | } 402 | 403 | void NinjaSetRoll() 404 | { 405 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 406 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 407 | myservoLeftArm.write(90); 408 | myservoRightArm.write(90); 409 | delay(200); 410 | myservoLeftArm.detach(); 411 | myservoRightArm.detach(); 412 | myservoLeftLeg.attach(ServoLeftLegPin, 544, 2400); 413 | myservoRightLeg.attach(ServoRightLegPin, 544, 2400); 414 | myservoLeftLeg.write(LA1); 415 | myservoRightLeg.write(RA1); 416 | delay(300); 417 | myservoLeftLeg.detach(); 418 | myservoRightLeg.detach(); 419 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 420 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 421 | myservoLeftArm.write(180); 422 | myservoRightArm.write(0); 423 | delay(300); 424 | myservoLeftArm.detach(); 425 | myservoRightArm.detach(); 426 | } 427 | 428 | void NinjaWalkStop() 429 | { 430 | myservoLeftFoot.write(90); 431 | myservoRightFoot.write(90); 432 | myservoLeftLeg.write(LA0); 433 | myservoRightLeg.write(RA0); 434 | } 435 | 436 | void NinjaRollStop() 437 | { 438 | myservoLeftFoot.write(90); 439 | myservoRightFoot.write(90); 440 | myservoLeftFoot.detach(); 441 | myservoRightFoot.detach(); 442 | } 443 | 444 | void NinjaLeftArm() 445 | { 446 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 447 | myservoLeftArm.write(90); 448 | } 449 | 450 | void NinjaRightArm() 451 | { 452 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 453 | myservoRightArm.write(90); 454 | } 455 | 456 | void NinjaLeftArmDown() 457 | { 458 | myservoLeftArm.write(180); 459 | } 460 | 461 | void NinjaRightArmDown() 462 | { 463 | myservoRightArm.write(0); 464 | } 465 | -------------------------------------------------------------------------------- /examples/App/OttoNinja_App_matrix/OttoNinja_App_matrix.ino: -------------------------------------------------------------------------------- 1 | // PINOUT FOR ESP8266 2 | 3 | // A0 = GPIO A0 TX = GPIO 1 4 | // D0 = GPIO 16 RX = GPIO 3 5 | // D5 = GPIO 14 D1 = GPIO 5 6 | // D6 = GPIO 12 D2 = GPIO 4 7 | // D7 = GPIO 13 D3 = GPIO 0 8 | // D8 = GPIO 15 D4 = GPIO 2 9 | // S3 = GPIO 9 10 | // SK = GPIO 10 11 | 12 | /* 13 | -- remote control car wemos -- 14 | 15 | This source code of graphical user interface 16 | has been generated automatically by RemoteXY editor. 17 | To compile this code using RemoteXY library 2.4.3 or later version 18 | download by link http://remotexy.com/en/library/ 19 | To connect using RemoteXY mobile app by link http://remotexy.com/en/download/ 20 | - for ANDROID 4.5.1 or later version; 21 | - for iOS 1.4.1 or later version; 22 | 23 | This source code is free software; you can redistribute it and/or 24 | modify it under the terms of the GNU Lesser General Public 25 | License as published by the Free Software Foundation; either 26 | version 2.1 of the License, or (at your option) any later version. 27 | */ 28 | 29 | ////////////////////////////////////////////// 30 | // RemoteXY include library // 31 | ////////////////////////////////////////////// 32 | 33 | // RemoteXY select connection mode and include library 34 | #define REMOTEXY_MODE__ESP8266WIFI_LIB_POINT 35 | #include 36 | 37 | #include 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | Adafruit_8x16matrix matrix = Adafruit_8x16matrix(); 46 | 47 | // RemoteXY connection settings 48 | #define REMOTEXY_WIFI_SSID "OTTO NINJA" 49 | #define REMOTEXY_WIFI_PASSWORD "12345678" 50 | #define REMOTEXY_SERVER_PORT 6377 51 | 52 | 53 | // RemoteXY configurate 54 | #pragma pack(push, 1) 55 | uint8_t RemoteXY_CONF[] = 56 | { 255,6,0,0,0,66,0,13,8,0, 57 | 5,32,3,12,41,41,1,26,31,1, 58 | 3,79,16,16,12,1,31,82,240,159, 59 | 166,190,0,1,3,56,39,18,12,1, 60 | 31,240,159,146,191,0,1,3,79,39, 61 | 17,12,1,31,240,159,166,191,0,1, 62 | 3,56,16,17,12,1,31,76,240,159, 63 | 166,190,0 }; 64 | 65 | // this structure defines all the variables and events of your control interface 66 | struct { 67 | 68 | // input variables 69 | int8_t J_x; // =-100..100 x-coordinate joystick position 70 | int8_t J_y; // =-100..100 y-coordinate joystick position 71 | uint8_t button_B; // =1 if button pressed, else =0 72 | uint8_t button_X; // =1 if button pressed, else =0 73 | uint8_t button_Y; // =1 if button pressed, else =0 74 | uint8_t button_A; // =1 if button pressed, else =0 75 | 76 | // other variable 77 | uint8_t connect_flag; // =1 if wire connected, else =0 78 | 79 | } RemoteXY; 80 | #pragma pack(pop) 81 | 82 | ///////////////////////////////////////////// 83 | // END RemoteXY include // 84 | ///////////////////////////////////////////// 85 | 86 | 87 | 88 | 89 | 90 | //CALIBRATION SETTINGS: 91 | 92 | 93 | 94 | ////////// 2: 95 | 96 | // Left foot forward walking rotation Speed 97 | int LFFWRS= 20; // 0 = Slowest 90 = Fastest Default = 12 98 | 99 | // Right foot forward walking rotation Speed 100 | int RFFWRS= 20; // 0 = Slowest 90 = Fastest Default = 12 101 | 102 | ////////// 3: 103 | 104 | // Left foot Backward walking rotation Speed 105 | int LFBWRS= 20; // 0 = Slowest 90 = Fastest Default = 12 106 | 107 | // Right foot Backward walking rotation Speed 108 | int RFBWRS= 20; // 0 = Slowest 90 = Fastest Default = 12 109 | 110 | ////////// 4: 111 | 112 | // Left Ankle standing Position 113 | int LA0= 60; // 0 = Full Tilt Right 180 = Full Tilt Left Default = 60 114 | 115 | // Right Ankle standing position 116 | int RA0= 120; // 0 = Full Tilt Right 180 = Full Tilt Left Default = 120 117 | 118 | ////////// 5: 119 | 120 | // Left Ankle tilt left walking position 121 | int LATL= 100; // 0 = Full Tilt Right 180 = Full Tilt Left Default BASIC = 85 Default HUMANOID = 80 122 | 123 | // Right Ankle tilt left walking position 124 | int RATL= 175; // 0 = Full Tilt Right 180 = Full Tilt Left Default BASIC = 175 Default HUMANOID = 150 125 | 126 | // Left Ankle tilt right walking position 127 | int LATR= 5; // 0 = Full Tilt Right 180 = Full Tilt Left Default BASIC = 5 Default HUMANOID = 30 128 | 129 | // Right Ankle tilt right walking position 130 | int RATR= 80; // 0 = Full Tilt Right 180 = Full Tilt Left Default BASIC = 95 Default HUMANOID = 100 131 | 132 | ////////// 6: 133 | 134 | // Left Ankle roll Position 135 | int LA1= 180; // 0 = Full Tilt Right 180 = Full Tilt Left Default = 170 136 | 137 | // Right Ankle roll position 138 | int RA1= 0; // 0 = Full Tilt Right 180 = Full Tilt Left Default = 10 139 | 140 | 141 | //////////////////////////////////////// 142 | 143 | 144 | 145 | 146 | int currentmillis1 = 0; 147 | int currentmillis2 = 0; 148 | int currentmillis3 = 0; 149 | 150 | 151 | // Mode counter for biped/wheel mode 152 | int ModeCounter = 0; 153 | 154 | 155 | 156 | 157 | 158 | const uint8_t ServoLeftFootPin = 13; //D7 159 | const uint8_t ServoLeftAnklePin = 15; //D8 160 | const uint8_t ServoRightFootPin = 0; //D3 161 | const uint8_t ServoRightAnklePin = 2; //D4 162 | const uint8_t ServoLeftArmPin = 16; //D0 163 | const uint8_t ServoRightArmPin = 3; //RX 164 | const uint8_t ServoHeadPin = 1; //TX 165 | 166 | Servo myservoLeftFoot; 167 | Servo myservoLeftAnkle; 168 | Servo myservoRightFoot; 169 | Servo myservoRightAnkle; 170 | 171 | Servo myservoLeftArm; 172 | Servo myservoRightArm; 173 | Servo myservoHead; 174 | 175 | 176 | 177 | void setup() 178 | { 179 | 180 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 181 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 182 | myservoLeftAnkle.attach(ServoLeftAnklePin, 544, 2400); 183 | myservoRightAnkle.attach(ServoRightAnklePin, 544, 2400); 184 | 185 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 186 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 187 | 188 | myservoHead.attach(ServoHeadPin, 544, 2400); 189 | 190 | myservoHead.write(90); 191 | myservoLeftArm.write(90); 192 | myservoRightArm.write(90); 193 | delay(300); 194 | myservoLeftFoot.write(90); 195 | myservoRightFoot.write(90); 196 | myservoLeftAnkle.write(60); 197 | myservoRightAnkle.write(120); 198 | delay(300); 199 | myservoLeftArm.write(180); 200 | myservoRightArm.write(0); 201 | 202 | 203 | 204 | delay(500); 205 | 206 | myservoLeftFoot.detach(); 207 | myservoRightFoot.detach(); 208 | myservoLeftAnkle.detach(); 209 | myservoRightAnkle.detach(); 210 | 211 | myservoLeftArm.detach(); 212 | myservoRightArm.detach(); 213 | 214 | myservoHead.detach(); 215 | 216 | Serial.begin(250000); 217 | 218 | 219 | 220 | matrix.begin(0x70); // pass in the address 221 | 222 | matrix.setTextSize(1); 223 | matrix.setTextWrap(false); // we dont want text to wrap so it scrolls nicely 224 | matrix.setTextColor(LED_ON); 225 | matrix.setRotation(1); 226 | for (int8_t x=7; x>=-50; x--) 227 | { 228 | matrix.clear(); 229 | matrix.setCursor(x,0); 230 | matrix.print("NINJA"); 231 | matrix.writeDisplay(); 232 | delay(50); 233 | } 234 | 235 | RemoteXY_Init (); 236 | } 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | void loop() 245 | { 246 | RemoteXY_Handler (); 247 | 248 | if (RemoteXY.button_X == HIGH) 249 | { 250 | RobotSetRoll(); 251 | ModeCounter = 1; 252 | } 253 | if (RemoteXY.button_Y == HIGH) 254 | { 255 | RobotSetWalk(); 256 | ModeCounter = 0; 257 | } 258 | if (RemoteXY.button_A == HIGH) 259 | { 260 | RobotLeftArm(); 261 | } 262 | 263 | 264 | if (RemoteXY.button_A == LOW) 265 | { 266 | RobotLeftArmDown(); 267 | } 268 | 269 | 270 | 271 | if (RemoteXY.button_B == HIGH) 272 | { 273 | RobotRightArm(); 274 | } 275 | 276 | if (RemoteXY.button_B == LOW) 277 | { 278 | RobotRightArmDown(); 279 | } 280 | 281 | 282 | 283 | 284 | 285 | if (ModeCounter == 0) 286 | { 287 | if ((RemoteXY.J_x >= -10)&&(RemoteXY.J_x <= 10)&&(RemoteXY.J_y >= -10)&&(RemoteXY.J_y <= 10)) 288 | { 289 | RobotWalkStop(); 290 | } 291 | 292 | if (RemoteXY.J_y > 0) 293 | { 294 | int lt= map(RemoteXY.J_x, 100, -100, 200, 700); 295 | int rt= map(RemoteXY.J_x, 100, -100, 700, 200); 296 | int Interval1 = 250; 297 | int Interval2 = 250 + rt; 298 | int Interval3 = 250 + rt + 250; 299 | int Interval4 = 250 + rt + 250 + lt; 300 | int Interval5 = 250 + rt + 250 + lt + 50; 301 | 302 | if(millis() > currentmillis1 + Interval5) 303 | { 304 | currentmillis1 = millis(); 305 | } 306 | 307 | 308 | if(millis() - currentmillis1 <= Interval1) 309 | { 310 | myservoLeftAnkle.attach(ServoLeftAnklePin, 544, 2400); 311 | myservoRightAnkle.attach(ServoRightAnklePin, 544, 2400); 312 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 313 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 314 | 315 | myservoLeftAnkle.write(LATR); 316 | myservoRightAnkle.write(RATR); 317 | } 318 | 319 | if((millis() - currentmillis1 >= Interval1)&&(millis() - currentmillis1 <= Interval2)) 320 | { 321 | myservoRightFoot.write(90-RFFWRS); 322 | 323 | } 324 | 325 | if((millis() - currentmillis1 >= Interval2)&&(millis() - currentmillis1 <= Interval3)) 326 | { 327 | myservoRightFoot.detach(); 328 | myservoLeftAnkle.write(LATL); 329 | myservoRightAnkle.write(RATL); 330 | } 331 | 332 | if((millis() - currentmillis1 >= Interval3)&&(millis() - currentmillis1 <= Interval4)) 333 | { 334 | myservoLeftFoot.write(90+LFFWRS); 335 | } 336 | 337 | if((millis() - currentmillis1 >= Interval4)&&(millis() - currentmillis1 <= Interval5)) 338 | { 339 | myservoLeftFoot.detach(); 340 | } 341 | 342 | 343 | } 344 | 345 | 346 | if (RemoteXY.J_y < 0) 347 | { 348 | 349 | int lt= map(RemoteXY.J_x, 100, -100, 200, 700); 350 | int rt= map(RemoteXY.J_x, 100, -100, 700, 200); 351 | int Interval1 = 250; 352 | int Interval2 = 250 + rt; 353 | int Interval3 = 250 + rt + 250; 354 | int Interval4 = 250 + rt + 250 + lt; 355 | int Interval5 = 250 + rt + 250 + lt + 50; 356 | 357 | if(millis() > currentmillis1 + Interval5) 358 | { 359 | currentmillis1 = millis(); 360 | } 361 | 362 | 363 | if(millis() - currentmillis1 <= Interval1) 364 | { 365 | myservoLeftAnkle.attach(ServoLeftAnklePin, 544, 2400); 366 | myservoRightAnkle.attach(ServoRightAnklePin, 544, 2400); 367 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 368 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 369 | 370 | myservoLeftAnkle.write(LATR); 371 | myservoRightAnkle.write(RATR); 372 | } 373 | 374 | if((millis() - currentmillis1 >= Interval1)&&(millis() - currentmillis1 <= Interval2)) 375 | { 376 | myservoRightFoot.write(90+RFBWRS); 377 | 378 | } 379 | 380 | if((millis() - currentmillis1 >= Interval2)&&(millis() - currentmillis1 <= Interval3)) 381 | { 382 | myservoRightFoot.detach(); 383 | myservoLeftAnkle.write(LATL); 384 | myservoRightAnkle.write(RATL); 385 | } 386 | 387 | if((millis() - currentmillis1 >= Interval3)&&(millis() - currentmillis1 <= Interval4)) 388 | { 389 | myservoLeftFoot.write(90-LFBWRS); 390 | } 391 | 392 | if((millis() - currentmillis1 >= Interval4)&&(millis() - currentmillis1 <= Interval5)) 393 | { 394 | myservoLeftFoot.detach(); 395 | } 396 | 397 | 398 | } 399 | } 400 | 401 | 402 | 403 | 404 | if (ModeCounter == 1) 405 | { 406 | if ((RemoteXY.J_x >= -10)&&(RemoteXY.J_x <= 10)&&(RemoteXY.J_y >= -10)&&(RemoteXY.J_y <= 10)) 407 | { 408 | RobotRollStop(); 409 | } 410 | 411 | else 412 | { 413 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 414 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 415 | 416 | int LWS= map(RemoteXY.J_y, 100, -100, 135, 45); 417 | int RWS= map(RemoteXY.J_y, 100, -100, 45, 135); 418 | int LWD= map(RemoteXY.J_x, 100, -100, 45, 0); 419 | int RWD= map(RemoteXY.J_x, 100, -100, 0, -45); 420 | 421 | myservoLeftFoot.write(LWS+LWD); 422 | myservoRightFoot.write(RWS+RWD); 423 | } 424 | } 425 | 426 | 427 | 428 | 429 | 430 | 431 | Serial.print(" X: "); 432 | Serial.print(RemoteXY.J_x); 433 | Serial.print(" Y: "); 434 | Serial.print(RemoteXY.J_y); 435 | Serial.print(" MC: "); 436 | Serial.println(ModeCounter); 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | } 446 | 447 | 448 | 449 | void RobotStop() 450 | { 451 | myservoLeftFoot.detach(); 452 | myservoRightFoot.detach(); 453 | myservoLeftAnkle.detach(); 454 | myservoRightAnkle.detach(); 455 | 456 | } 457 | 458 | 459 | void RobotSetWalk() 460 | { 461 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 462 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 463 | myservoLeftArm.write(90); 464 | myservoRightArm.write(90); 465 | delay(200); 466 | myservoLeftArm.detach(); 467 | myservoRightArm.detach(); 468 | 469 | myservoLeftAnkle.attach(ServoLeftAnklePin, 544, 2400); 470 | myservoRightAnkle.attach(ServoRightAnklePin, 544, 2400); 471 | myservoLeftAnkle.write(LA0); 472 | myservoRightAnkle.write(RA0); 473 | delay(300); 474 | myservoLeftAnkle.detach(); 475 | myservoRightAnkle.detach(); 476 | 477 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 478 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 479 | myservoLeftArm.write(180); 480 | myservoRightArm.write(0); 481 | myservoLeftArm.detach(); 482 | myservoRightArm.detach(); 483 | } 484 | 485 | 486 | void RobotSetRoll() 487 | { 488 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 489 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 490 | myservoLeftArm.write(90); 491 | myservoRightArm.write(90); 492 | delay(200); 493 | myservoLeftArm.detach(); 494 | myservoRightArm.detach(); 495 | myservoLeftAnkle.attach(ServoLeftAnklePin, 544, 2400); 496 | myservoRightAnkle.attach(ServoRightAnklePin, 544, 2400); 497 | myservoLeftAnkle.write(LA1); 498 | myservoRightAnkle.write(RA1); 499 | delay(300); 500 | myservoLeftAnkle.detach(); 501 | myservoRightAnkle.detach(); 502 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 503 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 504 | myservoLeftArm.write(180); 505 | myservoRightArm.write(0); 506 | myservoLeftArm.detach(); 507 | myservoRightArm.detach(); 508 | 509 | 510 | 511 | } 512 | 513 | 514 | 515 | void RobotWalkStop() 516 | { 517 | myservoLeftFoot.write(90); 518 | myservoRightFoot.write(90); 519 | myservoLeftAnkle.write(LA0); 520 | myservoRightAnkle.write(RA0); 521 | 522 | } 523 | 524 | 525 | 526 | void RobotRollStop() 527 | { 528 | myservoLeftFoot.write(90); 529 | myservoRightFoot.write(90); 530 | myservoLeftFoot.detach(); 531 | myservoRightFoot.detach(); 532 | } 533 | 534 | 535 | 536 | 537 | void RobotLeftArm() 538 | { 539 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 540 | myservoLeftArm.write(90); 541 | } 542 | 543 | 544 | 545 | 546 | void RobotRightArm() 547 | { 548 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 549 | myservoRightArm.write(90); 550 | } 551 | 552 | 553 | 554 | void RobotLeftArmDown() 555 | { 556 | myservoLeftArm.write(180); 557 | } 558 | 559 | 560 | 561 | 562 | void RobotRightArmDown() 563 | { 564 | myservoRightArm.write(0); 565 | } 566 | -------------------------------------------------------------------------------- /examples/Humanoid/OttoNinjaHumanoid_Avoid/OttoNinjaHumanoid_Avoid.ino: -------------------------------------------------------------------------------- 1 | // PINOUT FOR ESP8266 2 | 3 | // A0 = GPIO A0 TX = GPIO 1 4 | // D0 = GPIO 16 RX = GPIO 3 5 | // D5 = GPIO 14 D1 = GPIO 5 6 | // D6 = GPIO 12 D2 = GPIO 4 7 | // D7 = GPIO 13 D3 = GPIO 0 8 | // D8 = GPIO 15 D4 = GPIO 2 9 | // S3 = GPIO 9 10 | // S2 = GPIO 10 11 | 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | Adafruit_8x16matrix matrix = Adafruit_8x16matrix(); 20 | 21 | //CALIBRATION SETTINGS: 22 | 23 | int LA0= 60 +0; // Left Leg standing Position - = Tilt Right + = Tilt Left 24 | int RA0= 120 +0; // Right Leg standing position - = Tilt Right + = Tilt Left 25 | int LA1= 180; // Left Leg roll Position - = Tilt Right + = Tilt Left 26 | int RA1= 0; // Right Leg roll position - = Tilt Right + = Tilt Left 27 | int LATL= LA0 +40; // Left Leg tilt left walking position - = Tilt Right + = Tilt Left 28 | int RATL= RA0 +60; // Right Leg tilt left walking position - = Tilt Right + = Tilt Left 29 | int LATR= LA0 -60; // Left Leg tilt right walking position - = Tilt Right + = Tilt Left 30 | int RATR= RA0 -40; // Right Leg tilt right walking position - = Tilt Right + = Tilt Left 31 | 32 | int LFFWRS=15; // Left foot forward walking rotation Speed 0 = SLOW 90 = FAST 33 | int RFFWRS=15 ; // Right foot forward walking rotation Speed 0 = SLOW 90 = FAST 34 | int LFBWRS= 15; // Left foot Backward walking rotation Speed 0 = SLOW 90 = FAST 35 | int RFBWRS= 15; // Right foot Backward walking rotation Speed 0 = SLOW 90 = FAST 36 | 37 | int LFFRRS=20; // Left foot forward rolling rotation Speed 0 = SLOW 90 = FAST 38 | int RFFRRS=20 ; // Right foot forward rolling rotation Speed 0 = SLOW 90 = FAST 39 | int LFBRRS= 20; // Left foot Backward rolling rotation Speed 0 = SLOW 90 = FAST 40 | int RFBRRS= 20; // Right foot Backward rolling rotation Speed 0 = SLOW 90 = FAST 41 | 42 | //////////////////////////////////////// 43 | 44 | 45 | 46 | int currentmillis1 = 0; 47 | 48 | int Interval1 = 300; 49 | int Interval2 = 600; 50 | int Interval3 = 900; 51 | int Interval4 = 1200; 52 | 53 | 54 | #define echoPin 14 // attach pin D5 ESP8266 to pin Echo of HC-SR04 55 | #define trigPin 12 //attach pin D6 ESP8266 to pin Trig of HC-SR04 56 | long duration; // variable for the duration of sound wave travel 57 | int distance; // variable for the distance measurement 58 | 59 | 60 | const uint8_t ServoLeftFootPin = 13; //D7 61 | const uint8_t ServoLeftLegPin = 15; //D8 62 | const uint8_t ServoRightFootPin = 0; //D3 63 | const uint8_t ServoRightLegPin = 2; //D4 64 | const uint8_t ServoLeftArmPin = 16; //D0 65 | const uint8_t ServoRightArmPin = 3; //RX 66 | const uint8_t ServoHeadPin = 1; //TX 67 | 68 | Servo myservoLeftFoot; 69 | Servo myservoLeftLeg; 70 | Servo myservoRightFoot; 71 | Servo myservoRightLeg; 72 | 73 | Servo myservoLeftArm; 74 | Servo myservoRightArm; 75 | Servo myservoHead; 76 | 77 | void setup() 78 | { 79 | 80 | NinjaHome(); 81 | 82 | Serial.begin(250000); 83 | 84 | pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT 85 | pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT 86 | 87 | 88 | matrix.begin(0x70); // pass in the address 89 | 90 | matrix.setTextSize(1); 91 | matrix.setTextWrap(false); // we dont want text to wrap so it scrolls nicely 92 | matrix.setTextColor(LED_ON); 93 | matrix.setRotation(3); 94 | for (int8_t x=7; x>=-50; x--) 95 | { 96 | matrix.clear(); 97 | matrix.setCursor(x,0); 98 | matrix.print("NINJA"); 99 | matrix.writeDisplay(); 100 | delay(50); 101 | } 102 | 103 | NinjaSetRoll(); 104 | 105 | } 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | void loop() 114 | { 115 | 116 | Distance(); 117 | 118 | 119 | if (distance >= 15) 120 | { 121 | NinjaRollForward(); 122 | HeadScan(); 123 | } 124 | 125 | if ((distance >= 2)&&(distance < 15)) 126 | { 127 | NinjaRollStop(); 128 | myservoHead.attach(ServoHeadPin, 544, 2400); 129 | myservoHead.write(90); 130 | delay(300); 131 | NinjaArmWave(); 132 | NinjaRollLeft(); 133 | delay(500); 134 | NinjaRollStop(); 135 | } 136 | 137 | } 138 | 139 | void NinjaHome() 140 | { 141 | myservoLeftLeg.attach(ServoLeftLegPin, 544, 2400); 142 | myservoRightLeg.attach(ServoRightLegPin, 544, 2400); 143 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 144 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 145 | myservoHead.attach(ServoHeadPin, 544, 2400); 146 | myservoLeftArm.write(180); 147 | myservoRightArm.write(0); 148 | myservoHead.write(90); 149 | delay(400); 150 | myservoLeftFoot.write(90); 151 | myservoRightFoot.write(90); 152 | myservoLeftLeg.write(60); 153 | myservoRightLeg.write(120); 154 | delay(400); 155 | myservoLeftLeg.detach(); 156 | myservoRightLeg.detach(); 157 | myservoLeftArm.detach(); 158 | myservoRightArm.detach(); 159 | myservoHead.detach(); 160 | } 161 | 162 | 163 | 164 | void NinjaSetWalk() 165 | { 166 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 167 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 168 | myservoLeftArm.write(90); 169 | myservoRightArm.write(90); 170 | delay(200); 171 | myservoLeftArm.detach(); 172 | myservoRightArm.detach(); 173 | myservoLeftLeg.attach(ServoLeftLegPin, 544, 2400); 174 | myservoRightLeg.attach(ServoRightLegPin, 544, 2400); 175 | myservoLeftLeg.write(LA0); 176 | myservoRightLeg.write(RA0); 177 | delay(300); 178 | myservoLeftLeg.detach(); 179 | myservoRightLeg.detach(); 180 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 181 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 182 | myservoLeftArm.write(180); 183 | myservoRightArm.write(0); 184 | delay(200); 185 | myservoLeftArm.detach(); 186 | myservoRightArm.detach(); 187 | } 188 | 189 | void NinjaWalkForward() 190 | { 191 | myservoLeftLeg.attach(ServoLeftLegPin, 544, 2400); 192 | myservoRightLeg.attach(ServoRightLegPin, 544, 2400); 193 | 194 | myservoLeftLeg.write(LATR); 195 | myservoRightLeg.write(RATR); 196 | delay(300); 197 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 198 | myservoRightFoot.write(90-RFFWRS); 199 | delay(300); 200 | myservoRightFoot.detach(); 201 | delay(100); 202 | myservoLeftLeg.write(LATL); 203 | myservoRightLeg.write(RATL); 204 | delay(300); 205 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 206 | myservoLeftFoot.write(90+LFFWRS); 207 | delay(300); 208 | myservoLeftFoot.detach(); 209 | delay(100); 210 | } 211 | 212 | void NinjaWalkBackward() 213 | { 214 | myservoLeftLeg.attach(ServoLeftLegPin, 544, 2400); 215 | myservoRightLeg.attach(ServoRightLegPin, 544, 2400); 216 | 217 | myservoLeftLeg.write(LATR); 218 | myservoRightLeg.write(RATR); 219 | delay(300); 220 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 221 | myservoRightFoot.write(90+RFBWRS); 222 | delay(300); 223 | myservoRightFoot.detach(); 224 | delay(100); 225 | myservoLeftLeg.write(LATL); 226 | myservoRightLeg.write(RATL); 227 | delay(300); 228 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 229 | myservoLeftFoot.write(90-LFBWRS); 230 | delay(300); 231 | myservoLeftFoot.detach(); 232 | delay(100); 233 | } 234 | 235 | void NinjaWalkLeft() 236 | { 237 | myservoLeftLeg.attach(ServoLeftLegPin, 544, 2400); 238 | myservoRightLeg.attach(ServoRightLegPin, 544, 2400); 239 | 240 | myservoLeftLeg.write(LATR); 241 | myservoRightLeg.write(RATR); 242 | delay(300); 243 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 244 | myservoRightFoot.write(90-RFFWRS); 245 | delay(50); 246 | myservoRightFoot.detach(); 247 | delay(100); 248 | myservoLeftLeg.write(LATL); 249 | myservoRightLeg.write(RATL); 250 | delay(300); 251 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 252 | myservoLeftFoot.write(90+LFFWRS); 253 | delay(300); 254 | myservoLeftFoot.detach(); 255 | delay(100); 256 | } 257 | 258 | void NinjaWalkRight() 259 | { 260 | myservoLeftLeg.attach(ServoLeftLegPin, 544, 2400); 261 | myservoRightLeg.attach(ServoRightLegPin, 544, 2400); 262 | 263 | myservoLeftLeg.write(LATR); 264 | myservoRightLeg.write(RATR); 265 | delay(300); 266 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 267 | myservoRightFoot.write(90-RFFWRS); 268 | delay(300); 269 | myservoRightFoot.detach(); 270 | delay(100); 271 | myservoLeftLeg.write(LATL); 272 | myservoRightLeg.write(RATL); 273 | delay(300); 274 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 275 | myservoLeftFoot.write(90+LFFWRS); 276 | delay(50); 277 | myservoLeftFoot.detach(); 278 | delay(100); 279 | } 280 | 281 | void NinjaWalkStop() 282 | { 283 | myservoLeftFoot.write(90); 284 | myservoRightFoot.write(90); 285 | myservoLeftLeg.write(LA0); 286 | myservoRightLeg.write(RA0); 287 | } 288 | 289 | void NinjaSetRoll() 290 | { 291 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 292 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 293 | myservoLeftArm.write(90); 294 | myservoRightArm.write(90); 295 | delay(200); 296 | myservoLeftArm.detach(); 297 | myservoRightArm.detach(); 298 | myservoLeftLeg.attach(ServoLeftLegPin, 544, 2400); 299 | myservoRightLeg.attach(ServoRightLegPin, 544, 2400); 300 | myservoLeftLeg.write(LA1); 301 | myservoRightLeg.write(RA1); 302 | delay(300); 303 | myservoLeftLeg.detach(); 304 | myservoRightLeg.detach(); 305 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 306 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 307 | myservoLeftArm.write(180); 308 | myservoRightArm.write(0); 309 | delay(300); 310 | myservoLeftArm.detach(); 311 | myservoRightArm.detach(); 312 | } 313 | 314 | void NinjaRollForward() 315 | { 316 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 317 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 318 | myservoLeftFoot.write(90+LFFRRS); 319 | myservoRightFoot.write(90-RFFRRS); 320 | } 321 | 322 | void NinjaRollBackward() 323 | { 324 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 325 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 326 | myservoLeftFoot.write(90-LFBRRS); 327 | myservoRightFoot.write(90+RFBRRS); 328 | } 329 | 330 | void NinjaRollLeft() 331 | { 332 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 333 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 334 | myservoLeftFoot.write(90-LFBRRS); 335 | myservoRightFoot.write(90-RFFRRS); 336 | } 337 | 338 | void NinjaRollRight() 339 | { 340 | myservoLeftFoot.attach(ServoLeftFootPin, 544, 2400); 341 | myservoRightFoot.attach(ServoRightFootPin, 544, 2400); 342 | myservoLeftFoot.write(90+LFFRRS); 343 | myservoRightFoot.write(90+RFBRRS); 344 | } 345 | 346 | void NinjaRollStop() 347 | { 348 | myservoLeftFoot.write(90); 349 | myservoRightFoot.write(90); 350 | myservoLeftFoot.detach(); 351 | myservoRightFoot.detach(); 352 | } 353 | 354 | 355 | 356 | void NinjaArmWave() 357 | { 358 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 359 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 360 | myservoLeftArm.write(0); 361 | myservoRightArm.write(180); 362 | delay(400); 363 | myservoLeftArm.write(0); 364 | myservoRightArm.write(135); 365 | delay(200); 366 | myservoLeftArm.write(45); 367 | myservoRightArm.write(180); 368 | delay(200); 369 | myservoLeftArm.write(0); 370 | myservoRightArm.write(135); 371 | delay(200); 372 | myservoLeftArm.write(45); 373 | myservoRightArm.write(180); 374 | delay(200); 375 | myservoLeftArm.write(180); 376 | myservoRightArm.write(0); 377 | delay(400); 378 | myservoLeftArm.detach(); 379 | myservoRightArm.detach(); 380 | } 381 | 382 | 383 | 384 | 385 | 386 | void Distance() 387 | { 388 | // Clears the trigPin condition 389 | digitalWrite(trigPin, LOW); 390 | delayMicroseconds(2); 391 | // Sets the trigPin HIGH (ACTIVE) for 10 microseconds 392 | digitalWrite(trigPin, HIGH); 393 | delayMicroseconds(10); 394 | digitalWrite(trigPin, LOW); 395 | // Reads the echoPin, returns the sound wave travel time in microseconds 396 | duration = pulseIn(echoPin, HIGH); 397 | // Calculating the distance 398 | distance = duration * 0.034 / 2; // Speed of sound wave divided by 2 (go and back) 399 | // Displays the distance on the Serial Monitor 400 | Serial.print("Distance: "); 401 | Serial.print(distance); 402 | Serial.println(" cm"); 403 | } 404 | 405 | 406 | void HeadScan() 407 | { 408 | 409 | if(millis() > currentmillis1 + Interval4) 410 | { 411 | currentmillis1 = millis(); 412 | } 413 | 414 | 415 | if(millis() - currentmillis1 <= Interval1) 416 | { 417 | myservoHead.attach(ServoHeadPin, 544, 2400); 418 | myservoHead.write(30); 419 | } 420 | 421 | if((millis() - currentmillis1 > Interval1)&&(millis() - currentmillis1 <= Interval2)) 422 | { 423 | myservoHead.attach(ServoHeadPin, 544, 2400); 424 | myservoHead.write(90); 425 | 426 | } 427 | 428 | if((millis() - currentmillis1 > Interval2)&&(millis() - currentmillis1 <= Interval3)) 429 | { 430 | myservoHead.attach(ServoHeadPin, 544, 2400); 431 | myservoHead.write(150); 432 | 433 | } 434 | 435 | if((millis() - currentmillis1 > Interval3)&&(millis() - currentmillis1 <= Interval4)) 436 | { 437 | myservoHead.attach(ServoHeadPin, 544, 2400); 438 | myservoHead.write(90); 439 | 440 | } 441 | } 442 | -------------------------------------------------------------------------------- /examples/Humanoid/OttoNinjaHumanoid_Demo/OttoNinjaHumanoid_Demo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This sketch uses a combination of ultrasonic sensor and matrix 3 | to enable Ninja humanoid to say hello Iam Ninja when you wave 4 | your hands in front of him. 5 | */ 6 | 7 | // PINOUT FOR ESP8266 8 | 9 | // A0 = GPIO A0 TX = GPIO 1 10 | // D0 = GPIO 16 RX = GPIO 3 11 | // D5 = GPIO 14 D1 = GPIO 5 12 | // D6 = GPIO 12 D2 = GPIO 4 13 | // D7 = GPIO 13 D3 = GPIO 0 14 | // D8 = GPIO 15 D4 = GPIO 2 15 | // S3 = GPIO 9 16 | // S2 = GPIO 10 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | Adafruit_8x16matrix matrix = Adafruit_8x16matrix(); 26 | 27 | //CALIBRATION SETTINGS: 28 | 29 | int LA0= 60 +0; // Left Leg standing Position - = Tilt Right + = Tilt Left 30 | int RA0= 120 +0; // Right Leg standing position - = Tilt Right + = Tilt Left 31 | int LA1= 180; // Left Leg roll Position - = Tilt Right + = Tilt Left 32 | int RA1= 0; // Right Leg roll position - = Tilt Right + = Tilt Left 33 | int LATL= LA0 +40; // Left Leg tilt left walking position - = Tilt Right + = Tilt Left 34 | int RATL= RA0 +60; // Right Leg tilt left walking position - = Tilt Right + = Tilt Left 35 | int LATR= LA0 -60; // Left Leg tilt right walking position - = Tilt Right + = Tilt Left 36 | int RATR= RA0 -40; // Right Leg tilt right walking position - = Tilt Right + = Tilt Left 37 | 38 | int LFFWRS=15; // Left foot forward walking rotation Speed 0 = SLOW 90 = FAST 39 | int RFFWRS=15 ; // Right foot forward walking rotation Speed 0 = SLOW 90 = FAST 40 | int LFBWRS= 15; // Left foot Backward walking rotation Speed 0 = SLOW 90 = FAST 41 | int RFBWRS= 15; // Right foot Backward walking rotation Speed 0 = SLOW 90 = FAST 42 | 43 | 44 | //////////////////////////////////////// 45 | 46 | const uint8_t ServoLeftFootPin = 13; //D7 47 | const uint8_t ServoLeftLegPin = 15; //D8 48 | const uint8_t ServoRightFootPin = 0; //D3 49 | const uint8_t ServoRightLegPin = 2; //D4 50 | const uint8_t ServoLeftArmPin = 16; //D0 51 | const uint8_t ServoRightArmPin = 3; //RX 52 | const uint8_t ServoHeadPin = 1; //TX 53 | 54 | Servo myservoLeftFoot; 55 | Servo myservoLeftLeg; 56 | Servo myservoRightFoot; 57 | Servo myservoRightLeg; 58 | 59 | Servo myservoLeftArm; 60 | Servo myservoRightArm; 61 | Servo myservoHead; 62 | 63 | #define echoPin 14 // attach pin D5 ESP8266 to pin Echo of HC-SR04 64 | #define trigPin 12 //attach pin D6 ESP8266 to pin Trig of HC-SR04 65 | long duration; // variable for the duration of sound wave travel 66 | int distance; // variable for the distance measurement 67 | 68 | void setup() 69 | { 70 | 71 | NinjaHome(); 72 | 73 | Serial.begin(250000); 74 | 75 | pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT 76 | pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT 77 | 78 | matrix.begin(0x70); // pass in the address 79 | 80 | matrix.setTextSize(1); 81 | matrix.setTextWrap(false); // we dont want text to wrap so it scrolls nicely 82 | matrix.setTextColor(LED_ON); 83 | matrix.setRotation(3); 84 | for (int8_t x=7; x>=-50; x--) 85 | { 86 | matrix.clear(); 87 | matrix.setCursor(x,0); 88 | matrix.print("NINJA"); 89 | matrix.writeDisplay(); 90 | delay(50); 91 | } 92 | 93 | } 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | void loop() 102 | { 103 | 104 | Distance(); 105 | 106 | if ((distance >= 2)&&(distance < 10)) 107 | { 108 | RobotHeadShake(); 109 | RobotLeftArmWave(); 110 | IAmNinja(); 111 | } 112 | 113 | } 114 | 115 | 116 | void NinjaHome() 117 | { 118 | myservoLeftLeg.attach(ServoLeftLegPin, 544, 2400); 119 | myservoRightLeg.attach(ServoRightLegPin, 544, 2400); 120 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 121 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 122 | myservoHead.attach(ServoHeadPin, 544, 2400); 123 | myservoLeftArm.write(180); 124 | myservoRightArm.write(0); 125 | myservoHead.write(90); 126 | delay(400); 127 | myservoLeftLeg.write(60); 128 | myservoRightLeg.write(120); 129 | delay(400); 130 | myservoLeftLeg.detach(); 131 | myservoRightLeg.detach(); 132 | myservoLeftArm.detach(); 133 | myservoRightArm.detach(); 134 | myservoHead.detach(); 135 | } 136 | 137 | 138 | void RobotHeadShake() 139 | { 140 | myservoHead.attach(ServoHeadPin, 544, 2400); 141 | myservoHead.write(135); 142 | delay(200); 143 | myservoHead.write(45); 144 | delay(400); 145 | myservoHead.write(90); 146 | delay(200); 147 | 148 | } 149 | 150 | 151 | void RobotLeftArmWave() 152 | { 153 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 154 | myservoRightArm.write(180); 155 | delay(400); 156 | myservoRightArm.write(135); 157 | delay(200); 158 | myservoRightArm.write(180); 159 | delay(200); 160 | myservoRightArm.write(135); 161 | delay(200); 162 | myservoRightArm.write(180); 163 | delay(200); 164 | myservoRightArm.write(0); 165 | delay(400); 166 | } 167 | 168 | 169 | 170 | void IAmNinja() 171 | { 172 | matrix.setTextSize(1); 173 | matrix.setTextWrap(false); // we dont want text to wrap so it scrolls nicely 174 | matrix.setTextColor(LED_ON); 175 | matrix.setRotation(3); 176 | for (int8_t x=7; x>=-80; x--) 177 | { 178 | matrix.clear(); 179 | matrix.setCursor(x,0); 180 | matrix.print("I AM NINJA"); 181 | matrix.writeDisplay(); 182 | delay(50); 183 | } 184 | } 185 | 186 | void Distance() 187 | { 188 | // Clears the trigPin condition 189 | digitalWrite(trigPin, LOW); 190 | delayMicroseconds(2); 191 | // Sets the trigPin HIGH (ACTIVE) for 10 microseconds 192 | digitalWrite(trigPin, HIGH); 193 | delayMicroseconds(10); 194 | digitalWrite(trigPin, LOW); 195 | // Reads the echoPin, returns the sound wave travel time in microseconds 196 | duration = pulseIn(echoPin, HIGH); 197 | // Calculating the distance 198 | distance = duration * 0.034 / 2; // Speed of sound wave divided by 2 (go and back) 199 | // Displays the distance on the Serial Monitor 200 | Serial.print("Distance: "); 201 | Serial.print(distance); 202 | Serial.println(" cm"); 203 | } 204 | -------------------------------------------------------------------------------- /examples/LED matrix/OttoE_alleyes/OttoE_alleyes.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Designed specifically to work with the Otto DIY 16x8 LED Matrix eyes 3 | 4 | These display use I2C to communicate, 2 pins are required to 5 | interface. There are multiple selectable I2C addresses. For 6 | with 2 Address Select pins: 0x70, 0x71, 0x72 or 0x73. For backpacks 7 | with 3 Address Select pins: 0x70 thru 0x77 8 | 9 | Otto DIY invests time and resources providing this open source code, 10 | please support Otto DIY and open-source hardware by purchasing 11 | products from ottodiy.com! 12 | ****************************************************/ 13 | 14 | #include 15 | #include 16 | Adafruit_8x16matrix matrix = Adafruit_8x16matrix(); 17 | 18 | static const uint8_t PROGMEM 19 | logo_bmp[] = { B01111110,B10000001,B10111001,B10101001,B10111001,B10010001,B10111001,B10010001,B10010001,B10111001,B10010001,B10111001,B10101001,B10111001,B10000001,B01111110}, 20 | happy_bmp[] = { B00000000,B00111100,B00000010,B00000010,B00000010,B00000010,B00111100,B00000000,B00000000,B00111100,B00000010,B00000010,B00000010,B00000010,B00111100,B00000000}, 21 | eyes_bmp[] = { B00000000,B00111100,B01000010,B01001010,B01000010,B01000010,B00111100,B00000000,B00000000,B00111100,B01000010,B01001010,B01000010,B01000010,B00111100,B00000000}, 22 | sad_bmp[] = { B00000000,B00010000,B00010000,B00010000,B00010000,B00010000,B00010000,B00000000,B00000000,B00010000,B00010000,B00010000,B00010000,B00010000,B00010000,B00000000}, 23 | xx_bmp[] = { B00000000,B00100010,B00010100,B00001000,B00010100,B00100010,B00000000,B00000000,B00000000,B00000000,B00100010,B00010100,B00001000,B00010100,B00100010,B00000000}, 24 | XX_bmp[] = { B01000001,B00100010,B00010100,B00001000,B00010100,B00100010,B01000001,B00000000,B00000000,B01000001,B00100010,B00010100,B00001000,B00010100,B00100010,B01000001}, 25 | angry_bmp[] = { B00000000,B00011110,B00111100,B01111000,B01110000,B00100000,B00000000,B00000000,B00000000,B00000000,B00100000,B01110000,B01111000,B00111100,B00011110,B00000000}, 26 | angry2_bmp[] = { B00000000,B00000010,B00000100,B00001000,B00010000,B00100000,B00000000,B00000000,B00000000,B00000000,B00100000,B00010000,B00001000,B00000100,B00000010,B00000000}, 27 | sleep_bmp[] = { B00000000,B00100010,B00110010,B00101010,B00100110,B00100010,B00000000,B00000000,B00000000,B00000000,B00100010,B00110010,B00101010,B00100110,B00100010,B00000000}, 28 | freetful_bmp[] = { B00000000,B00100000,B00010000,B00001000,B00000100,B00000010,B00000000,B00000000,B00000000,B00000000,B00000010,B00000100,B00001000,B00010000,B00100000,B00000000}, 29 | love_bmp[] = { B00000000,B00001100,B00011110,B00111100,B00111100,B00011110,B00001100,B00000000,B00000000,B00001100,B00011110,B00111100,B00111100,B00011110,B00001100,B00000000}, 30 | confused_bmp[] = { B00000000,B01111100,B10000010,B10111010,B10101010,B10001010,B01111000,B00000000,B00000000,B01111100,B10000010,B10111010,B10101010,B10001010,B01111000,B00000000}, 31 | wave_bmp[] = { B00000000,B00100000,B00010000,B00001000,B00010000,B00100000,B00010000,B00000000,B00000000,B00100000,B00010000,B00001000,B00010000,B00100000,B00010000,B00000000}, 32 | magic_bmp[] = { B00000000,B00000000,B01111110,B11111111,B01111110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111110,B11111111,B01111110,B00000000,B00000000}, 33 | fail_bmp[] = { B00000000,B00110000,B01111000,B01111000,B01111100,B00111100,B00001000,B00000000,B00000000,B00001000,B00111100,B01111100,B01111000,B01111000,B00110000,B00000000}, 34 | full_bmp[] = { B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111 }; 35 | 36 | void setup() { 37 | Serial.begin(9600); 38 | Serial.println("16x8 LED Matrix Test"); 39 | matrix.begin(0x70); // pass in the address 40 | } 41 | 42 | void loop() { 43 | 44 | matrix.setTextSize(1); 45 | matrix.setTextWrap(true); // we dont want text to wrap so it scrolls nicely 46 | matrix.setTextColor(LED_ON); 47 | matrix.setRotation(1); 48 | for (int8_t x=0; x>=-70; x--) { 49 | matrix.clear(); 50 | matrix.setCursor(x,0); 51 | matrix.print("I am a Ninja!"); 52 | matrix.writeDisplay(); 53 | delay(100); 54 | } 55 | matrix.setRotation(0); 56 | 57 | matrix.clear(); 58 | matrix.drawBitmap(0, 8, full_bmp, 8, 8, LED_ON); 59 | matrix.writeDisplay(); 60 | delay(1000); 61 | 62 | matrix.clear(); 63 | matrix.drawBitmap(0, 0, full_bmp, 8, 8, LED_ON); 64 | matrix.writeDisplay(); 65 | delay(1000); 66 | matrix.clear(); 67 | matrix.drawBitmap(0, 0, happy_bmp, 8, 16, LED_ON); 68 | matrix.writeDisplay(); 69 | delay(2000); 70 | matrix.clear(); 71 | matrix.drawBitmap(0, 0, eyes_bmp, 8, 16, LED_ON); 72 | matrix.writeDisplay(); 73 | delay(2000); 74 | matrix.clear(); 75 | matrix.drawBitmap(0, 0, sad_bmp, 8, 16, LED_ON); 76 | matrix.writeDisplay(); 77 | delay(2000); 78 | matrix.clear(); 79 | matrix.drawBitmap(0, 0, angry_bmp, 8, 16, LED_ON); 80 | matrix.writeDisplay(); 81 | delay(2000); 82 | matrix.clear(); 83 | matrix.drawBitmap(0, 0, sleep_bmp, 8, 16, LED_ON); 84 | matrix.writeDisplay(); 85 | delay(2000); 86 | matrix.clear(); 87 | matrix.drawBitmap(0, 0, freetful_bmp, 8, 16, LED_ON); 88 | matrix.writeDisplay(); 89 | delay(2000); 90 | matrix.clear(); 91 | matrix.drawBitmap(0, 0, love_bmp, 8, 16, LED_ON); 92 | matrix.writeDisplay(); 93 | delay(2000); 94 | matrix.clear(); 95 | matrix.drawBitmap(0, 0, confused_bmp, 8, 16, LED_ON); 96 | matrix.writeDisplay(); 97 | delay(2000); 98 | matrix.clear(); 99 | matrix.drawBitmap(0, 0, wave_bmp, 8, 16, LED_ON); 100 | matrix.writeDisplay(); 101 | delay(2000); 102 | matrix.clear(); 103 | matrix.drawBitmap(0, 0, magic_bmp, 8, 16, LED_ON); 104 | matrix.writeDisplay(); 105 | delay(2000); 106 | matrix.clear(); 107 | matrix.drawBitmap(0, 0, fail_bmp, 8, 16, LED_ON); 108 | matrix.writeDisplay(); 109 | delay(500); 110 | matrix.clear(); 111 | matrix.drawBitmap(0, 0, xx_bmp, 8, 16, LED_ON); 112 | matrix.writeDisplay(); 113 | delay(200); 114 | matrix.clear(); 115 | matrix.drawBitmap(0, 0, XX_bmp, 8, 16, LED_ON); 116 | matrix.writeDisplay(); 117 | delay(1000); 118 | 119 | matrix.clear(); 120 | matrix.drawBitmap(0, 0, logo_bmp, 8, 16, LED_ON); 121 | matrix.writeDisplay(); 122 | delay(1000); 123 | 124 | matrix.setTextSize(1); 125 | matrix.setTextWrap(false); // we dont want text to wrap so it scrolls nicely 126 | matrix.setTextColor(LED_ON); 127 | matrix.setRotation(1); 128 | for (int8_t x=7; x>=-36; x--) { 129 | matrix.clear(); 130 | matrix.setCursor(x,0); 131 | matrix.print("Otto DIY"); 132 | matrix.writeDisplay(); 133 | delay(100); 134 | } 135 | matrix.setRotation(0); 136 | 137 | matrix.clear(); // clear display 138 | matrix.drawPixel(0, 0, LED_ON); 139 | matrix.writeDisplay(); // write the changes we just made to the display 140 | delay(500); 141 | 142 | matrix.clear(); 143 | matrix.drawLine(0,0, 7,15, LED_ON); 144 | matrix.writeDisplay(); // write the changes we just made to the display 145 | delay(500); 146 | 147 | matrix.clear(); 148 | matrix.drawRect(0,0, 8,16, LED_ON); 149 | matrix.fillRect(2,2, 4,12, LED_ON); 150 | matrix.writeDisplay(); // write the changes we just made to the display 151 | delay(500); 152 | 153 | matrix.clear(); 154 | matrix.drawCircle(3,8, 3, LED_ON); 155 | matrix.writeDisplay(); // write the changes we just made to the display 156 | delay(500); 157 | 158 | } 159 | -------------------------------------------------------------------------------- /examples/LED matrix/OttoE_flappybird/OttoE_flappybird.ino: -------------------------------------------------------------------------------- 1 | // Arduino Flappy Bird homage by augustzf@gmail.com 2 | #include 3 | #include 4 | #include 5 | #include 6 | Adafruit_8x16matrix matrix = Adafruit_8x16matrix(); 7 | 8 | static const uint8_t PROGMEM 9 | bird0[] = 10 | { 11 | B00011000, 12 | B00111100, 13 | B00110100, 14 | B11111111, 15 | B10111111, 16 | B11011100, 17 | B01111100, 18 | B00111000 } 19 | , 20 | bird1[] = 21 | { 22 | B00000000, 23 | B00011000, 24 | B00111100, 25 | B00110111, 26 | B11111111, 27 | B10011100, 28 | B11111100, 29 | B00111000 } 30 | , 31 | bird2[] = 32 | { 33 | B00011000, 34 | B00111100, 35 | B00110100, 36 | B00111111, 37 | B01111111, 38 | B11011100, 39 | B10111100, 40 | B11111000 }; 41 | 42 | const byte vibration PROGMEM = A0; // vibration sensor 43 | const int tapLevel PROGMEM = 512; 44 | 45 | double initYVelocity = 6.5; 46 | double gravity = -9.8; 47 | long birdTime; 48 | long previousBirdTime; 49 | byte birdPos = 3; 50 | byte tailPos = 3; 51 | byte birdStart; 52 | byte topWall; 53 | byte bottomWall; 54 | int wallDelay = 250; 55 | byte wallGap = 5; 56 | long wallTime; 57 | int wallCount; 58 | long previousWallTime; 59 | byte wallPosition = 0; 60 | boolean gameMode = false; 61 | long frameTime; 62 | long previousFrameTime; 63 | byte frame = 0; 64 | byte frameChange = 1; 65 | byte lives = 2; 66 | 67 | void setup() { 68 | 69 | pinMode(vibration, INPUT_PULLUP); 70 | 71 | matrix.begin(0x70); 72 | matrix.setRotation(1); 73 | matrix.setBrightness(3); 74 | matrix.setTextSize(1); 75 | matrix.setTextWrap(false); // we dont want text to wrap so it scrolls nicely 76 | matrix.setTextColor(LED_ON); 77 | matrix.clear(); 78 | matrix.writeDisplay(); 79 | previousBirdTime = millis(); 80 | topWall = random(0,4); 81 | bottomWall = topWall + 4; 82 | wallPosition = 0; 83 | gameMode = false; 84 | } 85 | 86 | void loop() { 87 | matrix.clear(); 88 | 89 | if(gameMode == false) 90 | { 91 | 92 | if(analogRead(vibration)< tapLevel) 93 | { 94 | gameMode = true; 95 | } 96 | 97 | frameTime = millis(); 98 | 99 | if(frameTime - previousFrameTime > 250) { 100 | previousFrameTime = frameTime; 101 | frame += frameChange; 102 | if(frame >= 2 || frame <= 0) frameChange *= -1; 103 | } 104 | 105 | if(frame == 0) matrix.drawBitmap(0, 0, bird0, 8, 8, LED_ON); 106 | else if(frame == 1) matrix.drawBitmap(0, 0, bird1, 8, 8, LED_ON); 107 | else if(frame == 2) matrix.drawBitmap(0, 0, bird2, 8, 8, LED_ON); 108 | } 109 | 110 | else 111 | { 112 | if(analogRead(vibration)= bottomWall || next <= topWall) 125 | { 126 | gameMode = false; 127 | 128 | int scoreInt = wallCount-1; 129 | 130 | const char* temp = "Game Over"; 131 | 132 | for (int8_t x=15; x>=-1*9*5+1; x--) 133 | { 134 | matrix.clear(); 135 | matrix.setCursor(x,0); 136 | matrix.print(temp); 137 | matrix.writeDisplay(); 138 | delay(75); 139 | } 140 | } 141 | wallCount++; 142 | } 143 | 144 | } 145 | 146 | matrix.writeDisplay(); 147 | } 148 | 149 | void drawWalls() 150 | { 151 | wallTime = millis(); 152 | 153 | if(wallPosition > 15) 154 | { 155 | topWall = random(0,4); 156 | bottomWall = topWall + 4; 157 | wallPosition = 0; 158 | } 159 | 160 | matrix.drawLine(15-wallPosition, 0, 15-wallPosition, topWall, LED_ON); 161 | 162 | matrix.drawLine(15-wallPosition, bottomWall, 15-wallPosition, 15, LED_ON); 163 | 164 | if(wallTime - previousWallTime > wallDelay) { 165 | previousWallTime = wallTime; 166 | wallPosition++; 167 | } 168 | } 169 | 170 | int calculateY() 171 | { 172 | return (int)(birdStart+((birdTime/1000.0)*(initYVelocity+gravity*(birdTime/1000.0)/2.0))); 173 | } 174 | 175 | int calculateTail() 176 | { 177 | return (int)(birdStart+(((birdTime-100)/1000.0)*(initYVelocity+gravity*((birdTime-100)/1000.0)/2.0))); 178 | } 179 | 180 | int calculateNextY() 181 | { 182 | return (int)(birdStart+(((birdTime+100)/1000.0)*(initYVelocity+gravity*((birdTime+100)/1000.0)/2.0))); 183 | } 184 | 185 | void drawBird() 186 | { 187 | birdTime = millis() - previousBirdTime; 188 | birdPos = calculateY(); 189 | tailPos = calculateTail(); 190 | if(calculateY() < 0) birdPos = 0; 191 | if(calculateTail() < 0) tailPos = 0; 192 | matrix.drawPixel(0, 7-tailPos, LED_ON); 193 | matrix.drawPixel(1, 7-birdPos, LED_ON); 194 | matrix.writeDisplay(); 195 | } 196 | -------------------------------------------------------------------------------- /examples/LED matrix/OttoE_rolleyes/OttoE_rolleyes.ino: -------------------------------------------------------------------------------- 1 | // This sketch demonstrates a couple of useful techniques: 2 | // 1) Addressing multiple matrices (using the 'A0' and 'A1' solder 3 | // pads on the back to select unique I2C addresses for each). 4 | // 2) Displaying the same data on multiple matrices by sharing the 5 | // same I2C address. 6 | // 7 | // This example uses 5 matrices at 4 addresses (two share an address) 8 | // to animate a face: 9 | // 10 | // 0 0 11 | // 12 | // 1 2 3 13 | // 14 | // The 'eyes' both display the same image (always looking the same 15 | // direction -- can't go cross-eyed) and thus share the same address 16 | // (0x70). The three matrices forming the mouth have unique addresses 17 | // (0x71, 0x72 and 0x73). 18 | // 19 | // The face animation as written is here semi-random; this neither 20 | // generates nor responds to actual sound, it's simply a visual effect 21 | // Consider this a stepping off point for your own project. Maybe you 22 | // could 'puppet' the face using joysticks, or synchronize the lips to 23 | // audio from a Wave Shield (see wavface example). Currently there are 24 | // only six images for the mouth. This is often sufficient for simple 25 | // animation, as explained here: 26 | // http://www.idleworm.com/how/anm/03t/talk1.shtml 27 | // 28 | // Adafruit invests time and resources providing this open source code, 29 | // please support Adafruit and open-source hardware by purchasing 30 | // products from Adafruit! 31 | // 32 | // Written by Camilo Parra Palacio for Otto DIY. 33 | // BSD license, all text above must be included in any redistribution. 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | // Because the two eye matrices share the same address, only four 41 | // matrix objects are needed for the five displays: 42 | #define MATRIX_EYES 0 43 | #define MATRIX_MOUTH_LEFT 1 44 | #define MATRIX_MOUTH_MIDDLE 2 45 | #define MATRIX_MOUTH_RIGHT 3 46 | Adafruit_8x16matrix matrix[4] = { // Array of Adafruit_8x16matrix objects 47 | Adafruit_8x16matrix(), Adafruit_8x16matrix(), 48 | Adafruit_8x16matrix(), Adafruit_8x16matrix() }; 49 | 50 | // Rather than assigning matrix addresses sequentially in a loop, each 51 | // has a spot in this array. This makes it easier if you inadvertently 52 | // install one or more matrices in the wrong physical position -- 53 | // re-order the addresses in this table and you can still refer to 54 | // matrices by index above, no other code or wiring needs to change. 55 | static const uint8_t matrixAddr[] = { 0x70, 0x71, 0x72, 0x73 }; 56 | 57 | static const uint8_t PROGMEM // Bitmaps are stored in program memory 58 | blinkImg[][8] = { // Eye animation frames 59 | { B00000000, // Fully open eye 60 | B00111100, 61 | B01111110, 62 | B01111110, 63 | B01111110, 64 | B01111110, 65 | B00111100, 66 | B00000000 }, 67 | { B00011000, 68 | B00011000, 69 | B00111110, 70 | B01111110, 71 | B01111110, 72 | B00111110, 73 | B00111100, 74 | B00011000 }, 75 | { B00011000, 76 | B00011000, 77 | B00011100, 78 | B00111100, 79 | B00111100, 80 | B00011100, 81 | B00011000, 82 | B00011000 }, 83 | { B00001000, 84 | B00011000, 85 | B00001100, 86 | B00001100, 87 | B00001100, 88 | B00001100, 89 | B00011000, 90 | B00001000 }, 91 | { B00001000, // Fully closed eye 92 | B00000100, 93 | B00000100, 94 | B00000100, 95 | B00000100, 96 | B00000100, 97 | B00000100, 98 | B00001000 } }, 99 | mouthImg[][24] = { // Mouth animation frames 100 | { B00000000, B00000000, B00000000, // Mouth position A 101 | B00000000, B00000000, B00000000, 102 | B01111111, B11111111, B11111110, 103 | B00000000, B00000000, B00000000, 104 | B00000000, B00000000, B00000000, 105 | B00000000, B00000000, B00000000, 106 | B00000000, B00000000, B00000000, 107 | B00000000, B00000000, B00000000 }, 108 | { B00000000, B00000000, B00000000, // Mouth position B 109 | B00000000, B00000000, B00000000, 110 | B00111111, B11111111, B11111100, 111 | B00000111, B00000000, B11100000, 112 | B00000000, B11111111, B00000000, 113 | B00000000, B00000000, B00000000, 114 | B00000000, B00000000, B00000000, 115 | B00000000, B00000000, B00000000 }, 116 | { B00000000, B00000000, B00000000, // Mouth position C 117 | B00000000, B00000000, B00000000, 118 | B00111111, B11111111, B11111100, 119 | B00001000, B00000000, B00010000, 120 | B00000110, B00000000, B01100000, 121 | B00000001, B11000011, B10000000, 122 | B00000000, B00111100, B00000000, 123 | B00000000, B00000000, B00000000 }, 124 | { B00000000, B00000000, B00000000, // Mouth position D 125 | B00000000, B00000000, B00000000, 126 | B00111111, B11111111, B11111100, 127 | B00100000, B00000000, B00000100, 128 | B00010000, B00000000, B00001000, 129 | B00001100, B00000000, B00110000, 130 | B00000011, B10000001, B11000000, 131 | B00000000, B01111110, B00000000 }, 132 | { B00000000, B00000000, B00000000, // Mouth position E 133 | B00000000, B00111100, B00000000, 134 | B00011111, B11000011, B11111000, 135 | B00000011, B10000001, B11000000, 136 | B00000000, B01111110, B00000000, 137 | B00000000, B00000000, B00000000, 138 | B00000000, B00000000, B00000000, 139 | B00000000, B00000000, B00000000 }, 140 | { B00000000, B00111100, B00000000, // Mouth position F 141 | B00000000, B11000011, B00000000, 142 | B00001111, B00000000, B11110000, 143 | B00000001, B00000000, B10000000, 144 | B00000000, B11000011, B00000000, 145 | B00000000, B00111100, B00000000, 146 | B00000000, B00000000, B00000000, 147 | B00000000, B00000000, B00000000 } }; 148 | 149 | uint8_t 150 | blinkIndex[] = { 1, 2, 3, 4, 3, 2, 1 }, // Blink bitmap sequence 151 | blinkCountdown = 100, // Countdown to next blink (in frames) 152 | gazeCountdown = 75, // Countdown to next eye movement 153 | gazeFrames = 50, // Duration of eye movement (smaller = faster) 154 | mouthPos = 0, // Current image number for mouth 155 | mouthCountdown = 10; // Countdown to next mouth change 156 | int8_t 157 | eyeX = 3, eyeY = 3, // Current eye position 158 | newX = 3, newY = 3, // Next eye position 159 | dX = 0, dY = 0; // Distance from prior to new position 160 | 161 | void setup() { 162 | 163 | // Seed random number generator from an unused analog input: 164 | randomSeed(analogRead(A0)); 165 | 166 | // Initialize each matrix object: 167 | for(uint8_t i=0; i<4; i++) { 168 | matrix[i].begin(matrixAddr[i]); 169 | // If using 'small' (1.2") displays vs. 'mini' (0.8"), enable this: 170 | // matrix[i].setRotation(3); 171 | } 172 | } 173 | 174 | void loop() { 175 | 176 | // Draw eyeball in current state of blinkyness (no pupil). Note that 177 | // only one eye needs to be drawn. Because the two eye matrices share 178 | // the same address, the same data will be received by both. 179 | matrix[MATRIX_EYES].clear(); 180 | // When counting down to the next blink, show the eye in the fully- 181 | // open state. On the last few counts (during the blink), look up 182 | // the corresponding bitmap index. 183 | matrix[MATRIX_EYES].drawBitmap(0, 0, 184 | blinkImg[ 185 | (blinkCountdown < sizeof(blinkIndex)) ? // Currently blinking? 186 | blinkIndex[blinkCountdown] : // Yes, look up bitmap # 187 | 0 // No, show bitmap 0 188 | ], 8, 8, LED_ON); 189 | matrix[MATRIX_EYES].drawBitmap(0, 8, 190 | blinkImg[ 191 | (blinkCountdown < sizeof(blinkIndex)) ? // Currently blinking? 192 | blinkIndex[blinkCountdown] : // Yes, look up bitmap # 193 | 0 // No, show bitmap 0 194 | ], 8, 8, LED_ON); 195 | // Decrement blink counter. At end, set random time for next blink. 196 | if(--blinkCountdown == 0) blinkCountdown = random(5, 180); 197 | 198 | // Add a pupil (2x2 black square) atop the blinky eyeball bitmap. 199 | // Periodically, the pupil moves to a new position... 200 | if(--gazeCountdown <= gazeFrames) { 201 | // Eyes are in motion - draw pupil at interim position 202 | matrix[MATRIX_EYES].fillRect( 203 | newX - (dX * gazeCountdown / gazeFrames), 204 | newY - (dY * gazeCountdown / gazeFrames), 205 | 2, 2, LED_OFF); 206 | matrix[MATRIX_EYES].fillRect( 207 | newX - (dX * gazeCountdown / gazeFrames), 208 | 8+newY - (dY * gazeCountdown / gazeFrames), 209 | 2, 2, LED_OFF); 210 | if(gazeCountdown == 0) { // Last frame? 211 | eyeX = newX; eyeY = newY; // Yes. What's new is old, then... 212 | do { // Pick random positions until one is within the eye circle 213 | newX = random(7); newY = random(7); 214 | dX = newX - 3; dY = newY - 3; 215 | } while((dX * dX + dY * dY) >= 10); // Thank you Pythagoras 216 | dX = newX - eyeX; // Horizontal distance to move 217 | dY = newY - eyeY; // Vertical distance to move 218 | gazeFrames = random(3, 15); // Duration of eye movement 219 | gazeCountdown = random(gazeFrames, 120); // Count to end of next movement 220 | } 221 | } else { 222 | // Not in motion yet -- draw pupil at current static position 223 | matrix[MATRIX_EYES].fillRect(eyeX, eyeY, 2, 2, LED_OFF); 224 | matrix[MATRIX_EYES].fillRect(eyeX, 8+eyeY, 2, 2, LED_OFF); 225 | } 226 | 227 | // Draw mouth, switch to new random image periodically 228 | drawMouth(mouthImg[mouthPos]); 229 | if(--mouthCountdown == 0) { 230 | mouthPos = random(6); // Random image 231 | // If the 'neutral' position was chosen, there's a 1-in-5 chance we'll 232 | // select a longer hold time. This gives the appearance of periodic 233 | // pauses in speech (e.g. between sentences, etc.). 234 | mouthCountdown = ((mouthPos == 0) && (random(5) == 0)) ? 235 | random(10, 40) : // Longer random duration 236 | random(2, 8); // Shorter random duration 237 | } 238 | 239 | // Refresh all of the matrices in one quick pass 240 | for(uint8_t i=0; i<4; i++) matrix[i].writeDisplay(); 241 | 242 | delay(20); // ~50 FPS 243 | } 244 | 245 | // Draw mouth image across three adjacent displays 246 | void drawMouth(const uint8_t *img) { 247 | for(uint8_t i=0; i<3; i++) { 248 | matrix[MATRIX_MOUTH_LEFT + i].clear(); 249 | matrix[MATRIX_MOUTH_LEFT + i].drawBitmap(i * -8, 0, img, 24, 8, LED_ON); 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /examples/LED matrix/OttoE_soundlevels/OttoE_soundlevels.ino: -------------------------------------------------------------------------------- 1 | /**************************************** 2 | Scrolling Sound Meter Sketch for the 3 | Adafruit Microphone Amplifier 4 | ****************************************/ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | // Include the Matrix code for display 11 | Adafruit_8x16matrix matrix = Adafruit_8x16matrix(); 12 | 13 | const int maxScale = 16; 14 | const int redZone = 5; 15 | const int sampleWindow = 50; // Sample window width in mS (50 mS = 20Hz) 16 | unsigned int sample; 17 | 18 | void setup() 19 | { 20 | Serial.begin(9600); 21 | matrix.begin(0x70); // pass in the address 22 | } 23 | 24 | void loop() 25 | { 26 | unsigned long startMillis= millis(); // Start of sample window 27 | unsigned int peakToPeak = 0; // peak-to-peak level 28 | 29 | unsigned int signalMax = 0; 30 | unsigned int signalMin = 1024; 31 | 32 | while (millis() - startMillis < sampleWindow) 33 | { 34 | sample = analogRead(0); 35 | if (sample < 1024) // toss out spurious readings 36 | { 37 | if (sample > signalMax) 38 | { 39 | signalMax = sample; // save just the max levels 40 | } 41 | else if (sample < signalMin) 42 | { 43 | signalMin = sample; // save just the min levels 44 | } 45 | } 46 | } 47 | peakToPeak = signalMax - signalMin; 48 | double volts = (peakToPeak * 5) / 1024; // convert to volts 49 | 50 | Serial.println(volts); 51 | // map 1v p-p level to the max scale of the display 52 | int displayPeak = map(peakToPeak, 0, 1023, 0, maxScale); 53 | 54 | // Update the display: 55 | for (int i = 0; i < 7; i++) // shift the display left 56 | { 57 | matrix.displaybuffer[i] = matrix.displaybuffer[i+1]; 58 | } 59 | 60 | // draw the new sample 61 | for (int i = 0; i <= maxScale; i++) 62 | { 63 | if (i >= displayPeak) // blank these pixels 64 | { 65 | matrix.drawPixel(7, i, 0); 66 | } 67 | else if (i < redZone) // draw in green 68 | { 69 | matrix.drawPixel(7, i, LED_ON); 70 | } 71 | else // Red Alert! Red Alert! 72 | { 73 | matrix.drawPixel(7, i, LED_ON); 74 | } 75 | } 76 | matrix.writeDisplay(); // write the changes we just made to the display 77 | } 78 | -------------------------------------------------------------------------------- /examples/LED matrix/Snake8x8matrix/Snake8x8matrix.ino: -------------------------------------------------------------------------------- 1 | // Snake on 8x8Matrix 2 | // 2013-06-15 JorgVisch 3 | // 4 | #include 5 | #include 6 | #include 7 | 8 | // Button pin 9 | const int buttonRightPin = 14; 10 | const int buttonLeftPin = 16; 11 | 12 | // Game constants 13 | // buttons 14 | const int RIGHTBUTTON = 0; 15 | const int LEFTBUTTON = 1; 16 | // direction 17 | const int TOP = 0; 18 | const int RIGHT = 1; 19 | const int BOTTOM = 2; 20 | const int LEFT = 3; 21 | // Snake 22 | const int MAX_SNAKE_LENGTH = 10; 23 | 24 | // Variables 25 | Adafruit_8x8matrix matrix = Adafruit_8x8matrix(); // Display 26 | int direction = TOP; // direction of movement 27 | int snakeX[MAX_SNAKE_LENGTH]; // X-coordinates of snake 28 | int snakeY[MAX_SNAKE_LENGTH]; // Y-coordinates of snake 29 | int snakeLength = 1; // nr of parts of snake 30 | boolean buttonRead = false; // is button already read in this loop 31 | unsigned long prevTime = 0; // for gamedelay (ms) 32 | unsigned long delayTime = 500; // Game step in ms 33 | 34 | int fruitX, fruitY; 35 | unsigned long fruitPrevTime = 0; 36 | unsigned long fruitBlinkTime = 1000/250; 37 | int fruitLed = LED_ON; 38 | 39 | void setup(){ 40 | Serial.begin(9600); 41 | Serial.println("Snake is started"); 42 | randomSeed(analogRead(0)); 43 | // Init led matrix 44 | matrix.begin(0x70); 45 | // init buttons 46 | int buttonpins[] = {buttonRightPin, buttonLeftPin}; 47 | initButtons(buttonpins, 2); 48 | // init snake 49 | snakeX[0] = 4; 50 | snakeY[0] = 7; 51 | for(int i=1; i= delayTime){ 61 | nextstep(); 62 | buttonRead = false; 63 | prevTime = currentTime; 64 | } 65 | draw(); 66 | } 67 | 68 | void checkButtons(){ 69 | if(!buttonRead){ 70 | int currentDirection = direction; 71 | if(buttonClicked(LEFTBUTTON)){ 72 | direction--; 73 | if(direction < 0){ 74 | direction = LEFT; 75 | } 76 | } 77 | else if(buttonClicked(RIGHTBUTTON)){ 78 | direction++; 79 | if(direction > 3){ 80 | direction = TOP; 81 | } 82 | } 83 | buttonRead = (currentDirection != direction); 84 | } 85 | } 86 | 87 | void draw(){ 88 | matrix.clear(); 89 | drawSnake(); 90 | drawFruit(); 91 | matrix.writeDisplay(); 92 | } 93 | 94 | void drawSnake(){ 95 | for(int i=0; i= fruitBlinkTime){ 104 | fruitLed = (fruitLed == LED_ON) ? LED_OFF : LED_ON; 105 | fruitPrevTime = currenttime; 106 | } 107 | matrix.drawPixel(fruitX, fruitY, fruitLed); 108 | } 109 | } 110 | 111 | boolean inPlayField(int x, int y){ 112 | return (x>=0) && (x<8) && (y>=0) && (y<8); 113 | } 114 | 115 | void nextstep(){ 116 | for(int i=snakeLength-1; i>0; i--){ 117 | snakeX[i] = snakeX[i-1]; 118 | snakeY[i] = snakeY[i-1]; 119 | } 120 | switch(direction){ 121 | case TOP: 122 | snakeY[0] = snakeY[0]-1; 123 | break; 124 | case RIGHT: 125 | snakeX[0] = snakeX[0]+1; 126 | break; 127 | case BOTTOM: 128 | snakeY[0] = snakeY[0]+1; 129 | break; 130 | case LEFT: 131 | snakeX[0]=snakeX[0]-1; 132 | break; 133 | } 134 | if((snakeX[0] == fruitX) && (snakeY[0] == fruitY)){ 135 | snakeLength++; 136 | if(snakeLength < MAX_SNAKE_LENGTH){ 137 | makeFruit(); 138 | } 139 | else { 140 | fruitX = fruitY = -1; 141 | } 142 | } 143 | } 144 | 145 | void makeFruit(){ 146 | int x, y; 147 | x = random(0, 8); 148 | y = random(0, 8); 149 | while(isPartOfSnake(x, y)){ 150 | x = random(0, 8); 151 | y = random(0, 8); 152 | } 153 | fruitX = x; 154 | fruitY = y; 155 | } 156 | 157 | boolean isPartOfSnake(int x, int y){ 158 | for(int i=0; i 23 | #include 24 | #include 25 | 26 | //CALIBRATION SETTINGS: 27 | int LA0= 60 +0; // Left Leg standing Position - = Tilt Right + = Tilt Left 28 | int RA0= 120 +0; // Right Leg standing position - = Tilt Right + = Tilt Left 29 | int LA1= 180; // Left Leg roll Position - = Tilt Right + = Tilt Left 30 | int RA1= 0; // Right Leg roll position - = Tilt Right + = Tilt Left 31 | int LATL= LA0 +40; // Left Leg tilt left walking position - = Tilt Right + = Tilt Left 32 | int RATL= RA0 +60; // Right Leg tilt left walking position - = Tilt Right + = Tilt Left 33 | int LATR= LA0 -60; // Left Leg tilt right walking position - = Tilt Right + = Tilt Left 34 | int RATR= RA0 -40; // Right Leg tilt right walking position - = Tilt Right + = Tilt Left 35 | 36 | int LFFWRS=15; // Left foot forward walking rotation Speed 0 = SLOW 90 = FAST 37 | int RFFWRS=15 ; // Right foot forward walking rotation Speed 0 = SLOW 90 = FAST 38 | int LFBWRS= 15; // Left foot Backward walking rotation Speed 0 = SLOW 90 = FAST 39 | int RFBWRS= 15; // Right foot Backward walking rotation Speed 0 = SLOW 90 = FAST 40 | 41 | 42 | //////////////////////////////////////// 43 | 44 | const uint8_t ServoLeftFootPin = 13; //D7 45 | const uint8_t ServoLeftLegPin = 15; //D8 46 | const uint8_t ServoRightFootPin = 0; //D3 47 | const uint8_t ServoRightLegPin = 2; //D4 48 | const uint8_t ServoLeftArmPin = 16; //D0 49 | const uint8_t ServoRightArmPin = 3; //RX 50 | const uint8_t ServoHeadPin = 1; //TX 51 | 52 | Servo myservoLeftFoot; 53 | Servo myservoLeftLeg; 54 | Servo myservoRightFoot; 55 | Servo myservoRightLeg; 56 | 57 | Servo myservoLeftArm; 58 | Servo myservoRightArm; 59 | Servo myservoHead; 60 | 61 | #define echoPin 4 // attach pin D2 ESP8266 to pin Echo of HC-SR04 62 | #define trigPin 5 //attach pin D1 ESP8266 to pin Trig of HC-SR04 63 | long duration; // variable for the duration of sound wave travel 64 | int distance; // variable for the distance measurement 65 | 66 | 67 | 68 | #define ButtonPin 14 //attach pin D5 ESP8266 to pin S Button 69 | int ButtonState = 0; // variable for reading the pushbutton status 70 | 71 | 72 | 73 | #define BuzzerPin 12 //attach pin D6 ESP8266 to pin S Buzzer 74 | 75 | #define NOTE_B0 31 76 | #define NOTE_C1 33 77 | #define NOTE_CS1 35 78 | #define NOTE_D1 37 79 | #define NOTE_DS1 39 80 | #define NOTE_E1 41 81 | #define NOTE_F1 44 82 | #define NOTE_FS1 46 83 | #define NOTE_G1 49 84 | #define NOTE_GS1 52 85 | #define NOTE_A1 55 86 | #define NOTE_AS1 58 87 | #define NOTE_B1 62 88 | #define NOTE_C2 65 89 | #define NOTE_CS2 69 90 | #define NOTE_D2 73 91 | #define NOTE_DS2 78 92 | #define NOTE_E2 82 93 | #define NOTE_F2 87 94 | #define NOTE_FS2 93 95 | #define NOTE_G2 98 96 | #define NOTE_GS2 104 97 | #define NOTE_A2 110 98 | #define NOTE_AS2 117 99 | #define NOTE_B2 123 100 | #define NOTE_C3 131 101 | #define NOTE_CS3 139 102 | #define NOTE_D3 147 103 | #define NOTE_DS3 156 104 | #define NOTE_E3 165 105 | #define NOTE_F3 175 106 | #define NOTE_FS3 185 107 | #define NOTE_G3 196 108 | #define NOTE_GS3 208 109 | #define NOTE_A3 220 110 | #define NOTE_AS3 233 111 | #define NOTE_B3 247 112 | #define NOTE_C4 262 113 | #define NOTE_CS4 277 114 | #define NOTE_D4 294 115 | #define NOTE_DS4 311 116 | #define NOTE_E4 330 117 | #define NOTE_F4 349 118 | #define NOTE_FS4 370 119 | #define NOTE_G4 392 120 | #define NOTE_GS4 415 121 | #define NOTE_A4 440 122 | #define NOTE_AS4 466 123 | #define NOTE_B4 494 124 | #define NOTE_C5 523 125 | #define NOTE_CS5 554 126 | #define NOTE_D5 587 127 | #define NOTE_DS5 622 128 | #define NOTE_E5 659 129 | #define NOTE_F5 698 130 | #define NOTE_FS5 740 131 | #define NOTE_G5 784 132 | #define NOTE_GS5 831 133 | #define NOTE_A5 880 134 | #define NOTE_AS5 932 135 | #define NOTE_B5 988 136 | #define NOTE_C6 1047 137 | #define NOTE_CS6 1109 138 | #define NOTE_D6 1175 139 | #define NOTE_DS6 1245 140 | #define NOTE_E6 1319 141 | #define NOTE_F6 1397 142 | #define NOTE_FS6 1480 143 | #define NOTE_G6 1568 144 | #define NOTE_GS6 1661 145 | #define NOTE_A6 1760 146 | #define NOTE_AS6 1865 147 | #define NOTE_B6 1976 148 | #define NOTE_C7 2093 149 | #define NOTE_CS7 2217 150 | #define NOTE_D7 2349 151 | #define NOTE_DS7 2489 152 | #define NOTE_E7 2637 153 | #define NOTE_F7 2794 154 | #define NOTE_FS7 2960 155 | #define NOTE_G7 3136 156 | #define NOTE_GS7 3322 157 | #define NOTE_A7 3520 158 | #define NOTE_AS7 3729 159 | #define NOTE_B7 3951 160 | #define NOTE_C8 4186 161 | #define NOTE_CS8 4435 162 | #define NOTE_D8 4699 163 | #define NOTE_DS8 4978 164 | 165 | void setup() 166 | { 167 | 168 | NinjaHome(); 169 | 170 | pinMode(BuzzerPin, OUTPUT);//buzzer 171 | 172 | pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT 173 | pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT 174 | pinMode(ButtonPin, INPUT_PULLUP); 175 | pinMode(BuzzerPin, OUTPUT); 176 | 177 | Serial.begin(250000); 178 | 179 | } 180 | 181 | 182 | void loop() 183 | { 184 | 185 | Distance(); 186 | ButtonState = digitalRead(ButtonPin); 187 | 188 | if ((ButtonState == LOW)&&(distance >= 2)&&(distance < 7)) 189 | { 190 | tone(BuzzerPin, NOTE_C5); 191 | } 192 | 193 | if ((ButtonState == LOW)&&(distance >= 7)&&(distance < 12)) 194 | { 195 | tone(BuzzerPin, NOTE_D5); 196 | } 197 | 198 | if ((ButtonState == LOW)&&(distance >= 12)&&(distance < 17)) 199 | { 200 | tone(BuzzerPin, NOTE_E5); 201 | } 202 | 203 | if ((ButtonState == LOW)&&(distance >= 17)&&(distance < 22)) 204 | { 205 | tone(BuzzerPin, NOTE_F5); 206 | } 207 | 208 | if ((ButtonState == LOW)&&(distance >= 22)&&(distance < 27)) 209 | { 210 | tone(BuzzerPin, NOTE_G5); 211 | } 212 | 213 | if ((ButtonState == LOW)&&(distance >= 27)&&(distance < 32)) 214 | { 215 | tone(BuzzerPin, NOTE_A5); 216 | } 217 | 218 | if ((ButtonState == LOW)&&(distance >= 32)&&(distance < 37)) 219 | { 220 | tone(BuzzerPin, NOTE_B5); 221 | } 222 | 223 | if ((ButtonState == LOW)&&(distance >= 37)&&(distance < 42)) 224 | { 225 | tone(BuzzerPin, NOTE_C6); 226 | } 227 | 228 | if (ButtonState == HIGH) 229 | { 230 | noTone(BuzzerPin); // Stop sound... 231 | } 232 | 233 | 234 | 235 | } 236 | 237 | //////////////////////////////////////////////////// 238 | 239 | void NinjaHome() 240 | { 241 | myservoLeftLeg.attach(ServoLeftLegPin, 544, 2400); 242 | myservoRightLeg.attach(ServoRightLegPin, 544, 2400); 243 | myservoLeftArm.attach(ServoLeftArmPin, 544, 2400); 244 | myservoRightArm.attach(ServoRightArmPin, 544, 2400); 245 | myservoHead.attach(ServoHeadPin, 544, 2400); 246 | myservoLeftArm.write(180); 247 | myservoRightArm.write(0); 248 | myservoHead.write(90); 249 | delay(400); 250 | myservoLeftFoot.write(90); 251 | myservoRightFoot.write(90); 252 | myservoLeftLeg.write(60); 253 | myservoRightLeg.write(120); 254 | delay(400); 255 | myservoLeftLeg.detach(); 256 | myservoRightLeg.detach(); 257 | myservoLeftArm.detach(); 258 | myservoRightArm.detach(); 259 | myservoHead.detach(); 260 | } 261 | 262 | void Distance() 263 | { 264 | // Clears the trigPin condition 265 | digitalWrite(trigPin, LOW); 266 | delayMicroseconds(2); 267 | // Sets the trigPin HIGH (ACTIVE) for 10 microseconds 268 | digitalWrite(trigPin, HIGH); 269 | delayMicroseconds(10); 270 | digitalWrite(trigPin, LOW); 271 | // Reads the echoPin, returns the sound wave travel time in microseconds 272 | duration = pulseIn(echoPin, HIGH); 273 | // Calculating the distance 274 | distance = duration * 0.034 / 2; // Speed of sound wave divided by 2 (go and back) 275 | // Displays the distance on the Serial Monitor 276 | Serial.print("Distance: "); 277 | Serial.print(distance); 278 | Serial.println(" cm"); 279 | } 280 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Otto9 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | Otto KEYWORD1 9 | ####################################### 10 | # Methods and Functions (KEYWORD2) 11 | ####################################### 12 | init KEYWORD2 13 | initDC KEYWORD2 14 | initMATRIX KEYWORD2 15 | home KEYWORD2 16 | putMouth KEYWORD2 17 | writeText KEYWORD2 18 | clearMouth KEYWORD2 19 | sing KEYWORD2 20 | walk KEYWORD2 21 | playGesture KEYWORD2 22 | ####################################### 23 | # Instances (KEYWORD2) 24 | ####################################### 25 | 26 | ####################################### 27 | # Constants (LITERAL1) 28 | ####################################### 29 | 30 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "OttoDIYLib", 3 | "version": "13.0.0", 4 | "description": "Official Arduino library for controlling original Otto DIY bipedal robots", 5 | "keywords": "otto, ottodiy, robot, servo", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/OttoDIY/OttoDIYLib" 9 | }, 10 | "authors": [ 11 | { 12 | "name": "Otto DIY community", 13 | "url": "https://github.com/OttoDIY", 14 | "maintainer": true 15 | } 16 | ], 17 | "license": "GPL-3.0-or-later", 18 | "frameworks": "arduino", 19 | "platforms": "atmelavr" 20 | } 21 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Otto Ninja 2 | version=1.0 3 | author=Sebastian Coddington 4 | maintainer=Sebastian Coddington, Camilo Parra Palacio 5 | sentence=Libraries for controlling Otto Ninja bipedal robot starter and Humanoid. 6 | paragraph=Otto Ninja can walk, transform, roll, show emotions, dance, sense motion and objects. Program Otto Ninja to think on it’s own using block-based coding with Blockly and C++ with Arduino IDE. 7 | 8 | category=Device Control 9 | url=https://github.com/OttoDIY/ 10 | architectures=esp8266 11 | -------------------------------------------------------------------------------- /src/RemoteXY.h: -------------------------------------------------------------------------------- 1 | /* RemoteXY.h 2 | A RemoteXY Library - Remote device control 3 | version 3.1.7 4 | =========================================================== 5 | For use RemoteXY library visit website http://remotexy.com 6 | This website will help you use the library for configuring 7 | a remote control from a smartphone or tablet. 8 | 9 | This library is free software; you can redistribute it and/or 10 | modify it under the terms of the GNU Lesser General Public 11 | License as published by the Free Software Foundation; either 12 | version 2.1 of the License, or (at your option) any later version. 13 | 14 | Supported modes: 15 | All boards: 16 | #define REMOTEXY_MODE__HARDSERIAL - direct data transfer via HARDSERIAL 17 | #define REMOTEXY_MODE__SOFTSERIAL - direct data transfer via SOFTSERIAL 18 | #define REMOTEXY_MODE__CDCSERIAL - direct data transfer via CDC for ATmega32u4 19 | #define REMOTEXY_MODE__ETHERNET - data transfer using library and open server 20 | #define REMOTEXY_MODE__ETHERNET_CLOUD - data transfer using library and cloud connection 21 | #define REMOTEXY_MODE__HARDSERIAL_ESP8266 - data transfer via HARDSERIAL using AT commands of ESP8266 and open server 22 | #define REMOTEXY_MODE__HARDSERIAL_ESP8266_POINT - data transfer via HARDSERIAL using AT commands of ESP8266 and open access point with a server 23 | #define REMOTEXY_MODE__HARDSERIAL_ESP8266_CLOUD - data transfer via HARDSERIAL using AT commands of ESP8266 and cloud connection 24 | #define REMOTEXY_MODE__SOFTSERIAL_ESP8266 - data transfer via SOFTSERIAL using AT commands of ESP8266 and open server 25 | #define REMOTEXY_MODE__SOFTSERIAL_ESP8266_POINT - data transfer via SOFTSERIAL using AT commands of ESP8266 and open access point with a server 26 | #define REMOTEXY_MODE__SOFTSERIAL_ESP8266_CLOUD - data transfer via SOFTSERIAL using AT commands of ESP8266 and cloud connection 27 | #define REMOTEXY_MODE__WIFI - data transfer using generic wifi.h library and open server 28 | #define REMOTEXY_MODE__WIFI_POINT - data transfer using generic wifi.h library and open access point with a server 29 | #define REMOTEXY_MODE__WIFI_CLOUD - data transfer using generic wifi.h library and cloud connection 30 | 31 | Only ESP8266 boards: 32 | #define REMOTEXY_MODE__ESP8266CORE_ESP8266WIFI or REMOTEXY_MODE__WIFI - data transfer using library and open server 33 | #define REMOTEXY_MODE__ESP8266CORE_ESP8266WIFI_POINT or REMOTEXY_MODE__WIFI_POINT - data transfer using library and open access point with a server 34 | #define REMOTEXY_MODE__ESP8266CORE_ESP8266WIFI_CLOUD or REMOTEXY_MODE__WIFI_CLOUD - data transfer using library and cloud connection 35 | 36 | Only ESP32 boards: 37 | #define REMOTEXY_MODE__ESP32CORE_WIFI or REMOTEXY_MODE__WIFI - data transfer using library and open server 38 | #define REMOTEXY_MODE__ESP32CORE_WIFI_POINT or REMOTEXY_MODE__WIFI_POINT - data transfer using library and open access point with a server 39 | #define REMOTEXY_MODE__ESP32CORE_WIFI_CLOUD or REMOTEXY_MODE__WIFI_CLOUD - data transfer using library and cloud connection 40 | #define REMOTEXY_MODE__ESP32CORE_BLE - data transfer using library 41 | #define REMOTEXY_MODE__ESP32CORE_BLUETOOTH - data transfer using library 42 | 43 | Only NRF52xx based boards: 44 | #define REMOTEXY_MODE__NRFCORE_BLEPERIPHERAL - data transfer using library 45 | 46 | Parameters depending on the selected mode (for example): 47 | #define REMOTEXY_SERIAL Serial // for Hardware Serial 48 | #define REMOTEXY_SERIAL_SPEED 115200 49 | #define REMOTEXY_SERIAL_RX 2 // for Software Serial 50 | #define REMOTEXY_SERIAL_TX 3 // for Software Serial 51 | #define REMOTEXY_WIFI_SSID "RemoteXY" 52 | #define REMOTEXY_WIFI_PASSWORD "1234567890" 53 | #define REMOTEXY_ETHERNET_MAC "DE:AD:BE:EF:EF:ED" // for Ethernet modules 54 | #define REMOTEXY_SERVER_PORT 6377 55 | #define REMOTEXY_BLUETOOTH_NAME "remotexy" // for ESP32 56 | #define REMOTEXY_CLOUD_TOKEN "xxxx" // for Cloud 57 | #define REMOTEXY_CLOUD_SERVER "cloud.remotexy.com" // for Cloud 58 | #define REMOTEXY_CLOUD_PORT 6376 // for Cloud 59 | #define REMOTEXY_ACCESS_PASSWORD "1" 60 | 61 | Debug log info on serial 115200 (define before include this library): 62 | #define REMOTEXY__DEBUGLOG 63 | #define REMOTEXY__DEBUGLOG_SERIAL Serial 64 | #define REMOTEXY__DEBUGLOG_SPEED 115200 65 | 66 | = Version history ======================================== 67 | 68 | version 2.2.5 69 | - support MPIDE; 70 | version 2.3.1 71 | - Support the device access password; 72 | - Support the cloud server as beta test; 73 | - Fixed a bug where the length of variables more than 255; 74 | - Fixed a bug where ESP module reboot and device did not see it; 75 | - Fixed a bug where the connection was filed and the device 76 | did not see it and reconnection is impossible 77 | version 2.3.4 78 | - Fixed a bug where the length of all input variables more than 256; 79 | - Fixed a bug where millis() overflow in 50 days; 80 | - Fixed some bugs; 81 | version 2.3.5 82 | - Fixed some bugs; 83 | version 2.4.1 84 | - support ESP32 WiFi and Bluetooth 85 | version 2.4.2 86 | - Fixed some bugs; 87 | version 2.4.3 88 | - Fixed some bugs; 89 | version 2.4.4 90 | - Fixed ESP32 BLE bugs; 91 | version 3.1.1 92 | - Full update the library: multiple connections, set input variables from board and more; 93 | version 3.1.3 94 | - Multiple connection for cloud, fixed some bugs; 95 | version 3.1.4 96 | - fixed some bugs; 97 | version 3.1.5 98 | - add NRF5XXX and BLEPeripheral.h library as Beta, need define REMOTEXY_MODE__NRFCORE_BLEPERIPHERAL; 99 | version 3.1.6 100 | - fixed some bugs; 101 | version 3.1.7 102 | - add CDC Serial for Leonardo, Micro, ..; 103 | 104 | */ 105 | 106 | #ifndef _REMOTEXY_H_ 107 | #define _REMOTEXY_H_ 108 | 109 | 110 | 111 | #ifndef REMOTEXY_MAX_CLIENTS 112 | #define REMOTEXY_MAX_CLIENTS 4 113 | #endif 114 | 115 | 116 | //#define REMOTEXY__DEBUGLOG 117 | //#define REMOTEXY__DEBUGLOG_SERIAL Serial 118 | //#define REMOTEXY__DEBUGLOG_SPEED 115200 119 | 120 | 121 | #include 122 | #include 123 | #include "RemoteXYDebugLog.h" 124 | 125 | #if defined(REMOTEXY_MODE__ESP32CORE_BLUETOOTH) 126 | #include "BluetoothSerial.h" 127 | #elif defined(REMOTEXY_MODE__ESP32CORE_BLE) 128 | #include "BLEDevice.h" 129 | 130 | #endif 131 | 132 | 133 | #include "RemoteXYApi.h" 134 | 135 | #include "RemoteXYStream_HardSerial.h" 136 | #include "RemoteXYStream_SoftSerial.h" // need SoftwareSerial.h or SoftSerial.h 137 | #include "RemoteXYStream_CDCSerial.h" 138 | #include "RemoteXYStream_BluetoothSerial.h" // need BluetoothSerial.h 139 | #include "RemoteXYStream_BLEDevice.h" // need BLEDevice.h 140 | #include "RemoteXYStream_BLEPeripheral.h" // need BLEPeripheral.h 141 | #include "RemoteXYComm_WiFi.h" // need ESP8266WiFi.h (ESP8266) or WiFi.h (ESP32) or WiFi.h (Arduino shield) 142 | #include "RemoteXYComm_Ethernet.h" // need Ethernet.h 143 | #include "RemoteXYComm_ESP8266.h" 144 | 145 | 146 | #ifndef REMOTEXY_ACCESS_PASSWORD 147 | #define REMOTEXY_ACCESS_PASSWORD "" 148 | #endif 149 | 150 | 151 | #define RemoteXY_Handler() remotexy->handler () 152 | #define RemoteXY_CONF const PROGMEM RemoteXY_CONF_PROGMEM 153 | 154 | // predefined configurations 155 | 156 | #if defined(REMOTEXY_MODE__HARDSERIAL) || defined(REMOTEXY_MODE__SERIAL) || defined(REMOTEXY_MODE__HC05_HARDSERIAL) 157 | CRemoteXY *remotexy; 158 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYStream_HardSerial (&REMOTEXY_SERIAL, REMOTEXY_SERIAL_SPEED)) 159 | 160 | #elif defined(REMOTEXY_MODE__SOFTSERIAL) || defined(REMOTEXY_MODE__SOFTWARESERIAL) || defined(REMOTEXY_MODE__HC05_SOFTSERIAL) 161 | CRemoteXY *remotexy; 162 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYStream_SoftSerial (REMOTEXY_SERIAL_RX, REMOTEXY_SERIAL_TX, REMOTEXY_SERIAL_SPEED)) 163 | 164 | #elif defined(REMOTEXY_MODE__CDCSERIAL) 165 | CRemoteXY *remotexy; 166 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYStream_CDCSerial (&REMOTEXY_SERIAL, REMOTEXY_SERIAL_SPEED)) 167 | 168 | #elif defined(REMOTEXY_MODE__ESP32CORE_BLE) 169 | CRemoteXY *remotexy; 170 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYStream_BLEDevice (REMOTEXY_BLUETOOTH_NAME)) 171 | 172 | #elif defined(REMOTEXY_MODE__ESP32CORE_WIFI) || defined(REMOTEXY_MODE__ESP8266CORE_ESP8266WIFI) || defined(REMOTEXY_MODE__ESP8266WIFI_LIB) || defined(REMOTEXY_MODE__WIFI) 173 | CRemoteXY *remotexy; 174 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYConnectionServer (new CRemoteXYComm_WiFi (REMOTEXY_WIFI_SSID, REMOTEXY_WIFI_PASSWORD), REMOTEXY_SERVER_PORT)) 175 | 176 | #elif defined(REMOTEXY_MODE__ESP32CORE_WIFI_POINT) || defined(REMOTEXY_MODE__ESP8266CORE_ESP8266WIFI_POINT) || defined(REMOTEXY_MODE__ESP8266WIFI_LIB_POINT) || defined(REMOTEXY_MODE__ESP8266WIFIPOINT_LIB) || defined(REMOTEXY_MODE__WIFI_POINT) 177 | CRemoteXY *remotexy; 178 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYConnectionServer (new CRemoteXYComm_WiFiPoint (REMOTEXY_WIFI_SSID, REMOTEXY_WIFI_PASSWORD), REMOTEXY_SERVER_PORT)) 179 | 180 | #elif defined(REMOTEXY_MODE__ESP32CORE_WIFI_CLOUD) || defined(REMOTEXY_MODE__ESP8266CORE_ESP8266WIFI_CLOUD) || defined(REMOTEXY_MODE__ESP8266WIFI_LIB_CLOUD) || defined(REMOTEXY_MODE__WIFI_CLOUD) 181 | CRemoteXY *remotexy; 182 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYConnectionCloud (new CRemoteXYComm_WiFi (REMOTEXY_WIFI_SSID, REMOTEXY_WIFI_PASSWORD), REMOTEXY_CLOUD_SERVER, REMOTEXY_CLOUD_PORT, REMOTEXY_CLOUD_TOKEN)) 183 | 184 | #elif defined(REMOTEXY_MODE__HARDSERIAL_ESP8266_POINT) || defined(REMOTEXY_MODE__ESP8266_HARDSERIAL_POINT) || defined(REMOTEXY_MODE__ESP8266POINT_HARDSERIAL) 185 | CRemoteXY *remotexy; 186 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYConnectionServer (new CRemoteXYComm_ESP8266Point (new CRemoteXYStream_HardSerial (&REMOTEXY_SERIAL, REMOTEXY_SERIAL_SPEED), REMOTEXY_WIFI_SSID, REMOTEXY_WIFI_PASSWORD), REMOTEXY_SERVER_PORT)) 187 | 188 | #elif defined(REMOTEXY_MODE__SOFTSERIAL_ESP8266_POINT) || defined(REMOTEXY_MODE__ESP8266_SOFTSERIAL_POINT) || defined(REMOTEXY_MODE__ESP8266POINT_SOFTSERIAL) 189 | CRemoteXY *remotexy; 190 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYConnectionServer (new CRemoteXYComm_ESP8266Point (new CRemoteXYStream_SoftSerial (REMOTEXY_SERIAL_RX, REMOTEXY_SERIAL_TX, REMOTEXY_SERIAL_SPEED), REMOTEXY_WIFI_SSID, REMOTEXY_WIFI_PASSWORD), REMOTEXY_SERVER_PORT)) 191 | 192 | #elif defined(REMOTEXY_MODE__HARDSERIAL_ESP8266) || defined(REMOTEXY_MODE__ESP8266_HARDSERIAL) 193 | CRemoteXY *remotexy; 194 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYConnectionServer (new CRemoteXYComm_ESP8266 (new CRemoteXYStream_HardSerial (&REMOTEXY_SERIAL, REMOTEXY_SERIAL_SPEED), REMOTEXY_WIFI_SSID, REMOTEXY_WIFI_PASSWORD), REMOTEXY_SERVER_PORT)) 195 | 196 | #elif defined(REMOTEXY_MODE__SOFTSERIAL_ESP8266) || defined(REMOTEXY_MODE__ESP8266_SOFTSERIAL) 197 | CRemoteXY *remotexy; 198 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYConnectionServer (new CRemoteXYComm_ESP8266 (new CRemoteXYStream_SoftSerial (REMOTEXY_SERIAL_RX, REMOTEXY_SERIAL_TX, REMOTEXY_SERIAL_SPEED), REMOTEXY_WIFI_SSID, REMOTEXY_WIFI_PASSWORD), REMOTEXY_SERVER_PORT)) 199 | 200 | #elif defined(REMOTEXY_MODE__HARDSERIAL_ESP8266_CLOUD) || defined(REMOTEXY_MODE__ESP8266_HARDSERIAL_CLOUD) 201 | CRemoteXY *remotexy; 202 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYConnectionCloud (new CRemoteXYComm_ESP8266 (new CRemoteXYStream_HardSerial (&REMOTEXY_SERIAL, REMOTEXY_SERIAL_SPEED), REMOTEXY_WIFI_SSID, REMOTEXY_WIFI_PASSWORD), REMOTEXY_CLOUD_SERVER, REMOTEXY_CLOUD_PORT, REMOTEXY_CLOUD_TOKEN)) 203 | 204 | #elif defined(REMOTEXY_MODE__SOFTSERIAL_ESP8266_CLOUD) || defined(REMOTEXY_MODE__ESP8266_SOFTSERIAL_CLOUD) 205 | CRemoteXYCloud *remotexy; 206 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYConnectionCloud (new CRemoteXYComm_ESP8266 (new CRemoteXYStream_SoftSerial (REMOTEXY_SERIAL_RX, REMOTEXY_SERIAL_TX, REMOTEXY_SERIAL_SPEED), REMOTEXY_WIFI_SSID, REMOTEXY_WIFI_PASSWORD), REMOTEXY_CLOUD_SERVER, REMOTEXY_CLOUD_PORT, REMOTEXY_CLOUD_TOKEN)) 207 | 208 | #elif defined(REMOTEXY_MODE__ETHERNET) || defined(REMOTEXY_MODE__ETHERNET_LIB) || defined(REMOTEXY_MODE__W5100_SPI) 209 | CRemoteXY *remotexy; 210 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYConnectionServer (new CRemoteXYComm_Ethernet (REMOTEXY_ETHERNET_MAC), REMOTEXY_SERVER_PORT)) 211 | 212 | #elif defined(REMOTEXY_MODE__ETHERNET_CLOUD) || defined(REMOTEXY_MODE__ETHERNET_LIB_CLOUD) 213 | CRemoteXY *remotexy; 214 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYConnectionCloud (new CRemoteXYComm_Ethernet (REMOTEXY_ETHERNET_MAC), REMOTEXY_CLOUD_SERVER, REMOTEXY_CLOUD_PORT, REMOTEXY_CLOUD_TOKEN)) 215 | 216 | #elif defined(REMOTEXY_MODE__ESP32CORE_BLUETOOTH) 217 | CRemoteXY *remotexy; 218 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYStream_BluetoothSerial (REMOTEXY_BLUETOOTH_NAME)) 219 | 220 | #elif defined(REMOTEXY_MODE__NRFCORE_BLEPERIPHERAL) 221 | CRemoteXY *remotexy; 222 | #define RemoteXY_Init() remotexy = new CRemoteXY (RemoteXY_CONF_PROGMEM, &RemoteXY, REMOTEXY_ACCESS_PASSWORD, new CRemoteXYStream_BLEPeripheral (REMOTEXY_BLUETOOTH_NAME)) 223 | 224 | #endif 225 | 226 | //API 227 | #define RemoteXY_isConnected() remotexy->isConnected () 228 | 229 | 230 | #endif //_REMOTEXY_H_ 231 | 232 | -------------------------------------------------------------------------------- /src/RemoteXYApi.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYApi_h 2 | #define RemoteXYApi_h 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "RemoteXYDebugLog.h" 9 | #include "RemoteXYApiData.h" 10 | #include "RemoteXYConnection.h" 11 | #include "RemoteXYConnectionStream.h" 12 | #include "RemoteXYConnectionServer.h" 13 | #include "RemoteXYConnectionCloud.h" 14 | 15 | #include "RemoteXYComm.h" 16 | #include "RemoteXYCloudServer.h" 17 | #include "RemoteXYThread.h" 18 | #include "RemoteXYWire.h" 19 | #include "RemoteXYWireStream.h" 20 | 21 | #include "RemoteXYCloudServer.h" 22 | 23 | 24 | 25 | class CRemoteXY { 26 | public: 27 | CRemoteXYData data; 28 | 29 | 30 | public: 31 | CRemoteXY (const void * _conf, void * _var, const char * _accessPassword) { 32 | data.init (_conf, _var, _accessPassword); 33 | 34 | #if defined(REMOTEXY__DEBUGLOG) 35 | RemoteXYDebugLog.init (); 36 | RemoteXYDebugLog.write("RemoteXY started"); 37 | #endif 38 | } 39 | 40 | public: 41 | CRemoteXY (const void * _conf, void * _var, const char * _accessPassword, CRemoteXYConnectionComm * _conn) { 42 | data.init (_conf, _var, _accessPassword); 43 | addConnection (_conn); 44 | 45 | #if defined(REMOTEXY__DEBUGLOG) 46 | RemoteXYDebugLog.init (); 47 | RemoteXYDebugLog.write("RemoteXY started"); 48 | #endif 49 | } 50 | 51 | public: 52 | CRemoteXY (const void * _conf, void * _var, const char * _accessPassword, CRemoteXYStream * _comm) { 53 | data.init (_conf, _var, _accessPassword); 54 | addConnection (_comm); 55 | 56 | #if defined(REMOTEXY__DEBUGLOG) 57 | RemoteXYDebugLog.init (); 58 | RemoteXYDebugLog.write("RemoteXY started"); 59 | #endif 60 | } 61 | 62 | 63 | 64 | public: 65 | void addConnection (CRemoteXYConnectionComm * conn) { 66 | CRemoteXYComm * p = data.comms; 67 | while (p) { 68 | if (p == conn->comm) break; 69 | p = p->next; 70 | } 71 | if (!p) { 72 | conn->comm->next = data.comms; 73 | data.comms = conn->comm; 74 | } 75 | conn->next = data.connections; 76 | data.connections = conn; 77 | conn->init (&data); 78 | } 79 | 80 | public: 81 | void addConnection (CRemoteXYStream * comm) { 82 | CRemoteXYConnection * conn = new CRemoteXYConnectionStream (comm); 83 | conn->init (&data); 84 | } 85 | 86 | 87 | public: 88 | void handler () { 89 | uint8_t connect_flag = 0; 90 | 91 | // threads handler 92 | 93 | CRemoteXYThread * pt = data.threads; 94 | while (pt) { 95 | pt->handler (); 96 | connect_flag += pt->connect_flag; 97 | pt = pt->next; 98 | } 99 | *data.connect_flag = connect_flag; 100 | 101 | // communications handler 102 | 103 | CRemoteXYComm * comm = data.comms; 104 | while (comm) { 105 | comm->handler (); 106 | comm = comm->next; 107 | } 108 | 109 | // connections handler 110 | 111 | CRemoteXYConnectionComm * connection = data.connections; 112 | while (connection) { 113 | connection->handler (); 114 | connection = connection->next; 115 | } 116 | 117 | 118 | } 119 | 120 | 121 | 122 | /////////////////////////////////////////////////////////////////////////////// 123 | // API - PUBLIC DOCUMENTED FUNCTIONS 124 | 125 | 126 | public: 127 | uint8_t isConnected () { 128 | return *data.connect_flag; 129 | } 130 | 131 | }; 132 | 133 | 134 | 135 | 136 | 137 | #endif //RemoteXYApi_h 138 | 139 | -------------------------------------------------------------------------------- /src/RemoteXYApiData.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYApiData_h 2 | #define RemoteXYApiData_h 3 | 4 | #include 5 | 6 | 7 | #define REMOTEXY_PASSWORD_LENGTH_MAX 26 8 | 9 | class CRemoteXYThread; 10 | class CRemoteXYComm; 11 | class CRemoteXYConnectionComm; 12 | 13 | 14 | class CRemoteXYData { 15 | 16 | public: 17 | uint8_t confVersion; 18 | uint8_t *conf; 19 | uint8_t *var; 20 | uint8_t *accessPassword; 21 | uint16_t outputLength; 22 | uint16_t inputLength; 23 | uint16_t confLength; 24 | uint8_t *connect_flag; 25 | 26 | uint16_t receiveBufferSize; 27 | 28 | CRemoteXYThread * threads; 29 | CRemoteXYComm * comms; 30 | CRemoteXYConnectionComm * connections; 31 | 32 | 33 | public: 34 | void init (const void * _conf, void * _var, const char * _accessPassword) { 35 | 36 | uint8_t i; 37 | uint8_t* p = (uint8_t*)_conf; 38 | uint8_t b = getConfByte (p++); 39 | 40 | if (b==0xff) { 41 | inputLength = getConfByte (p++); 42 | inputLength |= getConfByte (p++)<<8; 43 | outputLength = getConfByte (p++); 44 | outputLength |= getConfByte (p++)<<8; 45 | } 46 | else { 47 | inputLength = b; 48 | outputLength = getConfByte (p++); 49 | } 50 | confLength = getConfByte (p++); 51 | confLength |= getConfByte (p++)<<8; 52 | conf = p; 53 | confVersion = getConfByte (p); 54 | var = (uint8_t*)_var; 55 | uint16_t varLength = outputLength + inputLength; 56 | connect_flag = var + varLength; 57 | *connect_flag = 0; 58 | 59 | accessPassword = (uint8_t*)_accessPassword; 60 | 61 | p = var; 62 | i = varLength; 63 | while (i--) *p++=0; 64 | 65 | receiveBufferSize = inputLength; 66 | if ((*accessPassword != 0) && (receiveBufferSize < REMOTEXY_PASSWORD_LENGTH_MAX)) receiveBufferSize = REMOTEXY_PASSWORD_LENGTH_MAX; 67 | receiveBufferSize +=6; 68 | 69 | comms = NULL; 70 | connections = NULL; 71 | threads = NULL; 72 | } 73 | 74 | public: 75 | inline uint8_t getConfByte (uint8_t* p) { 76 | return pgm_read_byte_near (p); 77 | } 78 | 79 | 80 | }; 81 | 82 | 83 | 84 | 85 | #endif //RemoteXYData_h -------------------------------------------------------------------------------- /src/RemoteXYCloudServer.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYCloudServer_h 2 | #define RemoteXYCloudServer_h 3 | 4 | 5 | #include "RemoteXYApiData.h" 6 | #include "RemoteXYComm.h" 7 | #include "RemoteXYWire.h" 8 | #include "RemoteXYWireStream.h" 9 | #include "RemoteXYWireCloud.h" 10 | 11 | #define REMOTEXY_CLOUD_CONNECT_TIMEOUT 10000 12 | #define REMOTEXY_CLOUD_ECHO_TIMEOUT 30000 13 | 14 | 15 | class CRemoteXYCloudClientAvailableListener { 16 | public: 17 | virtual void clientAvailable (CRemoteXYWireCloud * wire) = 0; 18 | }; 19 | 20 | 21 | class CRemoteXYCloudServer : public CRemoteXYReceivePackageListener, CRemoteXYSendPackageListener { 22 | public: 23 | CRemoteXYWireStream * wire; 24 | CRemoteXYWireCloud * cloudWires; 25 | 26 | private: 27 | CRemoteXYCloudClientAvailableListener * clientAvailableListener; 28 | 29 | uint8_t cloudRegistPackage[38]; 30 | enum { Registring, Working, Stopped } state; 31 | uint32_t timeOut; 32 | 33 | 34 | public: 35 | CRemoteXYCloudServer (CRemoteXYData * data, const char * _cloudToken, CRemoteXYCloudClientAvailableListener * listener) { 36 | 37 | 38 | uint8_t i; 39 | uint8_t *p = cloudRegistPackage; 40 | *p++ = data->getConfByte(data->conf+0); 41 | *p++ = 0; 42 | for (i=0; i<32; i++) { 43 | if (*_cloudToken==0) *(p++)=0; 44 | else *(p++)=*(_cloudToken++); 45 | } 46 | uint16_t *len = (uint16_t*)p; 47 | *len = data->outputLength + data->inputLength; 48 | if (data->confLength>*len) *len = data->confLength; 49 | *len += 6+1; 50 | len = (uint16_t*)(p+2); 51 | *len = data->receiveBufferSize; 52 | #if REMOTEXY_MAX_CLIENTS == 1 53 | wire = new CRemoteXYWireStream (data); 54 | #else 55 | wire = new CRemoteXYWireStream (data, 2); 56 | #endif 57 | cloudWires = NULL; 58 | state = Stopped; 59 | 60 | clientAvailableListener = listener; 61 | } 62 | 63 | 64 | public: 65 | void begin (CRemoteXYClient * client) { 66 | wire->begin(client); 67 | wire->setReceivePackageListener (this); 68 | state = Registring; 69 | wire->sendPackage (0x11, cloudRegistPackage, 38, 0); 70 | timeOut = millis (); 71 | } 72 | 73 | public: 74 | void stop () { 75 | if (state != Stopped) { 76 | wire->stop (); 77 | state = Stopped; 78 | #if defined(REMOTEXY__DEBUGLOG) 79 | RemoteXYDebugLog.write ("Cloud server stoped"); 80 | #endif 81 | } 82 | } 83 | 84 | public: 85 | uint8_t running () { 86 | if (state != Stopped) return 1; 87 | return 0; 88 | } 89 | 90 | 91 | public: 92 | void handler () { 93 | if (state != Stopped) { 94 | CRemoteXYClient * client = wire->getClient (); 95 | wire->handler (); 96 | if (!client->connected ()) stop (); 97 | if (wire->running ()) { 98 | 99 | if (state == Registring) { 100 | if (millis() - timeOut > REMOTEXY_CLOUD_CONNECT_TIMEOUT) stop (); 101 | } 102 | else if (state == Working) { 103 | if (millis() - timeOut > REMOTEXY_CLOUD_ECHO_TIMEOUT) { 104 | #if defined(REMOTEXY__DEBUGLOG) 105 | RemoteXYDebugLog.write("Cloud server timed out"); 106 | #endif 107 | stop (); 108 | } 109 | } 110 | } 111 | else stop (); 112 | } 113 | } 114 | 115 | public: 116 | void sendPackage (uint8_t command, uint8_t *buf, uint16_t length, uint8_t fromPgm) override { 117 | wire->sendPackage (command, buf, length, fromPgm); 118 | } 119 | 120 | 121 | public: 122 | void receivePackage (CRemoteXYPackage * package) override { 123 | timeOut = millis (); 124 | if (package->command == 0x10) { 125 | wire->sendPackage (0x10, 0, 0, 0); 126 | } 127 | else if (package->command == 0x11) { 128 | state = Working; 129 | #if defined(REMOTEXY__DEBUGLOG) 130 | RemoteXYDebugLog.write ("Cloud server registration successfully"); 131 | #endif 132 | } 133 | else { 134 | uint8_t id = (package->command & 0x0e)>>1; 135 | package->command &= 0xf1; 136 | 137 | CRemoteXYWireCloud * pw = cloudWires; 138 | while (pw) { 139 | if ((pw->running ()) && (pw->id == id)) { 140 | pw->receivePackage (package); 141 | return; 142 | } 143 | pw = pw->next; 144 | } 145 | pw = getFreeWireCloud (); 146 | pw->init (id); 147 | clientAvailableListener->clientAvailable (pw); 148 | pw->receivePackage (package); 149 | } 150 | } 151 | 152 | private: 153 | CRemoteXYWireCloud * getFreeWireCloud () { 154 | CRemoteXYWireCloud * pw = cloudWires; 155 | while (pw) { 156 | if (!pw->running ()) return pw; 157 | pw = pw->next; 158 | } 159 | pw = new CRemoteXYWireCloud (this); 160 | pw->next = cloudWires; 161 | cloudWires = pw; 162 | return pw; 163 | } 164 | }; 165 | 166 | 167 | 168 | #endif //RemoteXYCloudServer_h -------------------------------------------------------------------------------- /src/RemoteXYComm.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYComm_h 2 | #define RemoteXYComm_h 3 | 4 | #include 5 | #include "RemoteXYDebugLog.h" 6 | #include "RemoteXYStream.h" 7 | 8 | 9 | #define UNUSED(x) (void)(x) 10 | 11 | class CRemoteXYClientAvailableListener { 12 | public: 13 | virtual void clientAvailable () = 0; 14 | }; 15 | 16 | 17 | 18 | class CRemoteXYClient: public CRemoteXYStream { 19 | public: 20 | CRemoteXYClient * next; 21 | 22 | public: 23 | CRemoteXYClient (): CRemoteXYStream() { 24 | } 25 | 26 | public: 27 | virtual uint8_t connect (const char *host, uint16_t port) {UNUSED (host); UNUSED (port); return 0;}; 28 | virtual void stop () {}; 29 | virtual uint8_t connected () {return 1;}; 30 | virtual uint8_t equal (CRemoteXYClient * cl) {UNUSED (cl); return 0;} 31 | }; 32 | 33 | 34 | class CRemoteXYServer { 35 | 36 | private: 37 | CRemoteXYClientAvailableListener * clientAvailableListener; 38 | 39 | public: 40 | void setClientAvailabListener (CRemoteXYClientAvailableListener * listener) { 41 | clientAvailableListener = listener; 42 | } 43 | 44 | public: 45 | void notifyClientAvailableListener () { 46 | if (clientAvailableListener) clientAvailableListener->clientAvailable (); 47 | } 48 | 49 | 50 | public: 51 | virtual uint8_t begin () {return 0;} 52 | virtual void stop () {}; 53 | virtual uint8_t available (CRemoteXYClient * client) {UNUSED (client); return 0;} 54 | 55 | }; 56 | 57 | 58 | 59 | class CRemoteXYComm { 60 | public: 61 | CRemoteXYComm * next; 62 | 63 | public: 64 | CRemoteXYComm () { 65 | #if defined(REMOTEXY__DEBUGLOG) 66 | RemoteXYDebugLog.init (); 67 | #endif 68 | } 69 | 70 | public: 71 | virtual void handler () {}; 72 | virtual uint8_t configured () {return 1;}; 73 | virtual CRemoteXYServer * createServer (uint16_t _port) {UNUSED (_port); return NULL;} 74 | virtual CRemoteXYClient * newClient () {return NULL;} 75 | }; 76 | 77 | 78 | 79 | #endif //RemoteXYComm_h -------------------------------------------------------------------------------- /src/RemoteXYComm_AT.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYComm_AT_h 2 | #define RemoteXYComm_AT_h 3 | 4 | #include "RemoteXYDebugLog.h" 5 | #include "RemoteXYComm.h" 6 | #include "RemoteXYFunc.h" 7 | #include 8 | 9 | #define UNUSED(x) (void)(x) 10 | 11 | #define REMOTEXYCOMM_AT__RECEIVE_BUFFER_SIZE 32 // maximum response length 12 | 13 | #define REMOTEXYCOMM_AT__COMMAND_TIMEOUT 1000 14 | #define REMOTEXYCOMM_AT__SEND_TIMEOUT 5000 15 | #define REMOTEXYCOMM_AT__TEST_TIMEOUT 30000 16 | #define REMOTEXYCOMM_AT__CONNECT_TIMEOUT 20000 17 | #define REMOTEXYCOMM_AT__NO_CHANNEL 0xff 18 | 19 | 20 | #define AT_ID_BLOCKING 255 21 | #define AT_ID_FINDMODULE 254 22 | #define AT_ID_TESTMODULE 253 23 | 24 | #define AT_RESULT_OK 1 25 | #define AT_RESULT_TIMEOUT 2 26 | #define AT_RESULT_ERROR 3 27 | #define AT_RESULT_FAIL 4 28 | #define AT_RESULT_BUSY 5 29 | #define AT_RESULT_RESET 6 30 | #define AT_RESULT_SEND_READY 7 31 | #define AT_RESULT_SEND_OK 8 32 | #define AT_RESULT_SEND_FAIL 9 33 | #define AT_RESULT_MESSAGE 10 34 | 35 | // standards answers 36 | const char * AT_ANSWER_ERROR = "ERROR"; 37 | const char * AT_ANSWER_FAIL = "FAIL"; 38 | const char * AT_ANSWER_BUSY = "BUSY *"; 39 | const char * AT_ANSWER_OK = "OK"; 40 | const char * AT_ANSWER_SEND_OK = "SEND OK"; 41 | const char * AT_ANSWER_SEND_FAIL = "SEND FAIL"; 42 | const char * AT_MESSAGE_READY = "READY"; 43 | const char * AT_MESSAGE_AT = "AT"; 44 | const char * AT_MESSAGE_CONNECT = "?,CONNECT"; 45 | const char * AT_MESSAGE_CLOSED = "?,CLOSED"; 46 | const char * AT_MESSAGE_CONNECT_FAIL = "?,CONNECT FAIL"; 47 | const char * AT_MESSAGE_IPD = "+IPD,?,*:"; 48 | const char * AT_MESSAGE_CIPSEND = "AT+CIPSEND="; 49 | const char * AT_MESSAGE_CIPCLOSE = "AT+CIPCLOSE="; 50 | const char * AT_MESSAGE_CIPSTART = "AT+CIPSTART="; 51 | 52 | 53 | 54 | class CRemoteXYClient_AT; 55 | class CRemoteXYComm_AT; 56 | 57 | class CRemoteXYClient_AT_Proto : public CRemoteXYClient { 58 | public: 59 | CRemoteXYComm_AT * comm; 60 | uint8_t id; 61 | uint8_t _connected; 62 | CRemoteXYClient_AT_Proto * next; 63 | 64 | }; 65 | 66 | 67 | 68 | class CRemoteXYComm_AT : public CRemoteXYComm, public CRemoteXYReadByteListener { 69 | 70 | private: 71 | CRemoteXYStream * serial; 72 | 73 | public: 74 | CRemoteXYServer * server; 75 | CRemoteXYClient_AT_Proto * clients; 76 | 77 | 78 | protected: 79 | char receiveBuffer[REMOTEXYCOMM_AT__RECEIVE_BUFFER_SIZE]; 80 | uint8_t receiveBufferIndex; 81 | 82 | char * params[3]; 83 | uint8_t paramsLength[3]; 84 | 85 | uint32_t lastAnswerTime; 86 | 87 | 88 | uint16_t connectAvailable; 89 | uint16_t freeAvailable; 90 | 91 | 92 | 93 | uint32_t commandTimeOut; 94 | uint32_t commandDelay; 95 | uint8_t commandIdentifier; 96 | void (*commandListener)(uint8_t, uint8_t); 97 | volatile uint8_t commandResult; 98 | volatile uint8_t commandBlocking; 99 | uint8_t commandFlag; 100 | 101 | uint16_t ipdId; 102 | uint16_t ipdSize; 103 | CRemoteXYClient_AT_Proto * ipdClient; 104 | 105 | int8_t availableClientID; 106 | 107 | uint8_t findModuleTryCount; 108 | uint8_t haveEcho; 109 | 110 | uint16_t sendByteMax; 111 | uint16_t sendByteSize; 112 | uint16_t sendByteNext; 113 | 114 | uint8_t clientConnectingID; 115 | uint8_t detected; 116 | 117 | public: 118 | virtual void moduleReset () {}; 119 | virtual void moduleLost () {}; 120 | virtual void moduleFound () {}; 121 | virtual uint8_t handleATMessage () {return 0;}; 122 | virtual void commandATListener (uint8_t identifier, uint8_t result) { UNUSED(identifier); UNUSED(result);}; 123 | 124 | 125 | 126 | 127 | 128 | public: 129 | CRemoteXYComm_AT (CRemoteXYStream *_serial, uint16_t _sendByteMax) : CRemoteXYComm () { 130 | serial = _serial; 131 | serial->setReadByteListener (this); 132 | sendByteMax = _sendByteMax; 133 | receiveBufferIndex=0; 134 | 135 | ipdSize = 0; 136 | lastAnswerTime = millis (); 137 | 138 | server = NULL; 139 | clients = NULL; 140 | availableClientID = -1; 141 | clientConnectingID = REMOTEXYCOMM_AT__NO_CHANNEL; 142 | detected = 0; // ??? 143 | 144 | 145 | commandDelay = 0; 146 | commandIdentifier = 0; 147 | commandListener = NULL; 148 | findModuleTryCount = 0; 149 | commandBlocking = 0; 150 | } 151 | 152 | 153 | 154 | private: 155 | void resultATcommand (uint8_t identifier, uint8_t result) { 156 | uint8_t id = identifier; 157 | if (result !=AT_RESULT_MESSAGE) { 158 | commandResult = result; 159 | commandDelay = 0; 160 | commandIdentifier = 0; 161 | } 162 | 163 | if (id == AT_ID_FINDMODULE) { 164 | if (result == AT_RESULT_OK) { 165 | findModuleTryCount = 0; 166 | moduleFound (); 167 | } 168 | } 169 | else if (id == AT_ID_TESTMODULE) { 170 | if (result == AT_RESULT_MESSAGE) { 171 | if (strcmpReceiveBuffer (AT_MESSAGE_AT)==0) haveEcho = 1; 172 | } 173 | else if (result == AT_RESULT_OK) { 174 | if (haveEcho) moduleLost (); 175 | 176 | } 177 | else moduleLost (); 178 | } 179 | else { 180 | commandATListener (id, result); 181 | if (commandListener) commandListener (id, result); 182 | } 183 | } 184 | 185 | 186 | private: 187 | void serialWrite (const char *p) { 188 | while (*p) { 189 | serial->write (*p++); 190 | } 191 | } 192 | 193 | 194 | public: 195 | uint8_t readyATCommand () { 196 | if ((commandIdentifier) || (ipdSize) || (commandBlocking)) return 0; 197 | return 1; 198 | } 199 | 200 | public: 201 | void setATCommandListener (void (*listener)(uint8_t, uint8_t)) { 202 | commandListener = listener; 203 | } 204 | 205 | public: 206 | void setATTimeOut (uint32_t timeOut) { 207 | commandDelay = timeOut; 208 | } 209 | 210 | public: 211 | uint8_t getATResult () { 212 | return commandResult; 213 | } 214 | 215 | 216 | private: 217 | void sendArgPtr (const char * p, va_list *argptr) { 218 | if (p) { 219 | while (p) { 220 | serialWrite (p); 221 | #if defined(REMOTEXY__DEBUGLOG) 222 | RemoteXYDebugLog.writeOutput (p); 223 | #endif 224 | p=va_arg(*argptr,char*); 225 | } 226 | serialWrite ("\r\n"); 227 | #if defined(REMOTEXY__DEBUGLOG) 228 | RemoteXYDebugLog.writeInputNewString (); 229 | #endif 230 | } 231 | commandTimeOut = millis(); 232 | if (commandDelay == 0) commandDelay = REMOTEXYCOMM_AT__COMMAND_TIMEOUT; 233 | commandResult = 0; 234 | } 235 | 236 | // not blocking funktion, use: 237 | // for children class - virtual commandATListener (identifier, result) 238 | // for static function - setATListener (func) 239 | // result: 240 | // 0 - command did not send 241 | // 1 - command sent 242 | public: 243 | uint8_t sendATCommand (uint8_t identifier, const char * command, ...) { 244 | if (!readyATCommand ()) { 245 | commandDelay = 0; 246 | return 0; 247 | } 248 | va_list argptr; 249 | va_start (argptr, command); 250 | sendArgPtr (command, &argptr); 251 | va_end(argptr); 252 | commandIdentifier = identifier; 253 | return 1; 254 | } 255 | 256 | 257 | // blocking funktion 258 | // result: AT_RESULT_XXXXX 259 | public: 260 | uint8_t sendATCommandForResult (const char * command, ...) { 261 | if (!readyATCommand ()) { 262 | commandDelay = 0; 263 | return AT_RESULT_BUSY; 264 | } 265 | va_list argptr; 266 | va_start (argptr, command); 267 | sendArgPtr (command, &argptr); 268 | va_end(argptr); 269 | 270 | commandIdentifier = AT_ID_BLOCKING; 271 | commandBlocking = 1; 272 | while (commandResult == 0) { 273 | if (millis() - commandTimeOut > commandDelay) { 274 | resultATcommand (commandIdentifier, AT_RESULT_TIMEOUT); 275 | } 276 | else serial->handler (); 277 | } 278 | commandBlocking = 0; 279 | return commandResult; 280 | } 281 | 282 | 283 | public: 284 | uint8_t waitATResult () { 285 | return sendATCommandForResult (NULL, NULL); 286 | } 287 | 288 | 289 | public: 290 | void readByte (uint8_t byte) override { 291 | 292 | if (ipdSize) { 293 | ipdSize--; 294 | if (ipdClient) { 295 | ipdClient->notifyReadByteListener (byte); 296 | } 297 | #if defined(REMOTEXY__DEBUGLOG) 298 | if (ipdSize == 0) RemoteXYDebugLog.writeInputNewString (); 299 | #endif 300 | return; 301 | } 302 | 303 | if (byte==10) return; 304 | #if defined(REMOTEXY__DEBUGLOG) 305 | if (byte==13) RemoteXYDebugLog.writeInputNewString (); 306 | else RemoteXYDebugLog.writeInputChar (byte); 307 | #endif 308 | if (byte==13) { 309 | lastAnswerTime = millis (); 310 | receiveBuffer[receiveBufferIndex]=0; 311 | if (receiveBufferIndex == 0) return; 312 | receiveBufferIndex=0; 313 | 314 | if (strcmpReceiveBuffer (AT_MESSAGE_CONNECT)==0) { // new client 315 | uint8_t id = getATParamInt(0); 316 | if (id != clientConnectingID) { 317 | availableClientID = id; 318 | if (server) server->notifyClientAvailableListener (); 319 | } 320 | return; 321 | } 322 | if (strcmpReceiveBuffer (AT_MESSAGE_CLOSED)==0) { clientClosed (); return; } // client closed 323 | if (strcmpReceiveBuffer (AT_MESSAGE_CONNECT_FAIL)==0) { clientClosed (); return; } // client closed 324 | if (strcmpReceiveBuffer (AT_MESSAGE_READY)==0) { 325 | if (commandIdentifier) resultATcommand (commandIdentifier, AT_RESULT_TIMEOUT); 326 | moduleReset (); 327 | return; 328 | } 329 | if (handleATMessage ()) return; 330 | if (commandIdentifier) { 331 | if (strcmpReceiveBuffer (AT_ANSWER_OK)==0) resultATcommand (commandIdentifier, AT_RESULT_OK); 332 | else if (strcmpReceiveBuffer (AT_ANSWER_SEND_OK)==0) resultATcommand (commandIdentifier, AT_RESULT_SEND_OK); 333 | else if (strcmpReceiveBuffer (AT_ANSWER_ERROR)==0) resultATcommand (commandIdentifier, AT_RESULT_ERROR); 334 | else if (strcmpReceiveBuffer (AT_ANSWER_FAIL)==0) resultATcommand (commandIdentifier, AT_RESULT_FAIL); 335 | else if (strcmpReceiveBuffer (AT_ANSWER_BUSY)==0) resultATcommand (commandIdentifier, AT_RESULT_BUSY); 336 | else if (strcmpReceiveBuffer (AT_ANSWER_SEND_FAIL)==0) resultATcommand (commandIdentifier, AT_RESULT_SEND_FAIL); 337 | else resultATcommand (commandIdentifier, AT_RESULT_MESSAGE); 338 | return; 339 | } 340 | } 341 | else { 342 | if ((byte>0x60) && (byte<=0x7a)) byte-=0x20; 343 | if (receiveBufferIndexid == ipdId) && (p->_connected)) break; 357 | p = p->next; 358 | } 359 | ipdClient = p; 360 | return; 361 | } 362 | } 363 | else if ((byte=='>') && (receiveBufferIndex==1)) { 364 | receiveBufferIndex = 0; 365 | resultATcommand (commandIdentifier, AT_RESULT_SEND_READY); 366 | } 367 | else if ((byte==' ') && (receiveBufferIndex==1)) { 368 | receiveBufferIndex = 0; 369 | } 370 | } 371 | } 372 | 373 | 374 | 375 | public: 376 | void handler () override { // override CRemoteXYComm 377 | 378 | serial->handler (); 379 | 380 | if (!ipdSize) { 381 | if (commandIdentifier) { 382 | if (millis() - commandTimeOut > commandDelay) { 383 | resultATcommand (commandIdentifier, AT_RESULT_TIMEOUT); 384 | } 385 | } 386 | else if (findModuleTryCount) { 387 | if (millis() - lastAnswerTime > REMOTEXYCOMM_AT__COMMAND_TIMEOUT) { 388 | findModuleTryCount--; 389 | if (findModuleTryCount == 0) { 390 | #if defined(REMOTEXY__DEBUGLOG) 391 | RemoteXYDebugLog.write ("Мodule does not respond to AT commands"); 392 | #endif 393 | findModuleTryCount = 10; 394 | } 395 | lastAnswerTime = millis (); 396 | sendATCommand (AT_ID_FINDMODULE, AT_MESSAGE_AT, NULL); 397 | } 398 | } 399 | else { 400 | if (millis() - lastAnswerTime > REMOTEXYCOMM_AT__TEST_TIMEOUT) { 401 | haveEcho = 0; 402 | if (sendATCommand (AT_ID_TESTMODULE, AT_MESSAGE_AT, NULL)) { 403 | lastAnswerTime = millis(); 404 | } 405 | } 406 | } 407 | } 408 | } 409 | 410 | 411 | private: 412 | void clientClosed () { 413 | uint8_t id = getATParamInt(0); 414 | if (availableClientID == id) availableClientID = -1; 415 | else { 416 | CRemoteXYClient_AT_Proto * p = clients; 417 | while (p) { 418 | if ((p->id == id) && (p->_connected)) { 419 | p->_connected = 0; 420 | //return; 421 | } 422 | p = p->next; 423 | } 424 | } 425 | } 426 | 427 | public: 428 | uint8_t server_available (CRemoteXYClient_AT_Proto * client) { 429 | if (availableClientID >= 0) { 430 | client->id = availableClientID; 431 | client->_connected = 1; 432 | availableClientID = -1; 433 | return 1; 434 | } 435 | return 0; 436 | } 437 | 438 | public: 439 | uint8_t client_connect (CRemoteXYClient_AT_Proto * client, const char *host, uint16_t port) { 440 | char sport[6]; 441 | char sid[2]; 442 | int8_t i; 443 | CRemoteXYClient_AT_Proto * p; 444 | if (client->_connected) client_stop (client); 445 | clientConnectingID = REMOTEXYCOMM_AT__NO_CHANNEL; 446 | for (i=3; i>=0; i--) { 447 | p = clients; 448 | while (p) { 449 | if ((p->_connected) && (client->id == i)) break; 450 | p=p->next; 451 | } 452 | if (!p) { 453 | clientConnectingID = i; 454 | break; 455 | } 456 | } 457 | if (clientConnectingID == REMOTEXYCOMM_AT__NO_CHANNEL) return 0; 458 | rxy_itos (port, sport); 459 | *sid=clientConnectingID+0x30; 460 | *(sid+1)=0; 461 | setATTimeOut (REMOTEXYCOMM_AT__CONNECT_TIMEOUT); 462 | uint8_t res = sendATCommandForResult (AT_MESSAGE_CIPSTART, sid, ",\"TCP\",\"", host,"\",", sport,NULL); 463 | i = clientConnectingID; 464 | clientConnectingID = REMOTEXYCOMM_AT__NO_CHANNEL; 465 | if (res != AT_RESULT_OK) return 0; 466 | client->id = i; 467 | client->_connected = 1; 468 | return 1; 469 | } 470 | 471 | public: 472 | void client_stop (CRemoteXYClient_AT_Proto * client) { 473 | if (client->_connected) { 474 | client->_connected = 0; 475 | char s[2]; 476 | *s=client->id+0x30; 477 | *(s+1) = 0; 478 | sendATCommandForResult (AT_MESSAGE_CIPCLOSE,s,NULL); 479 | } 480 | } 481 | 482 | public: 483 | void client_startWrite (CRemoteXYClient_AT_Proto * client, uint16_t size) { 484 | if (client->_connected) { 485 | char s[8]; 486 | sendByteSize = size; 487 | if (sendByteSize > sendByteMax) sendByteSize = sendByteMax; 488 | sendByteNext = size - sendByteSize; 489 | 490 | rxy_itos (sendByteSize, s+2); 491 | *s=client->id+0x30; 492 | *(s+1)=','; 493 | #if defined(REMOTEXY__DEBUGLOG) 494 | RemoteXYDebugLog.writeInputNewString (); 495 | #endif 496 | uint8_t res = sendATCommandForResult (AT_MESSAGE_CIPSEND,s,NULL); 497 | if (res == AT_RESULT_OK) res = waitATResult (); 498 | if (res == AT_RESULT_SEND_READY) { 499 | #if defined(REMOTEXY__DEBUGLOG) 500 | RemoteXYDebugLog.writeAdd (" *send "); 501 | RemoteXYDebugLog.writeAdd (sendByteSize); 502 | RemoteXYDebugLog.writeAdd (" bytes*"); 503 | #endif 504 | return; 505 | } 506 | sendByteSize = 0; 507 | } 508 | } 509 | 510 | public: 511 | void client_write (CRemoteXYClient_AT_Proto * client, uint8_t byte) { 512 | if (sendByteSize) { 513 | serial->write (byte); 514 | sendByteSize--; 515 | if (sendByteSize == 0) { 516 | setATTimeOut (REMOTEXYCOMM_AT__SEND_TIMEOUT); 517 | if (waitATResult () == AT_RESULT_SEND_OK) { 518 | if (sendByteNext) client_startWrite (client, sendByteNext); 519 | } 520 | } 521 | } 522 | } 523 | 524 | 525 | 526 | 527 | public: 528 | void findModule () { 529 | findModuleTryCount=10; 530 | lastAnswerTime = millis (); 531 | } 532 | 533 | 534 | protected: 535 | uint8_t strcmpReceiveBuffer (const char * temp) { 536 | uint8_t k = 0; 537 | char * str = receiveBuffer; 538 | while (*temp) { 539 | if (!*str) return 1; 540 | switch (*temp) { 541 | case '?': 542 | params[k]=str; 543 | paramsLength[k]=1; 544 | temp++; 545 | str++; 546 | k++; 547 | break; 548 | case '*': 549 | params[k]=str; 550 | paramsLength[k]=0; 551 | temp++; 552 | while (*str!=*temp) { 553 | if (!*str++) return 1; 554 | paramsLength[k]++; 555 | } 556 | k++; 557 | break; 558 | default: 559 | if (*(str++)!=*(temp++)) return 1; 560 | break; 561 | } 562 | } 563 | if (*str) return 1; 564 | return 0; 565 | } 566 | 567 | protected: 568 | uint16_t getATParamInt (uint8_t k) { 569 | uint16_t res = 0; 570 | char * p=params[k]; 571 | uint8_t i=paramsLength[k]; 572 | while (i--) res = res*10+(*p++)-'0'; 573 | return res; 574 | } 575 | 576 | public: 577 | void registerClient (CRemoteXYClient_AT_Proto * client) { 578 | client->next = clients; 579 | clients = client; 580 | } 581 | 582 | public: 583 | void removeClient (CRemoteXYClient_AT_Proto * client) { 584 | CRemoteXYClient_AT_Proto ** pclient = &clients; 585 | while (*pclient) { 586 | if (*pclient == client) { 587 | if ((*pclient)->_connected) client_stop (*pclient); 588 | *pclient = client->next; 589 | return; 590 | } 591 | pclient = &((*pclient)->next); 592 | } 593 | } 594 | 595 | 596 | }; 597 | 598 | 599 | class CRemoteXYServer_AT : public CRemoteXYServer { 600 | 601 | 602 | protected: 603 | CRemoteXYComm_AT * comm; 604 | uint16_t port; 605 | 606 | public: 607 | CRemoteXYServer_AT (CRemoteXYComm_AT * _comm, uint16_t _port) { 608 | comm = _comm; 609 | port = _port; 610 | comm->server = this; 611 | } 612 | 613 | ~CRemoteXYServer_AT () { 614 | if (comm) comm->server = NULL; 615 | } 616 | 617 | 618 | public: 619 | uint8_t available (CRemoteXYClient * client) override { 620 | return comm->server_available ((CRemoteXYClient_AT_Proto *)client); 621 | } 622 | 623 | uint8_t begin () override { 624 | char sport[6]; 625 | rxy_itos (port, sport); 626 | if (comm->sendATCommandForResult ("AT+CIPSERVER=1,", sport, NULL) != AT_RESULT_OK) return 0; 627 | if (comm->sendATCommandForResult ("AT+CIPSTO=30", NULL) != AT_RESULT_OK) return 0; 628 | return 1; 629 | } 630 | 631 | void stop () override { 632 | comm->sendATCommandForResult ("AT+CIPSERVER=0", NULL); 633 | } 634 | 635 | }; 636 | 637 | 638 | class CRemoteXYClient_AT : public CRemoteXYClient_AT_Proto { 639 | 640 | public: 641 | CRemoteXYClient_AT (CRemoteXYComm_AT * _comm) { 642 | comm = _comm; 643 | _connected = 0; 644 | comm->registerClient (this); 645 | } 646 | 647 | ~CRemoteXYClient_AT () { 648 | if (comm) comm->removeClient (this); 649 | } 650 | 651 | public: 652 | uint8_t connect (const char *host, uint16_t port) override { 653 | if (comm) return comm->client_connect (this, host, port); 654 | return 0; 655 | } 656 | 657 | public: 658 | uint8_t connected () override { 659 | return _connected; 660 | } 661 | 662 | public: 663 | void stop () override { 664 | if (comm) comm->client_stop (this); 665 | } 666 | 667 | void startWrite (uint16_t size) override { 668 | if (comm) comm->client_startWrite (this, size); 669 | } 670 | 671 | void write (uint8_t byte) override { 672 | if (comm) comm->client_write (this, byte); 673 | } 674 | 675 | }; 676 | 677 | 678 | 679 | 680 | 681 | #endif // RemoteXYComm_AT_h 682 | -------------------------------------------------------------------------------- /src/RemoteXYComm_ESP8266.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYComm_ESP8266_h 2 | #define RemoteXYComm_ESP8266_h 3 | 4 | #include "RemoteXYDebugLog.h" 5 | #include "RemoteXYComm_AT.h" 6 | 7 | #define REMOTEXYCOMM_ESP8266__SERVER_TIMEOUT 10000 8 | #define REMOTEXYCOMM_ESP8266__WIFICONNECT_TIMEOUT 30000 9 | 10 | #define REMOTEXYCOMM_ESP8266__ID_WIFICONNECT 1 11 | 12 | #define REMOTEXYCOMM_ESP8266__MAX_SEND_BYTE_SIZE 2048 13 | 14 | const char * AT_MESSAGE_WIFI_DISCONNECT = "WIFI DISCONNECT"; 15 | 16 | 17 | class CRemoteXYComm_ESP8266_Proto : public CRemoteXYComm_AT { 18 | 19 | protected: 20 | const char * wifiSsid; 21 | const char * wifiPassword; 22 | enum { Search, Reset, SearchAfterReset, Init, WaitWiFi, WaitReconnect, Configured } state; 23 | uint32_t timeOut; 24 | 25 | public: 26 | CRemoteXYComm_ESP8266_Proto (CRemoteXYStream *_serial, const char * _wifiSsid, const char * _wifiPassword) : CRemoteXYComm_AT (_serial, REMOTEXYCOMM_ESP8266__MAX_SEND_BYTE_SIZE) { 27 | wifiSsid = _wifiSsid; 28 | wifiPassword = _wifiPassword; 29 | state = Search; 30 | findModule (); 31 | } 32 | 33 | 34 | void moduleFound () override { 35 | if ((state == Reset) || (state == SearchAfterReset)) moduleReset (); 36 | else { 37 | state = Reset; 38 | timeOut = millis (); 39 | sendATCommandForResult ("AT+RST",NULL); // reset module 40 | } 41 | } 42 | 43 | protected: 44 | void moduleLost () override { 45 | state = Search; 46 | findModule (); 47 | } 48 | 49 | 50 | 51 | uint8_t configured () override { 52 | return (state == Configured); 53 | }; 54 | 55 | virtual CRemoteXYServer * createServer (uint16_t _port) override { 56 | if (!server) { 57 | server = new CRemoteXYServer_AT (this, _port); 58 | return server; 59 | } 60 | return NULL; 61 | } 62 | 63 | public: 64 | CRemoteXYClient * newClient () override { 65 | return new CRemoteXYClient_AT (this); 66 | } 67 | 68 | }; 69 | 70 | class CRemoteXYComm_ESP8266 : public CRemoteXYComm_ESP8266_Proto { 71 | 72 | public: 73 | CRemoteXYComm_ESP8266 (CRemoteXYStream *_serial, const char * _wifiSsid, const char * _wifiPassword) : CRemoteXYComm_ESP8266_Proto (_serial, _wifiSsid, _wifiPassword) { 74 | } 75 | 76 | protected: 77 | void moduleReset () override { 78 | if (!initModule ()) { 79 | state = Search; 80 | findModule (); 81 | } 82 | } 83 | 84 | 85 | 86 | private: 87 | uint8_t initModule () { 88 | state = Init; 89 | if (sendATCommandForResult ("ATE0",NULL) != AT_RESULT_OK) return 0; 90 | if (sendATCommandForResult ("AT+CWMODE=1",NULL) != AT_RESULT_OK) return 0; 91 | if (sendATCommandForResult ("AT+CWQAP",NULL) != AT_RESULT_OK) return 0; 92 | if (sendATCommandForResult ("AT+CWDHCP=1,1",NULL) != AT_RESULT_OK) return 0; 93 | if (sendATCommandForResult ("AT+CIPMODE=0",NULL) != AT_RESULT_OK) return 0; 94 | if (sendATCommandForResult ("AT+CIPMUX=1",NULL) != AT_RESULT_OK) return 0; 95 | beginWiFi (); 96 | return 1; 97 | } 98 | 99 | private: 100 | void beginWiFi () { 101 | state = Init; 102 | setATTimeOut (REMOTEXYCOMM_ESP8266__WIFICONNECT_TIMEOUT); 103 | if (sendATCommand (REMOTEXYCOMM_ESP8266__ID_WIFICONNECT, "AT+CWJAP=\"",wifiSsid,"\",\"",wifiPassword,"\"",NULL)) state = WaitWiFi; 104 | } 105 | 106 | 107 | protected: 108 | void commandATListener (uint8_t identifier, uint8_t result) override { 109 | if (identifier == REMOTEXYCOMM_ESP8266__ID_WIFICONNECT) { 110 | if (result == AT_RESULT_OK) { 111 | #if defined(REMOTEXY__DEBUGLOG) 112 | sendATCommandForResult ("AT+CIPSTA?",NULL); 113 | #endif 114 | state = Configured; 115 | } 116 | else { 117 | state = WaitReconnect; 118 | timeOut = millis(); 119 | } 120 | } 121 | } 122 | 123 | virtual void handler () override { // override CRemoteXYComm_AT 124 | CRemoteXYComm_AT::handler (); 125 | if (state == Reset) { 126 | if (millis() - timeOut > 5000) { 127 | state = SearchAfterReset; 128 | findModule (); 129 | } 130 | } 131 | else if (state == Init) beginWiFi (); 132 | else if (state == WaitReconnect) { 133 | if (millis() - timeOut > REMOTEXYCOMM_ESP8266__WIFICONNECT_TIMEOUT) beginWiFi (); 134 | } 135 | } 136 | 137 | uint8_t handleATMessage () override { // override CRemoteXYComm_AT 138 | if (strcmpReceiveBuffer (AT_MESSAGE_WIFI_DISCONNECT)==0) { 139 | if (state == Configured) state = Init; 140 | return 1; 141 | } 142 | return 0; 143 | } 144 | 145 | 146 | }; 147 | 148 | 149 | class CRemoteXYComm_ESP8266Point : public CRemoteXYComm_ESP8266_Proto { 150 | 151 | public: 152 | CRemoteXYComm_ESP8266Point (CRemoteXYStream *_serial, const char * _wifiSsid, const char * _wifiPassword) : CRemoteXYComm_ESP8266_Proto (_serial, _wifiSsid, _wifiPassword) { 153 | } 154 | 155 | protected: 156 | void moduleReset () override { 157 | initModule (); 158 | if (state != Configured) { 159 | state = Search; 160 | findModule (); 161 | } 162 | } 163 | 164 | private: 165 | void initModule () { 166 | state = Init; 167 | if (sendATCommandForResult ("ATE0",NULL) != AT_RESULT_OK) return; 168 | if (sendATCommandForResult ("AT+CWMODE=2",NULL) != AT_RESULT_OK) return; 169 | if (sendATCommandForResult ("AT+CWDHCP=0,1",NULL) != AT_RESULT_OK) return; 170 | 171 | char crypt[2] = {*wifiPassword?'4':'0',0}; 172 | setATTimeOut (5000); 173 | if (sendATCommandForResult ("AT+CWSAP=\"",wifiSsid,"\",\"",wifiPassword,"\",10,",crypt,NULL) != AT_RESULT_OK) return; 174 | if (sendATCommandForResult ("AT+CIPMODE=0",NULL) != AT_RESULT_OK) return; 175 | if (sendATCommandForResult ("AT+CIPMUX=1",NULL) != AT_RESULT_OK) return; 176 | state = Configured; 177 | } 178 | 179 | virtual void handler () override { 180 | CRemoteXYComm_AT::handler (); 181 | if (state == Reset) { 182 | if (millis() - timeOut > 5000) { 183 | state = SearchAfterReset; 184 | findModule (); 185 | } 186 | } 187 | } 188 | 189 | }; 190 | 191 | 192 | 193 | 194 | #endif // RemoteXYComm_ESP8266_h 195 | -------------------------------------------------------------------------------- /src/RemoteXYComm_Ethernet.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYComm_Ethernet_h 2 | #define RemoteXYComm_Ethernet_h 3 | 4 | 5 | #if defined (ethernet_h_) 6 | 7 | #include "RemoteXYDebugLog.h" 8 | #include "RemoteXYComm.h" 9 | #include "RemoteXYFunc.h" 10 | 11 | 12 | #define REMOREXYCOMM_ETHERNET__SEND_BUFFER_SIZE 32 13 | 14 | class CRemoteXYClient_Ethernet : public CRemoteXYClient { 15 | public: 16 | EthernetClient client; 17 | 18 | uint8_t sendBuffer[REMOREXYCOMM_ETHERNET__SEND_BUFFER_SIZE]; 19 | uint16_t sendBufferCount; 20 | uint16_t sendBytesAvailable; 21 | 22 | public: 23 | uint8_t connect (const char *host, uint16_t port) override { 24 | return client.connect(host, port); 25 | }; 26 | 27 | public: 28 | uint8_t connected () override { 29 | return client.connected(); 30 | }; 31 | 32 | public: 33 | void stop () override { 34 | client.stop (); 35 | }; 36 | 37 | public: 38 | void handler () override { 39 | while (client.available ()) notifyReadByteListener (client.read ()); 40 | } 41 | 42 | 43 | 44 | public: 45 | void startWrite (uint16_t len) override { 46 | sendBytesAvailable = len; 47 | sendBufferCount = 0; 48 | } 49 | 50 | public: 51 | void write (uint8_t b) override { 52 | sendBuffer[sendBufferCount++] = b; 53 | sendBytesAvailable--; 54 | if ((sendBufferCount == REMOREXYCOMM_ETHERNET__SEND_BUFFER_SIZE) || (sendBytesAvailable==0)) { 55 | client.write (sendBuffer, sendBufferCount); 56 | sendBufferCount=0; 57 | } 58 | } 59 | 60 | 61 | }; 62 | 63 | #if defined (ESP32) 64 | class EthernetServerESP32: public EthernetServer { 65 | public: 66 | EthernetServerESP32 (uint16_t port) : EthernetServer (port) {} 67 | void begin(uint16_t port=0) {} 68 | }; 69 | #endif 70 | 71 | class CRemoteXYServer_Ethernet : public CRemoteXYServer { 72 | private: 73 | EthernetServer * server; 74 | uint8_t soketConnectArr[MAX_SOCK_NUM]; 75 | 76 | public: 77 | CRemoteXYServer_Ethernet (uint16_t _port) { 78 | #if defined (ESP32) 79 | server = new EthernetServerESP32 (_port); 80 | #else 81 | server = new EthernetServer (_port); 82 | #endif 83 | for (uint8_t i = 0; i < MAX_SOCK_NUM; i++) soketConnectArr[i] = 0; 84 | } 85 | 86 | 87 | public: 88 | virtual uint8_t begin () override { 89 | server->begin (); 90 | return 1; 91 | } 92 | 93 | 94 | uint8_t available (CRemoteXYClient * client) override { 95 | EthernetClient cl; 96 | uint8_t i; 97 | for (i = 0; i < MAX_SOCK_NUM; i++) { 98 | cl = EthernetClient (i); 99 | if (!cl.connected ()) soketConnectArr[i] = 0; 100 | } 101 | cl = server->available (); 102 | if (cl.connected ()) { 103 | i = cl.getSocketNumber(); 104 | if (iclient = cl; 108 | return 1; 109 | } 110 | } 111 | } 112 | return 0; 113 | } 114 | 115 | }; 116 | 117 | 118 | class CRemoteXYComm_Ethernet : public CRemoteXYComm { 119 | 120 | private: 121 | uint8_t mac[6]; 122 | enum {NoHardware, LinkDetecting, Work} state; 123 | uint32_t timeout; 124 | 125 | 126 | public: 127 | CRemoteXYComm_Ethernet (const char * macAddress) : CRemoteXYComm () { 128 | rxy_getMacAddr (macAddress, mac); 129 | 130 | #if defined(REMOTEXY__DEBUGLOG) 131 | RemoteXYDebugLog.write("Ethernet begin ..."); 132 | #endif 133 | 134 | Ethernet.begin(mac, 1000); 135 | 136 | if (Ethernet.hardwareStatus() == EthernetNoHardware) { 137 | state = NoHardware; 138 | #if defined(REMOTEXY__DEBUGLOG) 139 | RemoteXYDebugLog.write("Ethernet module was not found"); 140 | #endif 141 | } 142 | else { 143 | state = LinkDetecting; 144 | #if defined(REMOTEXY__DEBUGLOG) 145 | if (!linkON ()) { 146 | RemoteXYDebugLog.write("Ethernet link OFF"); 147 | } 148 | #endif 149 | } 150 | timeout = millis (); 151 | } 152 | 153 | 154 | private: 155 | uint8_t linkON () { 156 | return 1; 157 | if (Ethernet.hardwareStatus () == EthernetW5100) { 158 | if (uint32_t(Ethernet.localIP()) != 0) return 1; 159 | } 160 | else { 161 | if (Ethernet.linkStatus () == LinkON) return 1; 162 | } 163 | return 0; 164 | } 165 | 166 | 167 | public: 168 | void handler () override { 169 | 170 | if (state == NoHardware) return; 171 | 172 | if (linkON ()) { 173 | if (state == LinkDetecting) { 174 | #if defined(REMOTEXY__DEBUGLOG) 175 | RemoteXYDebugLog.write ("Ethernet link ON"); 176 | RemoteXYDebugLog.write("IP: "); 177 | RemoteXYDebugLog.serial->print(Ethernet.localIP()); 178 | #endif 179 | state = Work; 180 | } 181 | timeout = millis (); 182 | } 183 | else { // LinkOFF 184 | if (state == Work) { 185 | state = LinkDetecting; 186 | #if defined(REMOTEXY__DEBUGLOG) 187 | RemoteXYDebugLog.write ("Ethernet link OFF"); 188 | #endif 189 | } 190 | else { 191 | if (millis () - timeout > 5000) { 192 | Ethernet.begin(mac, 100); 193 | timeout = millis (); 194 | } 195 | } 196 | } 197 | } 198 | 199 | 200 | public: 201 | uint8_t configured () override { 202 | if (state == Work) return 1; 203 | return 0; 204 | } 205 | 206 | public: 207 | CRemoteXYServer * createServer (uint16_t _port) override { 208 | return new CRemoteXYServer_Ethernet (_port); 209 | } 210 | 211 | 212 | CRemoteXYClient * newClient () override { 213 | return new CRemoteXYClient_Ethernet (); 214 | } 215 | 216 | }; 217 | 218 | 219 | #endif // ethernet_h_ 220 | 221 | #endif //RemoteXYComm_Ethernet_h -------------------------------------------------------------------------------- /src/RemoteXYComm_WiFi.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYComm_WiFi_h 2 | #define RemoteXYComm_WiFi_h 3 | 4 | #include "RemoteXYDebugLog.h" 5 | #include "RemoteXYComm.h" 6 | 7 | #if defined (WiFi_h) 8 | 9 | #if defined (ESP8266) || defined (ESP32) 10 | #define REMOREXYCOMM_WIFI__SEND_BUFFER_SIZE 256 11 | #else // arduino shield 12 | #define REMOREXYCOMM_WIFI__SEND_BUFFER_SIZE 64 13 | #endif 14 | 15 | 16 | 17 | 18 | 19 | class CRemoteXYClient_WiFi : public CRemoteXYClient { 20 | public: 21 | WiFiClient client; 22 | 23 | uint8_t sendBuffer[REMOREXYCOMM_WIFI__SEND_BUFFER_SIZE]; 24 | uint16_t sendBufferCount; 25 | uint16_t sendBytesAvailable; 26 | 27 | public: 28 | uint8_t connect (const char *host, uint16_t port) override { 29 | return client.connect(host, port); 30 | }; 31 | 32 | public: 33 | uint8_t connected () override { 34 | return client.connected(); 35 | }; 36 | 37 | public: 38 | void stop () override { 39 | client.stop (); 40 | }; 41 | 42 | public: 43 | void handler () override { 44 | while (client.available ()) notifyReadByteListener (client.read ()); 45 | } 46 | 47 | 48 | public: 49 | void startWrite (uint16_t len) override { 50 | sendBytesAvailable = len; 51 | sendBufferCount = 0; 52 | } 53 | 54 | public: 55 | void write (uint8_t b) override { 56 | sendBuffer[sendBufferCount++] = b; 57 | sendBytesAvailable--; 58 | if ((sendBufferCount == REMOREXYCOMM_WIFI__SEND_BUFFER_SIZE) || (sendBytesAvailable==0)) { 59 | client.write (sendBuffer, sendBufferCount); 60 | sendBufferCount=0; 61 | } 62 | } 63 | 64 | }; 65 | 66 | class CRemoteXYServer_WiFi : public CRemoteXYServer { 67 | private: 68 | WiFiServer * server; 69 | 70 | public: 71 | CRemoteXYServer_WiFi (uint16_t _port) { 72 | server = new WiFiServer (_port); 73 | } 74 | 75 | 76 | public: 77 | virtual uint8_t begin () override { 78 | server->begin (); 79 | return 1; 80 | } 81 | 82 | 83 | void stop () override { 84 | #if defined (ESP8266) || defined (ESP32) 85 | server->stop (); 86 | #endif 87 | } 88 | 89 | 90 | 91 | uint8_t available (CRemoteXYClient * client) override { 92 | #if defined (ESP8266) || defined (ESP32) 93 | if (!server->hasClient()) return 0; 94 | #endif 95 | WiFiClient cl = server->available (); 96 | if (cl) { 97 | if (cl.connected ()) { 98 | #if defined (ESP8266) 99 | cl.disableKeepAlive (); // remove memory leak 100 | #endif 101 | ((CRemoteXYClient_WiFi*) client)->client = cl; 102 | return 1; 103 | } 104 | } 105 | return 0; 106 | } 107 | 108 | }; 109 | 110 | 111 | class CRemoteXYComm_WiFi : public CRemoteXYComm { 112 | 113 | private: 114 | char * wifiSsid; 115 | char * wifiPassword; 116 | uint8_t wifiStatus; 117 | 118 | 119 | public: 120 | CRemoteXYComm_WiFi (const char * _wifiSsid, const char * _wifiPassword) : CRemoteXYComm () { 121 | wifiSsid = (char *)_wifiSsid; 122 | wifiPassword = (char *)_wifiPassword; 123 | 124 | 125 | wifiStatus = WiFi.status(); 126 | 127 | #if defined (ESP8266) || defined (ESP32) 128 | 129 | WiFi.disconnect(); 130 | WiFi.softAPdisconnect(true); 131 | WiFi.mode(WIFI_STA); 132 | 133 | #else // NOT ESP 134 | 135 | if (wifiStatus == WL_NO_SHIELD) { 136 | #if defined(REMOTEXY__DEBUGLOG) 137 | RemoteXYDebugLog.write("WiFi module was not found"); 138 | #endif 139 | return; 140 | } 141 | 142 | #endif // ESP 143 | 144 | 145 | #if defined(REMOTEXY__DEBUGLOG) 146 | RemoteXYDebugLog.write("Сonnecting to WiFi: "); 147 | RemoteXYDebugLog.writeAdd(wifiSsid); 148 | RemoteXYDebugLog.writeAdd(" ..."); 149 | #endif 150 | 151 | WiFi.begin(wifiSsid, wifiPassword); 152 | 153 | #if defined (ESP8266) || defined (ESP32) 154 | WiFi.setAutoReconnect (true); 155 | #endif 156 | 157 | } 158 | 159 | 160 | void handler () override { 161 | 162 | uint8_t prev_wifiStatus = wifiStatus; 163 | wifiStatus = WiFi.status(); 164 | 165 | if (wifiStatus == WL_CONNECTED) { 166 | if (prev_wifiStatus != WL_CONNECTED) { 167 | #if defined(REMOTEXY__DEBUGLOG) 168 | RemoteXYDebugLog.write ("WiFi connected"); 169 | RemoteXYDebugLog.write ("IP: "); 170 | RemoteXYDebugLog.serial->print (WiFi.localIP()); 171 | #endif 172 | 173 | } 174 | } 175 | else { // != WL_CONNECTED 176 | if (prev_wifiStatus == WL_CONNECTED) { 177 | #if defined(REMOTEXY__DEBUGLOG) 178 | RemoteXYDebugLog.write ("WiFi disconnected"); 179 | #endif 180 | #if defined (ESP32) 181 | WiFi.disconnect(); 182 | WiFi.mode(WIFI_STA); 183 | WiFi.begin(wifiSsid, wifiPassword); 184 | #endif 185 | } 186 | } 187 | } 188 | 189 | 190 | public: 191 | uint8_t configured () override { 192 | if (wifiStatus == WL_CONNECTED) return 1; 193 | return 0; 194 | } 195 | 196 | public: 197 | CRemoteXYServer * createServer (uint16_t _port) override { 198 | return new CRemoteXYServer_WiFi (_port); 199 | } 200 | 201 | 202 | CRemoteXYClient * newClient () override { 203 | return new CRemoteXYClient_WiFi (); 204 | } 205 | 206 | }; 207 | 208 | 209 | 210 | class CRemoteXYComm_WiFiPoint : public CRemoteXYComm { 211 | 212 | uint8_t state; 213 | 214 | public: 215 | CRemoteXYComm_WiFiPoint (const char * _wifiSsid, const char * _wifiPassword) : CRemoteXYComm () { 216 | 217 | 218 | #if defined(REMOTEXY__DEBUGLOG) 219 | RemoteXYDebugLog.write("Creating WiFi point: "); 220 | RemoteXYDebugLog.writeAdd(_wifiSsid); 221 | RemoteXYDebugLog.writeAdd(" ..."); 222 | #endif 223 | 224 | #if defined (ESP8266) || defined (ESP32) 225 | 226 | WiFi.mode(WIFI_AP); 227 | WiFi.softAP(_wifiSsid, _wifiPassword); 228 | state = 1; 229 | #if defined(REMOTEXY__DEBUGLOG) 230 | RemoteXYDebugLog.write("WiFi point created"); 231 | RemoteXYDebugLog.write ("IP: "); 232 | RemoteXYDebugLog.serial->print (WiFi.softAPIP()); 233 | #endif 234 | 235 | #elif defined (WiFiNINA_h) // WiFiNINA 236 | 237 | state = 0; 238 | if (WiFi.status() == WL_NO_SHIELD) { 239 | #if defined(REMOTEXY__DEBUGLOG) 240 | RemoteXYDebugLog.write("WiFi module was not found"); 241 | #endif 242 | return; 243 | } 244 | if (WiFi.beginAP (_wifiSsid, _wifiPassword) != WL_AP_LISTENING) { 245 | #if defined(REMOTEXY__DEBUGLOG) 246 | RemoteXYDebugLog.write("WiFi module does not support AP mode"); 247 | #endif 248 | return; 249 | } 250 | state = 1; 251 | 252 | #if defined(REMOTEXY__DEBUGLOG) 253 | RemoteXYDebugLog.write("WiFi point created"); 254 | #endif 255 | 256 | #else // other boards not support AP mode 257 | state = 0; 258 | #if defined(REMOTEXY__DEBUGLOG) 259 | RemoteXYDebugLog.write("WiFi module does not support AP mode"); 260 | #endif 261 | 262 | #endif // ESP 263 | 264 | } 265 | 266 | public: 267 | uint8_t configured () override { 268 | return state; 269 | } 270 | 271 | 272 | public: 273 | CRemoteXYServer * createServer (uint16_t _port) override { 274 | return new CRemoteXYServer_WiFi (_port); 275 | } 276 | 277 | 278 | CRemoteXYClient * newClient () override { 279 | return new CRemoteXYClient_WiFi (); 280 | } 281 | 282 | }; 283 | 284 | 285 | #endif // WiFi_h 286 | 287 | #endif //RemoteXYComm_WiFi_h -------------------------------------------------------------------------------- /src/RemoteXYConnection.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYConnection_h 2 | #define RemoteXYConnection_h 3 | 4 | #include "RemoteXYComm.h" 5 | #include "RemoteXYWire.h" 6 | #include "RemoteXYCloudServer.h" 7 | 8 | #define UNUSED(x) (void)(x) 9 | 10 | class CRemoteXYConnection { 11 | 12 | public: 13 | virtual void init (CRemoteXYData * _data); 14 | 15 | public: 16 | virtual void handler () {}; 17 | virtual void handleWire (CRemoteXYWire * wire) {UNUSED (wire);}; 18 | virtual void stopThreadListener (CRemoteXYWire * wire) {UNUSED (wire);}; 19 | 20 | }; 21 | 22 | 23 | class CRemoteXYConnectionComm : public CRemoteXYConnection { 24 | public: 25 | CRemoteXYConnectionComm * next; 26 | CRemoteXYComm * comm; 27 | 28 | public: 29 | CRemoteXYConnectionComm (CRemoteXYComm * _comm) { 30 | comm = _comm; 31 | } 32 | 33 | }; 34 | 35 | #endif //RemoteXYConnection_h -------------------------------------------------------------------------------- /src/RemoteXYConnectionCloud.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYConnectionCloud_h 2 | #define RemoteXYConnectionCloud_h 3 | 4 | #include "RemoteXYDebugLog.h" 5 | #include "RemoteXYConnection.h" 6 | #include "RemoteXYThread.h" 7 | 8 | #define REMOTEXY_CLOUDCLIENT_RETRY_TIMEOUT 20000 9 | 10 | class CRemoteXYConnectionCloud: public CRemoteXYConnectionComm, CRemoteXYCloudClientAvailableListener { 11 | public: 12 | uint16_t port; 13 | CRemoteXYCloudServer * cloudServer; 14 | const char * cloudHost; 15 | const char * cloudToken; 16 | CRemoteXYData * data; 17 | CRemoteXYClient * client; 18 | uint32_t timeOut; 19 | 20 | public: 21 | CRemoteXYConnectionCloud (CRemoteXYComm * _comm, const char * _cloudHost, uint16_t _port, const char * _cloudToken) : CRemoteXYConnectionComm (_comm) { 22 | port = _port; 23 | cloudHost = _cloudHost; 24 | cloudToken = _cloudToken; 25 | } 26 | 27 | public: 28 | void init (CRemoteXYData * _data) override { 29 | data = _data; 30 | cloudServer = new CRemoteXYCloudServer (data, cloudToken, this); 31 | client = comm->newClient (); 32 | timeOut = -REMOTEXY_CLOUDCLIENT_RETRY_TIMEOUT; 33 | } 34 | 35 | void handler () override { 36 | 37 | if (comm->configured ()) { 38 | if (cloudServer->running ()) { 39 | cloudServer->handler(); 40 | timeOut = millis(); 41 | } 42 | else { // not serverRunning 43 | if (millis() - timeOut > REMOTEXY_CLOUDCLIENT_RETRY_TIMEOUT) { 44 | #if defined(REMOTEXY__DEBUGLOG) 45 | RemoteXYDebugLog.write ("Connecting to cloud: "); 46 | RemoteXYDebugLog.writeAdd (cloudHost); 47 | RemoteXYDebugLog.writeAdd (" "); 48 | RemoteXYDebugLog.writeAdd (port); 49 | RemoteXYDebugLog.writeAdd (" .."); 50 | #endif 51 | if (client->connect (cloudHost, port)) { 52 | #if defined(REMOTEXY__DEBUGLOG) 53 | RemoteXYDebugLog.write ("Cloud server connected"); 54 | #endif 55 | cloudServer->begin (client); 56 | } 57 | #if defined(REMOTEXY__DEBUGLOG) 58 | else { 59 | RemoteXYDebugLog.write ("Cloud server not available"); 60 | } 61 | #endif 62 | timeOut = millis(); 63 | } 64 | } 65 | } 66 | else cloudServer->stop (); 67 | if (!cloudServer->running ()) { 68 | if (client->connected ()) { 69 | client->stop (); 70 | } 71 | } 72 | } 73 | 74 | void clientAvailable (CRemoteXYWireCloud * cloudWire) override { 75 | if (CRemoteXYThread::runningCount (data) < REMOTEXY_MAX_CLIENTS) { 76 | CRemoteXYThread::startThread (data, this, cloudWire, 1); 77 | } 78 | else { 79 | cloudWire->stop (); 80 | #if defined(REMOTEXY__DEBUGLOG) 81 | RemoteXYDebugLog.write ("Client reject"); 82 | #endif 83 | } 84 | 85 | } 86 | 87 | 88 | void handleWire (CRemoteXYWire * wire) override { 89 | if (cloudServer->running () && comm->configured ()) wire->handler (); 90 | else stopThreadListener (wire); 91 | } 92 | 93 | void stopThreadListener (CRemoteXYWire * wire) override { 94 | wire->stop (); 95 | } 96 | 97 | 98 | 99 | }; 100 | 101 | 102 | #endif // RemoteXYConnectionCloud_h -------------------------------------------------------------------------------- /src/RemoteXYConnectionServer.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYConnectionServer_h 2 | #define RemoteXYConnectionServer_h 3 | 4 | #include "RemoteXYDebugLog.h" 5 | #include "RemoteXYConnection.h" 6 | #include "RemoteXYWireStream.h" 7 | #include "RemoteXYThread.h" 8 | 9 | 10 | 11 | class CRemoteXYConnectionServer: public CRemoteXYConnectionComm, public CRemoteXYClientAvailableListener { 12 | public: 13 | uint16_t port; 14 | CRemoteXYData * data; 15 | CRemoteXYServer * server; 16 | CRemoteXYClient * clients; 17 | CRemoteXYWireStream * wires; 18 | uint8_t serverRunning; 19 | 20 | 21 | CRemoteXYConnectionServer (CRemoteXYComm * _comm, uint16_t _port = 0) : CRemoteXYConnectionComm (_comm) { 22 | port = _port; 23 | clients = NULL; 24 | server = comm->createServer (port); 25 | server->setClientAvailabListener (this); 26 | #if defined(REMOTEXY__DEBUGLOG) 27 | if (!server) { 28 | RemoteXYDebugLog.write ("Server was not created"); 29 | } 30 | #endif 31 | serverRunning = 0; 32 | wires = NULL; 33 | } 34 | 35 | void init (CRemoteXYData * _data) { 36 | data = _data; 37 | } 38 | 39 | public: 40 | void handler () override { 41 | if (!server) return; 42 | if (comm->configured ()) { 43 | if (serverRunning) clientAvailable (); 44 | else { 45 | if (server->begin ()) { 46 | serverRunning=1; 47 | #if defined(REMOTEXY__DEBUGLOG) 48 | RemoteXYDebugLog.write ("Server opened on port "); 49 | RemoteXYDebugLog.writeAdd (port); 50 | #endif 51 | } 52 | #if defined(REMOTEXY__DEBUGLOG) 53 | else { 54 | RemoteXYDebugLog.write ("Server was not started"); 55 | } 56 | #endif 57 | } 58 | } 59 | else { 60 | if (serverRunning) { 61 | server->stop (); 62 | serverRunning =0; 63 | } 64 | } 65 | } 66 | 67 | void clientAvailable () override { 68 | CRemoteXYClient * client = clients; 69 | while (client) { 70 | if (!client->connected ()) break; 71 | client = client->next; 72 | } 73 | if (!client) { 74 | client = comm->newClient (); 75 | client->next = clients; 76 | clients = client; 77 | } 78 | if (server->available (client)) { 79 | 80 | if (CRemoteXYThread::runningCount (data) < REMOTEXY_MAX_CLIENTS) { 81 | CRemoteXYWireStream * wire = wires; 82 | while (wire) { 83 | if (!wire->running()) break; 84 | wire = wire->next; 85 | } 86 | if (!wire) { 87 | wire = new CRemoteXYWireStream (data); 88 | wire->next = wires; 89 | wires = wire; 90 | } 91 | wire->begin (client); 92 | CRemoteXYThread::startThread (data, this, wire, 1); 93 | } 94 | else { 95 | client->stop (); 96 | #if defined(REMOTEXY__DEBUGLOG) 97 | RemoteXYDebugLog.write ("Client reject"); 98 | #endif 99 | } 100 | } 101 | 102 | } 103 | 104 | void handleWire (CRemoteXYWire * wire) override { 105 | CRemoteXYClient * client = ((CRemoteXYWireStream*)wire)->getClient (); 106 | if (client) { 107 | if (client->connected () && serverRunning && comm->configured ()) wire->handler (); 108 | else stopThreadListener (wire); 109 | } 110 | } 111 | 112 | void stopThreadListener (CRemoteXYWire * wire) override { 113 | CRemoteXYClient * client = ((CRemoteXYWireStream*)wire)->getClient (); 114 | if (client) { 115 | client->stop (); 116 | wire->stop (); 117 | } 118 | } 119 | 120 | 121 | 122 | }; 123 | 124 | 125 | #endif // RemoteXYConnectionServer_h -------------------------------------------------------------------------------- /src/RemoteXYConnectionStream.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYConnectionStream_h 2 | #define RemoteXYConnectionStream_h 3 | 4 | #include "RemoteXYDebugLog.h" 5 | #include "RemoteXYConnection.h" 6 | #include "RemoteXYThread.h" 7 | 8 | class CRemoteXYConnectionStream: public CRemoteXYConnection { 9 | CRemoteXYStream * stream; 10 | 11 | public: 12 | CRemoteXYConnectionStream (CRemoteXYStream * _stream) { 13 | stream = _stream; 14 | } 15 | 16 | void init (CRemoteXYData * _data) override { 17 | CRemoteXYWireStream * wire = new CRemoteXYWireStream (_data); 18 | wire->begin (stream); 19 | CRemoteXYThread::startThread (_data, this, wire, 0); 20 | }; 21 | 22 | void handleWire (CRemoteXYWire * wire) override { 23 | wire->handler (); 24 | }; 25 | 26 | }; 27 | 28 | #endif // CRemoteXYConnectionStream -------------------------------------------------------------------------------- /src/RemoteXYDebugLog.h: -------------------------------------------------------------------------------- 1 | #ifndef _REMOTEXY_DEBUGLOG_H_ 2 | #define _REMOTEXY_DEBUGLOG_H_ 3 | 4 | #if defined(REMOTEXY__DEBUGLOG) 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #ifndef REMOTEXY__DEBUGLOG_SERIAL 11 | #define REMOTEXY__DEBUGLOG_SERIAL Serial 12 | #endif 13 | #ifndef REMOTEXY__DEBUGLOG_SPEED 14 | #define REMOTEXY__DEBUGLOG_SPEED 115200 15 | #endif 16 | 17 | 18 | class CRemoteXYDebugLog { 19 | public: 20 | HardwareSerial * serial; 21 | long speed; 22 | uint8_t inited; 23 | 24 | private: 25 | uint8_t debug_flags; 26 | uint8_t debug_hexcounter; 27 | 28 | public: 29 | CRemoteXYDebugLog (HardwareSerial * _serial, long _speed) { 30 | debug_flags=0; 31 | serial = _serial; 32 | speed = _speed; 33 | inited = 0; 34 | } 35 | 36 | public: 37 | void init () { 38 | if (!inited) { 39 | serial->begin (speed); 40 | serial->println (); 41 | write ("Debug log started"); 42 | inited = 1; 43 | } 44 | } 45 | 46 | 47 | public: 48 | void writeTime () { 49 | uint32_t d = millis(); 50 | long ds = d/1000; 51 | long dm = d%1000; 52 | char s[15]; 53 | sprintf (s, "[%5ld.%03ld] ",ds, dm); 54 | serial->println (); 55 | serial->print (s); 56 | } 57 | 58 | 59 | public: 60 | void write (const char *s) { 61 | debug_flags = 0; 62 | writeTime (); 63 | serial->print(s); 64 | } 65 | 66 | public: 67 | void writeAdd (const char *s) { 68 | serial->print(s); 69 | } 70 | 71 | 72 | public: 73 | void writeAdd (uint16_t i) { 74 | serial->print(i); 75 | } 76 | 77 | public: 78 | void writeAdd (uint32_t i) { 79 | serial->print(i); 80 | } 81 | 82 | public: 83 | void writeAdd (int i) { 84 | serial->print(i); 85 | } 86 | 87 | public: 88 | void writeAdd (long i) { 89 | serial->print(i); 90 | } 91 | 92 | public: 93 | void writeInput (const char *s) { 94 | if ((debug_flags & 0x01)==0) { 95 | writeTime (); 96 | serial->print("<- "); 97 | } 98 | debug_flags = 0x01; 99 | serial->print(s); 100 | } 101 | 102 | public: 103 | void writeOutput (const char *s) { 104 | if ((debug_flags & 0x02)==0) { 105 | writeTime (); 106 | serial->print("-> "); 107 | } 108 | debug_flags = 0x02; 109 | serial->print(s); 110 | } 111 | 112 | public: 113 | void writeInputHex (uint8_t b) { 114 | if ((debug_flags & 0x01)==0) { 115 | writeTime (); 116 | serial->print("<-"); 117 | debug_hexcounter=0; 118 | } 119 | debug_flags = 0x01; 120 | writeHex (b); 121 | } 122 | 123 | public: 124 | void writeOutputHex (uint8_t b) { 125 | if ((debug_flags & 0x02)==0) { 126 | writeTime (); 127 | serial->print("->"); 128 | debug_hexcounter=0; 129 | } 130 | debug_flags = 0x02; 131 | writeHex (b); 132 | } 133 | 134 | public: 135 | void writeInputChar (char s) { 136 | if ((debug_flags & 0x01)==0) { 137 | writeTime (); 138 | serial->print("<- "); 139 | } 140 | debug_flags = 0x01; 141 | serial->print(s); 142 | } 143 | 144 | public: 145 | void writeInputNewString () { 146 | debug_flags = 0; 147 | } 148 | 149 | public: 150 | void writeHex (uint8_t b) { 151 | debug_hexcounter++; 152 | if (debug_hexcounter>16) { 153 | serial->println(); 154 | serial->print(" "); 155 | debug_hexcounter=1; 156 | } 157 | serial->print(' '); 158 | serial->print(b>>4, HEX); 159 | serial->print(b&0x0f, HEX); 160 | } 161 | 162 | public: 163 | void writeAvailableMemory () { 164 | write ( "Available memory: " ); 165 | writeAdd (availableMemory()); 166 | } 167 | 168 | 169 | 170 | private: 171 | uint32_t availableMemory() { 172 | #if defined (ESP8266) || defined (ESP32) 173 | return ESP.getFreeHeap (); 174 | #elif defined (__AVR__) 175 | uint16_t size = RAMEND; 176 | uint8_t *buf; 177 | while ((buf = (uint8_t *)malloc(size)) == NULL) size--; 178 | free(buf); 179 | return size; 180 | #else 181 | return 0; 182 | #endif 183 | } 184 | 185 | 186 | }; 187 | 188 | 189 | CRemoteXYDebugLog RemoteXYDebugLog (& REMOTEXY__DEBUGLOG_SERIAL, REMOTEXY__DEBUGLOG_SPEED); 190 | 191 | 192 | #endif //REMOTEXY__DEBUGLOG 193 | 194 | #endif //_REMOTEXY_DEBUGLOG_H_ -------------------------------------------------------------------------------- /src/RemoteXYFunc.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYFunc_h 2 | #define RemoteXYFunc_h 3 | 4 | #include 5 | 6 | 7 | char* rxy_itos (uint16_t i, char* s) { 8 | uint8_t len=0; 9 | char *p=s+5; 10 | while (i) { 11 | *p--=i%10+'0'; 12 | i/=10; 13 | len++; 14 | } 15 | for (i=0; i0; i--) { 31 | b=rxy_xctoi (*s++)<<4; 32 | b|=rxy_xctoi (*s++); 33 | *m++=b; 34 | s++; 35 | } 36 | } 37 | 38 | 39 | 40 | #endif //RemoteXYFunc_h -------------------------------------------------------------------------------- /src/RemoteXYStream.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYStream_h 2 | #define RemoteXYStream_h 3 | 4 | #include 5 | #include "RemoteXYDebugLog.h" 6 | 7 | #define UNUSED(x) (void)(x) 8 | 9 | class CRemoteXYReadByteListener { 10 | public: 11 | virtual void readByte (uint8_t byte) = 0; 12 | }; 13 | 14 | 15 | class CRemoteXYStream { 16 | private: 17 | CRemoteXYReadByteListener * readByteListener; 18 | 19 | 20 | public: 21 | CRemoteXYStream () { 22 | readByteListener = NULL; 23 | #if defined(REMOTEXY__DEBUGLOG) 24 | RemoteXYDebugLog.init (); 25 | #endif 26 | } 27 | 28 | public: 29 | void setReadByteListener (CRemoteXYReadByteListener * listener) { 30 | readByteListener = listener; 31 | } 32 | 33 | public: 34 | void notifyReadByteListener (uint8_t byte) { 35 | if (readByteListener) readByteListener->readByte (byte); 36 | } 37 | 38 | public: 39 | virtual void handler () {}; 40 | virtual void startWrite (uint16_t size) {UNUSED (size);}; 41 | virtual void write (uint8_t byte) {UNUSED (byte);}; 42 | }; 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | #endif //RemoteXYStream_h -------------------------------------------------------------------------------- /src/RemoteXYStream_BLEDevice.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYStream_BLEDevice_h 2 | #define RemoteXYStream_BLEDevice_h 3 | 4 | #if defined(MAIN_BLEDevice_H_) 5 | 6 | #include "RemoteXYComm.h" 7 | #include 8 | 9 | 10 | #define REMOTEXYCOMM_BLEDEVICE__SEND_BUFFER_SIZE 20 11 | #define REMOTEXYCOMM_BLEDEVICE__RECEIVE_BUFFER_SIZE 1024 12 | #define REMOTEXYCOMM_BLEDEVICE__SERVICE_UUID "0000FFE0-0000-1000-8000-00805F9B34FB" // UART service UUID 13 | #define REMOTEXYCOMM_BLEDEVICE__CHARACTERISTIC_UUID_RXTX "0000FFE1-0000-1000-8000-00805F9B34FB" 14 | 15 | 16 | class CRemoteXYStream_BLEDevice : public CRemoteXYStream, BLEServerCallbacks, BLECharacteristicCallbacks { 17 | 18 | protected: 19 | const char * bleDeviceName; // need to delete 20 | 21 | BLEServer *pServer; 22 | BLECharacteristic * pRxTxCharacteristic; 23 | 24 | uint8_t sendBuffer[REMOTEXYCOMM_BLEDEVICE__SEND_BUFFER_SIZE]; 25 | uint16_t sendBufferCount; 26 | uint16_t sendBytesAvailable; 27 | 28 | uint8_t receiveBuffer[REMOTEXYCOMM_BLEDEVICE__RECEIVE_BUFFER_SIZE]; 29 | uint16_t receiveBufferStart; 30 | uint16_t receiveBufferPos; 31 | uint16_t receiveBufferCount; 32 | 33 | volatile uint8_t receiveBufferLook; 34 | 35 | public: 36 | CRemoteXYStream_BLEDevice (const char * _bleDeviceName) : CRemoteXYStream () { 37 | bleDeviceName = _bleDeviceName; 38 | 39 | receiveBufferLook = 0; 40 | receiveBufferCount = 0; 41 | receiveBufferStart = 0; 42 | receiveBufferPos = 0; 43 | receiveBufferCount = 0; 44 | 45 | #if defined(REMOTEXY__DEBUGLOG) 46 | RemoteXYDebugLog.write("Init ESP32 BLE on chip"); 47 | #endif 48 | // Create the BLE Device 49 | BLEDevice::init(_bleDeviceName); 50 | 51 | // Create the BLE Server 52 | pServer = BLEDevice::createServer(); 53 | pServer->setCallbacks(this); 54 | 55 | // Create the BLE Service 56 | BLEService *pService = pServer->createService(REMOTEXYCOMM_BLEDEVICE__SERVICE_UUID); 57 | 58 | // Create a BLE Characteristic 59 | pRxTxCharacteristic = pService->createCharacteristic( 60 | REMOTEXYCOMM_BLEDEVICE__CHARACTERISTIC_UUID_RXTX, 61 | BLECharacteristic::PROPERTY_READ | 62 | BLECharacteristic::PROPERTY_NOTIFY | 63 | BLECharacteristic::PROPERTY_WRITE_NR 64 | ); 65 | 66 | BLE2902 *ble2902 = new BLE2902(); 67 | ble2902->setNotifications(true); 68 | pRxTxCharacteristic->addDescriptor(ble2902); 69 | pRxTxCharacteristic->setCallbacks(this); 70 | 71 | // Start the service 72 | pService->start(); 73 | 74 | // Start advertising 75 | pServer->getAdvertising()->addServiceUUID(pService->getUUID()); 76 | pServer->getAdvertising()->start(); 77 | 78 | #if defined(REMOTEXY__DEBUGLOG) 79 | RemoteXYDebugLog.write("BLE started"); 80 | #endif 81 | 82 | } 83 | 84 | void onConnect(BLEServer* pServer) { 85 | #if defined(REMOTEXY__DEBUGLOG) 86 | RemoteXYDebugLog.write("BLE client connected"); 87 | #endif 88 | receiveBufferStart = 0; 89 | receiveBufferPos = 0; 90 | receiveBufferCount = 0; 91 | }; 92 | 93 | void onDisconnect(BLEServer* pServer) { 94 | #if defined(REMOTEXY__DEBUGLOG) 95 | RemoteXYDebugLog.write("BLE client disconnected"); 96 | #endif 97 | receiveBufferCount = 0; 98 | pServer->getAdvertising ()->start (); 99 | } 100 | 101 | void onWrite (BLECharacteristic *pCharacteristic) { 102 | std::string rxValue = pCharacteristic->getValue(); 103 | 104 | if (rxValue.length() > 0) { 105 | while (receiveBufferLook!=0) { delay(1); } 106 | receiveBufferLook=1; 107 | for (uint16_t i = 0; i < rxValue.length(); i++) { 108 | uint8_t b = (uint8_t)rxValue[i]; 109 | receiveBuffer[receiveBufferPos++] = b; 110 | if (receiveBufferPos >= REMOTEXYCOMM_BLEDEVICE__RECEIVE_BUFFER_SIZE) receiveBufferPos=0; 111 | if (receiveBufferCount < REMOTEXYCOMM_BLEDEVICE__RECEIVE_BUFFER_SIZE) receiveBufferCount++; 112 | else { 113 | receiveBufferStart++; 114 | if (receiveBufferStart >= REMOTEXYCOMM_BLEDEVICE__RECEIVE_BUFFER_SIZE) receiveBufferStart=0; 115 | } 116 | } 117 | receiveBufferLook=0; 118 | } 119 | } 120 | 121 | 122 | void startWrite (uint16_t len) override { 123 | sendBytesAvailable = len; 124 | sendBufferCount = 0; 125 | } 126 | 127 | 128 | void write (uint8_t b) override { 129 | sendBuffer[sendBufferCount++] = b; 130 | sendBytesAvailable--; 131 | if ((sendBufferCount == REMOTEXYCOMM_BLEDEVICE__SEND_BUFFER_SIZE) || (sendBytesAvailable == 0)) { 132 | pRxTxCharacteristic->setValue((uint8_t *)sendBuffer, sendBufferCount); 133 | pRxTxCharacteristic->notify(); 134 | sendBufferCount = 0; 135 | } 136 | } 137 | 138 | void handler () override { 139 | if (receiveBufferCount>0) { 140 | while (receiveBufferLook!=0) { delay(1); } 141 | receiveBufferLook=1; 142 | while (receiveBufferCount) { 143 | notifyReadByteListener (receiveBuffer[receiveBufferStart++]); 144 | if (receiveBufferStart >= REMOTEXYCOMM_BLEDEVICE__RECEIVE_BUFFER_SIZE) receiveBufferStart=0; 145 | receiveBufferCount--; 146 | } 147 | receiveBufferLook=0; 148 | } 149 | } 150 | 151 | 152 | 153 | }; 154 | 155 | #endif // MAIN_BLEDevice_H_ 156 | #endif // RemoteXYStream_BLEDevice_h -------------------------------------------------------------------------------- /src/RemoteXYStream_BLEPeripheral.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYStream_BLEPeripheral_h 2 | #define RemoteXYStream_BLEPeripheral_h 3 | 4 | #if defined(_BLE_PERIPHERAL_H_) 5 | 6 | #include "RemoteXYStream.h" 7 | 8 | #define REMOTEXYCOMM_BLEPERIPHERAL__SEND_BUFFER_SIZE BLE_ATTRIBUTE_MAX_VALUE_LENGTH 9 | #define REMOTEXYCOMM_BLEPERIPHERAL__RECEIVE_BUFFER_SIZE 1024 10 | #define REMOTEXYCOMM_BLEPERIPHERAL__SERVICE_UUID "0000FFE0-0000-1000-8000-00805F9B34FB" // UART service UUID 11 | #define REMOTEXYCOMM_BLEPERIPHERAL__CHARACTERISTIC_UUID "0000FFE1-0000-1000-8000-00805F9B34FB" 12 | //#define REMOTEXYCOMM_BLEPERIPHERAL__DESCRIPTOR_UUID "2902" 13 | 14 | #define REMOTEXYCOMM_BLEPERIPHERAL__CANNOTIFY_TIMEOUT 1000 15 | 16 | class CRemoteXYStream_BLEPeripheral : public CRemoteXYStream, public BLEPeripheral { 17 | 18 | private: 19 | BLEService *pService; 20 | BLECharacteristic *pCharacteristic; 21 | BLEDescriptor *pDescriptor; 22 | 23 | uint8_t sendBuffer[REMOTEXYCOMM_BLEPERIPHERAL__SEND_BUFFER_SIZE]; 24 | uint16_t sendBufferCount; 25 | uint16_t sendBytesAvailable; 26 | 27 | uint8_t receiveBuffer[REMOTEXYCOMM_BLEPERIPHERAL__RECEIVE_BUFFER_SIZE]; 28 | uint16_t receiveBufferStart; 29 | uint16_t receiveBufferPos; 30 | uint16_t receiveBufferCount; 31 | 32 | 33 | public: 34 | CRemoteXYStream_BLEPeripheral (const char * _bleDeviceName) : CRemoteXYStream (), BLEPeripheral () { 35 | #if defined(REMOTEXY__DEBUGLOG) 36 | RemoteXYDebugLog.write("Init NRF BLE on chip"); 37 | #endif 38 | 39 | receiveBufferCount = 0; 40 | receiveBufferStart = 0; 41 | receiveBufferPos = 0; 42 | receiveBufferCount = 0; 43 | 44 | pService = new BLEService (REMOTEXYCOMM_BLEPERIPHERAL__SERVICE_UUID); 45 | pCharacteristic = new BLECharacteristic( REMOTEXYCOMM_BLEPERIPHERAL__CHARACTERISTIC_UUID, BLERead | BLEWriteWithoutResponse | BLENotify, BLE_ATTRIBUTE_MAX_VALUE_LENGTH); 46 | //pDescriptor = new BLEDescriptor(REMOTEXYCOMM_BLEPERIPHERAL__DESCRIPTOR_UUID); 47 | 48 | setLocalName(_bleDeviceName); 49 | setDeviceName(_bleDeviceName); 50 | setAdvertisedServiceUuid (pService->uuid()); 51 | setAppearance(0x0080); 52 | 53 | addAttribute (*pService); 54 | addAttribute (*pCharacteristic); 55 | //addAttribute (*pDescriptor); 56 | 57 | pCharacteristic->setValue(0); 58 | begin(); 59 | 60 | #if defined(REMOTEXY__DEBUGLOG) 61 | RemoteXYDebugLog.write("BLE started"); 62 | #endif 63 | 64 | } 65 | 66 | 67 | void BLEDeviceConnected(BLEDevice& device, const unsigned char* address) override { 68 | #if defined(REMOTEXY__DEBUGLOG) 69 | RemoteXYDebugLog.write("BLE client connected"); 70 | #endif 71 | receiveBufferStart = 0; 72 | receiveBufferPos = 0; 73 | receiveBufferCount = 0; 74 | } 75 | 76 | void BLEDeviceDisconnected(BLEDevice& device) { 77 | #if defined(REMOTEXY__DEBUGLOG) 78 | RemoteXYDebugLog.write("BLE client disconnected"); 79 | #endif 80 | receiveBufferCount = 0; 81 | } 82 | 83 | void BLEDeviceCharacteristicValueChanged (BLEDevice& device, BLECharacteristic& characteristic, const unsigned char* data, unsigned char size) override { 84 | 85 | for (uint16_t i = 0; i < size; i++) { 86 | receiveBuffer[receiveBufferPos++] = data[i]; 87 | if (receiveBufferPos >= REMOTEXYCOMM_BLEPERIPHERAL__RECEIVE_BUFFER_SIZE) receiveBufferPos=0; 88 | if (receiveBufferCount < REMOTEXYCOMM_BLEPERIPHERAL__RECEIVE_BUFFER_SIZE) receiveBufferCount++; 89 | else { 90 | receiveBufferStart++; 91 | if (receiveBufferStart >= REMOTEXYCOMM_BLEPERIPHERAL__RECEIVE_BUFFER_SIZE) receiveBufferStart=0; 92 | } 93 | } 94 | 95 | } 96 | 97 | 98 | void startWrite (uint16_t len) override { 99 | sendBytesAvailable = len; 100 | sendBufferCount = 0; 101 | } 102 | 103 | void write (uint8_t b) override { 104 | if (pCharacteristic->subscribed() == false) { 105 | #if defined(REMOTEXY__DEBUGLOG) 106 | RemoteXYDebugLog.write("BLE: tx characteristic not subscribed"); 107 | #endif 108 | return; 109 | } 110 | sendBuffer[sendBufferCount++] = b; 111 | sendBytesAvailable--; 112 | if ((sendBufferCount == REMOTEXYCOMM_BLEPERIPHERAL__SEND_BUFFER_SIZE) || (sendBytesAvailable == 0)) { 113 | uint32_t t = millis (); 114 | while (pCharacteristic->canNotify () == 0) { 115 | if (millis () - t > REMOTEXYCOMM_BLEPERIPHERAL__CANNOTIFY_TIMEOUT) break; 116 | poll(); 117 | } 118 | pCharacteristic->setValue(sendBuffer, sendBufferCount); 119 | poll(); 120 | sendBufferCount = 0; 121 | 122 | } 123 | } 124 | 125 | void handler () override { 126 | uint8_t b; 127 | BLEPeripheral::poll(); 128 | while (receiveBufferCount > 0) { 129 | b = receiveBuffer[receiveBufferStart++]; 130 | if (receiveBufferStart >= REMOTEXYCOMM_BLEPERIPHERAL__RECEIVE_BUFFER_SIZE) receiveBufferStart=0; 131 | receiveBufferCount--; 132 | notifyReadByteListener (b); 133 | } 134 | } 135 | }; 136 | 137 | 138 | 139 | 140 | 141 | #endif // _BLE_PERIPHERAL_H_ 142 | 143 | #endif //RemoteXYStream_BLEPeripheral_h -------------------------------------------------------------------------------- /src/RemoteXYStream_BluetoothSerial.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYStream_BluetoothSerial_h 2 | #define RemoteXYStream_BluetoothSerial_h 3 | 4 | #if defined (BluetoothSerial_h) || defined (_BLUETOOTH_SERIAL_H_) 5 | 6 | #include "RemoteXYComm.h" 7 | 8 | 9 | class CRemoteXYStream_BluetoothSerial : public CRemoteXYStream { 10 | 11 | private: 12 | BluetoothSerial * serial; 13 | 14 | public: 15 | CRemoteXYStream_BluetoothSerial (const char * _bleDeviceName) : CRemoteXYStream () { 16 | serial = new BluetoothSerial (); 17 | serial->begin (_bleDeviceName); 18 | 19 | #if defined(REMOTEXY__DEBUGLOG) 20 | RemoteXYDebugLog.write("Init bluetooth serial"); 21 | #endif 22 | } 23 | 24 | 25 | void handler () override { 26 | while (serial->available ()) notifyReadByteListener (serial->read ()); 27 | } 28 | 29 | 30 | void write (uint8_t byte) override { 31 | serial->write (byte); 32 | } 33 | 34 | 35 | }; 36 | 37 | #endif // BluetoothSerial_h _BLUETOOTH_SERIAL_H_ 38 | #endif //RemoteXYStream_BluetoothSerial_h -------------------------------------------------------------------------------- /src/RemoteXYStream_CDCSerial.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYStream_CDCSerial_h 2 | #define RemoteXYStream_CDCSerial_h 3 | 4 | #if defined(USBCON) 5 | 6 | #include "RemoteXYStream.h" 7 | 8 | 9 | class CRemoteXYStream_CDCSerial : public CRemoteXYStream { 10 | 11 | private: 12 | Serial_ * serial; 13 | 14 | public: 15 | CRemoteXYStream_CDCSerial (Serial_ * _serial, long _serialSpeed) : CRemoteXYStream () { 16 | serial = _serial; 17 | serial->begin (_serialSpeed); 18 | #if defined(REMOTEXY__DEBUGLOG) 19 | RemoteXYDebugLog.write("Init CDC serial "); 20 | RemoteXYDebugLog.writeAdd(_serialSpeed); 21 | RemoteXYDebugLog.writeAdd(" baud"); 22 | #endif 23 | } 24 | 25 | void handler () override { 26 | while (serial->available ()) notifyReadByteListener (serial->read ()); 27 | } 28 | 29 | void write (uint8_t byte) override { 30 | serial->write (byte); 31 | } 32 | 33 | }; 34 | 35 | 36 | #endif //USBCON 37 | 38 | #endif //RemoteXYStream_CDCSerial_h -------------------------------------------------------------------------------- /src/RemoteXYStream_HardSerial.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYStream_HardSerial_h 2 | #define RemoteXYStream_HardSerial_h 3 | 4 | #include "RemoteXYStream.h" 5 | 6 | 7 | class CRemoteXYStream_HardSerial : public CRemoteXYStream { 8 | 9 | private: 10 | HardwareSerial * serial; 11 | 12 | public: 13 | CRemoteXYStream_HardSerial (HardwareSerial * _serial, long _serialSpeed) : CRemoteXYStream () { 14 | serial = _serial; 15 | serial->begin (_serialSpeed); 16 | #if defined(REMOTEXY__DEBUGLOG) 17 | RemoteXYDebugLog.write("Init hardware serial "); 18 | RemoteXYDebugLog.writeAdd(_serialSpeed); 19 | RemoteXYDebugLog.writeAdd(" baud"); 20 | #endif 21 | } 22 | 23 | void handler () override { 24 | while (serial->available ()) notifyReadByteListener (serial->read ()); 25 | } 26 | 27 | void write (uint8_t byte) override { 28 | serial->write (byte); 29 | } 30 | 31 | }; 32 | 33 | 34 | 35 | 36 | #endif //RemoteXYStream_HardSerial_h -------------------------------------------------------------------------------- /src/RemoteXYStream_SoftSerial.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYStream_SoftSerial_h 2 | #define RemoteXYStream_SoftSerial_h 3 | 4 | 5 | // if not defined SoftwareSerial.h 6 | #if defined(REMOTEXY_MODE__SOFTSERIAL) || defined(REMOTEXY_MODE__ESP8266_SOFTSERIAL_POINT) || defined(REMOTEXY_MODE__SOFTSERIAL_ESP8266) || defined(REMOTEXY_MODE__SOFTSERIAL_ESP8266_CLOUD) 7 | #if !defined (SoftwareSerial_h) && !defined(SoftSerial_h) 8 | #include "SoftwareSerial.h" 9 | #endif 10 | #endif 11 | 12 | #if defined(SoftwareSerial_h) || defined(SoftSerial_h) 13 | 14 | #include "RemoteXYComm.h" 15 | 16 | 17 | class CRemoteXYStream_SoftSerial : public CRemoteXYStream { 18 | 19 | #if defined(SoftwareSerial_h) 20 | 21 | private: 22 | SoftwareSerial * serial; 23 | 24 | public: 25 | CRemoteXYStream_SoftSerial (uint8_t _serialRx, uint8_t _serialTx, long _serialSpeed) : CRemoteXYStream () { 26 | serial = new SoftwareSerial (_serialRx, _serialTx); 27 | serial->begin (_serialSpeed); 28 | #if defined(REMOTEXY__DEBUGLOG) 29 | RemoteXYDebugLog.write("Init software serial "); 30 | RemoteXYDebugLog.writeAdd(_serialSpeed); 31 | RemoteXYDebugLog.writeAdd(" baud"); 32 | RemoteXYDebugLog.write("pin RX="); 33 | RemoteXYDebugLog.writeAdd(_serialRx); 34 | RemoteXYDebugLog.writeAdd("; pin TX="); 35 | RemoteXYDebugLog.writeAdd(_serialTx); 36 | #endif 37 | } 38 | 39 | #elif defined(SoftSerial_h) 40 | 41 | private: 42 | SoftSerial * serial; 43 | 44 | public: 45 | CRemoteXYStream_SoftSerial (uint8_t _serialRx, uint8_t _serialTx, long _serialSpeed) : CRemoteXYStream () { 46 | serial = new SoftSerial (_serialRx, _serialTx); 47 | serial->begin (_serialSpeed); 48 | #if defined(REMOTEXY__DEBUGLOG) 49 | RemoteXYDebugLog.write("Init soft serial "); 50 | RemoteXYDebugLog.writeAdd(_serialSpeed); 51 | RemoteXYDebugLog.writeAdd(" baud"); 52 | RemoteXYDebugLog.write("pin RX="); 53 | RemoteXYDebugLog.writeAdd(_serialRx); 54 | RemoteXYDebugLog.writeAdd("; pin TX="); 55 | RemoteXYDebugLog.writeAdd(_serialTx); 56 | #endif 57 | } 58 | 59 | 60 | #endif 61 | 62 | void handler () override { 63 | while (serial->available ()) notifyReadByteListener (serial->read ()); 64 | } 65 | 66 | void write (uint8_t byte) override { 67 | serial->write (byte); 68 | } 69 | 70 | 71 | }; 72 | 73 | 74 | #endif // SoftwareSerial_h SoftSerial_h 75 | 76 | #endif //RemoteXYStream_SoftSerial_h -------------------------------------------------------------------------------- /src/RemoteXYThread.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYThread_h 2 | #define RemoteXYThread_h 3 | 4 | 5 | #include "RemoteXYApiData.h" 6 | #include "RemoteXYComm.h" 7 | #include "RemoteXYConnection.h" 8 | #include "RemoteXYWire.h" 9 | 10 | 11 | #define REMOTEXY_INIT_CRC 0xffff 12 | #define REMOTEXY_PACKAGE_START_BYTE 0x55 13 | #define REMOTEXY_THREAD_TIMEOUT 8000 14 | 15 | 16 | class CRemoteXYThread : public CRemoteXYReceivePackageListener { 17 | 18 | public: 19 | CRemoteXYThread * next; 20 | 21 | private: 22 | CRemoteXYData* data; 23 | CRemoteXYConnection* conn; 24 | CRemoteXYWire * wire; 25 | 26 | uint8_t *inputVar; 27 | 28 | uint32_t timeOut; 29 | uint8_t stopByTimeOut; 30 | 31 | uint8_t inputVarNeedSend; 32 | 33 | 34 | public: 35 | uint8_t connect_flag; 36 | 37 | public: 38 | CRemoteXYThread (CRemoteXYData * _data) { 39 | 40 | data = _data; 41 | wire = NULL; 42 | 43 | inputVar = (uint8_t*)malloc (data->inputLength); 44 | copyInputVars (); 45 | } 46 | 47 | 48 | 49 | public: 50 | void begin (CRemoteXYConnection * _conn, CRemoteXYWire * _wire, uint8_t _stopByTimeOut) { 51 | conn = _conn; 52 | wire = _wire; 53 | wire->setReceivePackageListener (this); 54 | stopByTimeOut = _stopByTimeOut; 55 | timeOut = millis (); 56 | connect_flag = 0; 57 | 58 | #if defined(REMOTEXY__DEBUGLOG) 59 | RemoteXYDebugLog.write("Client started"); 60 | //RemoteXYDebugLog.writeAvailableMemory (); 61 | #endif 62 | } 63 | 64 | 65 | public: 66 | void stop () { 67 | if (wire) { 68 | conn->stopThreadListener (wire); 69 | wire = NULL; 70 | connect_flag = 0; 71 | #if defined(REMOTEXY__DEBUGLOG) 72 | RemoteXYDebugLog.write("Client stoped"); 73 | #endif 74 | } 75 | } 76 | 77 | public: 78 | uint8_t running () { 79 | if (wire) return 1; 80 | return 0; 81 | } 82 | 83 | 84 | public: 85 | void receivePackage (CRemoteXYPackage * package) override { 86 | uint16_t i, length; 87 | uint8_t *p, *kp, *ip; 88 | 89 | if (wire == NULL) return; 90 | if ((package->command != 0x00) && (!connect_flag)) return; 91 | switch (package->command) { 92 | case 0x00: 93 | uint8_t available; 94 | if (package->length==0) { 95 | if (*data->accessPassword==0) available=1; 96 | else available=0; 97 | } 98 | else { 99 | uint8_t ch; 100 | available = 1; 101 | p = package->buffer; 102 | kp = data->accessPassword; 103 | while (true) { 104 | ch=*kp++; 105 | if (ch!=*p++) available=0; 106 | if (!ch) break; 107 | } 108 | } 109 | if (available!=0) { 110 | wire->sendPackage (0x00, data->conf, data->confLength, 1); 111 | connect_flag = 1; 112 | } 113 | else { 114 | uint8_t buf[4]; 115 | p = buf; 116 | kp = data->conf; 117 | i=data->confVersion>=5?3:2; 118 | length = i+1; 119 | while (i--) *p++ = data->getConfByte(kp++); 120 | *p++ = 0xf0; 121 | wire->sendPackage (0x00, buf, length, 0); 122 | } 123 | break; 124 | case 0x40: 125 | copyInputVars (); 126 | wire->sendPackage (0x40, data->var, data->inputLength + data->outputLength, 0); 127 | break; 128 | case 0x80: 129 | checkInputVars (); 130 | if ((package->length == data->inputLength) && (inputVarNeedSend==0)) { 131 | p=package->buffer; 132 | kp=data->var; 133 | ip=inputVar; 134 | i= data->inputLength; 135 | while (i--) *ip++=*kp++=*p++; 136 | } 137 | wire->sendPackage (0x80, 0, 0, 0); 138 | break; 139 | case 0xC0: 140 | checkInputVars (); 141 | uint8_t c; 142 | if (inputVarNeedSend==0) c = 0xC0; 143 | else c = 0xC1; 144 | wire->sendPackage (c, data->var + data->inputLength, data->outputLength, 0); 145 | break; 146 | } 147 | timeOut = millis (); 148 | } 149 | 150 | private: 151 | void copyInputVars () { 152 | inputVarNeedSend = 0; 153 | uint8_t * pc = data->var; 154 | uint8_t * p = inputVar; 155 | uint16_t ilen = data->inputLength; 156 | while (ilen--) *p++ = *pc++; 157 | } 158 | 159 | private: 160 | void checkInputVars () { 161 | if (inputVarNeedSend) return; 162 | uint8_t * pc = data->var; 163 | uint8_t * p = inputVar; 164 | uint16_t ilen = data->inputLength; 165 | while (ilen--) { 166 | if (*p++ != *pc++) { 167 | inputVarNeedSend = 1; 168 | break; 169 | } 170 | } 171 | } 172 | 173 | 174 | 175 | public: 176 | void handler () { 177 | if (wire) { 178 | conn->handleWire (wire); 179 | if (wire->running ()) { 180 | if (millis () - timeOut > REMOTEXY_THREAD_TIMEOUT) { 181 | timeOut = millis (); 182 | connect_flag = 0; 183 | if (stopByTimeOut) stop (); 184 | } 185 | } 186 | else stop (); 187 | } 188 | } 189 | 190 | public: 191 | static void startThread (CRemoteXYData * data, CRemoteXYConnection * conn, CRemoteXYWire * wire, uint8_t stopByTimeOut) { 192 | CRemoteXYThread * pt = data->threads; 193 | while (pt) { 194 | if (!pt->running ()) { 195 | pt->begin (conn, wire, stopByTimeOut); 196 | return; 197 | } 198 | pt = pt->next; 199 | } 200 | pt = new CRemoteXYThread (data); 201 | pt->next = data->threads; 202 | data->threads = pt; 203 | pt->begin (conn, wire, stopByTimeOut); 204 | } 205 | 206 | public: 207 | static uint8_t runningCount (CRemoteXYData * data) { 208 | uint8_t c = 0; 209 | CRemoteXYThread * pt = data->threads; 210 | while (pt) { 211 | if (pt->running ()) c++; 212 | pt = pt->next; 213 | } 214 | return c; 215 | } 216 | 217 | }; 218 | 219 | 220 | #endif //RemoteXYThread_h -------------------------------------------------------------------------------- /src/RemoteXYWire.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYWire_h 2 | #define RemoteXYWire_h 3 | 4 | #include "RemoteXYComm.h" 5 | 6 | #define REMOTEXY_INIT_CRC 0xffff 7 | #define REMOTEXY_PACKAGE_START_BYTE 0x55 8 | #define REMOTEXY_PACKAGE_MIN_LENGTH 6 9 | 10 | 11 | struct CRemoteXYPackage { 12 | uint8_t command; 13 | uint8_t * buffer; 14 | uint16_t length; 15 | }; 16 | 17 | class CRemoteXYReceivePackageListener { 18 | public: 19 | virtual void receivePackage (CRemoteXYPackage * package) = 0; 20 | }; 21 | 22 | class CRemoteXYWire { 23 | 24 | private: 25 | CRemoteXYReceivePackageListener * receivePackageListener; 26 | 27 | public: 28 | CRemoteXYWire () { 29 | receivePackageListener = NULL; 30 | } 31 | 32 | public: 33 | void setReceivePackageListener (CRemoteXYReceivePackageListener * listener) { 34 | receivePackageListener = listener; 35 | } 36 | 37 | public: 38 | void notifyReceivePackageListener (CRemoteXYPackage * package) { 39 | if (receivePackageListener) receivePackageListener->receivePackage (package); 40 | } 41 | 42 | 43 | public: 44 | virtual void handler () {}; 45 | virtual uint8_t running (); 46 | virtual void stop (); 47 | virtual void sendPackage (uint8_t command, uint8_t *buf, uint16_t length, uint8_t fromPgm); 48 | 49 | }; 50 | 51 | 52 | #endif // RemoteXYWire_h -------------------------------------------------------------------------------- /src/RemoteXYWireCloud.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYWireCloud_h 2 | #define RemoteXYWireCloud_h 3 | 4 | #include "RemoteXYWire.h" 5 | 6 | 7 | #define REMOTEXYWIRECLOUD_FREE_ID 0xff 8 | 9 | 10 | class CRemoteXYSendPackageListener { 11 | public: 12 | virtual void sendPackage (uint8_t command, uint8_t *buf, uint16_t length, uint8_t fromPgm) = 0; 13 | }; 14 | 15 | class CRemoteXYWireCloud: public CRemoteXYWire { 16 | 17 | public: 18 | CRemoteXYWireCloud * next; 19 | uint8_t id; // 0..7 20 | uint8_t newConnection; 21 | 22 | private: 23 | CRemoteXYSendPackageListener * sendPackageListener; 24 | 25 | public: 26 | CRemoteXYWireCloud (CRemoteXYSendPackageListener * _sendPackageListener) : CRemoteXYWire () { 27 | sendPackageListener = _sendPackageListener; 28 | id = REMOTEXYWIRECLOUD_FREE_ID; 29 | newConnection = 0; 30 | } 31 | 32 | public: 33 | void init (uint8_t _id) { 34 | id = _id; 35 | newConnection = 1; 36 | } 37 | 38 | /* 39 | public: 40 | void begin () { 41 | newConnection = 0; 42 | } 43 | */ 44 | 45 | public: 46 | void stop () override { 47 | setReceivePackageListener (NULL); 48 | id = REMOTEXYWIRECLOUD_FREE_ID; 49 | newConnection = 0; 50 | } 51 | 52 | public: 53 | uint8_t running () override { 54 | if (id == REMOTEXYWIRECLOUD_FREE_ID) return 0; 55 | return 1; 56 | } 57 | 58 | public: 59 | uint8_t isNewConnection () { 60 | return newConnection; 61 | } 62 | 63 | 64 | public: 65 | void sendPackage (uint8_t command, uint8_t *buf, uint16_t length, uint8_t fromPgm) override { 66 | sendPackageListener->sendPackage (command | (id<<1), buf, length, fromPgm); 67 | } 68 | 69 | 70 | public: 71 | void receivePackage (CRemoteXYPackage * package) { 72 | notifyReceivePackageListener (package); 73 | } 74 | 75 | }; 76 | 77 | #endif //RemoteXYWireCloud_h -------------------------------------------------------------------------------- /src/RemoteXYWireStream.h: -------------------------------------------------------------------------------- 1 | #ifndef RemoteXYWireStream_h 2 | #define RemoteXYWireStream_h 3 | 4 | 5 | #include "RemoteXYWire.h" 6 | #include "RemoteXYApiData.h" 7 | 8 | 9 | class CRemoteXYWireStream : public CRemoteXYWire, public CRemoteXYReadByteListener { 10 | 11 | public: 12 | CRemoteXYWireStream * next; 13 | CRemoteXYStream * stream; 14 | 15 | private: 16 | uint16_t sendCRC; 17 | 18 | uint8_t *receiveBuffer; 19 | uint16_t receiveBufferSize; 20 | uint16_t receiveIndex; 21 | uint8_t receiveModified; 22 | volatile uint8_t receiveLock; // =1 only add to receive buffer 23 | 24 | 25 | public: 26 | CRemoteXYWireStream (CRemoteXYData * data) : CRemoteXYWire () { 27 | stream = NULL; 28 | receiveBufferSize = data->receiveBufferSize; 29 | receiveBuffer = (uint8_t*)malloc (receiveBufferSize); 30 | } 31 | 32 | public: 33 | CRemoteXYWireStream (CRemoteXYData * data, uint8_t multiple) : CRemoteXYWire () { 34 | stream = NULL; 35 | receiveBufferSize = data->receiveBufferSize * multiple; 36 | receiveBuffer = (uint8_t*)malloc (receiveBufferSize); 37 | } 38 | 39 | public: 40 | void begin (CRemoteXYStream * _stream) { 41 | stream = _stream; 42 | stream->setReadByteListener (this); 43 | receiveIndex = 0; 44 | receiveModified = 0; 45 | receiveLock = 0; 46 | } 47 | 48 | public: 49 | void stop () override { 50 | setReceivePackageListener (NULL); 51 | stream = NULL; 52 | } 53 | 54 | public: 55 | uint8_t running () override { 56 | if (stream) return 1; 57 | else return 0; 58 | } 59 | 60 | CRemoteXYClient * getClient () { 61 | return (CRemoteXYClient*)stream; 62 | } 63 | 64 | 65 | 66 | public: 67 | void handler () override { 68 | if (stream) { 69 | stream->handler (); 70 | receivePackage (); 71 | } 72 | } 73 | 74 | 75 | private: 76 | void updateCRC (uint16_t *crc, uint8_t b) { 77 | *crc ^= b; 78 | for (uint8_t i=0; i<8; ++i) { 79 | if ((*crc) & 1) *crc = ((*crc) >> 1) ^ 0xA001; 80 | else *crc >>= 1; 81 | } 82 | } 83 | 84 | 85 | private: 86 | inline void sendByteUpdateCRC (uint8_t b) { 87 | #if defined(REMOTEXY__DEBUGLOG) 88 | RemoteXYDebugLog.writeOutputHex (b); 89 | #endif 90 | stream->write (b); 91 | updateCRC (&sendCRC, b); 92 | } 93 | 94 | 95 | public: 96 | void sendPackage (uint8_t command, uint8_t *buf, uint16_t length, uint8_t fromPgm) { 97 | uint16_t packageLength; 98 | if (stream) { 99 | sendCRC = REMOTEXY_INIT_CRC; 100 | packageLength = length+6; 101 | stream->startWrite (packageLength); 102 | 103 | sendByteUpdateCRC (REMOTEXY_PACKAGE_START_BYTE); 104 | sendByteUpdateCRC (packageLength); 105 | sendByteUpdateCRC (packageLength>>8); 106 | sendByteUpdateCRC (command); 107 | uint8_t b; 108 | while (length--) { 109 | if (fromPgm) b=pgm_read_byte_near (buf++); 110 | else b=*buf++; 111 | sendByteUpdateCRC (b); 112 | } 113 | #if defined(REMOTEXY__DEBUGLOG) 114 | RemoteXYDebugLog.writeOutputHex (sendCRC); 115 | RemoteXYDebugLog.writeOutputHex (sendCRC>>8); 116 | #endif 117 | stream->write (sendCRC); 118 | stream->write (sendCRC>>8); 119 | } 120 | } 121 | 122 | public: 123 | void readByte (uint8_t byte) override { 124 | uint16_t pi, i; 125 | 126 | #if defined(REMOTEXY__DEBUGLOG) 127 | RemoteXYDebugLog.writeInputHex (byte); 128 | #endif 129 | if ((receiveIndex==0) && (byte!=REMOTEXY_PACKAGE_START_BYTE)) return; 130 | if (receiveIndex >= receiveBufferSize) { 131 | if (receiveLock) return; 132 | pi = 1; 133 | while (pi < receiveBufferSize) { 134 | if (receiveBuffer[pi] == REMOTEXY_PACKAGE_START_BYTE) break; 135 | pi++; 136 | } 137 | receiveIndex = receiveBufferSize - pi; 138 | i=0; 139 | while (pi < receiveBufferSize) receiveBuffer[i++] = receiveBuffer[pi++]; 140 | } 141 | receiveBuffer[receiveIndex++]=byte; 142 | receiveModified = 1; 143 | } 144 | 145 | private: 146 | void receivePackage () { 147 | if (receiveModified) { 148 | receiveModified = 0; 149 | 150 | uint16_t crc; 151 | uint16_t si, i; 152 | uint16_t packageLength; 153 | si = 0; 154 | while (si + REMOTEXY_PACKAGE_MIN_LENGTH <= receiveIndex) { 155 | if (receiveBuffer[si] == REMOTEXY_PACKAGE_START_BYTE) { 156 | packageLength = receiveBuffer[si+1]|(receiveBuffer[si+2]<<8); 157 | if ((packageLength <= receiveIndex - si) && (packageLength >=6)) { 158 | crc=REMOTEXY_INIT_CRC; 159 | for (i = si; i < si + packageLength; i++) updateCRC (&crc, receiveBuffer[i]); 160 | if (crc == 0) { 161 | CRemoteXYPackage package; 162 | package.command = receiveBuffer[si+3]; 163 | package.buffer = receiveBuffer+si+4; 164 | package.length = packageLength-6; 165 | 166 | receiveLock = 1; 167 | notifyReceivePackageListener (&package); 168 | si += packageLength; 169 | i = 0; 170 | while (si < receiveIndex) receiveBuffer[i++] = receiveBuffer[si++]; 171 | receiveIndex = i; 172 | receiveLock = 0; 173 | si = 0; 174 | continue; 175 | } 176 | } 177 | } 178 | si++; 179 | } 180 | } 181 | } 182 | 183 | }; 184 | 185 | 186 | #endif // RemoteXYWireStream_h --------------------------------------------------------------------------------