├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md └── workflows │ ├── stale.yml │ └── sync_issues.yml ├── .gitignore ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── examples ├── Fingerprint_lock │ └── Fingerprint_lock.ino ├── GPS_Terminal │ └── GPS_Terminal.ino ├── HID_PC_Media_Controller │ ├── HID_PC_Media_Controller.ino │ ├── other_functions.gif │ └── volume_control.gif ├── IR_Terminal │ └── IR_Terminal.ino ├── Lidar_Terminal │ └── Lidar_Terminal.ino ├── SeeeduinoXIAO_SPISlave │ └── SeeeduinoXIAO_SPISlave.ino ├── SeeeduinoXIAO_TinyML_7_Posture_Detection │ ├── README.md │ ├── Xiao_EI_Accelerometer_Data_Collection │ │ └── Xiao_EI_Accelerometer_Data_Collection.ino │ └── Xiao_EI_Accelerometer_Inference │ │ └── Xiao_EI_Accelerometer_Inference.ino ├── WioTerminal-ADS1115 │ ├── Free_Fonts.h │ └── WioTerminal-ADS1115.ino ├── WioTerminal_AWSIoT_Bridge │ └── WioTerminal_AWSIoT_Bridge.ino ├── WioTerminal_AttitudeIndicator │ └── WioTerminal_AttitudeIndicator.ino ├── WioTerminal_Azure_Central │ ├── AzureDpsClient.cpp │ ├── AzureDpsClient.h │ ├── CliMode.cpp │ ├── CliMode.h │ ├── Config.h │ ├── Signature.cpp │ ├── Signature.h │ ├── Storage.cpp │ ├── Storage.h │ └── WioTerminal_Azure_Central.ino ├── WioTerminal_BackLight │ ├── WioTerminal_BackLight.ino │ └── lcd_backlight.hpp ├── WioTerminal_Blynk_Edgent │ ├── BlynkEdgent.h │ ├── BlynkState.h │ ├── ConfigMode.h │ ├── ConfigStore.h │ ├── Indicator.h │ ├── OTA.h │ ├── ResetButton.h │ ├── Settings.h │ └── WioTerminal_Blynk_Edgent.ino ├── WioTerminal_ButtonMouseControl │ ├── WioTerminal_ButtonMouseControl.ino │ └── WioTerminal_ButtonMouseControl_demo.gif ├── WioTerminal_Face │ └── WioTerminal_Face.ino ├── WioTerminal_GPS │ └── WioTerminal_GPS.ino ├── WioTerminal_Https_Stock_Demo │ ├── Free_Fonts.h │ └── WioTerminal_Https_Stock_Demo.ino ├── WioTerminal_Level │ └── WioTerminal_Level.ino ├── WioTerminal_MP3_Player │ ├── RawImage.h │ └── WioTerminal_MP3_Player.ino ├── WioTerminal_MaggieMaker_Customisable_Timer │ ├── Free_Fonts.h │ └── WioTerminal_MaggieMaker_Customisable_Timer.ino ├── WioTerminal_NTP │ └── WioTerminal_NTP.ino ├── WioTerminal_PC_Stats_Display │ ├── PC_stats_display │ │ ├── Free_Fonts.h │ │ └── PC_stats_display.ino │ ├── PC_stats_send.py │ └── README.md ├── WioTerminal_TF_MNIST │ ├── TF_MNIST.ipynb │ ├── WioTerminal_TF_MNIST.ino │ ├── mnist.h │ └── model.h ├── WioTerminal_Timer │ └── WioTerminal_Timer.ino ├── WioTerminal_TinyML_1_Intro │ ├── Wio_Terminal_EI_Rock_Paper_Scissors │ │ └── Wio_Terminal_EI_Rock_Paper_Scissors.ino │ └── Wio_Terminal_EI_Rock_Paper_Scissors_Continious │ │ └── Wio_Terminal_EI_Rock_Paper_Scissors_Continious.ino ├── WioTerminal_TinyML_2_Audio_Scene_Recognition │ ├── WioTerminal_EI_Microphone_Inference │ │ └── WioTerminal_EI_Microphone_Inference.ino │ └── WioTerminal_EI_Microphone_Inference_Blynk │ │ └── WioTerminal_EI_Microphone_Inference_Blynk.ino ├── WioTerminal_TinyML_3_People_Counting │ ├── WioTerminal_EI_People_Counting_Azure_Central_LVGL │ │ ├── AzureDpsClient.cpp │ │ ├── AzureDpsClient.h │ │ ├── CliMode.cpp │ │ ├── CliMode.h │ │ ├── Config.h │ │ ├── Signature.cpp │ │ ├── Signature.h │ │ ├── Storage.cpp │ │ ├── Storage.h │ │ └── WioTerminal_EI_People_Counting_Azure_Central_LVGL.ino │ └── WioTerminal_EI_People_Counting_Continious │ │ └── WioTerminal_EI_People_Counting_Continious.ino ├── WioTerminal_TinyML_4_Weather_Prediction │ ├── README.md │ ├── Wio_Terminal_TF-MICRO_Weather_Prediction_LVGL │ │ ├── Wio_Terminal_TF-MICRO_Weather_Prediction_LVGL.ino │ │ ├── get_hist_weather.cpp │ │ ├── get_hist_weather.h │ │ ├── gui.cpp │ │ ├── gui.h │ │ ├── model_Conv1D.h │ │ └── resources.h │ ├── Wio_Terminal_TF-MICRO_Weather_Prediction_test_static │ │ ├── Wio_Terminal_TF-MICRO_Weather_Prediction_test_static.ino │ │ └── model_Conv1D.h │ └── weather_prediction_final.ipynb ├── WioTerminal_TinyML_5_Anomaly_Detection │ ├── WioTerminal_EI_Anomaly_Detection_Blynk │ │ ├── BlynkEdgent.h │ │ ├── BlynkState.h │ │ ├── ConfigMode.h │ │ ├── ConfigStore.h │ │ ├── Indicator.h │ │ ├── OTA.h │ │ ├── ResetButton.h │ │ ├── Settings.h │ │ └── WioTerminal_EI_Anomaly_Detection_Blynk.ino │ └── WioTerminal_EI_Anomaly_Detection_LCD │ │ └── WioTerminal_EI_Anomaly_Detection_LCD.ino ├── WioTerminal_TinyML_6_Speech_Recognition │ ├── README.md │ ├── Wio_Terminal_TF-MICRO_Speech_Recognition_Mic │ │ ├── Wio_Terminal_TF-MICRO_Speech_Recognition_Mic.ino │ │ ├── dma_rec.cpp │ │ ├── dma_rec.h │ │ ├── mfcc.cpp │ │ ├── mfcc.h │ │ └── slu_model.h │ └── Wio_Terminal_TF-MICRO_Speech_Recognition_SD_card │ │ ├── Wio_Terminal_TF-MICRO_Speech_Recognition_SD_card.ino │ │ ├── mfcc.cpp │ │ ├── mfcc.h │ │ ├── read_wav.cpp │ │ ├── read_wav.h │ │ └── slu_model.h ├── WioTerminal_USB2Serial_Burn8720 │ ├── Free_Fonts.h │ └── WioTerminal_USB2Serial_Burn8720.ino ├── WioTerminal_UncannyEyes │ ├── WioTerminal_UncannyEyes.ino │ ├── catEye.h │ ├── defaultEye.h │ ├── doeEye.h │ ├── dragonEye.h │ ├── goatEye.h │ ├── naugaEye.h │ ├── newtEye.h │ ├── noScleraEye.h │ ├── owlEye.h │ ├── screenshotToConsole.ino │ └── terminatorEye.h ├── WioTerminal_WebBluetooth │ └── WioTerminal_WebBluetooth.ino └── jumper │ ├── jumper.ino │ ├── raw.h │ └── rgb332 │ ├── 0.bmp │ ├── 1.bmp │ ├── 2.bmp │ ├── 3.bmp │ ├── 4.bmp │ ├── 5.bmp │ ├── 6.bmp │ ├── 7.bmp │ ├── 8.bmp │ ├── 9.bmp │ ├── big_1.bmp │ ├── big_2.bmp │ ├── big_3.bmp │ ├── big_block.bmp │ ├── breaking_out.bmp │ ├── cloud.bmp │ ├── failure.bmp │ ├── fly0.bmp │ ├── fly1.bmp │ ├── game_over.bmp │ ├── go.bmp │ ├── jump.bmp │ ├── moon.bmp │ ├── road.bmp │ ├── run0.bmp │ ├── run1.bmp │ ├── setup.bmp │ ├── small_block.bmp │ ├── wait_play.bmp │ └── wire.bmp ├── library.properties ├── others └── RawImage.h └── src └── Seeed_Arduino_Sketchbook.h /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues and PRs' 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 4 * * *' 7 | 8 | jobs: 9 | stale: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v4 15 | 16 | - name: Checkout script repository 17 | uses: actions/checkout@v4 18 | with: 19 | repository: Seeed-Studio/sync-github-all-issues 20 | path: ci 21 | 22 | - name: Run script 23 | run: ./ci/tools/stale.sh 24 | env: 25 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | -------------------------------------------------------------------------------- /.github/workflows/sync_issues.yml: -------------------------------------------------------------------------------- 1 | name: Automate Issue Management 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | - edited 8 | - assigned 9 | - unassigned 10 | - labeled 11 | - unlabeled 12 | - reopened 13 | 14 | jobs: 15 | add_issue_to_project: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Add issue to GitHub Project 19 | uses: actions/add-to-project@v1.0.2 20 | with: 21 | project-url: https://github.com/orgs/Seeed-Studio/projects/17 22 | github-token: ${{ secrets.ISSUE_ASSEMBLE }} 23 | labeled: bug 24 | label-operator: NOT -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.bin 3 | *.elf 4 | *.DS_Store -------------------------------------------------------------------------------- /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 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at zuobaozhu@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing guidelines 2 | 3 | All guidelines for contributing to the Seeed_Arduino_Sketchbook repository can be found at [`How to contribute guideline`](https://github.com/Seeed-Studio/Seeed_Arduino_Sketchbook/wiki/How_to_contribute). 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Seeed Studio 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 | # Seeed_Arduino_Sketchbook [![Build Status](https://travis-ci.com/Seeed-Studio/Seeed_Arduino_Sketchbook.svg?branch=master)](https://travis-ci.com/Seeed-Studio/Seeed_Arduino_Sketchbook) 2 | demo about seeed's product 3 | -------------------------------------------------------------------------------- /examples/Fingerprint_lock/Fingerprint_lock.ino: -------------------------------------------------------------------------------- 1 | #include "ATSerial.h" 2 | #include "Protocol.h" 3 | #include "KCT202.h" 4 | #include 5 | #include "rgb_lcd.h" 6 | #include 7 | #include "Adafruit_NeoPixel.h" 8 | #include 9 | #ifdef __AVR__ 10 | #include 11 | #endif 12 | 13 | #if defined(ARDUINO_ARCH_AVR) 14 | #define debug Serial 15 | SoftwareSerial uart(2, 3); 16 | FingerPrint_KCT202 kct202; 17 | #elif defined(ARDUINO_ARCH_SAM) 18 | #define debug SerialUSB 19 | #define uart Serial 20 | FingerPrint_KCT202 kct202; 21 | #elif defined(ARDUINO_ARCH_SAMD) 22 | #define debug SerialUSB 23 | #define uart Serial1 24 | FingerPrint_KCT202 kct202; 25 | #else 26 | #define debug Serial 27 | SoftwareSerial uart(2, 3); 28 | FingerPrint_KCT202 kct202; 29 | #endif 30 | 31 | const int RealyPin = 0; 32 | 33 | char buffer [20]; 34 | 35 | char name_table[][8]={"None","Hansen","None","None","Junjie","None","None","None","None","None"}; 36 | 37 | rgb_lcd lcd; 38 | 39 | const int colorR = 255; 40 | const int colorG = 0; 41 | const int colorB = 0; 42 | 43 | #define OFF 0 44 | #define GREEN 1 45 | #define RED 2 46 | 47 | // Which pin on the Arduino is connected to the NeoPixels? 48 | // On a Trinket or Gemma we suggest changing this to 1 49 | #define PIN 1 50 | 51 | // How many NeoPixels are attached to the Arduino? 52 | #define NUMPIXELS 20 53 | 54 | // When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals. 55 | // Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest 56 | // example for more information on possible values. 57 | Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); 58 | uint8_t dot_num; 59 | 60 | Servo myservo; // create servo object to control a servo 61 | const int servo_pin = 0; // analog pin used to connect the potentiometer 62 | void display_update(rgb_lcd* lcddev,char* str) 63 | { 64 | if(!dot_num)lcddev->clear(); 65 | dot_num++; 66 | if(dot_num > 5) 67 | { 68 | dot_num = 0; 69 | } 70 | lcddev->print(str); 71 | } 72 | void led_ring_enable(uint8_t led_ring_color) 73 | { 74 | for (int i = 0; i < NUMPIXELS; i++) { 75 | // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255 76 | if(GREEN == led_ring_color){ 77 | pixels.setPixelColor(i, pixels.Color(0, 150, 0)); // Moderately bright green color. 78 | } 79 | else if(RED == led_ring_color){ 80 | pixels.setPixelColor(i, pixels.Color(150, 0, 0)); // Moderately bright red color. 81 | } 82 | else 83 | { 84 | pixels.setPixelColor(i, pixels.Color(0, 0, 0)); 85 | } 86 | 87 | pixels.show(); // This sends the updated pixel color to the hardware. 88 | } 89 | } 90 | void open_door() 91 | { 92 | myservo.write(90); // sets the servo position according to the scaled value 93 | delay(2000); 94 | myservo.write(0); // sets the servo position according to the scaled value 95 | // digitalWrite(servo_pin, HIGH); 96 | // delay(2000); 97 | // digitalWrite(servo_pin, LOW); 98 | } 99 | 100 | void setup() { 101 | // setup fingerprint sensor 102 | debug.begin(115200); 103 | kct202.begin(uart, debug); 104 | // set up the LCD's number of columns and rows: 105 | lcd.begin(16, 2); 106 | // set up the TimerTc3 107 | TimerTc3.initialize(1000000); 108 | TimerTc3.attachInterrupt(timerIsr); 109 | // set up servo 110 | myservo.attach(servo_pin); // attaches the servo on pin 0 to the servo object 111 | // End of trinket special code 112 | pixels.setBrightness(100); 113 | pixels.begin(); // This initializes the NeoPixel library. 114 | } 115 | 116 | uint16_t finger_num; 117 | uint8_t led_ring_color; 118 | void loop() { 119 | 120 | kct202.autoVerifyFingerPrint(CHECK_ALL_FINGER_TEMP, 121 | LED_OFF_AFTER_GET_GRAGH | PRETREATMENT_GRAGH | NOT_RET_FOR_EVERY_STEP); 122 | //The first param is the finger-print ID to check. 123 | //if set 0xffff,indicates that search for all the finger-print templates and try to match. 124 | debug.println(" "); 125 | debug.println("Please put your finger on the touchpad."); 126 | debug.println("To verify your finger print."); 127 | debug.println(" "); 128 | debug.println(" "); 129 | debug.println(" "); 130 | sprintf(buffer, "."); 131 | led_ring_color = OFF; 132 | if (0 == kct202.getVerifyResponAndparse(finger_num)) { 133 | debug.println("Verify ok!"); 134 | debug.print("Your finger temp id = "); 135 | debug.println(finger_num, HEX); 136 | sprintf (buffer, "welcome %s", name_table[finger_num]); 137 | dot_num = 0; 138 | display_update(&lcd,buffer); 139 | TimerTc3.stop(); 140 | led_ring_enable(GREEN); 141 | open_door(); 142 | dot_num = 0; 143 | sprintf(buffer, "."); 144 | display_update(&lcd,buffer); 145 | TimerTc3.start(); 146 | } 147 | else 148 | { 149 | sprintf (buffer, "cannot recognize"); 150 | dot_num = 0; 151 | display_update(&lcd,buffer); 152 | TimerTc3.stop(); 153 | led_ring_enable(RED); 154 | delay(1000); 155 | dot_num = 0; 156 | sprintf(buffer, "."); 157 | display_update(&lcd,buffer); 158 | TimerTc3.start(); 159 | } 160 | 161 | } 162 | void timerIsr() 163 | { 164 | display_update(&lcd,buffer); 165 | led_ring_enable(led_ring_color); 166 | } 167 | -------------------------------------------------------------------------------- /examples/GPS_Terminal/GPS_Terminal.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static const int RXPin = 0, TXPin = 1; 5 | static const uint32_t GPSBaud = 9600; 6 | 7 | // The serial connection to the GPS device 8 | SoftwareSerial ss(RXPin, TXPin); 9 | 10 | TFT_eSPI tft; 11 | TFT_eSprite spr = TFT_eSprite(&tft); // Sprite 12 | 13 | void setup() 14 | { 15 | Serial.begin(9600); 16 | ss.begin(GPSBaud); 17 | tft.begin(); 18 | tft.setRotation(3); 19 | spr.createSprite(tft.width(),tft.height()); 20 | } 21 | void loop() 22 | { 23 | spr.fillSprite(TFT_BLACK); 24 | spr.setFreeFont(&FreeSansBoldOblique18pt7b); 25 | spr.setTextColor(TFT_GREEN); 26 | spr.drawString("GPS RAW DATA", 20, 10 , 1);// Print the test text in the cust 27 | for(int8_t line_index = 0;line_index < 5 ; line_index++) 28 | { 29 | spr.drawLine(0, 50 + line_index, tft.width(), 50 + line_index, TFT_GREEN); 30 | } 31 | spr.setTextColor(TFT_WHITE); 32 | spr.setTextFont(2); 33 | spr.setCursor(0,60); 34 | while(ss.available()) // if date is coming from software serial port ==> data is coming from ss shield 35 | { 36 | uint8_t reciver = ss.read(); 37 | Serial.write(reciver); 38 | spr.write(reciver); 39 | int basetime = millis(); 40 | while (!ss.available()); 41 | int timecost = millis() - basetime; 42 | if(timecost > 709){ 43 | break; 44 | } 45 | } 46 | if (Serial.available()) // if data is available on hardware serial port ==> data is coming from PC or notebook 47 | ss.write(Serial.read()); // write it to the ss shield 48 | spr.pushSprite(0, 0); 49 | Serial.print("----------------------------------------------------------\r\n"); 50 | } -------------------------------------------------------------------------------- /examples/HID_PC_Media_Controller/other_functions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/HID_PC_Media_Controller/other_functions.gif -------------------------------------------------------------------------------- /examples/HID_PC_Media_Controller/volume_control.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/HID_PC_Media_Controller/volume_control.gif -------------------------------------------------------------------------------- /examples/Lidar_Terminal/Lidar_Terminal.ino: -------------------------------------------------------------------------------- 1 | #include"seeed_line_chart.h" //include the library 2 | #include "TFLidar.h" 3 | #define LINE_DIS 0X00 4 | #define STRING_DIS 0X01 5 | TFMini SeeedTFMini; 6 | TFLidar SeeedTFLidar(&SeeedTFMini); 7 | #define uart Serial1 8 | 9 | TFT_eSPI tft; 10 | 11 | #define max_size 10 //maximum size of data 12 | doubles data; //Initilising a doubles type to store data 13 | TFT_eSprite spr = TFT_eSprite(&tft); // Sprite 14 | 15 | void setup() { 16 | Serial.begin(115200); 17 | pinMode(WIO_KEY_C, INPUT_PULLUP); 18 | tft.begin(); 19 | tft.setRotation(3); 20 | spr.createSprite(TFT_HEIGHT,TFT_WIDTH); 21 | SeeedTFLidar.begin(&uart,115200); 22 | } 23 | uint8_t mode = LINE_DIS; 24 | void loop() { 25 | 26 | if (digitalRead(WIO_KEY_C) == LOW) { 27 | mode ++; 28 | if(mode > STRING_DIS ) mode = LINE_DIS; 29 | while(!digitalRead(WIO_KEY_C)); 30 | } 31 | display(get_Lidar_data(),mode); 32 | delay(50); 33 | } 34 | 35 | uint16_t get_Lidar_data() 36 | { 37 | while(!SeeedTFLidar.get_frame_data()){ 38 | delay(1); 39 | } 40 | return SeeedTFLidar.get_distance(); 41 | } 42 | 43 | void display(uint16_t lidar_data,uint8_t mode){ 44 | 45 | spr.fillSprite(TFT_WHITE); 46 | //Settings for the line graph title 47 | auto header = text(0, 0) 48 | .value("Lidar Terminal") 49 | .align(center) 50 | .valign(vcenter) 51 | .width(tft.width()) 52 | .color(green) 53 | .thickness(3); 54 | header.height(header.font_height() * 2); 55 | header.draw(); //Header height is the twice the height of the font 56 | if (LINE_DIS == mode){ 57 | if (data.size() == max_size) { 58 | data.pop();//this is used to remove the first read variable 59 | } 60 | data.push(lidar_data); //read variables and store in data 61 | //Settings for the line graph 62 | auto content = line_chart(10, header.height()); //(x,y) where the line graph begins 63 | content 64 | .height(tft.height() - header.height() * 1.5) //actual height of the line chart 65 | .width(tft.width() - content.x() * 2) //actual width of the line chart 66 | .based_on(0.0) //Starting point of y-axis, must be a float 67 | .show_circle(false) //drawing a cirle at each point, default is on. 68 | .value(data) //passing through the data to line graph 69 | .color(TFT_RED) //Setting the color for the line 70 | .draw(); 71 | } 72 | else if (STRING_DIS == mode){ 73 | for(int8_t line_index = 0;line_index < 5 ; line_index++) 74 | { 75 | spr.drawLine(0, 50 + line_index, tft.width(), 50 + line_index, TFT_GREEN); 76 | } 77 | auto header = text(0, 0) 78 | .thickness(1); 79 | spr.setFreeFont(&FreeSansBoldOblique24pt7b); 80 | spr.setTextColor(TFT_BLUE); 81 | spr.drawFloat(lidar_data / 100.00,2,80,110); 82 | spr.drawString(" M",80 + 90,110,1); 83 | 84 | } 85 | spr.pushSprite(0, 0); 86 | 87 | } -------------------------------------------------------------------------------- /examples/SeeeduinoXIAO_TinyML_7_Posture_Detection/README.md: -------------------------------------------------------------------------------- 1 | # TinyML Course 7 Posture Detection (Edge Impulse) 2 | 3 | -------------------------------------------------------------------------------- /examples/SeeeduinoXIAO_TinyML_7_Posture_Detection/Xiao_EI_Accelerometer_Data_Collection/Xiao_EI_Accelerometer_Data_Collection.ino: -------------------------------------------------------------------------------- 1 | // This example shows the 3 axis acceleration. 2 | #include "LIS3DHTR.h" 3 | #include 4 | LIS3DHTR LIS; //IIC 5 | #define WIRE Wire 6 | 7 | #define CONVERT_G_TO_MS2 9.80665f 8 | #define FREQUENCY_HZ 50 9 | #define INTERVAL_MS (1000 / (FREQUENCY_HZ + 1)) 10 | 11 | static unsigned long last_interval_ms = 0; 12 | 13 | void setup() { 14 | Serial.begin(115200); 15 | while (!Serial) {}; 16 | Serial.println("hi"); 17 | //LIS.begin(WIRE); //IIC init dafault :0x18 18 | LIS.begin(WIRE, 0x23); //IIC init 19 | delay(100); 20 | // LIS.setFullScaleRange(LIS3DHTR_RANGE_2G); 21 | // LIS.setFullScaleRange(LIS3DHTR_RANGE_4G); 22 | // LIS.setFullScaleRange(LIS3DHTR_RANGE_8G); 23 | // LIS.setFullScaleRange(LIS3DHTR_RANGE_16G); 24 | // LIS.setOutputDataRate(LIS3DHTR_DATARATE_1HZ); 25 | // LIS.setOutputDataRate(LIS3DHTR_DATARATE_10HZ); 26 | // LIS.setOutputDataRate(LIS3DHTR_DATARATE_25HZ); 27 | // LIS.setOutputDataRate(LIS3DHTR_DATARATE_50HZ); 28 | //LIS.setOutputDataRate(LIS3DHTR_DATARATE_100HZ); 29 | // LIS.setOutputDataRate(LIS3DHTR_DATARATE_200HZ); 30 | // LIS.setOutputDataRate(LIS3DHTR_DATARATE_1_6KHZ); 31 | // LIS.setOutputDataRate(LIS3DHTR_DATARATE_5KHZ); 32 | //LIS.setHighSolution(true); //High solution enable 33 | Serial.println(LIS.getDeviceID()); 34 | if (!LIS.isConnection()) { 35 | Serial.println("LIS3DHTR didn't connect."); 36 | while (1); 37 | return; 38 | } 39 | } 40 | void loop() { 41 | 42 | float x, y, z; 43 | 44 | if (millis() > last_interval_ms + INTERVAL_MS) { 45 | last_interval_ms = millis(); 46 | 47 | LIS.getAcceleration(&x, &y, &z); 48 | 49 | Serial.print(x * CONVERT_G_TO_MS2); 50 | Serial.print('\t'); 51 | Serial.print(y * CONVERT_G_TO_MS2); 52 | Serial.print('\t'); 53 | Serial.println(z * CONVERT_G_TO_MS2); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/SeeeduinoXIAO_TinyML_7_Posture_Detection/Xiao_EI_Accelerometer_Inference/Xiao_EI_Accelerometer_Inference.ino: -------------------------------------------------------------------------------- 1 | /* 2 | An example sketch for Edge Impulse trained model inference 3 | for Posture recognition with Accelerometer 4 | and Buzzer indication 5 | 6 | Copyright (c) 2021 Dmitry Maslov 7 | Author : Dmitry Maslov 8 | Create Time : November 2021 9 | Change Log : 10 | 11 | The MIT License (MIT) 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy 14 | of this software and associated documentation files (the "Software"), to deal 15 | in the Software without restriction, including without limitation the rights 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in 21 | all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | THE SOFTWARE. 30 | */ 31 | 32 | /* Includes ---------------------------------------------------------------- */ 33 | #include 34 | #include"LIS3DHTR.h" 35 | #include 36 | 37 | #define ALARM_THRESHOLD 0.8 38 | #define BUZZER_PIN A3 39 | 40 | LIS3DHTR lis; 41 | 42 | /* Constant defines -------------------------------------------------------- */ 43 | #define CONVERT_G_TO_MS2 9.80665f 44 | 45 | /* Private variables ------------------------------------------------------- */ 46 | static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal 47 | 48 | /** 49 | * @brief Arduino setup function 50 | */ 51 | void setup() 52 | { 53 | pinMode(BUZZER_PIN, OUTPUT); 54 | 55 | Serial.begin(115200); 56 | while (!Serial) {delay(10);} 57 | 58 | Serial.println("Edge Impulse Inferencing Demo"); 59 | 60 | lis.begin(Wire); 61 | 62 | if (!lis.available()) { 63 | Serial.println("Failed to initialize IMU!"); 64 | while (1); 65 | } 66 | else { 67 | ei_printf("IMU initialized\r\n"); 68 | } 69 | lis.setOutputDataRate(LIS3DHTR_DATARATE_100HZ); // Setting output data rage to 25Hz, can be set up tp 5kHz 70 | lis.setFullScaleRange(LIS3DHTR_RANGE_16G); // Setting scale range to 2g, select from 2,4,8,16g 71 | 72 | 73 | if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != 3) { 74 | ei_printf("ERR: EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME should be equal to 3 (the 3 sensor axes)\n"); 75 | return; 76 | } 77 | } 78 | 79 | /** 80 | * @brief Printf function uses vsnprintf and output using Arduino Serial 81 | * 82 | * @param[in] format Variable argument list 83 | */ 84 | void ei_printf(const char *format, ...) { 85 | static char print_buf[1024] = { 0 }; 86 | 87 | va_list args; 88 | va_start(args, format); 89 | int r = vsnprintf(print_buf, sizeof(print_buf), format, args); 90 | va_end(args); 91 | 92 | if (r > 0) { 93 | Serial.write(print_buf); 94 | } 95 | } 96 | 97 | /** 98 | * @brief Get data and run inferencing 99 | * 100 | * @param[in] debug Get debug info if true 101 | */ 102 | void loop() 103 | { 104 | 105 | ei_printf("Sampling...\n"); 106 | 107 | // Allocate a buffer here for the values we'll read from the IMU 108 | float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 }; 109 | 110 | for (size_t ix = 0; ix < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; ix += 3) { 111 | // Determine the next tick (and then sleep later) 112 | uint64_t next_tick = micros() + (EI_CLASSIFIER_INTERVAL_MS * 1000); 113 | 114 | lis.getAcceleration(&buffer[ix], &buffer[ix+1], &buffer[ix + 2]); 115 | buffer[ix + 0] *= CONVERT_G_TO_MS2; 116 | buffer[ix + 1] *= CONVERT_G_TO_MS2; 117 | buffer[ix + 2] *= CONVERT_G_TO_MS2; 118 | 119 | delayMicroseconds(next_tick - micros()); 120 | } 121 | 122 | // Turn the raw buffer in a signal which we can the classify 123 | signal_t signal; 124 | int err = numpy::signal_from_buffer(buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal); 125 | if (err != 0) { 126 | ei_printf("Failed to create signal from buffer (%d)\n", err); 127 | return; 128 | } 129 | 130 | // Run the classifier 131 | ei_impulse_result_t result = { 0 }; 132 | 133 | err = run_classifier(&signal, &result, debug_nn); 134 | if (err != EI_IMPULSE_OK) { 135 | ei_printf("ERR: Failed to run classifier (%d)\n", err); 136 | return; 137 | } 138 | 139 | // print the predictions 140 | ei_printf("Predictions "); 141 | ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)", 142 | result.timing.dsp, result.timing.classification, result.timing.anomaly); 143 | ei_printf(": \n"); 144 | for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) { 145 | ei_printf(" %s: %.5f\n", result.classification[ix].label, result.classification[ix].value); 146 | } 147 | #if EI_CLASSIFIER_HAS_ANOMALY == 1 148 | ei_printf(" anomaly score: %.3f\n", result.anomaly); 149 | #endif 150 | 151 | if (result.classification[1].value > ALARM_THRESHOLD || result.classification[2].value > ALARM_THRESHOLD) 152 | { 153 | tone(BUZZER_PIN, 523, 250); 154 | delay(250); 155 | noTone(BUZZER_PIN); 156 | delay(250); 157 | tone(BUZZER_PIN, 523, 250); 158 | delay(250); 159 | noTone(BUZZER_PIN); 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /examples/WioTerminal_Azure_Central/AzureDpsClient.cpp: -------------------------------------------------------------------------------- 1 | #include "AzureDpsClient.h" 2 | #include 3 | #include 4 | 5 | static constexpr size_t SignatureMaxSize = 256; 6 | static constexpr size_t MqttClientIdMaxSize = 128; 7 | static constexpr size_t MqttUsernameMaxSize = 128; 8 | static constexpr size_t MqttPasswordMaxSize = 300; 9 | static constexpr size_t RegisterPublishTopicMaxSize = 128; 10 | static constexpr size_t QueryStatusPublishTopicMaxSize = 256; 11 | 12 | AzureDpsClient::AzureDpsClient() : 13 | ResponseValid{ false } 14 | { 15 | } 16 | 17 | int AzureDpsClient::Init(const std::string& endpoint, const std::string& idScope, const std::string& registrationId) 18 | { 19 | ResponseValid = false; 20 | 21 | Endpoint = endpoint; 22 | IdScope = idScope; 23 | RegistrationId = registrationId; 24 | 25 | const az_span endpointSpan{ az_span_create((uint8_t*)&Endpoint[0], Endpoint.size()) }; 26 | const az_span idScopeSpan{ az_span_create((uint8_t*)&IdScope[0], IdScope.size()) }; 27 | const az_span registrationIdSpan{ az_span_create((uint8_t*)&RegistrationId[0], RegistrationId.size()) }; 28 | if (az_result_failed(az_iot_provisioning_client_init(&ProvClient, endpointSpan, idScopeSpan, registrationIdSpan, NULL))) return -1; 29 | 30 | return 0; 31 | } 32 | 33 | std::vector AzureDpsClient::GetSignature(const uint64_t& expirationEpochTime) 34 | { 35 | uint8_t signature[SignatureMaxSize]; 36 | az_span signatureSpan = az_span_create(signature, sizeof(signature)); 37 | az_span signatureValidSpan; 38 | if (az_result_failed(az_iot_provisioning_client_sas_get_signature(&ProvClient, expirationEpochTime, signatureSpan, &signatureValidSpan))) return std::vector(); 39 | 40 | return std::vector(az_span_ptr(signatureValidSpan), az_span_ptr(signatureValidSpan) + az_span_size(signatureValidSpan)); 41 | } 42 | 43 | std::string AzureDpsClient::GetMqttClientId() 44 | { 45 | char mqttClientId[MqttClientIdMaxSize]; 46 | if (az_result_failed(az_iot_provisioning_client_get_client_id(&ProvClient, mqttClientId, sizeof(mqttClientId), NULL))) return std::string(); 47 | 48 | return mqttClientId; 49 | } 50 | 51 | std::string AzureDpsClient::GetMqttUsername() 52 | { 53 | char mqttUsername[MqttUsernameMaxSize]; 54 | if (az_result_failed(az_iot_provisioning_client_get_user_name(&ProvClient, mqttUsername, sizeof(mqttUsername), NULL))) return std::string(); 55 | 56 | return mqttUsername; 57 | } 58 | 59 | std::string AzureDpsClient::GetMqttPassword(const std::string& encryptedSignature, const uint64_t& expirationEpochTime) 60 | { 61 | char mqttPassword[MqttPasswordMaxSize]; 62 | az_span encryptedSignatureSpan = az_span_create((uint8_t*)&encryptedSignature[0], encryptedSignature.size()); 63 | if (az_result_failed(az_iot_provisioning_client_sas_get_password(&ProvClient, encryptedSignatureSpan, expirationEpochTime, AZ_SPAN_EMPTY, mqttPassword, sizeof(mqttPassword), NULL))) return std::string(); 64 | 65 | return mqttPassword; 66 | } 67 | 68 | std::string AzureDpsClient::GetRegisterPublishTopic() 69 | { 70 | char registerPublishTopic[RegisterPublishTopicMaxSize]; 71 | if (az_result_failed(az_iot_provisioning_client_register_get_publish_topic(&ProvClient, registerPublishTopic, sizeof(registerPublishTopic), NULL))) return std::string(); 72 | 73 | return registerPublishTopic; 74 | } 75 | 76 | std::string AzureDpsClient::GetRegisterSubscribeTopic() const 77 | { 78 | return AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC; 79 | } 80 | 81 | int AzureDpsClient::RegisterSubscribeWork(const std::string& topic, const std::vector& payload) 82 | { 83 | ResponseValid = false; 84 | 85 | ResponseTopic = topic; 86 | ResponsePayload = payload; 87 | 88 | if (az_result_failed(az_iot_provisioning_client_parse_received_topic_and_payload(&ProvClient, az_span_create((uint8_t*)&ResponseTopic[0], ResponseTopic.size()), az_span_create((uint8_t*)&ResponsePayload[0], ResponsePayload.size()), &Response))) return -1; 89 | 90 | ResponseValid = true; 91 | 92 | return 0; 93 | } 94 | 95 | bool AzureDpsClient::IsRegisterOperationCompleted() 96 | { 97 | if (!ResponseValid) return false; 98 | 99 | return az_iot_provisioning_client_operation_complete(GetOperationStatus(Response)); 100 | } 101 | 102 | int AzureDpsClient::GetWaitBeforeQueryStatusSeconds() const 103 | { 104 | if (!ResponseValid) return 0; 105 | 106 | return Response.retry_after_seconds; 107 | } 108 | 109 | std::string AzureDpsClient::GetQueryStatusPublishTopic() 110 | { 111 | if (!ResponseValid) return std::string(); 112 | 113 | char queryStatusPublishTopic[QueryStatusPublishTopicMaxSize]; 114 | if (az_result_failed(az_iot_provisioning_client_query_status_get_publish_topic(&ProvClient, Response.operation_id, queryStatusPublishTopic, sizeof(queryStatusPublishTopic), NULL))) return std::string(); 115 | 116 | return queryStatusPublishTopic; 117 | } 118 | 119 | bool AzureDpsClient::IsAssigned() 120 | { 121 | if (!ResponseValid) return false; 122 | 123 | return GetOperationStatus(Response) == AZ_IOT_PROVISIONING_STATUS_ASSIGNED; 124 | } 125 | 126 | std::string AzureDpsClient::GetHubHost() 127 | { 128 | if (!IsAssigned()) return std::string(); 129 | 130 | const az_span& span{ Response.registration_state.assigned_hub_hostname }; 131 | return std::string(az_span_ptr(span), az_span_ptr(span) + az_span_size(span)); 132 | } 133 | 134 | std::string AzureDpsClient::GetDeviceId() 135 | { 136 | if (!IsAssigned()) return std::string(); 137 | 138 | const az_span& span{ Response.registration_state.device_id }; 139 | return std::string(az_span_ptr(span), az_span_ptr(span) + az_span_size(span)); 140 | } 141 | 142 | az_iot_provisioning_client_operation_status AzureDpsClient::GetOperationStatus(az_iot_provisioning_client_register_response& response) 143 | { 144 | return response.operation_status; 145 | } 146 | -------------------------------------------------------------------------------- /examples/WioTerminal_Azure_Central/AzureDpsClient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class AzureDpsClient 8 | { 9 | public: 10 | AzureDpsClient(); 11 | AzureDpsClient(const AzureDpsClient&) = delete; 12 | AzureDpsClient& operator=(const AzureDpsClient&) = delete; 13 | 14 | std::string GetEndpoint() const { return Endpoint; } 15 | void SetEndpoint(const std::string& endpoint) { Endpoint = endpoint; } 16 | std::string GetIdScope() const { return IdScope; } 17 | void SetIdScope(const std::string& idScope) { IdScope = idScope; } 18 | std::string GetRegistrationId() const { return RegistrationId; } 19 | void SetRegistrationId(const std::string& registrationId) { RegistrationId = registrationId; } 20 | 21 | int Init(const std::string& endpoint, const std::string& idScope, const std::string& registrationId); 22 | 23 | std::vector GetSignature(const uint64_t& expirationEpochTime); 24 | 25 | std::string GetMqttClientId(); 26 | std::string GetMqttUsername(); 27 | std::string GetMqttPassword(const std::string& encryptedSignature, const uint64_t& expirationEpochTime); 28 | 29 | std::string GetRegisterPublishTopic(); 30 | std::string GetRegisterSubscribeTopic() const; 31 | int RegisterSubscribeWork(const std::string& topic, const std::vector& payload); 32 | bool IsRegisterOperationCompleted(); 33 | int GetWaitBeforeQueryStatusSeconds() const; 34 | std::string GetQueryStatusPublishTopic(); 35 | 36 | bool IsAssigned(); 37 | std::string GetHubHost(); 38 | std::string GetDeviceId(); 39 | 40 | private: 41 | std::string Endpoint; 42 | std::string IdScope; 43 | std::string RegistrationId; 44 | 45 | az_iot_provisioning_client ProvClient; 46 | 47 | bool ResponseValid; 48 | std::string ResponseTopic; 49 | std::vector ResponsePayload; 50 | az_iot_provisioning_client_register_response Response; 51 | 52 | private: 53 | static az_iot_provisioning_client_operation_status GetOperationStatus(az_iot_provisioning_client_register_response& response); 54 | 55 | }; 56 | -------------------------------------------------------------------------------- /examples/WioTerminal_Azure_Central/CliMode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void CliMode(); 4 | -------------------------------------------------------------------------------- /examples/WioTerminal_Azure_Central/Config.h: -------------------------------------------------------------------------------- 1 | #define USE_CLI 2 | //#define USE_DPS 3 | 4 | #if defined(USE_CLI) 5 | 6 | // Wi-Fi 7 | #define IOT_CONFIG_WIFI_SSID Storage::WiFiSSID.c_str() 8 | #define IOT_CONFIG_WIFI_PASSWORD Storage::WiFiPassword.c_str() 9 | 10 | // Azure IoT Hub DPS 11 | #define IOT_CONFIG_GLOBAL_DEVICE_ENDPOINT "global.azure-devices-provisioning.net" 12 | #define IOT_CONFIG_ID_SCOPE Storage::IdScope 13 | #define IOT_CONFIG_REGISTRATION_ID Storage::RegistrationId 14 | #define IOT_CONFIG_SYMMETRIC_KEY Storage::SymmetricKey 15 | 16 | #else // USE_CLI 17 | 18 | // Wi-Fi 19 | #define IOT_CONFIG_WIFI_SSID "[wifi ssid]" 20 | #define IOT_CONFIG_WIFI_PASSWORD "[wifi password]" 21 | 22 | #if !defined(USE_DPS) 23 | // Azure IoT Hub 24 | #define IOT_CONFIG_IOTHUB "[Azure IoT Hub host name].azure-devices.net" 25 | #define IOT_CONFIG_DEVICE_ID "[device id]" 26 | #define IOT_CONFIG_SYMMETRIC_KEY "[symmetric key]" 27 | #else // USE_DPS 28 | // Azure IoT Hub DPS 29 | #define IOT_CONFIG_GLOBAL_DEVICE_ENDPOINT "global.azure-devices-provisioning.net" 30 | #define IOT_CONFIG_ID_SCOPE "[id scope]" 31 | #define IOT_CONFIG_REGISTRATION_ID "[registration id]" 32 | #define IOT_CONFIG_SYMMETRIC_KEY "[symmetric key]" 33 | #endif // USE_DPS 34 | 35 | #endif // USE_CLI 36 | 37 | #define IOT_CONFIG_MODEL_ID "dtmi:seeedkk:wioterminal:wioterminal_aziot_example;2" 38 | 39 | #define TOKEN_LIFESPAN 3600 40 | 41 | #define TELEMETRY_FREQUENCY_MILLISECS 2000 42 | #define TELEMETRY_ACCEL_X "accelX" 43 | #define TELEMETRY_ACCEL_Y "accelY" 44 | #define TELEMETRY_ACCEL_Z "accelZ" 45 | #define TELEMETRY_LIGHT "light" 46 | #define COMMAND_RING_BUZZER "ringBuzzer" 47 | -------------------------------------------------------------------------------- /examples/WioTerminal_Azure_Central/Signature.cpp: -------------------------------------------------------------------------------- 1 | #include "Signature.h" 2 | #include 3 | #include "Seeed_mbedtls.h" 4 | 5 | 6 | std::string GenerateEncryptedSignature(const std::string& symmetricKey, const std::vector& signature) 7 | { 8 | unsigned char base64DecodedSymmetricKey[symmetricKey.size() + 1]; 9 | 10 | // Base64-decode device key 11 | // <-- symmetricKey 12 | // --> base64DecodedSymmetricKey 13 | size_t base64DecodedSymmetricKeyLength; 14 | if (mbedtls_base64_decode(base64DecodedSymmetricKey, sizeof(base64DecodedSymmetricKey), &base64DecodedSymmetricKeyLength, (unsigned char*)&symmetricKey[0], symmetricKey.size()) != 0) abort(); 15 | if (base64DecodedSymmetricKeyLength == 0) abort(); 16 | 17 | // SHA-256 encrypt 18 | // <-- base64DecodedSymmetricKey 19 | // <-- signature 20 | // --> encryptedSignature 21 | uint8_t encryptedSignature[32]; // SHA-256 22 | mbedtls_md_context_t ctx; 23 | const mbedtls_md_type_t mdType{ MBEDTLS_MD_SHA256 }; 24 | if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(mdType), 1) != 0) abort(); 25 | if (mbedtls_md_hmac_starts(&ctx, base64DecodedSymmetricKey, base64DecodedSymmetricKeyLength) != 0) abort(); 26 | if (mbedtls_md_hmac_update(&ctx, &signature[0], signature.size()) != 0) abort(); 27 | if (mbedtls_md_hmac_finish(&ctx, encryptedSignature) != 0) abort(); 28 | 29 | // Base64 encode encrypted signature 30 | // <-- encryptedSignature 31 | // --> b64encHmacsha256Signature 32 | char b64encHmacsha256Signature[(size_t)(sizeof(encryptedSignature) * 1.5f) + 1]; 33 | size_t b64encHmacsha256SignatureLength; 34 | if (mbedtls_base64_encode((unsigned char*)b64encHmacsha256Signature, sizeof(b64encHmacsha256Signature), &b64encHmacsha256SignatureLength, encryptedSignature, mbedtls_md_get_size(mbedtls_md_info_from_type(mdType))) != 0) abort(); 35 | 36 | return std::string(b64encHmacsha256Signature, b64encHmacsha256SignatureLength); 37 | } 38 | 39 | std::string ComputeDerivedSymmetricKey(const std::string& masterKey, const std::string& registrationId) 40 | { 41 | unsigned char base64DecodedMasterKey[masterKey.size() + 1]; 42 | 43 | // Base64-decode device key 44 | // <-- masterKey 45 | // --> base64DecodedMasterKey 46 | size_t base64DecodedMasterKeyLength; 47 | if (mbedtls_base64_decode(base64DecodedMasterKey, sizeof(base64DecodedMasterKey), &base64DecodedMasterKeyLength, (unsigned char*)&masterKey[0], masterKey.size()) != 0) abort(); 48 | if (base64DecodedMasterKeyLength == 0) abort(); 49 | 50 | // SHA-256 encrypt 51 | // <-- base64DecodedMasterKey 52 | // <-- registrationId 53 | // --> derivedSymmetricKey 54 | uint8_t derivedSymmetricKey[32]; // SHA-256 55 | mbedtls_md_context_t ctx; 56 | const mbedtls_md_type_t mdType{ MBEDTLS_MD_SHA256 }; 57 | if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(mdType), 1) != 0) abort(); 58 | if (mbedtls_md_hmac_starts(&ctx, base64DecodedMasterKey, base64DecodedMasterKeyLength) != 0) abort(); 59 | if (mbedtls_md_hmac_update(&ctx, (const unsigned char*)®istrationId[0], registrationId.size()) != 0) abort(); 60 | if (mbedtls_md_hmac_finish(&ctx, derivedSymmetricKey) != 0) abort(); 61 | 62 | // Base64 encode encrypted signature 63 | // <-- derivedSymmetricKey 64 | // --> b64encDerivedSymmetricKey 65 | char b64encDerivedSymmetricKey[(size_t)(sizeof(derivedSymmetricKey) * 1.5f) + 1]; 66 | size_t b64encDerivedSymmetricKeyLength; 67 | if (mbedtls_base64_encode((unsigned char*)b64encDerivedSymmetricKey, sizeof(b64encDerivedSymmetricKey), &b64encDerivedSymmetricKeyLength, derivedSymmetricKey, mbedtls_md_get_size(mbedtls_md_info_from_type(mdType))) != 0) abort(); 68 | 69 | return std::string(b64encDerivedSymmetricKey, b64encDerivedSymmetricKeyLength); 70 | } 71 | -------------------------------------------------------------------------------- /examples/WioTerminal_Azure_Central/Signature.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | std::string GenerateEncryptedSignature(const std::string& symmetricKey, const std::vector& signature); 7 | std::string ComputeDerivedSymmetricKey(const std::string& masterKey, const std::string& registrationId); 8 | -------------------------------------------------------------------------------- /examples/WioTerminal_Azure_Central/Storage.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Storage.h" 3 | #include 4 | #include 5 | 6 | static auto FlashStartAddress = reinterpret_cast(0x04000000); 7 | 8 | static ExtFlashLoader::QSPIFlash Flash; 9 | 10 | std::string Storage::WiFiSSID; 11 | std::string Storage::WiFiPassword; 12 | std::string Storage::IdScope; 13 | std::string Storage::RegistrationId; 14 | std::string Storage::SymmetricKey; 15 | 16 | int Storage::Init = [] { 17 | Flash.initialize(); 18 | Flash.reset(); 19 | Flash.enterToMemoryMode(); 20 | 21 | WiFiSSID.clear(); 22 | WiFiPassword.clear(); 23 | IdScope.clear(); 24 | RegistrationId.clear(); 25 | SymmetricKey.clear(); 26 | 27 | return 0; 28 | }(); 29 | 30 | void Storage::Load() 31 | { 32 | if (memcmp(&FlashStartAddress[0], "AZ01", 4) != 0) 33 | { 34 | Storage::WiFiSSID.clear(); 35 | Storage::WiFiPassword.clear(); 36 | Storage::IdScope.clear(); 37 | Storage::RegistrationId.clear(); 38 | Storage::SymmetricKey.clear(); 39 | } 40 | else 41 | { 42 | MsgPack::Unpacker unpacker; 43 | unpacker.feed(&FlashStartAddress[8], *(const uint32_t*)&FlashStartAddress[4]); 44 | 45 | MsgPack::str_t str[5]; 46 | unpacker.deserialize(str[0], str[1], str[2], str[3], str[4]); 47 | 48 | Storage::WiFiSSID = str[0].c_str(); 49 | Storage::WiFiPassword = str[1].c_str(); 50 | Storage::IdScope = str[2].c_str(); 51 | Storage::RegistrationId = str[3].c_str(); 52 | Storage::SymmetricKey = str[4].c_str(); 53 | } 54 | } 55 | 56 | void Storage::Save() 57 | { 58 | MsgPack::Packer packer; 59 | { 60 | MsgPack::str_t str[5]; 61 | str[0] = Storage::WiFiSSID.c_str(); 62 | str[1] = Storage::WiFiPassword.c_str(); 63 | str[2] = Storage::IdScope.c_str(); 64 | str[3] = Storage::RegistrationId.c_str(); 65 | str[4] = Storage::SymmetricKey.c_str(); 66 | packer.serialize(str[0], str[1], str[2], str[3], str[4]); 67 | } 68 | 69 | std::vector buf(4 + 4 + packer.size()); 70 | memcpy(&buf[0], "AZ01", 4); 71 | *(uint32_t*)&buf[4] = packer.size(); 72 | memcpy(&buf[8], packer.data(), packer.size()); 73 | 74 | ExtFlashLoader::writeExternalFlash(Flash, 0, &buf[0], buf.size(), [](std::size_t bytes_processed, std::size_t bytes_total, bool verifying) { return true; }); 75 | } 76 | 77 | void Storage::Erase() 78 | { 79 | Flash.exitFromMemoryMode(); 80 | Flash.writeEnable(); 81 | Flash.eraseSector(0); 82 | Flash.waitProgram(0); 83 | Flash.enterToMemoryMode(); 84 | } 85 | -------------------------------------------------------------------------------- /examples/WioTerminal_Azure_Central/Storage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class Storage 6 | { 7 | public: 8 | static std::string WiFiSSID; 9 | static std::string WiFiPassword; 10 | static std::string IdScope; 11 | static std::string RegistrationId; 12 | static std::string SymmetricKey; 13 | 14 | public: 15 | static void Load(); 16 | static void Save(); 17 | static void Erase(); 18 | 19 | private: 20 | static int Init; 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /examples/WioTerminal_BackLight/WioTerminal_BackLight.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lcd_backlight.hpp" 3 | #include 4 | 5 | TFT_eSPI tft; 6 | static LCDBackLight backLight; 7 | void setup() { 8 | Serial.begin(115200); 9 | while(!Serial); 10 | 11 | tft.begin(); 12 | tft.setRotation(3); 13 | 14 | tft.fillScreen(tft.color565(255, 0, 0)); 15 | 16 | Serial.println("initializing backlight..."); 17 | backLight.initialize(); 18 | } 19 | 20 | static std::uint8_t brightness = 0; 21 | void loop() { 22 | std::uint8_t maxBrightness = backLight.getMaxBrightness(); 23 | brightness += 1; 24 | if( brightness > maxBrightness ) { 25 | brightness = 0; 26 | } 27 | backLight.setBrightness(brightness); 28 | delay(50); 29 | } 30 | -------------------------------------------------------------------------------- /examples/WioTerminal_BackLight/lcd_backlight.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Kenta IDA 2 | // LICENSE: Boost Software License 3 | /** 4 | * @file lcd_backlight.hpp 5 | */ 6 | 7 | #ifndef LCD_BACKLIGHT_HPP__ 8 | #define LCD_BACKLIGHT_HPP__ 9 | 10 | //#include 11 | #include 12 | 13 | /** 14 | * @brief Controls Wio Terminal LCD back light brightness 15 | */ 16 | class LCDBackLight 17 | { 18 | private: 19 | std::uint8_t currentBrightness = 100; 20 | std::uint8_t maxBrightness = 100; 21 | public: 22 | /** 23 | * @brief Gets current brightness 24 | * @return current brightness. 25 | */ 26 | std::uint8_t getBrightness() const { return this->currentBrightness; } 27 | /** 28 | * @brief Gets maximum brightness 29 | * @return maximum brightness. 30 | */ 31 | std::uint8_t getMaxBrightness() const { return this->maxBrightness; } 32 | 33 | /** 34 | * @brief Sets brightness. 35 | * @param [in] brightness new value of brightness. If the brightness value exceeds maximum brightness, the value will be clipped. 36 | * 37 | */ 38 | void setBrightness(std::uint8_t brightness) 39 | { 40 | this->currentBrightness = brightness < this->maxBrightness ? brightness : this->maxBrightness; 41 | TC0->COUNT8.CC[0].reg = this->currentBrightness; 42 | while(TC0->COUNT8.SYNCBUSY.bit.CC0); 43 | } 44 | /** 45 | * @brief Sets maximum brightness. 46 | * @param [in] maxBrightness new value of maximum brightness. If the current brightness value exceeds maximum brightness, the current brightness will be clipped. 47 | * 48 | */ 49 | void setMaxBrightness(std::uint8_t maxBrightness) 50 | { 51 | this->maxBrightness = maxBrightness; 52 | if( this->currentBrightness > this->maxBrightness ) { 53 | this->currentBrightness = this->maxBrightness; 54 | } 55 | TC0->COUNT8.PER.reg = this->maxBrightness; 56 | while(TC0->COUNT8.SYNCBUSY.bit.PER); 57 | TC0->COUNT8.CC[0].reg = this->currentBrightness; 58 | while(TC0->COUNT8.SYNCBUSY.bit.CC0); 59 | } 60 | 61 | /** 62 | * @brief Initialize hardware/peripherals to control back light brightness. 63 | * @remark This function must be called before using other LCDBackLight class member functions. 64 | */ 65 | void initialize() 66 | { 67 | /* Enable Peripheral Clocks */ 68 | GCLK->PCHCTRL[9].reg = 0 | (1u<<6); // TC0, TC1 69 | while(!GCLK->PCHCTRL[9].bit.CHEN); 70 | GCLK->PCHCTRL[11].reg = 0 | (1u<<6); // EVSYS[0] 71 | while(!GCLK->PCHCTRL[11].bit.CHEN); 72 | GCLK->PCHCTRL[33].reg = 0 | (1u<<6); // CCL 73 | while(!GCLK->PCHCTRL[33].bit.CHEN); 74 | /* Enable Peropheral APB Clocks */ 75 | MCLK->APBAMASK.bit.TC0_ = 1; 76 | MCLK->APBBMASK.bit.EVSYS_ = 1; 77 | MCLK->APBCMASK.bit.CCL_ = 1; 78 | 79 | /* Configure PORT */ 80 | PORT->Group[2].DIRSET.reg = (1<<5); 81 | PORT->Group[2].EVCTRL.reg = 0x85; // PC05, OUT 82 | /* Configure EVSYS */ 83 | EVSYS->USER[1].reg = 0x01; // Channel0 -> PORT_EV0 84 | EVSYS->Channel[0].CHANNEL.reg = 0x74 | (0x02<<8) | (0x00<<10); // CCL_LUTOUT0, ASYNCHRONOUS, NO_EVT_OUTPUT 85 | /* Configure CCL */ 86 | CCL->CTRL.reg = (1<<0); // SWRST 87 | CCL->SEQCTRL[0].reg = 0x0; // Disable SEQCTRL 88 | CCL->LUTCTRL[0].reg = (0xaau << 24) | (1u<<22) | (0x6<<8) | (1<<1); // TRUTH=0xaa, LUTEO, INSEL0=0x06(TC), ENABLE 89 | CCL->CTRL.reg = (1<<1); // ENABLE 90 | 91 | /* Configure TC0 */ 92 | TC0->COUNT8.CTRLA.reg = (1u<<0); // SWRST; 93 | while( TC0->COUNT8.SYNCBUSY.bit.SWRST ); 94 | 95 | TC0->COUNT8.CTRLA.reg = (0x01 << 2) | (0x01 << 4) | (0x04 << 8); // MODE=COUNT8, PRESCALER=DIV16, PRESCSYNC=PRESC 96 | TC0->COUNT8.WAVE.reg = 0x02; // WAVEGEN=NPWM; 97 | TC0->COUNT8.CTRLBSET.reg = (1u<<1); // LUPD 98 | TC0->COUNT8.PER.reg = this->maxBrightness; 99 | TC0->COUNT8.CC[0].reg = this->currentBrightness; 100 | TC0->COUNT8.CC[1].reg = 0u; 101 | TC0->COUNT8.DBGCTRL.bit.DBGRUN = 1; 102 | TC0->COUNT8.INTFLAG.reg = 0x33; // Clear all flags 103 | while( TC0->COUNT8.SYNCBUSY.reg ); 104 | 105 | TC0->COUNT8.CTRLA.bit.ENABLE = 1; // ENABLE 106 | while( TC0->COUNT8.SYNCBUSY.bit.ENABLE ); 107 | } 108 | }; 109 | #endif //LCD_BACKLIGHT_HPP__ -------------------------------------------------------------------------------- /examples/WioTerminal_Blynk_Edgent/BlynkEdgent.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkEdgent.h 3 | * @author Blynk Inc. 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2021 Blynk Inc. 6 | * @date May 2021 7 | * @brief 8 | * 9 | */ 10 | 11 | extern "C" { 12 | void app_loop(); 13 | void eraseMcuConfig(); 14 | void restartMCU(); 15 | } 16 | 17 | #include "Settings.h" 18 | #include 19 | 20 | #ifndef BLYNK_NEW_LIBRARY 21 | #error "Old version of Blynk library is in use. Please replace it with the new one." 22 | #endif 23 | 24 | #include "BlynkState.h" 25 | #include "ConfigStore.h" 26 | #include "ResetButton.h" 27 | #include "ConfigMode.h" 28 | #include "Indicator.h" 29 | //#include "OTA.h" 30 | 31 | inline 32 | void BlynkState::set(State m) { 33 | if (state != m && m < MODE_MAX_VALUE) { 34 | DEBUG_PRINT(String(StateStr[state]) + " => " + StateStr[m]); 35 | state = m; 36 | 37 | // You can put your state handling here, 38 | // i.e. implement custom indication 39 | } 40 | } 41 | 42 | void printDeviceBanner() 43 | { 44 | Blynk.printBanner(); 45 | DEBUG_PRINT("--------------------------"); 46 | DEBUG_PRINT(String("Product: ") + BLYNK_DEVICE_NAME); 47 | DEBUG_PRINT(String("Hardware: ") + BOARD_HARDWARE_VERSION); 48 | DEBUG_PRINT(String("Firmware: ") + BLYNK_FIRMWARE_VERSION " (build " __DATE__ " " __TIME__ ")"); 49 | if (configStore.getFlag(CONFIG_FLAG_VALID)) { 50 | DEBUG_PRINT(String("Token: ...") + (configStore.cloudToken+28)); 51 | } 52 | DEBUG_PRINT(String("Device: ") + BLYNK_INFO_DEVICE); 53 | DEBUG_PRINT(String("MAC: ") + WiFi.macAddress()); 54 | DEBUG_PRINT("--------------------------"); 55 | } 56 | 57 | void runBlynkWithChecks() { 58 | Blynk.run(); 59 | if (BlynkState::get() == MODE_RUNNING) { 60 | if (!Blynk.connected()) { 61 | if (WiFi.status() == WL_CONNECTED) { 62 | BlynkState::set(MODE_CONNECTING_CLOUD); 63 | } else { 64 | BlynkState::set(MODE_CONNECTING_NET); 65 | } 66 | } 67 | } 68 | } 69 | 70 | class Edgent { 71 | 72 | public: 73 | void begin() 74 | { 75 | //indicator_init(); 76 | button_init(); 77 | config_init(); 78 | 79 | WiFi.persistent(false); 80 | WiFi.enableSTA(true); // Needed to get MAC 81 | 82 | printDeviceBanner(); 83 | 84 | if (configStore.getFlag(CONFIG_FLAG_VALID)) { 85 | BlynkState::set(MODE_CONNECTING_NET); 86 | } else if (config_load_blnkopt()) { 87 | DEBUG_PRINT("Firmware is preprovisioned"); 88 | BlynkState::set(MODE_CONNECTING_NET); 89 | } else { 90 | BlynkState::set(MODE_WAIT_CONFIG); 91 | } 92 | } 93 | 94 | void run() { 95 | app_loop(); 96 | switch (BlynkState::get()) { 97 | case MODE_WAIT_CONFIG: 98 | case MODE_CONFIGURING: enterConfigMode(); break; 99 | case MODE_CONNECTING_NET: enterConnectNet(); break; 100 | case MODE_CONNECTING_CLOUD: enterConnectCloud(); break; 101 | case MODE_RUNNING: runBlynkWithChecks(); break; 102 | //case MODE_OTA_UPGRADE: enterOTA(); break; 103 | case MODE_SWITCH_TO_STA: enterSwitchToSTA(); break; 104 | case MODE_RESET_CONFIG: enterResetConfig(); break; 105 | default: enterError(); break; 106 | } 107 | } 108 | 109 | }; 110 | 111 | Edgent BlynkEdgent; 112 | BlynkTimer timer; 113 | 114 | void app_loop() { 115 | timer.run(); 116 | } 117 | -------------------------------------------------------------------------------- /examples/WioTerminal_Blynk_Edgent/BlynkState.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkState.h 3 | * @author Blynk Inc. 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2021 Blynk Inc. 6 | * @date May 2021 7 | * @brief 8 | * 9 | */ 10 | 11 | enum State { 12 | MODE_WAIT_CONFIG, 13 | MODE_CONFIGURING, 14 | MODE_CONNECTING_NET, 15 | MODE_CONNECTING_CLOUD, 16 | MODE_RUNNING, 17 | //MODE_OTA_UPGRADE, 18 | MODE_SWITCH_TO_STA, 19 | MODE_RESET_CONFIG, 20 | MODE_ERROR, 21 | 22 | MODE_MAX_VALUE 23 | }; 24 | 25 | #if defined(APP_DEBUG) 26 | const char* StateStr[MODE_MAX_VALUE+1] = { 27 | "WAIT_CONFIG", 28 | "CONFIGURING", 29 | "CONNECTING_NET", 30 | "CONNECTING_CLOUD", 31 | "RUNNING", 32 | //"OTA_UPGRADE", 33 | "SWITCH_TO_STA", 34 | "RESET_CONFIG", 35 | "ERROR", 36 | 37 | "INIT" 38 | }; 39 | #endif 40 | 41 | namespace BlynkState 42 | { 43 | volatile State state = MODE_MAX_VALUE; 44 | 45 | State get() { return state; } 46 | bool is (State m) { return (state == m); } 47 | void set(State m); 48 | }; 49 | -------------------------------------------------------------------------------- /examples/WioTerminal_Blynk_Edgent/ConfigStore.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ConfigStore.h 3 | * @author Blynk Inc. 4 | * @modified Dmitry Maslov (Seeed Studio) 5 | * @license This project is released under the MIT License (MIT) 6 | * @copyright Copyright (c) 2021 Blynk Inc. 7 | * @date May 2021 8 | * @brief 9 | * 10 | */ 11 | 12 | #define CONFIG_FLAG_VALID 0x01 13 | #define CONFIG_FLAG_STATIC_IP 0x02 14 | 15 | #define BLYNK_PROV_ERR_NONE 0 // All good 16 | #define BLYNK_PROV_ERR_CONFIG 700 // Invalid config from app (malformed token,etc) 17 | #define BLYNK_PROV_ERR_NETWORK 701 // Could not connect to the router 18 | #define BLYNK_PROV_ERR_CLOUD 702 // Could not connect to the cloud 19 | #define BLYNK_PROV_ERR_TOKEN 703 // Invalid token error (after connection) 20 | #define BLYNK_PROV_ERR_INTERNAL 704 // Other issues (i.e. hardware failure) 21 | 22 | struct ConfigStore { 23 | uint32_t magic; 24 | char version[15]; 25 | uint8_t flags; 26 | 27 | char wifiSSID[34]; 28 | char wifiPass[64]; 29 | 30 | char cloudToken[34]; 31 | char cloudHost[34]; 32 | uint16_t cloudPort; 33 | 34 | uint32_t staticIP; 35 | uint32_t staticMask; 36 | uint32_t staticGW; 37 | uint32_t staticDNS; 38 | uint32_t staticDNS2; 39 | 40 | int last_error; 41 | 42 | void setFlag(uint8_t mask, bool value) { 43 | if (value) { 44 | flags |= mask; 45 | } else { 46 | flags &= ~mask; 47 | } 48 | } 49 | 50 | bool getFlag(uint8_t mask) { 51 | return (flags & mask) == mask; 52 | } 53 | 54 | } __attribute__((packed)); 55 | 56 | ConfigStore configStore; 57 | 58 | const ConfigStore configDefault = { 59 | 0x626C6E6B, 60 | BLYNK_FIRMWARE_VERSION, 61 | 0x00, 62 | 63 | "", 64 | "", 65 | 66 | "invalid token", 67 | CONFIG_DEFAULT_SERVER, 68 | CONFIG_DEFAULT_PORT, 69 | 0, 70 | BLYNK_PROV_ERR_NONE 71 | }; 72 | 73 | template 74 | void CopyString(const String& s, T(&arr)[size]) { 75 | s.toCharArray(arr, size); 76 | } 77 | 78 | static bool config_load_blnkopt() 79 | { 80 | static const char blnkopt[] = "blnkopt\0" 81 | BLYNK_PARAM_KV("ssid" , BLYNK_PARAM_PLACEHOLDER_64 82 | BLYNK_PARAM_PLACEHOLDER_64 83 | BLYNK_PARAM_PLACEHOLDER_64 84 | BLYNK_PARAM_PLACEHOLDER_64) 85 | BLYNK_PARAM_KV("host" , CONFIG_DEFAULT_SERVER) 86 | BLYNK_PARAM_KV("port" , BLYNK_TOSTRING(CONFIG_DEFAULT_PORT)) 87 | "\0"; 88 | 89 | BlynkParam prov(blnkopt+8, sizeof(blnkopt)-8-2); 90 | BlynkParam::iterator ssid = prov["ssid"]; 91 | BlynkParam::iterator pass = prov["pass"]; 92 | BlynkParam::iterator auth = prov["auth"]; 93 | BlynkParam::iterator host = prov["host"]; 94 | BlynkParam::iterator port = prov["port"]; 95 | 96 | if (!(ssid.isValid() && auth.isValid())) { 97 | return false; 98 | } 99 | 100 | // reset to defaut before loading values from blnkopt 101 | configStore = configDefault; 102 | 103 | if (ssid.isValid()) { CopyString(ssid.asStr(), configStore.wifiSSID); } 104 | if (pass.isValid()) { CopyString(pass.asStr(), configStore.wifiPass); } 105 | if (auth.isValid()) { CopyString(auth.asStr(), configStore.cloudToken); } 106 | if (host.isValid()) { CopyString(host.asStr(), configStore.cloudHost); } 107 | if (port.isValid()) { configStore.cloudPort = port.asInt(); } 108 | 109 | return true; 110 | } 111 | 112 | #include 113 | const sfud_flash *_flash = sfud_get_device_table() + 0; 114 | 115 | void config_load() 116 | { 117 | 118 | uint8_t has_config; 119 | sfud_err result = sfud_read(_flash, 0, 1, &has_config); 120 | 121 | if (has_config == 0) 122 | { 123 | DEBUG_PRINT("Using default config."); 124 | configStore = configDefault; 125 | return; 126 | } 127 | 128 | memset(&configStore, 0, sizeof(configStore)); 129 | 130 | uint8_t b[sizeof(configStore)]; 131 | 132 | result = sfud_read(_flash, 1, sizeof(b), b); 133 | memcpy(&configStore, b, sizeof(configStore)); 134 | 135 | } 136 | 137 | bool config_save() 138 | { 139 | 140 | sfud_err result = sfud_erase(_flash, 0, sizeof(configStore)+1); 141 | delay(100); 142 | if (!result == SFUD_SUCCESS) { DEBUG_PRINT("Erase flash data failed"); return false; } 143 | 144 | uint8_t b[sizeof(configStore)]; 145 | memcpy(b, &configStore, sizeof(configStore)); 146 | 147 | uint8_t status = 1; 148 | result = sfud_write(_flash, 0, sizeof(status), &status); 149 | delay(10); 150 | 151 | if (!result == SFUD_SUCCESS) { DEBUG_PRINT("Write the flash data failed"); return false; } 152 | 153 | result = sfud_write(_flash, 1, sizeof(b), b); 154 | delay(50); 155 | 156 | if (!result == SFUD_SUCCESS) { DEBUG_PRINT("Write the flash data failed"); return false; } 157 | 158 | DEBUG_PRINT("Configuration stored to flash"); 159 | return true; 160 | } 161 | 162 | bool config_init() 163 | { 164 | if (sfud_init() != SFUD_SUCCESS) { DEBUG_PRINT("SFUD init failed"); return false; } 165 | 166 | sfud_qspi_fast_read_enable(sfud_get_device(SFUD_W25Q32_DEVICE_INDEX), 2); 167 | 168 | config_load(); 169 | return true; 170 | } 171 | 172 | void enterResetConfig() 173 | { 174 | DEBUG_PRINT("Resetting configuration!"); 175 | configStore = configDefault; 176 | config_save(); 177 | //eraseMcuConfig(); 178 | BlynkState::set(MODE_WAIT_CONFIG); 179 | } 180 | 181 | void config_set_last_error(int error) { 182 | // Only set error if not provisioned 183 | if (!configStore.getFlag(CONFIG_FLAG_VALID)) { 184 | configStore = configDefault; 185 | 186 | sfud_err result = sfud_erase(_flash, 0, 1); 187 | 188 | configStore.last_error = error; 189 | BLYNK_LOG2("Last error code: ", error); 190 | config_save(); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /examples/WioTerminal_Blynk_Edgent/Indicator.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Indicator.h 3 | * @author Blynk Inc. 4 | * @modified Dmitry Maslov (Seeed Studio) 5 | * @license This project is released under the MIT License (MIT) 6 | * @copyright Copyright (c) 2021 Blynk Inc. 7 | * @date May 2021 8 | * @brief 9 | * 10 | */ 11 | 12 | void indicator_run(); 13 | 14 | #if !defined(BOARD_LED_BRIGHTNESS) 15 | #define BOARD_LED_BRIGHTNESS 255 16 | #endif 17 | 18 | #define DIMM(x) ((x)*(BOARD_LED_BRIGHTNESS)/255) 19 | #define RGB(r,g,b) (DIMM(r) << 16 | DIMM(g) << 8 | DIMM(b) << 0) 20 | 21 | class Indicator { 22 | public: 23 | 24 | enum Colors { 25 | COLOR_BLACK = RGB(0x00, 0x00, 0x00), 26 | COLOR_WHITE = RGB(0xFF, 0xFF, 0xE7), 27 | COLOR_BLUE = RGB(0x0D, 0x36, 0xFF), 28 | COLOR_BLYNK = RGB(0x2E, 0xFF, 0xB9), 29 | COLOR_RED = RGB(0xFF, 0x10, 0x08), 30 | COLOR_MAGENTA = RGB(0xA7, 0x00, 0xFF), 31 | }; 32 | 33 | Indicator() { 34 | m_Counter = 0; 35 | initLED(); 36 | } 37 | 38 | uint32_t run() { 39 | State currState = BlynkState::get(); 40 | 41 | // Reset counter if indicator state changes 42 | if (m_PrevState != currState) { 43 | m_PrevState = currState; 44 | m_Counter = 0; 45 | } 46 | 47 | if (g_buttonPressed) { 48 | if (millis() - g_buttonPressTime > BUTTON_HOLD_TIME_ACTION) { return beatLED(COLOR_WHITE, (int[]){ 100, 100 }); } 49 | if (millis() - g_buttonPressTime > BUTTON_HOLD_TIME_INDICATION) { return waveLED(COLOR_WHITE, 1000); } 50 | } 51 | switch (currState) { 52 | case MODE_RESET_CONFIG: 53 | case MODE_WAIT_CONFIG: return beatLED(COLOR_BLUE, (int[]){ 50, 500 }); 54 | case MODE_CONFIGURING: return beatLED(COLOR_BLUE, (int[]){ 200, 200 }); 55 | case MODE_CONNECTING_NET: return beatLED(COLOR_BLYNK, (int[]){ 50, 500 }); 56 | case MODE_CONNECTING_CLOUD: return beatLED(COLOR_BLYNK, (int[]){ 100, 100 }); 57 | case MODE_RUNNING: return waveLED(COLOR_BLYNK, 5000); 58 | //case MODE_OTA_UPGRADE: return beatLED(COLOR_MAGENTA, (int[]){ 50, 50 }); 59 | default: return beatLED(COLOR_RED, (int[]){ 80, 100, 80, 1000 } ); 60 | } 61 | } 62 | 63 | protected: 64 | 65 | /* 66 | * LED drivers 67 | */ 68 | 69 | #if defined(BOARD_LED_PIN) // Single color LED 70 | 71 | void initLED() { 72 | pinMode(LED_BUILTIN, OUTPUT); 73 | } 74 | 75 | void setLED(uint32_t color) { 76 | #if BOARD_LED_INVERSE 77 | analogWrite(LED_BUILTIN, BOARD_PWM_MAX - color); 78 | #else 79 | analogWrite(LED_BUILTIN, color); 80 | #endif 81 | } 82 | 83 | #else 84 | 85 | #warning Invalid LED configuration. 86 | void initLED() {} 87 | void setLED(uint32_t color) {} 88 | 89 | #endif 90 | 91 | /* 92 | * Animations 93 | */ 94 | 95 | uint32_t skipLED() { 96 | return 20; 97 | } 98 | 99 | template 100 | uint32_t beatLED(uint32_t, const T& beat) { 101 | const uint8_t cnt = sizeof(beat)/sizeof(beat[0]); 102 | setLED((m_Counter % 2 == 0) ? DIMM(BOARD_PWM_MAX) : 0); 103 | uint32_t next = beat[m_Counter % cnt]; 104 | m_Counter = (m_Counter+1) % cnt; 105 | return next; 106 | } 107 | 108 | uint32_t waveLED(uint32_t, unsigned breathePeriod) { 109 | uint8_t brightness = (m_Counter < 128) ? m_Counter : 255 - m_Counter; 110 | 111 | setLED(BOARD_PWM_MAX * (DIMM((float)brightness) / (BOARD_PWM_MAX/2))); 112 | 113 | // This function relies on the 8-bit, unsigned m_Counter rolling over. 114 | m_Counter = (m_Counter+1) % 256; 115 | return breathePeriod / 256; 116 | } 117 | 118 | private: 119 | uint8_t m_Counter; 120 | State m_PrevState; 121 | }; 122 | 123 | Indicator indicator; 124 | 125 | /* 126 | * Animation timers 127 | */ 128 | 129 | #if defined(USE_TC3) 130 | 131 | #include 132 | 133 | void indicator_run() { 134 | uint32_t returnTime = indicator.run(); 135 | if (returnTime) { 136 | TimerTc3.initialize(returnTime*1000); 137 | } 138 | } 139 | 140 | void indicator_init() { 141 | TimerTc3.initialize(100*1000); 142 | TimerTc3.attachInterrupt(indicator_run); 143 | } 144 | 145 | #elif defined(USE_TCC0) 146 | 147 | #include 148 | 149 | void indicator_run() { 150 | uint32_t returnTime = indicator.run(); 151 | if (returnTime) { 152 | Timer3.initialize(returnTime*1000); 153 | } 154 | } 155 | 156 | void indicator_init() { 157 | Timer3.initialize(100*1000); 158 | Timer3.attachInterrupt(indicator_run); 159 | } 160 | 161 | #else 162 | 163 | #warning LED indicator needs a functional timer! 164 | 165 | void indicator_run() {} 166 | void indicator_init() {} 167 | 168 | #endif 169 | -------------------------------------------------------------------------------- /examples/WioTerminal_Blynk_Edgent/OTA.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | String overTheAirURL; 7 | 8 | extern BlynkTimer timer; 9 | 10 | BLYNK_WRITE(InternalPinOTA) { 11 | overTheAirURL = param.asString(); 12 | 13 | timer.setTimeout(2000L, [](){ 14 | // Start OTA 15 | Blynk.logEvent("sys_ota", "OTA started"); 16 | 17 | // Disconnect, not to interfere with OTA process 18 | Blynk.disconnect(); 19 | 20 | BlynkState::set(MODE_OTA_UPGRADE); 21 | }); 22 | } 23 | 24 | void enterOTA() { 25 | BlynkState::set(MODE_OTA_UPGRADE); 26 | 27 | DEBUG_PRINT(String("Firmware update URL: ") + overTheAirURL); 28 | 29 | HTTPClient http; 30 | http.begin(overTheAirURL); 31 | 32 | int httpCode = http.GET(); 33 | if (httpCode != HTTP_CODE_OK) { 34 | DEBUG_PRINT("HTTP response should be 200"); 35 | BlynkState::set(MODE_ERROR); 36 | return; 37 | } 38 | int contentLength = http.getSize(); 39 | if (contentLength <= 0) { 40 | DEBUG_PRINT("Content-Length not defined"); 41 | BlynkState::set(MODE_ERROR); 42 | return; 43 | } 44 | 45 | bool canBegin = Update.begin(contentLength); 46 | if (!canBegin) { 47 | DEBUG_PRINT("Not enough space to begin OTA"); 48 | BlynkState::set(MODE_ERROR); 49 | return; 50 | } 51 | 52 | Client& client = http.getStream(); 53 | int written = Update.writeStream(client); 54 | if (written != contentLength) { 55 | DEBUG_PRINT(String("OTA written ") + written + " / " + contentLength + " bytes"); 56 | BlynkState::set(MODE_ERROR); 57 | return; 58 | } 59 | 60 | if (!Update.end()) { 61 | DEBUG_PRINT("Error #" + String(Update.getError())); 62 | BlynkState::set(MODE_ERROR); 63 | return; 64 | } 65 | 66 | if (!Update.isFinished()) { 67 | DEBUG_PRINT("Update failed."); 68 | BlynkState::set(MODE_ERROR); 69 | return; 70 | } 71 | 72 | DEBUG_PRINT("=== Update successfully completed. Rebooting."); 73 | restartMCU(); 74 | } 75 | 76 | -------------------------------------------------------------------------------- /examples/WioTerminal_Blynk_Edgent/ResetButton.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ResetButton.h 3 | * @author Blynk Inc. 4 | * @modified Dmitry Maslov (Seeed Studio) 5 | * @license This project is released under the MIT License (MIT) 6 | * @copyright Copyright (c) 2021 Blynk Inc. 7 | * @date May 2021 8 | * @brief 9 | * 10 | */ 11 | 12 | volatile bool g_buttonPressed = false; 13 | volatile uint32_t g_buttonPressTime = -1; 14 | 15 | void button_action(void) 16 | { 17 | BlynkState::set(MODE_RESET_CONFIG); 18 | } 19 | 20 | void button_change(void) 21 | { 22 | #if BOARD_BUTTON_ACTIVE_LOW 23 | bool buttonState = !digitalRead(BOARD_BUTTON_PIN); 24 | #else 25 | bool buttonState = digitalRead(BOARD_BUTTON_PIN); 26 | #endif 27 | 28 | if (buttonState && !g_buttonPressed) { 29 | g_buttonPressTime = millis(); 30 | g_buttonPressed = true; 31 | DEBUG_PRINT("Hold the button for 10 seconds to reset configuration..."); 32 | } else if (!buttonState && g_buttonPressed) { 33 | g_buttonPressed = false; 34 | uint32_t buttonHoldTime = millis() - g_buttonPressTime; 35 | if (buttonHoldTime >= BUTTON_HOLD_TIME_ACTION) { 36 | button_action(); 37 | } else { 38 | // User action 39 | } 40 | g_buttonPressTime = -1; 41 | } 42 | } 43 | 44 | void button_init() 45 | { 46 | #if BOARD_BUTTON_ACTIVE_LOW 47 | pinMode(BOARD_BUTTON_PIN, INPUT_PULLUP); 48 | #else 49 | pinMode(BOARD_BUTTON_PIN, INPUT_PULLDOWN); 50 | #endif 51 | attachInterrupt(BOARD_BUTTON_PIN, button_change, CHANGE); 52 | } 53 | -------------------------------------------------------------------------------- /examples/WioTerminal_Blynk_Edgent/Settings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * General options 3 | */ 4 | 5 | #define BOARD_HARDWARE_VERSION "1.0.0" 6 | 7 | /* 8 | * Board configuration (see examples below). 9 | */ 10 | 11 | // Custom board configuration 12 | #define BOARD_BUTTON_PIN WIO_KEY_A // Pin where user button is attached 13 | #define BOARD_BUTTON_ACTIVE_LOW true // true if button is "active-low" 14 | 15 | #define BOARD_LED_PIN LED_BUILTIN // Set LED pin - if you have a single-color LED attached 16 | #define BOARD_LED_INVERSE false // true if LED is common anode, false if common cathode 17 | #define BOARD_LED_BRIGHTNESS 255 // 0..255 brightness control 18 | 19 | /** 20 | * @file Settings.h 21 | * @author Blynk Inc. 22 | * @modified Dmitry Maslov (Seeed Studio) 23 | * @license This project is released under the MIT License (MIT) 24 | * @copyright Copyright (c) 2021 Blynk Inc. 25 | * @date May 2021 26 | * @brief 27 | * 28 | */ 29 | 30 | /* 31 | * Advanced options 32 | */ 33 | 34 | #define BUTTON_HOLD_TIME_INDICATION 3000 35 | #define BUTTON_HOLD_TIME_ACTION 10000 36 | 37 | #define BOARD_PWM_MAX 1023 38 | 39 | #define LEDC_CHANNEL_1 1 40 | #define LEDC_CHANNEL_2 2 41 | #define LEDC_CHANNEL_3 3 42 | #define LEDC_TIMER_BITS 10 43 | #define LEDC_BASE_FREQ 12000 44 | 45 | #define CONFIG_AP_URL "blynk.setup" 46 | #define CONFIG_DEFAULT_SERVER "blynk.cloud" 47 | #define CONFIG_DEFAULT_PORT 80 48 | 49 | 50 | #define WIFI_NET_CONNECT_TIMEOUT 30000 51 | #define WIFI_CLOUD_CONNECT_TIMEOUT 30000 52 | #define WIFI_AP_CONFIG_PORT 80 53 | #define WIFI_AP_IP IPAddress(192, 168, 4, 1) 54 | #define WIFI_AP_Subnet IPAddress(255, 255, 255, 0) 55 | #define WIFI_CAPTIVE_PORTAL_ENABLE 1 56 | 57 | //#define USE_TC3 58 | //#define USE_TCC0 59 | 60 | //#define BLYNK_NO_DEFAULT_BANNER 61 | 62 | #if defined(APP_DEBUG) 63 | #define DEBUG_PRINT(...) BLYNK_LOG1(__VA_ARGS__) 64 | #else 65 | #define DEBUG_PRINT(...) 66 | #endif 67 | -------------------------------------------------------------------------------- /examples/WioTerminal_Blynk_Edgent/WioTerminal_Blynk_Edgent.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Edgent_Wio_Terminal.ino 3 | * @author Blynk Inc. 4 | * @modified Dmitry Maslov (Seeed Studio) 5 | * @license This project is released under the MIT License (MIT) 6 | * @copyright Copyright (c) 2021 Blynk Inc. 7 | * @date May 2021 8 | * @brief 9 | * 10 | */ 11 | 12 | // Fill-in information from your Blynk Template here 13 | #define BLYNK_TEMPLATE_ID "" 14 | #define BLYNK_DEVICE_NAME "" 15 | 16 | #define BLYNK_FIRMWARE_VERSION "0.1.0" 17 | 18 | #define BLYNK_PRINT Serial 19 | //#define BLYNK_DEBUG 20 | 21 | #define APP_DEBUG 22 | 23 | #include "BlynkEdgent.h" 24 | 25 | void sendData() { 26 | 27 | 28 | uint16_t noise = analogRead(WIO_MIC); 29 | uint16_t light = analogRead(WIO_LIGHT); 30 | 31 | String str = String(noise); 32 | Blynk.virtualWrite(V0, str); 33 | Serial.println(str); 34 | str = String(light); 35 | Blynk.virtualWrite(V1, str); 36 | Serial.println(str); 37 | } 38 | 39 | void setup() 40 | { 41 | 42 | Serial.begin(115200); 43 | delay(100); 44 | 45 | #ifdef APP_DEBUG 46 | while (!Serial) {delay(10);} 47 | #endif 48 | 49 | BlynkEdgent.begin(); 50 | timer.setInterval(1000L, sendData); 51 | } 52 | 53 | void loop() { 54 | BlynkEdgent.run(); 55 | } 56 | -------------------------------------------------------------------------------- /examples/WioTerminal_ButtonMouseControl/WioTerminal_ButtonMouseControl.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * A demo for Wio Terminal to simulate mouse by buttons. 3 | * Such as Mouse Up, Mouse Down, Mouse Left, Mouse Right, 4 | * Click the left mouse button, Click the right mouse button, 5 | * Up roll, Down roll and etc. 6 | * 7 | * Copyright (c) 2020 seeed technology co., ltd. 8 | * Author : weihong.cai (weihong.cai@seeed.cc) 9 | * Create Time : July 2020 10 | * Change Log : 11 | * 12 | * The MIT License (MIT) 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy 15 | * of this software and associated documentation files (the "Software"), to deal 16 | * in the Software without restriction, including without limitation the rights 17 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | * copies of the Software, and to permit persons to whom the Software istm 19 | * furnished to do so, subject to the following conditions: 20 | * 21 | * The above copyright notice and this permission notice shall be included in 22 | * all copies or substantial portions of the Software. 23 | * 24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS INcommInterface 30 | * THE SOFTWARE. 31 | * 32 | * Usage(in Wio Terminal): 33 | * Press the WIO_5S_UP --------------------> Mouse Up 34 | * Press the WIO_5S_DOWN --------------------> Mouse Down 35 | * Press the WIO_5S_LEFT --------------------> Mouse Left 36 | * Press the WIO_5S_RIGHT --------------------> Mouse Right 37 | * Press the BUTTON_3 ------------------------> Click the left mouse button 38 | * Press the BUTTON_2 ------------------------> Click the right mouse button 39 | * Press the WIO_5S_PRESS and WIO_5S_UP ----> Up roll 40 | * Press the WIO_5S_PRESS and WIO_5S_DOWN ----> Down roll 41 | * 42 | * Some tips: 43 | * 1. If your PC unables to recognize USB device leading the Wio Terminal can’t work. 44 | * You can solve this problem through updating your ArduinoCore. 45 | * Please follow this: https://forum.seeedstudio.com/t/seeeduino-xiao-cant-simulate-keys-pressed/252819/6?u=weihong.cai 46 | * 47 | * You can know more about the Wio Terminal from: https://wiki.seeedstudio.com/Wio-Terminal-Getting-Started/ 48 | * If you have any questions, you can leave a message on the forum: https://forum.seeedstudio.com 49 | */ 50 | 51 | #include "Mouse.h" 52 | 53 | /*----------------define the button pins---------------------------*/ 54 | const int upButton = WIO_5S_UP; 55 | const int downButton = WIO_5S_DOWN; 56 | const int leftButton = WIO_5S_LEFT; 57 | const int rightButton = WIO_5S_RIGHT; 58 | const int mouseWheel = WIO_5S_PRESS; 59 | const int mouseBttonLeft = BUTTON_3; 60 | const int mouseBttonRight = BUTTON_2; 61 | 62 | // output range of X or Y movement; affects movement speed 63 | int range = 2; 64 | 65 | // response delay of the mouse, in ms 66 | int responseDelay = 5; 67 | 68 | // the time record paramas 69 | unsigned long _currentMillis; 70 | unsigned long _previousMillis; 71 | 72 | void setup() { 73 | // initialize the buttons' inputs: 74 | pinMode(upButton, INPUT); 75 | pinMode(downButton, INPUT); 76 | pinMode(leftButton, INPUT); 77 | pinMode(rightButton, INPUT); 78 | pinMode(mouseWheel, INPUT); 79 | pinMode(mouseBttonLeft, INPUT); 80 | pinMode(mouseBttonRight, INPUT); 81 | 82 | // initialize mouse control: 83 | Mouse.begin(); 84 | } 85 | 86 | void loop() { 87 | // read the button state: 88 | int upState = digitalRead(upButton); 89 | int downState = digitalRead(downButton); 90 | int rightState = digitalRead(rightButton); 91 | int leftState = digitalRead(leftButton); 92 | int clickState_mouseWheel = digitalRead(mouseWheel); 93 | int clickState_mouseButtonLeft = digitalRead(mouseBttonLeft); 94 | int clickState_mouseButtonRight = digitalRead(mouseBttonRight); 95 | 96 | // calculate the movement distance based on the button states: 97 | int xDistance = (leftState - rightState) * range; 98 | int yDistance = (upState - downState) * range; 99 | 100 | /*------------------Mouse Move--------------------------------------*/ 101 | // if X or Y is non-zero, move: 102 | if ((xDistance != 0) || (yDistance != 0)) { 103 | Mouse.move(xDistance, yDistance, 0); 104 | } 105 | 106 | /*-------------Mouse Button Left Click------------------------------*/ 107 | // if the mouse button left is pressed: 108 | if (clickState_mouseButtonLeft == LOW) { 109 | // if the mouse is not pressed, press it: 110 | if (!Mouse.isPressed(MOUSE_LEFT)) { 111 | Mouse.press(MOUSE_LEFT); 112 | //Mouse.click(MOUSE_LEFT); 113 | } 114 | } 115 | // else the mouse button left is not pressed: 116 | else { 117 | // if the mouse is pressed, release it: 118 | if (Mouse.isPressed(MOUSE_LEFT)) { 119 | Mouse.release(MOUSE_LEFT); 120 | } 121 | } 122 | 123 | /*-------------Mouse Button Right Click-----------------------------*/ 124 | // if the mouse button right is pressed: 125 | if (clickState_mouseButtonRight == LOW) { 126 | // if the mouse is not pressed, press it: 127 | if (!Mouse.isPressed(MOUSE_RIGHT)) { 128 | Mouse.press(MOUSE_RIGHT); 129 | //Mouse.click(MOUSE_RIGHT); 130 | } 131 | } 132 | // else the mouse button right is not pressed: 133 | else { 134 | // if the mouse is pressed, release it: 135 | if (Mouse.isPressed(MOUSE_RIGHT)) { 136 | Mouse.release(MOUSE_RIGHT); 137 | } 138 | } 139 | 140 | /*------------------Up roll----------------------------------------*/ 141 | if ((upState == LOW) && (clickState_mouseWheel == LOW)) { 142 | Mouse.move(0, 0, 1); 143 | My_delay(200); 144 | } 145 | 146 | /*------------------Down roll--------------------------------------*/ 147 | if ((downState == LOW) && (clickState_mouseWheel == LOW)) { 148 | Mouse.move(0, 0, -1); 149 | My_delay(200); 150 | } 151 | 152 | /*-----------------------------------------------------------------*/ 153 | // a delay so the mouse doesn't move too fast: 154 | My_delay(responseDelay); 155 | } 156 | 157 | // a delay function uses millis() 158 | void My_delay(int Time) 159 | { 160 | while((_currentMillis - _previousMillis) <= Time) 161 | { 162 | _currentMillis = millis(); 163 | } 164 | _previousMillis = _currentMillis; 165 | } 166 | -------------------------------------------------------------------------------- /examples/WioTerminal_ButtonMouseControl/WioTerminal_ButtonMouseControl_demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/WioTerminal_ButtonMouseControl/WioTerminal_ButtonMouseControl_demo.gif -------------------------------------------------------------------------------- /examples/WioTerminal_Face/WioTerminal_Face.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | Servo myservo; 4 | 5 | //int outpin=D2; 6 | 7 | int counter = 0; 8 | int i = 0; 9 | static LGFX lcd; 10 | static LGFX_Sprite sprite(&lcd); 11 | 12 | int pos = 0; 13 | 14 | void drawEye(int x, int y) { 15 | sprite.clear(); 16 | sprite.fillCircle(65,65,60,0xFFFF); 17 | //sprite.drawEllipse(65,65,60,30,0xFFFF); 18 | //sprite.drawFastHLine(5,62,120,0xFF); 19 | sprite.fillCircle(x,y,15,0); 20 | sprite.fillArc(65,65,60,1,180,360,0xED6E); 21 | sprite.setPivot(65,65); 22 | sprite.pushRotateZoom(80,70,0,1,0.5); 23 | sprite.pushRotateZoom(240,70,0,1,0.5); 24 | } 25 | 26 | void sleepyEyes() { 27 | int p_rect[4][4] = {{9,65,112,22},{22,65,86,41},{40,65,49,55},{63,65,4,59}}; 28 | sprite.clear(); 29 | sprite.fillCircle(65,65,60,0xFFFF); 30 | sprite.fillCircle(65,70,10,0); 31 | //sprite.fillArc(65,65,60,1,180,360,0xED6E); 32 | sprite.setPivot(65,65); 33 | for (int i=0;i<4;i++) { 34 | sprite.fillArc(65,65,60,1,180,360,0xED6E); 35 | sprite.fillArc(65,65,60,1,0,22*(i+1),0xED6E); 36 | sprite.fillArc(65,65,60,1,180-(22*(i+1)),180,0xED6E); 37 | sprite.fillRect(p_rect[i][0],p_rect[i][1],p_rect[i][2],p_rect[i][3],0xED6E); 38 | sprite.pushRotateZoom(80,70,0,1,0.5); 39 | sprite.pushRotateZoom(240,70,0,1,0.5); 40 | delay(200); 41 | } 42 | delay(2000); 43 | //sprite.pushRotateZoom(80,70,0,1,0.5); 44 | //sprite.pushRotateZoom(240,70,0,1,0.5); 45 | } 46 | 47 | 48 | void setup() { 49 | pinMode(WIO_5S_UP, INPUT_PULLUP); 50 | pinMode(WIO_5S_DOWN, INPUT_PULLUP); 51 | 52 | myservo.attach(0); 53 | 54 | lcd.init(); 55 | lcd.setRotation(3); 56 | lcd.setBrightness(128); 57 | lcd.setColorDepth(16); 58 | lcd.clear(); 59 | 60 | sprite.setColorDepth(16); 61 | sprite.createSprite(130, 130); 62 | drawEye(50,80); 63 | lcd.drawArc(160,90,120,119,30,150,0xE800); 64 | 65 | } 66 | 67 | void loop() { 68 | int x = random(15, 115); 69 | 70 | for (pos = 0; pos <= 60; pos += 1) { 71 | int l = pos + 20; 72 | drawEye(l,80); 73 | myservo.write(pos); 74 | delay(80); 75 | } 76 | 77 | for (pos = 60; pos >= 0; pos -= 1) { 78 | int l = pos; 79 | drawEye(l,80); 80 | myservo.write(pos); 81 | delay(80); 82 | } 83 | 84 | delay(3000); 85 | 86 | sleepyEyes(); 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /examples/WioTerminal_Level/WioTerminal_Level.ino: -------------------------------------------------------------------------------- 1 | #include"LIS3DHTR.h" 2 | #include "TFT_eSPI.h" 3 | #include 4 | 5 | LIS3DHTR lis; 6 | TFT_eSPI tft; 7 | 8 | void disp_sight() { 9 | tft.drawCircle(159,119,90,TFT_WHITE); 10 | tft.drawCircle(159,119,60,TFT_WHITE); 11 | tft.drawCircle(159,119,30,TFT_WHITE); 12 | tft.drawLine(159,29,159,209,TFT_WHITE); 13 | tft.drawLine(69,119,249,119,TFT_WHITE); 14 | tft.fillCircle(159,119,3,TFT_RED); 15 | 16 | tft.fillRoundRect(56,215,206,20,10,TFT_DARKGREEN); 17 | tft.fillRoundRect(295,16,20,206,10,TFT_DARKGREEN); 18 | 19 | } 20 | 21 | void setup() { 22 | Serial.begin(115200); 23 | // while (!Serial); 24 | pinMode(WIO_5S_UP, INPUT_PULLUP); 25 | pinMode(WIO_5S_DOWN, INPUT_PULLUP); 26 | 27 | lis.begin(Wire1); 28 | 29 | if (!lis) { 30 | Serial.println("ERROR"); 31 | while(1); 32 | } 33 | lis.setOutputDataRate(LIS3DHTR_DATARATE_25HZ); //Data output rate 34 | lis.setFullScaleRange(LIS3DHTR_RANGE_2G); //Scale range set to 2g 35 | 36 | // Display set up 37 | tft.begin(); 38 | tft.setRotation(3); 39 | tft.setTextColor(TFT_YELLOW); 40 | tft.setTextSize(2); 41 | tft.fillScreen(TFT_BLACK); 42 | disp_sight(); 43 | tft.drawString("Angle", 5, 20); 44 | tft.drawString("X: ", 10, 40); 45 | tft.drawString("Y: ", 10, 60); 46 | tft.drawString("Accel.", 5, 120); 47 | tft.drawString("X: ", 10, 140); 48 | tft.drawString("Y: ", 10, 160); 49 | tft.drawString("Z: ", 10, 180); 50 | tft.drawString("Scale", 238, 20); 51 | } 52 | 53 | int p_plot_x = 159, p_plot_y = 119; 54 | int scale = 1, p_scale = 5; 55 | 56 | void loop() { 57 | float x_values, y_values, z_values; 58 | int plot_x, plot_y; 59 | x_values = lis.getAccelerationX(); 60 | y_values = lis.getAccelerationY(); 61 | z_values = lis.getAccelerationZ(); 62 | /* 63 | Serial.print("X: "); Serial.print(x_values); 64 | Serial.print(" Y: "); Serial.print(y_values); 65 | Serial.print(" Z: "); Serial.print(z_values); 66 | Serial.println(); 67 | */ 68 | tft.fillRect(50,40,72,35,TFT_BLACK); 69 | tft.fillRect(50,140,72,55,TFT_BLACK); 70 | tft.drawString(String(180.0/3.1415*asin(x_values)), 50, 40); 71 | tft.drawString(String(180.0/3.1415*asin(y_values)), 50, 60); 72 | tft.drawString(String(x_values), 50, 140); 73 | tft.drawString(String(y_values), 50, 160); 74 | tft.drawString(String(z_values), 50, 180); 75 | if (scale != p_scale) { 76 | tft.fillRect(260,41,25,20,TFT_BLACK); 77 | tft.drawString(String(scale), 260, 41); 78 | } 79 | 80 | tft.fillCircle(p_plot_x,p_plot_y,10,TFT_BLACK); 81 | tft.fillRect(p_plot_x+3,215,6,20,TFT_DARKGREEN); 82 | tft.fillRect(295,p_plot_y-3,20,6,TFT_DARKGREEN); 83 | disp_sight(); 84 | plot_x = 159 + scale*(90.0/3.1415 * 2 * asin(y_values)); 85 | if (plot_x > 249) plot_x = 249; 86 | if (plot_x < 69) plot_x = 69; 87 | plot_y = 119 - scale*(90.0/3.1415 * 2 * asin(x_values)); 88 | if (plot_y > 209) plot_y = 209; 89 | if (plot_y < 29) plot_y = 29; 90 | tft.fillCircle(plot_x,plot_y,10,TFT_YELLOW); 91 | tft.fillRect(plot_x-3,215,6,20,TFT_WHITE); 92 | tft.drawLine(plot_x,215,plot_x,235,TFT_BLACK); 93 | tft.fillRect(295,plot_y-3,20,6,TFT_WHITE); 94 | tft.drawLine(295,plot_y,315,plot_y,TFT_BLACK); 95 | 96 | if (digitalRead(WIO_5S_UP) == LOW) { 97 | scale++; 98 | if (scale > 5) scale = 5; 99 | while(digitalRead(WIO_5S_UP) == LOW); 100 | } 101 | if (digitalRead(WIO_5S_DOWN) == LOW) { 102 | scale--; 103 | if (scale <1) scale = 1; 104 | while(digitalRead(WIO_5S_DOWN) == LOW); 105 | } 106 | 107 | p_plot_x = plot_x; 108 | p_plot_y = plot_y; 109 | 110 | delay(50); 111 | } 112 | -------------------------------------------------------------------------------- /examples/WioTerminal_MP3_Player/RawImage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | 6 | /* 7 | USAGE: 8 | 9 | // when use 8bit color. 10 | Raw8 * img8 = newImage("path to sd card image."); 11 | 12 | // when use 16bit color. 13 | Raw16 * img16 = newImage("path to sd card image."); 14 | 15 | // do some drawing. 16 | // img8->draw(); 17 | 18 | // remember release it 19 | img8->release(); 20 | img16->release(); 21 | */ 22 | 23 | extern TFT_eSPI tft; 24 | 25 | template 26 | struct RawImage{ 27 | type * ptr(){ 28 | return (type *)(this + 1); 29 | } 30 | type get(int16_t x, int16_t y){ 31 | return this->ptr()[y * width() + x]; 32 | } 33 | void draw(size_t x = 0, size_t y = 0){ 34 | tft.pushImage(x, y, width(), height(), ptr()); 35 | } 36 | void release(){ 37 | delete [] this; 38 | } 39 | int16_t width(){ return _width; } 40 | int16_t height(){ return _height; } 41 | private: 42 | int16_t _width; 43 | int16_t _height; 44 | }; 45 | 46 | typedef RawImage Raw8; 47 | typedef RawImage Raw16; 48 | 49 | template 50 | RawImage * newImage(const char * path){ 51 | typedef RawImage raw; 52 | File f = SD.open(path, FILE_READ); 53 | if (!f){ 54 | return nullptr; 55 | } 56 | int32_t size = f.size(); 57 | raw * mem = (raw *)new uint8_t[size]; 58 | if (mem == nullptr){ 59 | return nullptr; 60 | } 61 | f.read(mem, size); 62 | f.close(); 63 | return mem; 64 | } 65 | 66 | template 67 | void drawImage(const char * path, size_t x = 0, size_t y = 0){ 68 | auto img = newImage(path); 69 | img->draw(x, y); 70 | img->release(); 71 | } 72 | -------------------------------------------------------------------------------- /examples/WioTerminal_PC_Stats_Display/PC_stats_display/PC_stats_display.ino: -------------------------------------------------------------------------------- 1 | //Libraries 2 | #include "TFT_eSPI.h" //TFT LCD library 3 | #include "Free_Fonts.h" //include the font library 4 | 5 | //Initializations 6 | TFT_eSPI tft; //Initializing TFT LCD 7 | TFT_eSprite spr = TFT_eSprite(&tft); //Initializing buffer 8 | 9 | void setup() { 10 | Serial.begin(9600); //start serial communication 11 | tft.begin(); //Start TFT LCD 12 | tft.setRotation(3); //Set LCD rotation 13 | spr.createSprite(TFT_HEIGHT,TFT_WIDTH); //Create buffer 14 | } 15 | 16 | //initialize data types for variables 17 | String serialReceive; 18 | String CPUstat; 19 | String cpufreq; 20 | String UsedMemStr; 21 | String FreeMemStr; 22 | String hddUsed; 23 | String hddFree; 24 | String ssdUsed; 25 | String ssdFree; 26 | String GPUstat; 27 | String GPUused; 28 | 29 | void loop() { 30 | if(Serial.available() > 0) { //check whether if any data is available in serial buffer 31 | serialReceive = Serial.readString(); //read it as string and put into serialReceive variable 32 | } 33 | 34 | CPUstat = serialReceive.substring(0, 5); //split the received long string to substrings. (5 characters/information) 35 | cpufreq = serialReceive.substring(5, 10); 36 | UsedMemStr = serialReceive.substring(10, 15); 37 | FreeMemStr = serialReceive.substring(15, 20); 38 | ssdUsed = serialReceive.substring(20, 25); 39 | ssdFree = serialReceive.substring(25, 30); 40 | hddUsed = serialReceive.substring(30, 35); 41 | hddFree = serialReceive.substring(35, 40); 42 | GPUstat = serialReceive.substring(40, 45); 43 | GPUused = serialReceive.substring(45, 50); 44 | 45 | spr.fillSprite(tft.color565(0,255,255)); //Fill background with white color 46 | 47 | spr.drawFastHLine(0,84,320,TFT_BLACK); //Draw horizontal line 48 | spr.drawFastHLine(0,143,320,TFT_BLACK); 49 | 50 | //CPU name 51 | spr.setTextColor(TFT_BLACK); //set text color 52 | spr.setFreeFont(FSSB12); //set font 53 | spr.drawString("RYZEN 3700X",5,5); //draw string 54 | 55 | //CPU stats 56 | spr.setFreeFont(FSS12); 57 | spr.drawString("Util: ",10,35); 58 | spr.drawString(CPUstat,70,35); 59 | spr.drawString("%",120,35); 60 | spr.drawString("Speed: ",10,60); 61 | spr.drawString(cpufreq,75,60); 62 | spr.drawString("GHz",118,60); 63 | 64 | //GPU name 65 | spr.setFreeFont(FSSB12); 66 | spr.drawString("GTX 1660S",180,5); 67 | 68 | //GPU stats 69 | spr.setFreeFont(FSS12); 70 | spr.drawString("Util: ",170,35); 71 | spr.drawString(GPUstat,235,35); 72 | spr.drawString("%",275,35); 73 | spr.drawString("Used: ",170,60); 74 | spr.drawString(GPUused,230,60); 75 | spr.drawString("GB",280,60); 76 | 77 | //RAM name 78 | spr.setFreeFont(FSSB12); 79 | spr.drawString("32GB DDR4",10,90); 80 | 81 | //RAM stats 82 | spr.setFreeFont(FSS12); 83 | spr.drawString("Used: ",10,120); 84 | spr.drawString(UsedMemStr,70,120); 85 | spr.drawString("GB",120,120); 86 | spr.drawString("Free: ",170,120); 87 | spr.drawString(FreeMemStr,230,120); 88 | spr.drawString("GB",280,120); 89 | 90 | //SSD and HDD names 91 | spr.setFreeFont(FSSB12); 92 | spr.drawString("500GB SSD",10,150); 93 | spr.drawString("1TB HDD",170,150); 94 | 95 | //SSD stats 96 | spr.setFreeFont(FSS12); 97 | spr.drawString("Used: ",10,180); 98 | spr.drawString(ssdUsed,70,180); 99 | spr.drawString("GB",125,180); 100 | spr.drawString("Free: ",10,210); 101 | spr.drawString(ssdFree,70,210); 102 | spr.drawString("GB",125,210); 103 | 104 | spr.drawFastVLine(165,0,84,TFT_BLACK); //draw vertical line 105 | spr.drawFastVLine(165,143,240,TFT_BLACK); 106 | 107 | //HDD stats 108 | spr.setFreeFont(FSS12); 109 | spr.drawString("Used: ",170,180); 110 | spr.drawString(hddUsed,225,180); 111 | spr.drawString("GB",280,180); 112 | spr.drawString("Free: ",170,210); 113 | spr.drawString(hddFree,225,210); 114 | spr.drawString("GB",280,210); 115 | 116 | spr.pushSprite(0,0); //Push to LCD 117 | delay(50); 118 | 119 | } 120 | -------------------------------------------------------------------------------- /examples/WioTerminal_PC_Stats_Display/PC_stats_send.py: -------------------------------------------------------------------------------- 1 | # include libraries 2 | import psutil # monitor CPU, RAM, Disks 3 | import serial # send data through serial interface 4 | from gpuinfo import GPUInfo # monitor GPU 5 | 6 | #pySerial settings 7 | ser = serial.Serial() # make instance of Serial 8 | ser.baudrate = 9600 # set serial baud rate 9 | ser.port = "COM4" # set serial port, replace with the port your Wio Terminal is connceted to the PC 10 | ser.open() # open the serial port 11 | 12 | while True: # while loop 13 | 14 | # CPU Utilization 15 | cpu = psutil.cpu_percent(interval=1.2) # get usage of CPU in percentage with interval of 1.2s 16 | 17 | if cpu < 10: 18 | cpuStr = " " + str(cpu) # if CPU usage is under 10%, put 2 artificial characters (spaces) before the value (to make 5 spaces in total) 19 | elif cpu < 100: 20 | cpuStr = " " + str(cpu) # here the same, but only 1 space. because 85.6 have only 4 characters 21 | else: 22 | cpuStr = str(cpu) #100.0 is 5 characters so there is no need to put spaces in before 23 | 24 | # CPU Speed 25 | cpufreq = round(psutil.cpu_freq().current/1000, 1) # get cpu frequency, divide by 1000 because 1GHz = 1000MHz, round to one decimal place 26 | cpufreqStr = " " + str(cpufreq) # convert to string and make 5 spaces in total 27 | 28 | # GPU Info 29 | percent,memory = GPUInfo.gpu_usage() # get GPU utilization and used memory info 30 | 31 | # GPU Utilization 32 | percentNum = percent[0] # obtain number from the percent list 33 | 34 | if percentNum < 10: # same as for CPU (make 5 spaces) 35 | percentStr = " " + str(percentNum) 36 | elif percentNum < 100: 37 | percentStr = " " + str(percentNum) 38 | else: 39 | percentStr = " " + str(percentNum) 40 | 41 | # GPU Used Memory 42 | memoryNum = round(memory[0] / 1024, 1) # obtain number from the memory list and round to one decimal place 43 | memoryStr = " " + str(memoryNum) # convert to string and make 5 spaces in total 44 | 45 | # RAM Used 46 | ramUsed = round(psutil.virtual_memory().used / 1073741824,1) # 1GB = 1073741824bytes 47 | 48 | if ramUsed < 10: # make 5 spaces in total 49 | ramUsedStr = " " + str(ramUsed) 50 | else: 51 | ramUsedStr = " " + str(ramUsed) 52 | 53 | # RAM Free 54 | ramFree = (round(psutil.virtual_memory().free / 1073741824,1)) 55 | 56 | if ramFree < 10: # make 5 spaces in total 57 | ramFreeStr = " " + str(ramFree) 58 | else: 59 | ramFreeStr = " " + str(ramFree) 60 | 61 | # SSD and HDD Usage 62 | sddused = round(psutil.disk_usage("C:").used / 1073741824) # get used space of C: disk (SSD) 63 | sddfree = round(psutil.disk_usage("C:").free / 1073741824) # get free space of C: disk (SSD) 64 | hddused = round(psutil.disk_usage("D:").used / 1073741824) # get free space of D: disk (HDD) 65 | hddfree = round(psutil.disk_usage("D:").free / 1073741824) # get free space of D: disk (HDD) 66 | 67 | if sddused < 100: # make 5 spaces in total 68 | sddUsedStr = " " + str(sddused) 69 | else: 70 | sddUsedStr = " " + str(sddused) 71 | 72 | if sddfree < 100: 73 | sddFreeStr = " " + str(sddfree) 74 | else: 75 | sddFreeStr = " " + str(sddfree) 76 | 77 | if hddused < 100: 78 | hddUsedStr = " " + str(hddused) 79 | else: 80 | hddUsedStr = " " + str(hddused) 81 | 82 | if hddfree < 100: 83 | hddFreeStr = " " + str(hddfree) 84 | else: 85 | hddFreeStr = " " + str(hddfree) 86 | 87 | serialDataStr = cpuStr + cpufreqStr + ramUsedStr + ramFreeStr + sddUsedStr + sddFreeStr + hddUsedStr + hddFreeStr + percentStr + memoryStr # concatenate all strings together by using "+" operand to form one long string of data 88 | serialDataBytes = serialDataStr.encode("UTF-8") # encode it to UTF-8 standard, since the strings should be a series of BYTES 89 | 90 | print(serialDataBytes) # print serial string, used for debugging 91 | ser.write(serialDataBytes) # send the long encoded string throught serial interface 92 | 93 | ser.close() 94 | -------------------------------------------------------------------------------- /examples/WioTerminal_PC_Stats_Display/README.md: -------------------------------------------------------------------------------- 1 | # PC Stats Display on Wio Terminal 2 | 3 | ## Introduction 4 | 5 | This demo can be used to display various different statistics of your computer such as: 6 | - CPU Utilization 7 | - CPU Speed 8 | - GPU Utilization 9 | - GPU Used Memory 10 | - Used Memory 11 | - Free Memory 12 | - Used SSD/ HDD 13 | - Free SSD/ HDD 14 | 15 | It simply grabs all the information from the computer using a Python script and sends that information to the Wio Terminal via serial interface and displays on the Wio Terminal LCD. 16 | Here [pyserial](https://pypi.org/project/pyserial/), [psutil](https://pypi.org/project/psutil/) and [gpuinfo](https://pypi.org/project/gpuinfo/) libraries are used for the Python code. 17 | 18 |

pir

19 | 20 | ## Prerequisites 21 | - [Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html) 22 | - [Arduino](https://www.arduino.cc/en/software) installed on PC 23 | - [Python](https://www.python.org/downloads/) installed on PC 24 | 25 | 26 | 27 | ## How to Use? 28 | - Upload `PC_stats_display.ino` to Wio Terminal 29 | - Navigate to the location of the folder containing the .py file on command prompt 30 | ```sh 31 | Example: 32 | C:\Users\user\Desktop>WioTerminal_PC_Stats 33 | ``` 34 | - Run the .py using the below command 35 | ```python 36 | python PC_stats_send.py 37 | ``` 38 | 39 |

pir

40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /examples/WioTerminal_TF_MNIST/WioTerminal_TF_MNIST.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tensorflow/lite/micro/all_ops_resolver.h" 3 | #include "tensorflow/lite/micro/micro_error_reporter.h" 4 | #include "tensorflow/lite/micro/micro_interpreter.h" 5 | #include "tensorflow/lite/schema/schema_generated.h" 6 | #include "tensorflow/lite/version.h" 7 | #include "model.h" 8 | #include "mnist.h" 9 | #include"TFT_eSPI.h" 10 | 11 | TFT_eSPI tft; 12 | TFT_eSprite spr = TFT_eSprite(&tft); // Sprite 13 | 14 | namespace { 15 | // Globals 16 | const tflite::Model* model = nullptr; 17 | tflite::MicroInterpreter* interpreter = nullptr; 18 | tflite::ErrorReporter* reporter = nullptr; 19 | TfLiteTensor* input = nullptr; 20 | TfLiteTensor* output = nullptr; 21 | constexpr int kTensorArenaSize = 8000; // Just pick a big enough number 22 | uint8_t tensor_arena[ kTensorArenaSize ] = { 0 }; 23 | float *input_buffer=nullptr; 24 | } // namespace 25 | 26 | 27 | float display_buffer[28224]; 28 | 29 | void bitmap_to_float_array( float* dest, const unsigned char* bitmap ) { // Populate input_vec with the monochrome 1bpp bitmap 30 | int pixel = 0; 31 | for( int y = 0; y < 28; y++ ) { 32 | for( int x = 0; x < 28; x++ ) { 33 | int B = x / 8; // the Byte # of the row 34 | int b = x % 8; // the Bit # of the Byte 35 | dest[ pixel ] = ( bitmap[ y * 4 + B ] >> ( 7 - b ) ) & 36 | 0x1 ? 1.0f : 0.0f; 37 | pixel++; 38 | } 39 | } 40 | } 41 | 42 | void draw_input_buffer() { 43 | 44 | int pre_i, pre_j, after_i, after_j;//缩放前后对应的像素点坐标 45 | 46 | for (int i = 0; i<168; i++) 47 | { 48 | for (int j = 0; j<168; j++) 49 | { 50 | after_i = i; 51 | after_j = j; 52 | pre_i = (int)(after_i / 6);/////取整,插值方法为:最邻近插值(近邻取样法) 53 | pre_j = (int)(after_j / 6); 54 | if (pre_i >= 0 && pre_i < 28 && pre_j >= 0 && pre_j < 28)//在原图范围内 55 | *(display_buffer + i * 168 + j) = *(input_buffer + pre_i * 28 + pre_j); 56 | } 57 | } 58 | 59 | for(int cy = 0; cy < 168; cy++) 60 | { 61 | for(int cx = 0; cx < 168; cx++) 62 | { 63 | 64 | tft.drawPixel( cx + 76, cy, display_buffer[ cy * 168 + cx ] > 0 ? 0xFFFFFFFF : 0xFF000000 ); 65 | 66 | } 67 | } 68 | 69 | 70 | } 71 | 72 | void print_input_buffer() { 73 | char output[ 28 * 29 ]; // Each row should end row newline 74 | for( int y = 0; y < 28; y++ ) { 75 | for( int x = 0; x < 28; x++ ) { 76 | output[ y * 29 + x ] = input_buffer[ y * 28 + x ] > 0 ? ' ' : '#'; 77 | } 78 | output[ y * 29 + 28 ] = '\n'; 79 | } 80 | reporter->Report( output ); 81 | } 82 | 83 | 84 | 85 | void setup() { 86 | // Load Model 87 | //Serial.begin(115200); 88 | static tflite::MicroErrorReporter error_reporter; 89 | reporter = &error_reporter; 90 | reporter->Report( "Let's use AI to recognize some numbers!" ); 91 | 92 | model = tflite::GetModel( tf_model ); 93 | if( model->version() != TFLITE_SCHEMA_VERSION ) { 94 | reporter->Report( "Model is schema version: %d\nSupported schema version is: %d", model->version(), TFLITE_SCHEMA_VERSION ); 95 | return; 96 | } 97 | // Setup our TF runner 98 | static tflite::AllOpsResolver resolver; 99 | static tflite::MicroInterpreter static_interpreter( 100 | model, resolver, tensor_arena, kTensorArenaSize, reporter ); 101 | interpreter = &static_interpreter; 102 | 103 | // Allocate memory from the tensor_arena for the model's tensors. 104 | TfLiteStatus allocate_status = interpreter->AllocateTensors(); 105 | if( allocate_status != kTfLiteOk ) { 106 | reporter->Report( "AllocateTensors() failed" ); 107 | return; 108 | } 109 | 110 | // Obtain pointers to the model's input and output tensors. 111 | input = interpreter->input(0); 112 | output = interpreter->output(0); 113 | 114 | // Save the input buffer to put our MNIST images into 115 | input_buffer = input->data.f; 116 | tft.begin(); 117 | tft.setRotation(3); 118 | tft.fillScreen(TFT_BLACK); // fills entire the screen with colour red 119 | tft.setTextColor(TFT_RED); 120 | tft.setTextSize(2); 121 | tft.drawString("It looks like the number:",0,200);//prints string at (70,80) 122 | TFT_eSprite spr = TFT_eSprite(&tft); // Sprite 123 | 124 | 125 | } 126 | 127 | void loop() { 128 | // Pick a random test image for input 129 | const int num_test_images = ( sizeof( test_images ) / sizeof( *test_images ) ); 130 | 131 | 132 | bitmap_to_float_array( input_buffer, test_images[ rand() % num_test_images ] ); 133 | 134 | draw_input_buffer(); 135 | //print_input_buffer(); 136 | // Run our model 137 | TfLiteStatus invoke_status = interpreter->Invoke(); 138 | if( invoke_status != kTfLiteOk ) { 139 | reporter->Report( "Invoke failed" ); 140 | return; 141 | } 142 | 143 | float* result = output->data.f; 144 | 145 | reporter->Report( "It looks like the number: %d", std::distance( result, std::max_element( result, result + 10 ) ) ); 146 | // tft.drawNumber(std::distance( result, std::max_element( result, result + 10 ) ), 300, 200), 147 | spr.createSprite(20, 20); 148 | // spr.fillSprite(TFT_RED); 149 | spr.setTextColor(TFT_RED); 150 | spr.setTextSize(2); 151 | spr.drawNumber(std::distance( result, std::max_element( result, result + 10 ) ),0, 0); 152 | spr.pushSprite(300, 200); 153 | spr.deleteSprite(); 154 | // Wait 1-sec til before running again 155 | delay( 200 ); 156 | 157 | } 158 | -------------------------------------------------------------------------------- /examples/WioTerminal_Timer/WioTerminal_Timer.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static LGFX lcd; 4 | static LGFX_Sprite ttext(&lcd); 5 | static LGFX_Sprite arc(&lcd); 6 | static LGFX_Sprite sp(&lcd); 7 | static auto transpalette = 0; 8 | 9 | unsigned int set_time = 180, pset_time = 0; 10 | unsigned int rm_time; 11 | int c_status = 0; 12 | unsigned long p_millis, c_millis; 13 | int c_pos = 0, p_pos = 0; 14 | int sound = 1; 15 | int pos[] = {91,123,167,199}; 16 | int inc[] = {600,60,10,1}; 17 | 18 | void disp_time(int d_min, int d_sec){ // Display Timer 19 | arc.pushRotateZoom(160,120,0,1.5,1); 20 | ttext.setCursor(0, 0); 21 | ttext.setTextColor(0xFFE0, 0); 22 | ttext.printf("%02d:%02d", d_min, d_sec); 23 | ttext.pushRotateZoom(160,115,0,1,1); 24 | 25 | } 26 | 27 | void pipipi() { // Alarm sound 28 | int j; 29 | while (digitalRead(WIO_KEY_C) == HIGH) { 30 | if (sound == 1) { 31 | j++; 32 | if (j>3)j=1; 33 | for (int i=0; i<3; i++){ 34 | digitalWrite(WIO_BUZZER, 1); 35 | delay(80); 36 | digitalWrite(WIO_BUZZER, 0); 37 | delay(80); 38 | Serial.print("11111"); 39 | } 40 | delay(100); 41 | } 42 | } 43 | } 44 | 45 | void setup() { 46 | Serial.begin(115200); 47 | pinMode(WIO_KEY_A, INPUT_PULLUP); 48 | pinMode(WIO_KEY_B, INPUT_PULLUP); 49 | pinMode(WIO_KEY_C, INPUT_PULLUP); 50 | pinMode(WIO_5S_UP, INPUT_PULLUP); 51 | pinMode(WIO_5S_DOWN, INPUT_PULLUP); 52 | pinMode(WIO_5S_LEFT, INPUT_PULLUP); 53 | pinMode(WIO_5S_RIGHT, INPUT_PULLUP); 54 | pinMode(WIO_5S_PRESS, INPUT_PULLUP); 55 | pinMode(WIO_BUZZER, OUTPUT); 56 | 57 | lcd.init(); 58 | lcd.setRotation(1); 59 | lcd.setBrightness(255); 60 | lcd.setColorDepth(16); 61 | lcd.clear(); 62 | 63 | // lcd.setTextColor(TFT_YELLOW); 64 | ttext.setFont(&fonts::Font7); 65 | lcd.fillScreen(TFT_BLACK); 66 | 67 | arc.setColorDepth(16); 68 | ttext.setColorDepth(16); 69 | sp.setColorDepth(16); 70 | arc.createSprite(240,160); 71 | ttext.createSprite(140,60); 72 | sp.createSprite(12,13); 73 | arc.fillScreen(transpalette); 74 | ttext.fillScreen(transpalette); 75 | sp.fillScreen(transpalette); 76 | arc.fillArc(80,80,60,80,0,360,0xC424); 77 | arc.setPivot(80,80); 78 | ttext.setPivot(70,15); 79 | // Speakericon 80 | sp.fillTriangle(5,0,5,13,0,6,0xFFFF); 81 | sp.fillRect(0,4,2,5,0xFFFF); 82 | sp.drawFastVLine(8,5,3,0xFFFF); 83 | sp.drawFastVLine(11,5,3,0xFFFF); 84 | sp.drawFastVLine(10,3,2,0xFFFF); 85 | sp.drawFastVLine(10,8,2,0xFFFF); 86 | sp.drawLine(8,1,10,3,0xFFFF); 87 | sp.drawLine(8,11,10,9,0xFFFF); 88 | sp.drawPixel(7,4,0xFFFF); 89 | sp.drawPixel(7,8,0xFFFF); 90 | sp.pushSprite(&lcd, 300, 5); 91 | lcd.setTextColor(0xFFE0, 0); 92 | pinMode(WIO_BUZZER, OUTPUT); 93 | } 94 | 95 | void loop() { 96 | int t_min, t_sec; 97 | 98 | if (digitalRead(WIO_5S_PRESS) == LOW) { // 5S Press button 99 | if (c_status == 0) { 100 | lcd.drawFastHLine(pos[c_pos],148,30,0); 101 | c_status = 1; // wait -> start 102 | rm_time = set_time; 103 | } 104 | else if (c_status == 1) c_status = 2; // start -> pause 105 | else if (c_status == 2) c_status = 1; // pause -> resume 106 | else c_status = 3; // time up 107 | 108 | while(digitalRead(WIO_5S_PRESS) == LOW); 109 | } 110 | 111 | if (digitalRead(WIO_KEY_C) == LOW) { // C button to Reset 112 | c_status = 0; 113 | arc.fillArc(80,80,60,80,0,360,0xC424); 114 | t_min = set_time/60; 115 | t_sec = set_time%60; 116 | disp_time(t_min, t_sec); 117 | lcd.drawFastHLine(pos[c_pos],148,30,0xFFFF); 118 | while(digitalRead(WIO_KEY_C) == LOW); 119 | } 120 | 121 | if (digitalRead(WIO_KEY_A) == LOW) { // A button to Alarm sound on/off 122 | if(sound == 1) { 123 | sound = 0; 124 | lcd.fillRect(300,5,15,15,0); 125 | } 126 | else { 127 | sound = 1; 128 | sp.pushSprite(&lcd, 300, 5); 129 | } 130 | while(digitalRead(WIO_KEY_A) == LOW); 131 | } 132 | 133 | if (c_status == 0 ) { // set up timer 134 | if (digitalRead(WIO_5S_RIGHT) == LOW) { // move set up cursor next 135 | lcd.drawFastHLine(pos[c_pos],148,30,0); 136 | c_pos++; 137 | if (c_pos > 3) c_pos = 0; 138 | lcd.drawFastHLine(pos[c_pos],148,30,0xFFFF); 139 | while(digitalRead(WIO_5S_RIGHT) == LOW); 140 | } 141 | if (digitalRead(WIO_5S_LEFT) == LOW) { // move set up cursor previous 142 | lcd.drawFastHLine(pos[c_pos],148,30,0); 143 | c_pos--; 144 | if (c_pos < 0) c_pos = 3; 145 | lcd.drawFastHLine(pos[c_pos],148,30,0xFFFF); 146 | while(digitalRead(WIO_5S_LEFT) == LOW); 147 | } 148 | 149 | if (digitalRead(WIO_5S_UP) == LOW) { // increase figure on cursor 150 | set_time += inc[c_pos]; 151 | if (set_time > 5999) set_time = 5999; 152 | while(digitalRead(WIO_5S_UP) == LOW); 153 | } 154 | 155 | if (digitalRead(WIO_5S_DOWN) == LOW) { // decrease figure on cursor 156 | set_time -= inc[c_pos]; 157 | if (set_time > 5999) { 158 | set_time += inc[c_pos]; 159 | set_time = set_time%inc[c_pos]; 160 | } 161 | while(digitalRead(WIO_5S_DOWN) == LOW); 162 | } 163 | 164 | if (set_time != pset_time) { 165 | t_min = set_time/60; 166 | t_sec = set_time%60; 167 | disp_time(t_min, t_sec); 168 | lcd.drawFastHLine(pos[c_pos],148,30,0xFFFF); 169 | } 170 | pset_time = set_time; 171 | } // end of c_status 0 172 | 173 | 174 | if (c_status == 1) { // count down timer 175 | c_millis = millis(); 176 | if( c_millis - p_millis >= 1000 ) { 177 | p_millis = c_millis; 178 | rm_time--; 179 | if (set_time > 5999) rm_time = 0; 180 | 181 | arc.clear(); 182 | if((360*rm_time)/set_time < 90) arc.fillArc(80,80,60,80,270,270+360*rm_time/set_time,0xC424); 183 | else arc.fillArc(80,80,60,80,270,(360*rm_time)/set_time-90,0xC424); 184 | arc.pushRotateZoom(160,120,0,1.5,1); 185 | 186 | t_min = rm_time/60; 187 | t_sec = rm_time%60; 188 | disp_time(t_min, t_sec); 189 | 190 | } //end of millis 191 | if (rm_time < 1) c_status = 3; 192 | } // end of c_status 1 193 | 194 | if (c_status == 3) { // timer reset 195 | pipipi(); 196 | c_status = 0; 197 | } 198 | } // end of loop 199 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_1_Intro/Wio_Terminal_EI_Rock_Paper_Scissors/Wio_Terminal_EI_Rock_Paper_Scissors.ino: -------------------------------------------------------------------------------- 1 | /* 2 | An example sketch for Edge Impulse trained model inference for Rock Paper Scissors classification with single Light sensor 3 | 4 | Copyright (c) 2021 Seeed technology co., ltd. 5 | Author : Dmitry Maslov 6 | Create Time : February 2021 7 | Change Log : 8 | 9 | The MIT License (MIT) 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | /* Includes ---------------------------------------------------------------- */ 31 | #include 32 | 33 | uint8_t axis_num = 1; 34 | 35 | /* Private variables ------------------------------------------------------- */ 36 | static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal 37 | 38 | /** 39 | * @brief Arduino setup function 40 | */ 41 | void setup() 42 | { 43 | // put your setup code here, to run once: 44 | Serial.begin(115200); 45 | Serial.println("Edge Impulse Inferencing Demo"); 46 | 47 | if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != axis_num) { 48 | ei_printf("ERR: EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME should be equal to (%d) (the (%d) sensor axes)\n", axis_num, axis_num); 49 | return; 50 | } 51 | } 52 | 53 | /** 54 | * @brief Printf function uses vsnprintf and output using Arduino Serial 55 | * 56 | * @param[in] format Variable argument list 57 | */ 58 | void ei_printf(const char *format, ...) { 59 | static char print_buf[1024] = { 0 }; 60 | 61 | va_list args; 62 | va_start(args, format); 63 | int r = vsnprintf(print_buf, sizeof(print_buf), format, args); 64 | va_end(args); 65 | 66 | if (r > 0) { 67 | Serial.write(print_buf); 68 | } 69 | } 70 | 71 | /** 72 | * @brief Get data and run inferencing 73 | * 74 | * @param[in] debug Get debug info if true 75 | */ 76 | void loop() 77 | { 78 | 79 | ei_printf("Sampling...\n"); 80 | 81 | // Allocate a buffer here for the values we'll read from the IMU 82 | float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = {0}; 83 | 84 | for (size_t ix = 0; ix < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; ix += axis_num) { 85 | // Determine the next tick (and then sleep later) 86 | uint64_t next_tick = micros() + (EI_CLASSIFIER_INTERVAL_MS * 1000); 87 | 88 | buffer[ix + 0] = analogRead(WIO_LIGHT); 89 | 90 | delayMicroseconds(next_tick - micros()); 91 | } 92 | 93 | // Turn the raw buffer in a signal which we can the classify 94 | signal_t signal; 95 | int err = numpy::signal_from_buffer(buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal); 96 | if (err != 0) { 97 | ei_printf("Failed to create signal from buffer (%d)\n", err); 98 | return; 99 | } 100 | 101 | // Run the classifier 102 | ei_impulse_result_t result = { 0 }; 103 | 104 | err = run_classifier(&signal, &result, debug_nn); 105 | if (err != EI_IMPULSE_OK) { 106 | ei_printf("ERR: Failed to run classifier (%d)\n", err); 107 | return; 108 | } 109 | 110 | // print the predictions 111 | ei_printf("Predictions "); 112 | ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)", 113 | result.timing.dsp, result.timing.classification, result.timing.anomaly); 114 | ei_printf(": \n"); 115 | for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) { 116 | ei_printf(" %s: %.5f\n", result.classification[ix].label, result.classification[ix].value); 117 | } 118 | #if EI_CLASSIFIER_HAS_ANOMALY == 1 119 | ei_printf(" anomaly score: %.3f\n", result.anomaly); 120 | #endif 121 | } 122 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_2_Audio_Scene_Recognition/WioTerminal_EI_Microphone_Inference_Blynk/WioTerminal_EI_Microphone_Inference_Blynk.ino: -------------------------------------------------------------------------------- 1 | /* 2 | An example sketch for Edge Impulse trained model inference for Audio scene classification and Blynk push notifications 3 | 4 | Copyright (c) 2021 Seeed technology co., ltd. 5 | Author : Dmitry Maslov 6 | Create Time : January 2021 7 | Change Log : 8 | 9 | The MIT License (MIT) 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | 31 | // If your target is limited in memory remove this macro to save 10K RAM 32 | #define EIDSP_QUANTIZE_FILTERBANK 0 33 | #define BLYNK_PRINT Serial 34 | 35 | /* Includes ---------------------------------------------------------------- */ 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | /** Audio buffers, pointers and selectors */ 42 | typedef struct { 43 | int16_t *buffer; 44 | uint8_t buf_ready; 45 | uint32_t buf_count; 46 | uint32_t n_samples; 47 | } inference_t; 48 | 49 | static inference_t inference; 50 | static signed short sampleBuffer[2048]; 51 | unsigned int sampling_period_us = round(600000 * (1.0 / 16000)); 52 | static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal 53 | 54 | char auth[] = "token"; 55 | char ssid[] = "ssid"; 56 | char pass[] = "password"; 57 | 58 | void infer() 59 | { 60 | ei_printf("Recording...\n"); 61 | 62 | bool m = microphone_inference_record(); 63 | if (!m) { 64 | ei_printf("ERR: Failed to record audio...\n"); 65 | return; 66 | } 67 | 68 | ei_printf("Recording done\n"); 69 | 70 | signal_t signal; 71 | signal.total_length = EI_CLASSIFIER_RAW_SAMPLE_COUNT; 72 | signal.get_data = µphone_audio_signal_get_data; 73 | ei_impulse_result_t result = { 0 }; 74 | 75 | EI_IMPULSE_ERROR r = run_classifier(&signal, &result, debug_nn); 76 | if (r != EI_IMPULSE_OK) { 77 | ei_printf("ERR: Failed to run classifier (%d)\n", r); 78 | return; 79 | } 80 | 81 | // print the predictions 82 | ei_printf("Predictions "); 83 | ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)", 84 | result.timing.dsp, result.timing.classification, result.timing.anomaly); 85 | ei_printf(": \n"); 86 | for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) { 87 | ei_printf(" %s: %.5f\n", result.classification[ix].label, result.classification[ix].value); 88 | } 89 | if (result.classification[1].value > 0.6) { Blynk.notify("Dog is barking"); } 90 | if (result.classification[2].value > 0.6) { Blynk.notify("Glass breaking"); } 91 | if (result.classification[3].value > 0.6) { Blynk.notify("Shots fired"); } 92 | } 93 | 94 | void setup() 95 | { 96 | // put your setup code here, to run once: 97 | Serial.begin(115200); 98 | Blynk.begin(auth, ssid, pass); 99 | Serial.println("Edge Impulse Inferencing Demo"); 100 | 101 | // summary of inferencing settings (from model_metadata.h) 102 | ei_printf("Inferencing settings:\n"); 103 | ei_printf("\tInterval: %.2f ms.\n", (float)EI_CLASSIFIER_INTERVAL_MS); 104 | ei_printf("\tFrame size: %d\n", EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE); 105 | ei_printf("\tSample length: %d ms.\n", EI_CLASSIFIER_RAW_SAMPLE_COUNT / 16); 106 | ei_printf("\tNo. of classes: %d\n", sizeof(ei_classifier_inferencing_categories) / sizeof(ei_classifier_inferencing_categories[0])); 107 | 108 | if (microphone_inference_start(EI_CLASSIFIER_RAW_SAMPLE_COUNT) == false) { 109 | ei_printf("ERR: Failed to setup audio sampling\r\n"); 110 | return; 111 | } 112 | } 113 | 114 | void loop() 115 | { 116 | Blynk.run(); 117 | infer(); 118 | } 119 | 120 | void ei_printf(const char *format, ...) { 121 | static char print_buf[1024] = { 0 }; 122 | 123 | va_list args; 124 | va_start(args, format); 125 | int r = vsnprintf(print_buf, sizeof(print_buf), format, args); 126 | va_end(args); 127 | 128 | if (r > 0) { 129 | Serial.write(print_buf); 130 | } 131 | } 132 | 133 | static bool microphone_inference_start(uint32_t n_samples) 134 | { 135 | inference.buffer = (int16_t *)malloc(n_samples * sizeof(int16_t)); 136 | 137 | if(inference.buffer == NULL) { 138 | return false; 139 | } 140 | 141 | inference.buf_count = 0; 142 | inference.n_samples = n_samples; 143 | inference.buf_ready = 0; 144 | pinMode(WIO_MIC, INPUT); 145 | 146 | return true; 147 | } 148 | 149 | static bool microphone_inference_record(void) 150 | { 151 | inference.buf_ready = 0; 152 | inference.buf_count = 0; 153 | 154 | if (inference.buf_ready == 0) { 155 | for(int i = 0; i < 8001; i++) { 156 | inference.buffer[inference.buf_count++] = map(analogRead(WIO_MIC), 0, 1023, -32768, 32767); 157 | delayMicroseconds(sampling_period_us); 158 | 159 | if(inference.buf_count >= inference.n_samples) { 160 | inference.buf_count = 0; 161 | inference.buf_ready = 1; 162 | break; 163 | } 164 | } 165 | } 166 | 167 | while(inference.buf_ready == 0) { 168 | delay(10); 169 | } 170 | 171 | return true; 172 | } 173 | 174 | static int microphone_audio_signal_get_data(size_t offset, size_t length, float *out_ptr) 175 | { 176 | numpy::int16_to_float(&inference.buffer[offset], out_ptr, length); 177 | 178 | return 0; 179 | } 180 | 181 | 182 | static void microphone_inference_end(void) 183 | { 184 | free(inference.buffer); 185 | } 186 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_3_People_Counting/WioTerminal_EI_People_Counting_Azure_Central_LVGL/AzureDpsClient.cpp: -------------------------------------------------------------------------------- 1 | #include "AzureDpsClient.h" 2 | #include 3 | #include 4 | 5 | static constexpr size_t SignatureMaxSize = 256; 6 | static constexpr size_t MqttClientIdMaxSize = 128; 7 | static constexpr size_t MqttUsernameMaxSize = 128; 8 | static constexpr size_t MqttPasswordMaxSize = 300; 9 | static constexpr size_t RegisterPublishTopicMaxSize = 128; 10 | static constexpr size_t QueryStatusPublishTopicMaxSize = 256; 11 | 12 | AzureDpsClient::AzureDpsClient() : 13 | ResponseValid{ false } 14 | { 15 | } 16 | 17 | int AzureDpsClient::Init(const std::string& endpoint, const std::string& idScope, const std::string& registrationId) 18 | { 19 | ResponseValid = false; 20 | 21 | Endpoint = endpoint; 22 | IdScope = idScope; 23 | RegistrationId = registrationId; 24 | 25 | const az_span endpointSpan{ az_span_create((uint8_t*)&Endpoint[0], Endpoint.size()) }; 26 | const az_span idScopeSpan{ az_span_create((uint8_t*)&IdScope[0], IdScope.size()) }; 27 | const az_span registrationIdSpan{ az_span_create((uint8_t*)&RegistrationId[0], RegistrationId.size()) }; 28 | if (az_result_failed(az_iot_provisioning_client_init(&ProvClient, endpointSpan, idScopeSpan, registrationIdSpan, NULL))) return -1; 29 | 30 | return 0; 31 | } 32 | 33 | std::vector AzureDpsClient::GetSignature(const uint64_t& expirationEpochTime) 34 | { 35 | uint8_t signature[SignatureMaxSize]; 36 | az_span signatureSpan = az_span_create(signature, sizeof(signature)); 37 | az_span signatureValidSpan; 38 | if (az_result_failed(az_iot_provisioning_client_sas_get_signature(&ProvClient, expirationEpochTime, signatureSpan, &signatureValidSpan))) return std::vector(); 39 | 40 | return std::vector(az_span_ptr(signatureValidSpan), az_span_ptr(signatureValidSpan) + az_span_size(signatureValidSpan)); 41 | } 42 | 43 | std::string AzureDpsClient::GetMqttClientId() 44 | { 45 | char mqttClientId[MqttClientIdMaxSize]; 46 | if (az_result_failed(az_iot_provisioning_client_get_client_id(&ProvClient, mqttClientId, sizeof(mqttClientId), NULL))) return std::string(); 47 | 48 | return mqttClientId; 49 | } 50 | 51 | std::string AzureDpsClient::GetMqttUsername() 52 | { 53 | char mqttUsername[MqttUsernameMaxSize]; 54 | if (az_result_failed(az_iot_provisioning_client_get_user_name(&ProvClient, mqttUsername, sizeof(mqttUsername), NULL))) return std::string(); 55 | 56 | return mqttUsername; 57 | } 58 | 59 | std::string AzureDpsClient::GetMqttPassword(const std::string& encryptedSignature, const uint64_t& expirationEpochTime) 60 | { 61 | char mqttPassword[MqttPasswordMaxSize]; 62 | az_span encryptedSignatureSpan = az_span_create((uint8_t*)&encryptedSignature[0], encryptedSignature.size()); 63 | if (az_result_failed(az_iot_provisioning_client_sas_get_password(&ProvClient, encryptedSignatureSpan, expirationEpochTime, AZ_SPAN_EMPTY, mqttPassword, sizeof(mqttPassword), NULL))) return std::string(); 64 | 65 | return mqttPassword; 66 | } 67 | 68 | std::string AzureDpsClient::GetRegisterPublishTopic() 69 | { 70 | char registerPublishTopic[RegisterPublishTopicMaxSize]; 71 | if (az_result_failed(az_iot_provisioning_client_register_get_publish_topic(&ProvClient, registerPublishTopic, sizeof(registerPublishTopic), NULL))) return std::string(); 72 | 73 | return registerPublishTopic; 74 | } 75 | 76 | std::string AzureDpsClient::GetRegisterSubscribeTopic() const 77 | { 78 | return AZ_IOT_PROVISIONING_CLIENT_REGISTER_SUBSCRIBE_TOPIC; 79 | } 80 | 81 | int AzureDpsClient::RegisterSubscribeWork(const std::string& topic, const std::vector& payload) 82 | { 83 | ResponseValid = false; 84 | 85 | ResponseTopic = topic; 86 | ResponsePayload = payload; 87 | 88 | if (az_result_failed(az_iot_provisioning_client_parse_received_topic_and_payload(&ProvClient, az_span_create((uint8_t*)&ResponseTopic[0], ResponseTopic.size()), az_span_create((uint8_t*)&ResponsePayload[0], ResponsePayload.size()), &Response))) return -1; 89 | 90 | ResponseValid = true; 91 | 92 | return 0; 93 | } 94 | 95 | bool AzureDpsClient::IsRegisterOperationCompleted() 96 | { 97 | if (!ResponseValid) return false; 98 | 99 | return az_iot_provisioning_client_operation_complete(GetOperationStatus(Response)); 100 | } 101 | 102 | int AzureDpsClient::GetWaitBeforeQueryStatusSeconds() const 103 | { 104 | if (!ResponseValid) return 0; 105 | 106 | return Response.retry_after_seconds; 107 | } 108 | 109 | std::string AzureDpsClient::GetQueryStatusPublishTopic() 110 | { 111 | if (!ResponseValid) return std::string(); 112 | 113 | char queryStatusPublishTopic[QueryStatusPublishTopicMaxSize]; 114 | if (az_result_failed(az_iot_provisioning_client_query_status_get_publish_topic(&ProvClient, Response.operation_id, queryStatusPublishTopic, sizeof(queryStatusPublishTopic), NULL))) return std::string(); 115 | 116 | return queryStatusPublishTopic; 117 | } 118 | 119 | bool AzureDpsClient::IsAssigned() 120 | { 121 | if (!ResponseValid) return false; 122 | 123 | return GetOperationStatus(Response) == AZ_IOT_PROVISIONING_STATUS_ASSIGNED; 124 | } 125 | 126 | std::string AzureDpsClient::GetHubHost() 127 | { 128 | if (!IsAssigned()) return std::string(); 129 | 130 | const az_span& span{ Response.registration_state.assigned_hub_hostname }; 131 | return std::string(az_span_ptr(span), az_span_ptr(span) + az_span_size(span)); 132 | } 133 | 134 | std::string AzureDpsClient::GetDeviceId() 135 | { 136 | if (!IsAssigned()) return std::string(); 137 | 138 | const az_span& span{ Response.registration_state.device_id }; 139 | return std::string(az_span_ptr(span), az_span_ptr(span) + az_span_size(span)); 140 | } 141 | 142 | az_iot_provisioning_client_operation_status AzureDpsClient::GetOperationStatus(az_iot_provisioning_client_register_response& response) 143 | { 144 | return response.operation_status; 145 | } 146 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_3_People_Counting/WioTerminal_EI_People_Counting_Azure_Central_LVGL/AzureDpsClient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class AzureDpsClient 8 | { 9 | public: 10 | AzureDpsClient(); 11 | AzureDpsClient(const AzureDpsClient&) = delete; 12 | AzureDpsClient& operator=(const AzureDpsClient&) = delete; 13 | 14 | std::string GetEndpoint() const { return Endpoint; } 15 | void SetEndpoint(const std::string& endpoint) { Endpoint = endpoint; } 16 | std::string GetIdScope() const { return IdScope; } 17 | void SetIdScope(const std::string& idScope) { IdScope = idScope; } 18 | std::string GetRegistrationId() const { return RegistrationId; } 19 | void SetRegistrationId(const std::string& registrationId) { RegistrationId = registrationId; } 20 | 21 | int Init(const std::string& endpoint, const std::string& idScope, const std::string& registrationId); 22 | 23 | std::vector GetSignature(const uint64_t& expirationEpochTime); 24 | 25 | std::string GetMqttClientId(); 26 | std::string GetMqttUsername(); 27 | std::string GetMqttPassword(const std::string& encryptedSignature, const uint64_t& expirationEpochTime); 28 | 29 | std::string GetRegisterPublishTopic(); 30 | std::string GetRegisterSubscribeTopic() const; 31 | int RegisterSubscribeWork(const std::string& topic, const std::vector& payload); 32 | bool IsRegisterOperationCompleted(); 33 | int GetWaitBeforeQueryStatusSeconds() const; 34 | std::string GetQueryStatusPublishTopic(); 35 | 36 | bool IsAssigned(); 37 | std::string GetHubHost(); 38 | std::string GetDeviceId(); 39 | 40 | private: 41 | std::string Endpoint; 42 | std::string IdScope; 43 | std::string RegistrationId; 44 | 45 | az_iot_provisioning_client ProvClient; 46 | 47 | bool ResponseValid; 48 | std::string ResponseTopic; 49 | std::vector ResponsePayload; 50 | az_iot_provisioning_client_register_response Response; 51 | 52 | private: 53 | static az_iot_provisioning_client_operation_status GetOperationStatus(az_iot_provisioning_client_register_response& response); 54 | 55 | }; 56 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_3_People_Counting/WioTerminal_EI_People_Counting_Azure_Central_LVGL/CliMode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void CliMode(); 4 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_3_People_Counting/WioTerminal_EI_People_Counting_Azure_Central_LVGL/Config.h: -------------------------------------------------------------------------------- 1 | #define USE_CLI 2 | //#define USE_DPS 3 | 4 | #if defined(USE_CLI) 5 | 6 | // Wi-Fi 7 | #define IOT_CONFIG_WIFI_SSID Storage::WiFiSSID.c_str() 8 | #define IOT_CONFIG_WIFI_PASSWORD Storage::WiFiPassword.c_str() 9 | 10 | // Azure IoT Hub DPS 11 | #define IOT_CONFIG_GLOBAL_DEVICE_ENDPOINT "global.azure-devices-provisioning.net" 12 | #define IOT_CONFIG_ID_SCOPE Storage::IdScope 13 | #define IOT_CONFIG_REGISTRATION_ID Storage::RegistrationId 14 | #define IOT_CONFIG_SYMMETRIC_KEY Storage::SymmetricKey 15 | #define IOT_CONFIG_MODEL_ID "dtmi:peopleCounterWintermute:newk7:peopleCount;1" 16 | 17 | #else // USE_CLI 18 | 19 | // Wi-Fi 20 | #define IOT_CONFIG_WIFI_SSID "[wifi ssid]" 21 | #define IOT_CONFIG_WIFI_PASSWORD "[wifi password]" 22 | 23 | #if !defined(USE_DPS) 24 | // Azure IoT Hub 25 | #define IOT_CONFIG_IOTHUB "[Azure IoT Hub host name].azure-devices.net" 26 | #define IOT_CONFIG_DEVICE_ID "[device id]" 27 | #define IOT_CONFIG_SYMMETRIC_KEY "[symmetric key]" 28 | #define IOT_CONFIG_MODEL_ID "dtmi:peopleCounterWintermute:newk7:peopleCount;1" 29 | #else // USE_DPS 30 | 31 | // Azure IoT Hub DPS 32 | #define IOT_CONFIG_GLOBAL_DEVICE_ENDPOINT "global.azure-devices-provisioning.net" 33 | #define IOT_CONFIG_ID_SCOPE "[id scope]" 34 | #define IOT_CONFIG_REGISTRATION_ID "[registration id]" 35 | #define IOT_CONFIG_SYMMETRIC_KEY "[symmetric key]" 36 | #define IOT_CONFIG_MODEL_ID "dtmi:peopleCounterWintermute:newk7:peopleCount;1" 37 | #endif // USE_DPS 38 | 39 | #endif // USE_CLI 40 | 41 | #define TOKEN_LIFESPAN 3600 42 | #define TELEMETRY_FREQUENCY_MILLISECS 5000 43 | 44 | #define TELEMETRY_PEOPLE_COUNT "peopleCount" 45 | #define TELEMETRY_PEOPLE_IN "peopleIn" 46 | #define TELEMETRY_PEOPLE_OUT "PeopleOut" 47 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_3_People_Counting/WioTerminal_EI_People_Counting_Azure_Central_LVGL/Signature.cpp: -------------------------------------------------------------------------------- 1 | #include "Signature.h" 2 | #include 3 | #include "Seeed_mbedtls.h" 4 | 5 | std::string GenerateEncryptedSignature(const std::string& symmetricKey, const std::vector& signature) 6 | { 7 | unsigned char base64DecodedSymmetricKey[symmetricKey.size() + 1]; 8 | 9 | // Base64-decode device key 10 | // <-- symmetricKey 11 | // --> base64DecodedSymmetricKey 12 | size_t base64DecodedSymmetricKeyLength; 13 | if (mbedtls_base64_decode(base64DecodedSymmetricKey, sizeof(base64DecodedSymmetricKey), &base64DecodedSymmetricKeyLength, (unsigned char*)&symmetricKey[0], symmetricKey.size()) != 0) abort(); 14 | if (base64DecodedSymmetricKeyLength == 0) abort(); 15 | 16 | // SHA-256 encrypt 17 | // <-- base64DecodedSymmetricKey 18 | // <-- signature 19 | // --> encryptedSignature 20 | uint8_t encryptedSignature[32]; // SHA-256 21 | mbedtls_md_context_t ctx; 22 | const mbedtls_md_type_t mdType{ MBEDTLS_MD_SHA256 }; 23 | if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(mdType), 1) != 0) abort(); 24 | if (mbedtls_md_hmac_starts(&ctx, base64DecodedSymmetricKey, base64DecodedSymmetricKeyLength) != 0) abort(); 25 | if (mbedtls_md_hmac_update(&ctx, &signature[0], signature.size()) != 0) abort(); 26 | if (mbedtls_md_hmac_finish(&ctx, encryptedSignature) != 0) abort(); 27 | 28 | // Base64 encode encrypted signature 29 | // <-- encryptedSignature 30 | // --> b64encHmacsha256Signature 31 | char b64encHmacsha256Signature[(size_t)(sizeof(encryptedSignature) * 1.5f) + 1]; 32 | size_t b64encHmacsha256SignatureLength; 33 | if (mbedtls_base64_encode((unsigned char*)b64encHmacsha256Signature, sizeof(b64encHmacsha256Signature), &b64encHmacsha256SignatureLength, encryptedSignature, mbedtls_md_get_size(mbedtls_md_info_from_type(mdType))) != 0) abort(); 34 | 35 | return std::string(b64encHmacsha256Signature, b64encHmacsha256SignatureLength); 36 | } 37 | 38 | std::string ComputeDerivedSymmetricKey(const std::string& masterKey, const std::string& registrationId) 39 | { 40 | unsigned char base64DecodedMasterKey[masterKey.size() + 1]; 41 | 42 | // Base64-decode device key 43 | // <-- masterKey 44 | // --> base64DecodedMasterKey 45 | size_t base64DecodedMasterKeyLength; 46 | if (mbedtls_base64_decode(base64DecodedMasterKey, sizeof(base64DecodedMasterKey), &base64DecodedMasterKeyLength, (unsigned char*)&masterKey[0], masterKey.size()) != 0) abort(); 47 | if (base64DecodedMasterKeyLength == 0) abort(); 48 | 49 | // SHA-256 encrypt 50 | // <-- base64DecodedMasterKey 51 | // <-- registrationId 52 | // --> derivedSymmetricKey 53 | uint8_t derivedSymmetricKey[32]; // SHA-256 54 | mbedtls_md_context_t ctx; 55 | const mbedtls_md_type_t mdType{ MBEDTLS_MD_SHA256 }; 56 | if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(mdType), 1) != 0) abort(); 57 | if (mbedtls_md_hmac_starts(&ctx, base64DecodedMasterKey, base64DecodedMasterKeyLength) != 0) abort(); 58 | if (mbedtls_md_hmac_update(&ctx, (const unsigned char*)®istrationId[0], registrationId.size()) != 0) abort(); 59 | if (mbedtls_md_hmac_finish(&ctx, derivedSymmetricKey) != 0) abort(); 60 | 61 | // Base64 encode encrypted signature 62 | // <-- derivedSymmetricKey 63 | // --> b64encDerivedSymmetricKey 64 | char b64encDerivedSymmetricKey[(size_t)(sizeof(derivedSymmetricKey) * 1.5f) + 1]; 65 | size_t b64encDerivedSymmetricKeyLength; 66 | if (mbedtls_base64_encode((unsigned char*)b64encDerivedSymmetricKey, sizeof(b64encDerivedSymmetricKey), &b64encDerivedSymmetricKeyLength, derivedSymmetricKey, mbedtls_md_get_size(mbedtls_md_info_from_type(mdType))) != 0) abort(); 67 | 68 | return std::string(b64encDerivedSymmetricKey, b64encDerivedSymmetricKeyLength); 69 | } 70 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_3_People_Counting/WioTerminal_EI_People_Counting_Azure_Central_LVGL/Signature.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | std::string GenerateEncryptedSignature(const std::string& symmetricKey, const std::vector& signature); 7 | std::string ComputeDerivedSymmetricKey(const std::string& masterKey, const std::string& registrationId); 8 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_3_People_Counting/WioTerminal_EI_People_Counting_Azure_Central_LVGL/Storage.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Storage.h" 3 | #include 4 | #include 5 | 6 | static auto FlashStartAddress = reinterpret_cast(0x04000000); 7 | 8 | static ExtFlashLoader::QSPIFlash Flash; 9 | 10 | std::string Storage::WiFiSSID; 11 | std::string Storage::WiFiPassword; 12 | std::string Storage::IdScope; 13 | std::string Storage::RegistrationId; 14 | std::string Storage::SymmetricKey; 15 | 16 | int Storage::Init = [] { 17 | Flash.initialize(); 18 | Flash.reset(); 19 | Flash.enterToMemoryMode(); 20 | 21 | WiFiSSID.clear(); 22 | WiFiPassword.clear(); 23 | IdScope.clear(); 24 | RegistrationId.clear(); 25 | SymmetricKey.clear(); 26 | 27 | return 0; 28 | }(); 29 | 30 | void Storage::Load() 31 | { 32 | if (memcmp(&FlashStartAddress[0], "AZ01", 4) != 0) 33 | { 34 | Storage::WiFiSSID.clear(); 35 | Storage::WiFiPassword.clear(); 36 | Storage::IdScope.clear(); 37 | Storage::RegistrationId.clear(); 38 | Storage::SymmetricKey.clear(); 39 | } 40 | else 41 | { 42 | MsgPack::Unpacker unpacker; 43 | unpacker.feed(&FlashStartAddress[8], *(const uint32_t*)&FlashStartAddress[4]); 44 | 45 | MsgPack::str_t str[5]; 46 | unpacker.deserialize(str[0], str[1], str[2], str[3], str[4]); 47 | 48 | Storage::WiFiSSID = str[0].c_str(); 49 | Storage::WiFiPassword = str[1].c_str(); 50 | Storage::IdScope = str[2].c_str(); 51 | Storage::RegistrationId = str[3].c_str(); 52 | Storage::SymmetricKey = str[4].c_str(); 53 | } 54 | } 55 | 56 | void Storage::Save() 57 | { 58 | MsgPack::Packer packer; 59 | { 60 | MsgPack::str_t str[5]; 61 | str[0] = Storage::WiFiSSID.c_str(); 62 | str[1] = Storage::WiFiPassword.c_str(); 63 | str[2] = Storage::IdScope.c_str(); 64 | str[3] = Storage::RegistrationId.c_str(); 65 | str[4] = Storage::SymmetricKey.c_str(); 66 | packer.serialize(str[0], str[1], str[2], str[3], str[4]); 67 | } 68 | 69 | std::vector buf(4 + 4 + packer.size()); 70 | memcpy(&buf[0], "AZ01", 4); 71 | *(uint32_t*)&buf[4] = packer.size(); 72 | memcpy(&buf[8], packer.data(), packer.size()); 73 | 74 | ExtFlashLoader::writeExternalFlash(Flash, 0, &buf[0], buf.size(), [](std::size_t bytes_processed, std::size_t bytes_total, bool verifying) { return true; }); 75 | } 76 | 77 | void Storage::Erase() 78 | { 79 | Flash.exitFromMemoryMode(); 80 | Flash.writeEnable(); 81 | Flash.eraseSector(0); 82 | Flash.waitProgram(0); 83 | Flash.enterToMemoryMode(); 84 | } 85 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_3_People_Counting/WioTerminal_EI_People_Counting_Azure_Central_LVGL/Storage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class Storage 6 | { 7 | public: 8 | static std::string WiFiSSID; 9 | static std::string WiFiPassword; 10 | static std::string IdScope; 11 | static std::string RegistrationId; 12 | static std::string SymmetricKey; 13 | 14 | public: 15 | static void Load(); 16 | static void Save(); 17 | static void Erase(); 18 | 19 | private: 20 | static int Init; 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_4_Weather_Prediction/README.md: -------------------------------------------------------------------------------- 1 | # TinyML Course 4 IoT Weather Prediction (TensorFlow Micro) 2 | 3 | To run test on static data you will need sufficiently new version of Tensorflow Lite for Microcontrollers. Read on how to get it in [Seeed Wiki](https://wiki.seeedstudio.com/Wio-Terminal-TinyML-TFLM-1/#install-the-arduino-tensorflow-lite-library). 4 | 5 | To run LVGL example you need: 6 | 7 | 1) Install WiFi libraries as specified [here](https://wiki.seeedstudio.com/Wio-Terminal-Network-Overview/). Before flashing RTL8720 firmware, check if you already have latest version by uploading the following code 8 | 9 | ```C 10 | #include "rpcWiFi.h" 11 | 12 | void setup() { 13 | Serial.begin(115200); 14 | while(!Serial); // Wait to open Serial Monitor 15 | Serial.printf("RTL8720 Firmware Version: %s", rpc_system_version()); 16 | } 17 | 18 | void loop() { 19 | } 20 | ``` 21 | If you already have the latest code and libraries for WiFi, proceed to the next step. 22 | 23 | 2) Install [ArduinoJson](https://github.com/bblanchon/ArduinoJson) 6.18.5. You can find it by searching for "ArduinoJson" in Arduino IDE libraries mananger. 24 | 25 | 3) Install [CircularBuffer](https://github.com/rlogiacco/CircularBuffer) 1.3.3. You can find it by searching for "CircularBuffer" in Arduino IDE libraries mananger. 26 | 27 | 4) Install LVGL 8.0.2 following the instructions [here](https://docs.lvgl.io/8/). Wio Terminal screen resolution is (320,240) and color depth is 16 bit. Make sure you install this particular version of LVGL - since the framework is under active development, API changes rapidly. 28 | 29 | Additionally in lv_conf.h file, make the following changes: 30 | 31 | ```line 30 #define LV_COLOR_16_SWAP 1``` 32 | 33 | ```line 208 #define LV_SPRINTF_USE_FLOAT 1``` 34 | 35 | ```C 36 | line 265 and below 37 | #define LV_FONT_MONTSERRAT_8 0 38 | #define LV_FONT_MONTSERRAT_10 0 39 | #define LV_FONT_MONTSERRAT_12 1 40 | #define LV_FONT_MONTSERRAT_14 1 41 | #define LV_FONT_MONTSERRAT_16 1 42 | #define LV_FONT_MONTSERRAT_18 1 43 | #define LV_FONT_MONTSERRAT_20 0 44 | #define LV_FONT_MONTSERRAT_22 1 45 | #define LV_FONT_MONTSERRAT_24 0 46 | #define LV_FONT_MONTSERRAT_26 0 47 | #define LV_FONT_MONTSERRAT_28 0 48 | #define LV_FONT_MONTSERRAT_30 0 49 | #define LV_FONT_MONTSERRAT_32 0 50 | #define LV_FONT_MONTSERRAT_34 0 51 | #define LV_FONT_MONTSERRAT_36 0 52 | #define LV_FONT_MONTSERRAT_38 0 53 | #define LV_FONT_MONTSERRAT_40 0 54 | #define LV_FONT_MONTSERRAT_42 0 55 | #define LV_FONT_MONTSERRAT_44 0 56 | #define LV_FONT_MONTSERRAT_46 0 57 | #define LV_FONT_MONTSERRAT_48 0 58 | ``` 59 | 60 | 5) Install [Grove - Barometer Sensor (BME280) Library](https://github.com/Seeed-Studio/Grove_BME280). You can find it by searching for "Grove BME280" in Arduino IDE libraries mananger. 61 | 62 | 6) Make sure you are using 1.8.2 board definitions for WIo Terminal. That is important for Tensorflow Lite for Microcontrollers to compile properly. 63 | 64 | 65 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_4_Weather_Prediction/Wio_Terminal_TF-MICRO_Weather_Prediction_LVGL/Wio_Terminal_TF-MICRO_Weather_Prediction_LVGL.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tensorflow/lite/micro/micro_mutable_op_resolver.h" 3 | #include "tensorflow/lite/micro/micro_error_reporter.h" 4 | #include "tensorflow/lite/micro/system_setup.h" 5 | #include "tensorflow/lite/micro/micro_interpreter.h" 6 | #include "tensorflow/lite/schema/schema_generated.h" 7 | 8 | #include "get_hist_weather.h" 9 | #include "gui.h" 10 | #include "model_Conv1D.h" 11 | #include "Seeed_BME280.h" 12 | #include 13 | 14 | #define DEBUG 0 15 | 16 | BME280 bme280; 17 | 18 | // Globals, used for compatibility with Arduino-style sketches. 19 | namespace { 20 | tflite::ErrorReporter* error_reporter = nullptr; 21 | const tflite::Model* model = nullptr; 22 | tflite::MicroInterpreter* interpreter = nullptr; 23 | TfLiteTensor* input = nullptr; 24 | TfLiteTensor* output_type = nullptr; 25 | TfLiteTensor* output_precip = nullptr; 26 | 27 | constexpr int kTensorArenaSize = 1024*10; 28 | uint8_t tensor_arena[kTensorArenaSize]; 29 | } // namespace 30 | 31 | // A buffer holding the last 24 sets of 3-channel values 32 | //float save_data[72]; 33 | // Most recent position in the save_data buffer 34 | int begin_index = 0; 35 | unsigned long previousMillis = 0; 36 | const long interval = 1000*60*60; //1 hour 37 | 38 | int freeMemory() { 39 | char top; 40 | return &top - reinterpret_cast(sbrk(0)); 41 | } 42 | 43 | void collect_data() { 44 | 45 | stack.unshift(bme280.getPressure() / 100000.0); 46 | stack.unshift(bme280.getHumidity() / 100.0); 47 | stack.unshift(bme280.getTemperature() / 60.0); 48 | 49 | print_buffer(); 50 | 51 | } 52 | 53 | void run_inference() { 54 | LogTFT("Running inference\n"); 55 | delay(100); 56 | 57 | for (byte i = 0; i < 72; i = i + 1) { 58 | input->data.int8[i] = stack[i] / input->params.scale + input->params.zero_point; 59 | } 60 | 61 | // Run inference, and report any error 62 | TfLiteStatus invoke_status = interpreter->Invoke(); 63 | 64 | if (invoke_status != kTfLiteOk) { 65 | Log("Invoke failed\n"); 66 | return; 67 | } 68 | 69 | // Obtain the quantized output from model's output tensor 70 | float y_type[4]; 71 | 72 | // Dequantize the output from integer to floating-point 73 | int8_t y_precip_q = output_precip->data.int8[0]; 74 | float y_precip = (y_precip_q - output_precip->params.zero_point) * output_precip->params.scale; 75 | 76 | Serial.print(F("Precip: ")); 77 | Serial.print(y_precip, 4); 78 | Serial.print(F("\t")); 79 | Serial.print(F("Type: ")); 80 | for (byte i = 0; i < 4; i = i + 1) { 81 | y_type[i] = (output_type->data.int8[i] - output_type->params.zero_point) * output_type->params.scale; 82 | Serial.print(y_type[i], 4); 83 | Serial.print(F(" ")); 84 | } 85 | Serial.print(F("\n")); 86 | 87 | uint8_t maxI = 0; 88 | for(int i = 0; i < 4; i++) 89 | if(y_type[i] > y_type[maxI]) 90 | maxI = i; 91 | 92 | update_screen(stack[69]*60, stack[71]*1000, stack[70], y_precip*100, maxI); 93 | LogTFT("Waiting\n"); 94 | } 95 | 96 | void print_buffer() { 97 | LogTFT("Data received\n"); 98 | Serial.print(F("Data buffer content:\n")); 99 | for (byte i = 1; i < 73; i = i + 1) { 100 | Serial.print(stack[i-1], 4); 101 | Serial.print(F(" ")); 102 | delay(10); 103 | if (i % 3 == 0) { Serial.print(F("\n")); } 104 | } 105 | Serial.print(F("\n")); 106 | } 107 | void setup() { 108 | 109 | Serial.begin(115200); 110 | 111 | #if DEBUG == 1 112 | while (!Serial) {delay(10);} 113 | #endif 114 | 115 | setupLVGL(); 116 | if (!bme280.init()) { LogTFT("Sensor init error!\n"); while (1) {} } 117 | 118 | update_screen(bme280.getTemperature(), bme280.getPressure()/100, bme280.getHumidity(), 50.0, 0); 119 | setupWIFI(); 120 | getCurrent(); 121 | getHistorical(); 122 | LogTFT("Free memory available: %d\n", freeMemory()/1024); 123 | delay(250); 124 | print_buffer(); 125 | 126 | static tflite::MicroErrorReporter micro_error_reporter; 127 | error_reporter = µ_error_reporter; 128 | // Map the model into a usable data structure. This doesn't involve any 129 | // copying or parsing, it's a very lightweight operation. 130 | model = tflite::GetModel(Conv1D_tflite); 131 | if (model->version() != TFLITE_SCHEMA_VERSION) { 132 | Log("Model provided is schema version %d not equal to supported version %d. \n", model->version(), TFLITE_SCHEMA_VERSION); 133 | while (1) {} 134 | } 135 | 136 | static tflite::MicroMutableOpResolver<8> resolver; 137 | resolver.AddConv2D(); 138 | resolver.AddFullyConnected(); 139 | resolver.AddAveragePool2D(); 140 | resolver.AddSoftmax(); 141 | resolver.AddRelu(); 142 | resolver.AddExpandDims(); 143 | resolver.AddReshape(); 144 | resolver.AddLogistic(); 145 | 146 | // Build an interpreter to run the model with. 147 | static tflite::MicroInterpreter static_interpreter(model, resolver, tensor_arena, kTensorArenaSize, error_reporter); 148 | interpreter = &static_interpreter; 149 | 150 | // Allocate memory from the tensor_arena for the model's tensors. 151 | TfLiteStatus allocate_status = interpreter->AllocateTensors(); 152 | if (allocate_status != kTfLiteOk) { 153 | Log("AllocateTensors() failed \n"); while (1) {} 154 | } 155 | 156 | // Obtain pointers to the model's input and output tensors. 157 | input = interpreter->input(0); 158 | output_type = interpreter->output(1); 159 | output_precip = interpreter->output(0); 160 | 161 | run_inference(); 162 | } 163 | 164 | void loop() { 165 | unsigned long currentMillis = millis(); 166 | 167 | if (currentMillis - previousMillis >= interval) { 168 | previousMillis = currentMillis; 169 | collect_data(); 170 | run_inference(); 171 | } 172 | 173 | lv_task_handler(); 174 | } 175 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_4_Weather_Prediction/Wio_Terminal_TF-MICRO_Weather_Prediction_LVGL/get_hist_weather.cpp: -------------------------------------------------------------------------------- 1 | #include "get_hist_weather.h" 2 | 3 | CircularBuffer stack; 4 | 5 | const char* ssid = ""; 6 | const char* password = ""; 7 | const char* apiKey = ""; 8 | extern const char* location = "Shenzhen,CN"; 9 | char server[] = "api.openweathermap.org"; 10 | 11 | int status = WL_IDLE_STATUS; 12 | uint32_t timestamp; 13 | float latitude; 14 | float longitude; 15 | 16 | // Use WiFiClient class to create TCP connections 17 | WiFiClient client; 18 | 19 | bool setupWIFI() { 20 | 21 | // Set WiFi to station mode and disconnect from an AP if it was previously connected 22 | WiFi.mode(WIFI_STA); 23 | WiFi.disconnect(); 24 | delay(100); 25 | 26 | WiFi.begin(ssid, password); 27 | 28 | while (WiFi.status() != WL_CONNECTED) { 29 | delay(250); 30 | LogTFT("Connecting to WiFi...\n"); 31 | } 32 | LogTFT("Connected to the WiFi network\n"); 33 | Serial.print(F("IP Address: ")); 34 | Serial.println(WiFi.localIP()); // prints out the device's IP address 35 | 36 | return true; 37 | } 38 | 39 | DynamicJsonDocument get_data(char request[], uint8_t kb) { 40 | 41 | while (true) 42 | { 43 | Serial.println(F("\nStarting connection to server...")); 44 | // if you get a connection, report back via serial: 45 | if (!client.connect(server, 80)) { 46 | LogTFT("Connection failed\n"); 47 | delay(50); 48 | continue; 49 | } 50 | 51 | LogTFT("Connected to server\n"); 52 | // Make a HTTP request: 53 | client.print(request); 54 | if (client.println() == 0) { 55 | LogTFT("Failed to send request\n"); 56 | client.stop(); 57 | delay(50); 58 | continue; 59 | } 60 | 61 | DynamicJsonDocument doc(1024*kb); 62 | 63 | // Parse JSON object 64 | DeserializationError error = deserializeJson(doc, client); 65 | if (error) { 66 | Serial.print(F("deserializeJson() failed: ")); 67 | Serial.println(error.f_str()); 68 | delay(50); 69 | continue; 70 | } 71 | LogTFT("Parsing OK\n"); 72 | //client.stop(); 73 | return doc; 74 | } 75 | } 76 | 77 | bool getCurrent() { 78 | char request[1024]; 79 | int n = sprintf (request, "GET /data/2.5/forecast?q=%s&appid=%s&cnt=1&units=metric\nHost: api.openweathermap.org\nConnection: close\n", location, apiKey); 80 | DynamicJsonDocument doc = get_data(request, 2); 81 | 82 | //get the data from the json tree 83 | timestamp = doc["list"][0]["dt"]; 84 | latitude = doc["city"]["coord"]["lat"]; 85 | longitude = doc["city"]["coord"]["lon"]; 86 | Serial.println(timestamp); 87 | Serial.println(latitude); 88 | Serial.println(longitude); 89 | doc.clear(); 90 | return true; 91 | } 92 | 93 | bool getHistorical() { 94 | char request[1024]; 95 | bool buf_full = false; 96 | uint32_t day_unix = 0; 97 | 98 | while (true) 99 | { 100 | 101 | int n = sprintf (request, "GET /data/2.5/onecall/timemachine?lat=%f&lon=%f&dt=%d&appid=%s&units=metric\nHost: api.openweathermap.org\nConnection: close\n", latitude, longitude, timestamp-3600*8-day_unix, apiKey); 102 | DynamicJsonDocument doc = get_data(request, 10); 103 | 104 | Serial.println(doc["hourly"].size()); 105 | for (uint8_t i = doc["hourly"].size()-1; i > 0; i = i - 1) { 106 | if (!stack.available()) { buf_full = true; break; } 107 | stack.push(float(doc["hourly"][i]["temp"]) / 60.0); 108 | stack.push(float(doc["hourly"][i]["humidity"]) / 100.0); 109 | stack.push(float(doc["hourly"][i]["pressure"]) / 1000.0); 110 | } 111 | 112 | day_unix += 86400; 113 | if (buf_full) { break; } 114 | doc.clear(); 115 | } 116 | 117 | return true; 118 | } 119 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_4_Weather_Prediction/Wio_Terminal_TF-MICRO_Weather_Prediction_LVGL/get_hist_weather.h: -------------------------------------------------------------------------------- 1 | #ifndef WIO_TERMINAL_WEATHER_GET_HIST_WEATHER_H_ 2 | #define WIO_TERMINAL_WEATHER_GET_HIST_WEATHER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "resources.h" 8 | #include "gui.h" 9 | 10 | extern CircularBuffer stack; 11 | 12 | bool getCurrent(); 13 | bool getHistorical(); 14 | DynamicJsonDocument get_data(char request[], uint8_t kb); 15 | bool setupWIFI(); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_4_Weather_Prediction/Wio_Terminal_TF-MICRO_Weather_Prediction_LVGL/gui.cpp: -------------------------------------------------------------------------------- 1 | #include "gui.h" 2 | 3 | #define HW_TIMER_INTERVAL_US 5000 4 | 5 | static lv_disp_draw_buf_t disp_buf; 6 | static lv_color_t buf[LV_HOR_RES_MAX * 10]; 7 | 8 | TFT_eSPI tft = TFT_eSPI(); 9 | 10 | lv_obj_t *city_label; 11 | lv_obj_t *rain_meter; 12 | lv_meter_indicator_t *rain_indic; 13 | lv_obj_t *rain_static; 14 | lv_obj_t *temp_label; 15 | lv_obj_t *pressure_label; 16 | lv_obj_t *humidity_label; 17 | lv_obj_t *temp_value_label; 18 | lv_obj_t *humid_value_label; 19 | lv_obj_t *pres_value_label; 20 | 21 | lv_obj_t *img1; 22 | lv_obj_t *LogOutput; 23 | 24 | extern const char* location; 25 | 26 | const lv_img_dsc_t *weather_types[4] = {&cloudy, &rainy, &sunny, &foggy}; 27 | 28 | void Log(const char *format, ...) { 29 | static char print_buf[1024] = { 0 }; 30 | 31 | va_list args; 32 | va_start(args, format); 33 | int r = vsnprintf(print_buf, sizeof(print_buf), format, args); 34 | va_end(args); 35 | 36 | if (r > 0) { 37 | Serial.write(print_buf); 38 | } 39 | } 40 | 41 | void LogTFT(const char *format, ...) { 42 | static char print_buf[1024] = { 0 }; 43 | 44 | va_list args; 45 | va_start(args, format); 46 | int r = vsnprintf(print_buf, sizeof(print_buf), format, args); 47 | va_end(args); 48 | 49 | if (r > 0) { 50 | Serial.write(print_buf); 51 | lv_label_set_text(LogOutput, print_buf); 52 | lv_task_handler(); 53 | } 54 | } 55 | 56 | /* Display flushing */ 57 | void disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) 58 | { 59 | uint32_t w = (area->x2 - area->x1 + 1); 60 | uint32_t h = (area->y2 - area->y1 + 1); 61 | 62 | tft.startWrite(); 63 | tft.setAddrWindow(area->x1, area->y1, w, h); 64 | tft.pushColors((uint16_t*)&color_p->full, w * h,true); 65 | tft.endWrite(); 66 | 67 | lv_disp_flush_ready( disp ); 68 | } 69 | 70 | void lv_tick_handler() 71 | { 72 | lv_tick_inc(5); 73 | } 74 | 75 | bool setupLVGL() { 76 | 77 | TimerTc3.initialize(HW_TIMER_INTERVAL_US * 1000); 78 | TimerTc3.attachInterrupt(lv_tick_handler); 79 | 80 | lv_init(); 81 | tft.begin(); /* TFT init */ 82 | tft.setRotation(3); /* Landscape orientation */ 83 | 84 | lv_disp_draw_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10); 85 | 86 | /*Initialize the display driver*/ 87 | static lv_disp_drv_t disp_drv; 88 | lv_disp_drv_init(&disp_drv); 89 | disp_drv.hor_res = LV_HOR_RES_MAX; 90 | disp_drv.ver_res = LV_VER_RES_MAX; 91 | disp_drv.flush_cb = disp_flush; 92 | disp_drv.draw_buf = &disp_buf; 93 | lv_disp_drv_register(&disp_drv); 94 | 95 | lv_theme_t * th = lv_theme_default_init(NULL, lv_color_black(), lv_color_white(), LV_THEME_DEFAULT_DARK, &lv_font_montserrat_14); 96 | 97 | img1 = lv_img_create(lv_scr_act()); 98 | city_label = lv_label_create(lv_scr_act()); 99 | rain_meter = lv_meter_create(lv_scr_act()); 100 | 101 | rain_static = lv_label_create(lv_scr_act()); 102 | temp_label = lv_label_create(lv_scr_act()); 103 | pressure_label = lv_label_create(lv_scr_act()); 104 | humidity_label = lv_label_create(lv_scr_act()); 105 | temp_value_label = lv_label_create(lv_scr_act()); 106 | humid_value_label = lv_label_create(lv_scr_act()); 107 | pres_value_label = lv_label_create(lv_scr_act()); 108 | 109 | static lv_style_t large_style; 110 | lv_style_init(&large_style); 111 | lv_style_set_text_font(&large_style, &lv_font_montserrat_22); 112 | 113 | lv_img_set_src(img1, &cloudy); 114 | lv_obj_set_x(img1, 20); 115 | lv_obj_set_y(img1, 120); 116 | //lv_obj_set_style_local_image_recolor_opa(img1, LV_IMG_PART_MAIN, LV_STATE_DEFAULT, 255); 117 | //lv_obj_set_style_local_image_recolor(img1, LV_IMG_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); 118 | 119 | lv_obj_add_style(city_label, &large_style, 0); 120 | lv_obj_set_x(city_label, 115); 121 | lv_obj_set_y(city_label, 10); 122 | lv_obj_set_height(city_label, 20); 123 | lv_obj_set_width(city_label, 120); 124 | lv_label_set_text(city_label, location); 125 | 126 | lv_meter_scale_t * scale = lv_meter_add_scale(rain_meter); 127 | lv_meter_set_scale_range(rain_meter, scale, 0, 100, 270, 90); 128 | rain_indic = lv_meter_add_arc(rain_meter, scale, 10, lv_palette_main(LV_PALETTE_RED), 0); 129 | 130 | lv_obj_set_x(rain_meter, 15); 131 | lv_obj_set_y(rain_meter, 10); 132 | lv_obj_set_width(rain_meter, 75); 133 | lv_obj_set_height(rain_meter, 75); 134 | 135 | lv_obj_set_x(rain_static, 25); 136 | lv_obj_set_y(rain_static, 90); 137 | lv_obj_set_width(rain_static, 60); 138 | lv_obj_set_height(rain_static, 40); 139 | lv_label_set_text(rain_static, "% Rain"); 140 | 141 | lv_obj_set_x(temp_label, 110); 142 | lv_obj_set_y(temp_label, 50); 143 | lv_label_set_text(temp_label, "Temp (C°)"); 144 | 145 | lv_obj_set_x(pressure_label, 110); 146 | lv_obj_set_y(pressure_label, 100); 147 | lv_label_set_text(pressure_label, "Pressure (bar)"); 148 | 149 | lv_obj_set_x(humidity_label, 110); 150 | lv_obj_set_y(humidity_label, 150); 151 | lv_label_set_text(humidity_label, "Humidity (%)"); 152 | 153 | lv_obj_add_style(temp_value_label, &large_style, 0); 154 | lv_obj_set_x(temp_value_label, 240); 155 | lv_obj_set_y(temp_value_label, 50); 156 | 157 | lv_obj_add_style(pres_value_label, &large_style, 0); 158 | lv_obj_set_x(pres_value_label, 240); 159 | lv_obj_set_y(pres_value_label, 100); 160 | 161 | lv_obj_add_style(humid_value_label, &large_style, 0); 162 | lv_obj_set_x(humid_value_label, 240); 163 | lv_obj_set_y(humid_value_label, 150); 164 | 165 | LogOutput = lv_label_create(lv_scr_act()); 166 | lv_label_set_long_mode(LogOutput, LV_LABEL_LONG_CLIP); 167 | lv_label_set_recolor(LogOutput, true); 168 | lv_obj_set_style_text_align(LogOutput, LV_TEXT_ALIGN_LEFT, 0); 169 | lv_obj_set_width(LogOutput, 280); 170 | lv_obj_align(LogOutput, LV_ALIGN_TOP_LEFT, 20, 200); 171 | } 172 | 173 | bool update_screen(float temp_value, float pres_value, float humid_value, float precip_value, uint8_t weather_type) { 174 | 175 | lv_meter_set_indicator_end_value(rain_meter, rain_indic, int8_t(precip_value)); 176 | 177 | lv_label_set_text_fmt(temp_value_label, "%.1f", temp_value); 178 | lv_label_set_text_fmt(pres_value_label, "%d", int16_t(pres_value)); 179 | lv_label_set_text_fmt(humid_value_label, "%.1f", humid_value); 180 | 181 | lv_img_set_src(img1, weather_types[weather_type]); 182 | 183 | lv_task_handler(); 184 | 185 | } 186 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_4_Weather_Prediction/Wio_Terminal_TF-MICRO_Weather_Prediction_LVGL/gui.h: -------------------------------------------------------------------------------- 1 | #ifndef WIO_TERMINAL_WEATHER_GUI_H_ 2 | #define WIO_TERMINAL_WEATHER_GUI_H_ 3 | 4 | #include 5 | #include "resources.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | 13 | bool setupLVGL(); 14 | bool update_screen(float temp_value, float pres_value, float humid_value, float precip_value, uint8_t weather_type); 15 | void disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p); 16 | void lv_tick_handler(); 17 | void Log(const char *format, ...); 18 | void LogTFT(const char *format, ...); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_4_Weather_Prediction/Wio_Terminal_TF-MICRO_Weather_Prediction_test_static/Wio_Terminal_TF-MICRO_Weather_Prediction_test_static.ino: -------------------------------------------------------------------------------- 1 | #include 2 | //#include "tensorflow/lite/micro/micro_mutable_op_resolver.h" 3 | #include "tensorflow/lite/micro/all_ops_resolver.h" 4 | #include "tensorflow/lite/micro/micro_error_reporter.h" 5 | #include "tensorflow/lite/micro/system_setup.h" 6 | #include "tensorflow/lite/micro/micro_interpreter.h" 7 | #include "tensorflow/lite/schema/schema_generated.h" 8 | 9 | #include "model_Conv1D.h" 10 | 11 | // Globals, used for compatibility with Arduino-style sketches. 12 | namespace { 13 | tflite::ErrorReporter* error_reporter = nullptr; 14 | const tflite::Model* model = nullptr; 15 | tflite::MicroInterpreter* interpreter = nullptr; 16 | TfLiteTensor* input = nullptr; 17 | TfLiteTensor* output_type = nullptr; 18 | TfLiteTensor* output_precip = nullptr; 19 | 20 | constexpr int kTensorArenaSize = 1024*25; 21 | uint8_t tensor_arena[kTensorArenaSize]; 22 | } // namespace 23 | 24 | void setup() { 25 | Serial.begin(115200); 26 | while (!Serial) {delay(10);} 27 | 28 | // Set up logging. Google style is to avoid globals or statics because of 29 | // lifetime uncertainty, but since this has a trivial destructor it's okay. 30 | // NOLINTNEXTLINE(runtime-global-variables) 31 | static tflite::MicroErrorReporter micro_error_reporter; 32 | error_reporter = µ_error_reporter; 33 | 34 | // Map the model into a usable data structure. This doesn't involve any 35 | // copying or parsing, it's a very lightweight operation. 36 | model = tflite::GetModel(Conv1D_tflite); 37 | if (model->version() != TFLITE_SCHEMA_VERSION) { 38 | TF_LITE_REPORT_ERROR(error_reporter, 39 | "Model provided is schema version %d not equal " 40 | "to supported version %d.", 41 | model->version(), TFLITE_SCHEMA_VERSION); 42 | return; 43 | } 44 | 45 | // This pulls in all the operation implementations we need. 46 | // NOLINTNEXTLINE(runtime-global-variables) 47 | //static tflite::MicroMutableOpResolver<1> resolver; 48 | static tflite::AllOpsResolver resolver; 49 | // Build an interpreter to run the model with. 50 | static tflite::MicroInterpreter static_interpreter(model, resolver, tensor_arena, kTensorArenaSize, error_reporter); 51 | interpreter = &static_interpreter; 52 | 53 | // Allocate memory from the tensor_arena for the model's tensors. 54 | TfLiteStatus allocate_status = interpreter->AllocateTensors(); 55 | if (allocate_status != kTfLiteOk) { 56 | TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed"); 57 | return; 58 | } 59 | 60 | // Obtain pointers to the model's input and output tensors. 61 | input = interpreter->input(0); 62 | output_type = interpreter->output(1); 63 | output_precip = interpreter->output(0); 64 | 65 | Serial.println(input->dims->size); 66 | Serial.println(input->dims->data[1]); 67 | Serial.println(input->dims->data[2]); 68 | Serial.println(input->type); 69 | 70 | Serial.println(output_type->dims->size); 71 | Serial.println(output_type->dims->data[1]); 72 | Serial.println(output_type->type); 73 | 74 | Serial.println(output_precip->dims->size); 75 | Serial.println(output_precip->dims->data[1]); 76 | Serial.println(output_precip->type); 77 | } 78 | 79 | void loop() { 80 | 81 | int8_t x_quantized[72]; 82 | float x[72] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85 | 0, 0, 0, 0, 0, 0}; 86 | 87 | for (byte i = 0; i < 72; i = i + 1) { 88 | input->data.int8[i] = x[i] / input->params.scale + input->params.zero_point; 89 | } 90 | 91 | // Run inference, and report any error 92 | TfLiteStatus invoke_status = interpreter->Invoke(); 93 | 94 | if (invoke_status != kTfLiteOk) { 95 | TF_LITE_REPORT_ERROR(error_reporter, "Invoke failed"); 96 | return; 97 | } 98 | 99 | // Obtain the quantized output from model's output tensor 100 | float y_type[4]; 101 | 102 | // Dequantize the output from integer to floating-point 103 | int8_t y_precip_q = output_precip->data.int8[0]; 104 | Serial.println(y_precip_q); 105 | float y_precip = (y_precip_q - output_precip->params.zero_point) * output_precip->params.scale; 106 | Serial.print("Precip: "); 107 | Serial.print(y_precip); 108 | Serial.print("\t"); 109 | Serial.print("Type: "); 110 | for (byte i = 0; i < 4; i = i + 1) { 111 | y_type[i] = (output_type->data.int8[i] - output_type->params.zero_point) * output_type->params.scale; 112 | Serial.print(y_type[i]); 113 | Serial.print(" "); 114 | } 115 | Serial.print("\n"); 116 | } 117 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_5_Anomaly_Detection/WioTerminal_EI_Anomaly_Detection_Blynk/BlynkEdgent.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkEdgent.h 3 | * @author Blynk Inc. 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2021 Blynk Inc. 6 | * @date May 2021 7 | * @brief 8 | * 9 | */ 10 | 11 | extern "C" { 12 | void app_loop(); 13 | void eraseMcuConfig(); 14 | void restartMCU(); 15 | } 16 | 17 | #include "Settings.h" 18 | #include 19 | 20 | #ifndef BLYNK_NEW_LIBRARY 21 | #error "Old version of Blynk library is in use. Please replace it with the new one." 22 | #endif 23 | 24 | #include "BlynkState.h" 25 | #include "ConfigStore.h" 26 | #include "ResetButton.h" 27 | #include "ConfigMode.h" 28 | #include "Indicator.h" 29 | //#include "OTA.h" 30 | 31 | inline 32 | void BlynkState::set(State m) { 33 | if (state != m && m < MODE_MAX_VALUE) { 34 | DEBUG_PRINT(String(StateStr[state]) + " => " + StateStr[m]); 35 | state = m; 36 | 37 | // You can put your state handling here, 38 | // i.e. implement custom indication 39 | } 40 | } 41 | 42 | void printDeviceBanner() 43 | { 44 | Blynk.printBanner(); 45 | DEBUG_PRINT("--------------------------"); 46 | DEBUG_PRINT(String("Product: ") + BLYNK_DEVICE_NAME); 47 | DEBUG_PRINT(String("Hardware: ") + BOARD_HARDWARE_VERSION); 48 | DEBUG_PRINT(String("Firmware: ") + BLYNK_FIRMWARE_VERSION " (build " __DATE__ " " __TIME__ ")"); 49 | if (configStore.getFlag(CONFIG_FLAG_VALID)) { 50 | DEBUG_PRINT(String("Token: ...") + (configStore.cloudToken+28)); 51 | } 52 | DEBUG_PRINT(String("Device: ") + BLYNK_INFO_DEVICE); 53 | DEBUG_PRINT(String("MAC: ") + WiFi.macAddress()); 54 | DEBUG_PRINT("--------------------------"); 55 | } 56 | 57 | void runBlynkWithChecks() { 58 | Blynk.run(); 59 | if (BlynkState::get() == MODE_RUNNING) { 60 | if (!Blynk.connected()) { 61 | if (WiFi.status() == WL_CONNECTED) { 62 | BlynkState::set(MODE_CONNECTING_CLOUD); 63 | } else { 64 | BlynkState::set(MODE_CONNECTING_NET); 65 | } 66 | } 67 | } 68 | } 69 | 70 | class Edgent { 71 | 72 | public: 73 | void begin() 74 | { 75 | //indicator_init(); 76 | button_init(); 77 | config_init(); 78 | 79 | WiFi.persistent(false); 80 | WiFi.enableSTA(true); // Needed to get MAC 81 | 82 | printDeviceBanner(); 83 | 84 | if (configStore.getFlag(CONFIG_FLAG_VALID)) { 85 | BlynkState::set(MODE_CONNECTING_NET); 86 | } else if (config_load_blnkopt()) { 87 | DEBUG_PRINT("Firmware is preprovisioned"); 88 | BlynkState::set(MODE_CONNECTING_NET); 89 | } else { 90 | BlynkState::set(MODE_WAIT_CONFIG); 91 | } 92 | } 93 | 94 | void run() { 95 | app_loop(); 96 | switch (BlynkState::get()) { 97 | case MODE_WAIT_CONFIG: 98 | case MODE_CONFIGURING: enterConfigMode(); break; 99 | case MODE_CONNECTING_NET: enterConnectNet(); break; 100 | case MODE_CONNECTING_CLOUD: enterConnectCloud(); break; 101 | case MODE_RUNNING: runBlynkWithChecks(); break; 102 | //case MODE_OTA_UPGRADE: enterOTA(); break; 103 | case MODE_SWITCH_TO_STA: enterSwitchToSTA(); break; 104 | case MODE_RESET_CONFIG: enterResetConfig(); break; 105 | default: enterError(); break; 106 | } 107 | } 108 | 109 | }; 110 | 111 | Edgent BlynkEdgent; 112 | BlynkTimer timer; 113 | 114 | void app_loop() { 115 | timer.run(); 116 | } 117 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_5_Anomaly_Detection/WioTerminal_EI_Anomaly_Detection_Blynk/BlynkState.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkState.h 3 | * @author Blynk Inc. 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2021 Blynk Inc. 6 | * @date May 2021 7 | * @brief 8 | * 9 | */ 10 | 11 | enum State { 12 | MODE_WAIT_CONFIG, 13 | MODE_CONFIGURING, 14 | MODE_CONNECTING_NET, 15 | MODE_CONNECTING_CLOUD, 16 | MODE_RUNNING, 17 | //MODE_OTA_UPGRADE, 18 | MODE_SWITCH_TO_STA, 19 | MODE_RESET_CONFIG, 20 | MODE_ERROR, 21 | 22 | MODE_MAX_VALUE 23 | }; 24 | 25 | #if defined(APP_DEBUG) 26 | const char* StateStr[MODE_MAX_VALUE+1] = { 27 | "WAIT_CONFIG", 28 | "CONFIGURING", 29 | "CONNECTING_NET", 30 | "CONNECTING_CLOUD", 31 | "RUNNING", 32 | //"OTA_UPGRADE", 33 | "SWITCH_TO_STA", 34 | "RESET_CONFIG", 35 | "ERROR", 36 | 37 | "INIT" 38 | }; 39 | #endif 40 | 41 | namespace BlynkState 42 | { 43 | volatile State state = MODE_MAX_VALUE; 44 | 45 | State get() { return state; } 46 | bool is (State m) { return (state == m); } 47 | void set(State m); 48 | }; 49 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_5_Anomaly_Detection/WioTerminal_EI_Anomaly_Detection_Blynk/ConfigStore.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ConfigStore.h 3 | * @author Blynk Inc. 4 | * @modified Dmitry Maslov (Seeed Studio) 5 | * @license This project is released under the MIT License (MIT) 6 | * @copyright Copyright (c) 2021 Blynk Inc. 7 | * @date May 2021 8 | * @brief 9 | * 10 | */ 11 | 12 | #define CONFIG_FLAG_VALID 0x01 13 | #define CONFIG_FLAG_STATIC_IP 0x02 14 | 15 | #define BLYNK_PROV_ERR_NONE 0 // All good 16 | #define BLYNK_PROV_ERR_CONFIG 700 // Invalid config from app (malformed token,etc) 17 | #define BLYNK_PROV_ERR_NETWORK 701 // Could not connect to the router 18 | #define BLYNK_PROV_ERR_CLOUD 702 // Could not connect to the cloud 19 | #define BLYNK_PROV_ERR_TOKEN 703 // Invalid token error (after connection) 20 | #define BLYNK_PROV_ERR_INTERNAL 704 // Other issues (i.e. hardware failure) 21 | 22 | struct ConfigStore { 23 | uint32_t magic; 24 | char version[15]; 25 | uint8_t flags; 26 | 27 | char wifiSSID[34]; 28 | char wifiPass[64]; 29 | 30 | char cloudToken[34]; 31 | char cloudHost[34]; 32 | uint16_t cloudPort; 33 | 34 | uint32_t staticIP; 35 | uint32_t staticMask; 36 | uint32_t staticGW; 37 | uint32_t staticDNS; 38 | uint32_t staticDNS2; 39 | 40 | int last_error; 41 | 42 | void setFlag(uint8_t mask, bool value) { 43 | if (value) { 44 | flags |= mask; 45 | } else { 46 | flags &= ~mask; 47 | } 48 | } 49 | 50 | bool getFlag(uint8_t mask) { 51 | return (flags & mask) == mask; 52 | } 53 | 54 | } __attribute__((packed)); 55 | 56 | ConfigStore configStore; 57 | 58 | const ConfigStore configDefault = { 59 | 0x626C6E6B, 60 | BLYNK_FIRMWARE_VERSION, 61 | 0x00, 62 | 63 | "", 64 | "", 65 | 66 | "invalid token", 67 | CONFIG_DEFAULT_SERVER, 68 | CONFIG_DEFAULT_PORT, 69 | 0, 70 | BLYNK_PROV_ERR_NONE 71 | }; 72 | 73 | template 74 | void CopyString(const String& s, T(&arr)[size]) { 75 | s.toCharArray(arr, size); 76 | } 77 | 78 | static bool config_load_blnkopt() 79 | { 80 | static const char blnkopt[] = "blnkopt\0" 81 | BLYNK_PARAM_KV("ssid" , BLYNK_PARAM_PLACEHOLDER_64 82 | BLYNK_PARAM_PLACEHOLDER_64 83 | BLYNK_PARAM_PLACEHOLDER_64 84 | BLYNK_PARAM_PLACEHOLDER_64) 85 | BLYNK_PARAM_KV("host" , CONFIG_DEFAULT_SERVER) 86 | BLYNK_PARAM_KV("port" , BLYNK_TOSTRING(CONFIG_DEFAULT_PORT)) 87 | "\0"; 88 | 89 | BlynkParam prov(blnkopt+8, sizeof(blnkopt)-8-2); 90 | BlynkParam::iterator ssid = prov["ssid"]; 91 | BlynkParam::iterator pass = prov["pass"]; 92 | BlynkParam::iterator auth = prov["auth"]; 93 | BlynkParam::iterator host = prov["host"]; 94 | BlynkParam::iterator port = prov["port"]; 95 | 96 | if (!(ssid.isValid() && auth.isValid())) { 97 | return false; 98 | } 99 | 100 | // reset to defaut before loading values from blnkopt 101 | configStore = configDefault; 102 | 103 | if (ssid.isValid()) { CopyString(ssid.asStr(), configStore.wifiSSID); } 104 | if (pass.isValid()) { CopyString(pass.asStr(), configStore.wifiPass); } 105 | if (auth.isValid()) { CopyString(auth.asStr(), configStore.cloudToken); } 106 | if (host.isValid()) { CopyString(host.asStr(), configStore.cloudHost); } 107 | if (port.isValid()) { configStore.cloudPort = port.asInt(); } 108 | 109 | return true; 110 | } 111 | 112 | #include 113 | const sfud_flash *_flash = sfud_get_device_table() + 0; 114 | 115 | void config_load() 116 | { 117 | 118 | uint8_t has_config; 119 | sfud_err result = sfud_read(_flash, 0, 1, &has_config); 120 | 121 | if (has_config == 0) 122 | { 123 | DEBUG_PRINT("Using default config."); 124 | configStore = configDefault; 125 | return; 126 | } 127 | 128 | memset(&configStore, 0, sizeof(configStore)); 129 | 130 | uint8_t b[sizeof(configStore)]; 131 | 132 | result = sfud_read(_flash, 1, sizeof(b), b); 133 | memcpy(&configStore, b, sizeof(configStore)); 134 | 135 | } 136 | 137 | bool config_save() 138 | { 139 | 140 | sfud_err result = sfud_erase(_flash, 0, sizeof(configStore)+1); 141 | delay(100); 142 | if (!result == SFUD_SUCCESS) { DEBUG_PRINT("Erase flash data failed"); return false; } 143 | 144 | uint8_t b[sizeof(configStore)]; 145 | memcpy(b, &configStore, sizeof(configStore)); 146 | 147 | uint8_t status = 1; 148 | result = sfud_write(_flash, 0, sizeof(status), &status); 149 | delay(10); 150 | 151 | if (!result == SFUD_SUCCESS) { DEBUG_PRINT("Write the flash data failed"); return false; } 152 | 153 | result = sfud_write(_flash, 1, sizeof(b), b); 154 | delay(50); 155 | 156 | if (!result == SFUD_SUCCESS) { DEBUG_PRINT("Write the flash data failed"); return false; } 157 | 158 | DEBUG_PRINT("Configuration stored to flash"); 159 | return true; 160 | } 161 | 162 | bool config_init() 163 | { 164 | if (sfud_init() != SFUD_SUCCESS) { DEBUG_PRINT("SFUD init failed"); return false; } 165 | 166 | sfud_qspi_fast_read_enable(sfud_get_device(SFUD_W25Q32_DEVICE_INDEX), 2); 167 | 168 | config_load(); 169 | return true; 170 | } 171 | 172 | void enterResetConfig() 173 | { 174 | DEBUG_PRINT("Resetting configuration!"); 175 | configStore = configDefault; 176 | config_save(); 177 | //eraseMcuConfig(); 178 | BlynkState::set(MODE_WAIT_CONFIG); 179 | } 180 | 181 | void config_set_last_error(int error) { 182 | // Only set error if not provisioned 183 | if (!configStore.getFlag(CONFIG_FLAG_VALID)) { 184 | configStore = configDefault; 185 | 186 | sfud_err result = sfud_erase(_flash, 0, 1); 187 | 188 | configStore.last_error = error; 189 | BLYNK_LOG2("Last error code: ", error); 190 | config_save(); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_5_Anomaly_Detection/WioTerminal_EI_Anomaly_Detection_Blynk/Indicator.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Indicator.h 3 | * @author Blynk Inc. 4 | * @modified Dmitry Maslov (Seeed Studio) 5 | * @license This project is released under the MIT License (MIT) 6 | * @copyright Copyright (c) 2021 Blynk Inc. 7 | * @date May 2021 8 | * @brief 9 | * 10 | */ 11 | 12 | void indicator_run(); 13 | 14 | #if !defined(BOARD_LED_BRIGHTNESS) 15 | #define BOARD_LED_BRIGHTNESS 255 16 | #endif 17 | 18 | #define DIMM(x) ((x)*(BOARD_LED_BRIGHTNESS)/255) 19 | #define RGB(r,g,b) (DIMM(r) << 16 | DIMM(g) << 8 | DIMM(b) << 0) 20 | 21 | class Indicator { 22 | public: 23 | 24 | enum Colors { 25 | COLOR_BLACK = RGB(0x00, 0x00, 0x00), 26 | COLOR_WHITE = RGB(0xFF, 0xFF, 0xE7), 27 | COLOR_BLUE = RGB(0x0D, 0x36, 0xFF), 28 | COLOR_BLYNK = RGB(0x2E, 0xFF, 0xB9), 29 | COLOR_RED = RGB(0xFF, 0x10, 0x08), 30 | COLOR_MAGENTA = RGB(0xA7, 0x00, 0xFF), 31 | }; 32 | 33 | Indicator() { 34 | m_Counter = 0; 35 | initLED(); 36 | } 37 | 38 | uint32_t run() { 39 | State currState = BlynkState::get(); 40 | 41 | // Reset counter if indicator state changes 42 | if (m_PrevState != currState) { 43 | m_PrevState = currState; 44 | m_Counter = 0; 45 | } 46 | 47 | if (g_buttonPressed) { 48 | if (millis() - g_buttonPressTime > BUTTON_HOLD_TIME_ACTION) { return beatLED(COLOR_WHITE, (int[]){ 100, 100 }); } 49 | if (millis() - g_buttonPressTime > BUTTON_HOLD_TIME_INDICATION) { return waveLED(COLOR_WHITE, 1000); } 50 | } 51 | switch (currState) { 52 | case MODE_RESET_CONFIG: 53 | case MODE_WAIT_CONFIG: return beatLED(COLOR_BLUE, (int[]){ 50, 500 }); 54 | case MODE_CONFIGURING: return beatLED(COLOR_BLUE, (int[]){ 200, 200 }); 55 | case MODE_CONNECTING_NET: return beatLED(COLOR_BLYNK, (int[]){ 50, 500 }); 56 | case MODE_CONNECTING_CLOUD: return beatLED(COLOR_BLYNK, (int[]){ 100, 100 }); 57 | case MODE_RUNNING: return waveLED(COLOR_BLYNK, 5000); 58 | //case MODE_OTA_UPGRADE: return beatLED(COLOR_MAGENTA, (int[]){ 50, 50 }); 59 | default: return beatLED(COLOR_RED, (int[]){ 80, 100, 80, 1000 } ); 60 | } 61 | } 62 | 63 | protected: 64 | 65 | /* 66 | * LED drivers 67 | */ 68 | 69 | #if defined(BOARD_LED_PIN) // Single color LED 70 | 71 | void initLED() { 72 | pinMode(LED_BUILTIN, OUTPUT); 73 | } 74 | 75 | void setLED(uint32_t color) { 76 | #if BOARD_LED_INVERSE 77 | analogWrite(LED_BUILTIN, BOARD_PWM_MAX - color); 78 | #else 79 | analogWrite(LED_BUILTIN, color); 80 | #endif 81 | } 82 | 83 | #else 84 | 85 | #warning Invalid LED configuration. 86 | void initLED() {} 87 | void setLED(uint32_t color) {} 88 | 89 | #endif 90 | 91 | /* 92 | * Animations 93 | */ 94 | 95 | uint32_t skipLED() { 96 | return 20; 97 | } 98 | 99 | template 100 | uint32_t beatLED(uint32_t, const T& beat) { 101 | const uint8_t cnt = sizeof(beat)/sizeof(beat[0]); 102 | setLED((m_Counter % 2 == 0) ? DIMM(BOARD_PWM_MAX) : 0); 103 | uint32_t next = beat[m_Counter % cnt]; 104 | m_Counter = (m_Counter+1) % cnt; 105 | return next; 106 | } 107 | 108 | uint32_t waveLED(uint32_t, unsigned breathePeriod) { 109 | uint8_t brightness = (m_Counter < 128) ? m_Counter : 255 - m_Counter; 110 | 111 | setLED(BOARD_PWM_MAX * (DIMM((float)brightness) / (BOARD_PWM_MAX/2))); 112 | 113 | // This function relies on the 8-bit, unsigned m_Counter rolling over. 114 | m_Counter = (m_Counter+1) % 256; 115 | return breathePeriod / 256; 116 | } 117 | 118 | private: 119 | uint8_t m_Counter; 120 | State m_PrevState; 121 | }; 122 | 123 | Indicator indicator; 124 | 125 | /* 126 | * Animation timers 127 | */ 128 | 129 | #if defined(USE_TC3) 130 | 131 | #include 132 | 133 | void indicator_run() { 134 | uint32_t returnTime = indicator.run(); 135 | if (returnTime) { 136 | TimerTc3.initialize(returnTime*1000); 137 | } 138 | } 139 | 140 | void indicator_init() { 141 | TimerTc3.initialize(100*1000); 142 | TimerTc3.attachInterrupt(indicator_run); 143 | } 144 | 145 | #elif defined(USE_TCC0) 146 | 147 | #include 148 | 149 | void indicator_run() { 150 | uint32_t returnTime = indicator.run(); 151 | if (returnTime) { 152 | Timer3.initialize(returnTime*1000); 153 | } 154 | } 155 | 156 | void indicator_init() { 157 | Timer3.initialize(100*1000); 158 | Timer3.attachInterrupt(indicator_run); 159 | } 160 | 161 | #else 162 | 163 | #warning LED indicator needs a functional timer! 164 | 165 | void indicator_run() {} 166 | void indicator_init() {} 167 | 168 | #endif 169 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_5_Anomaly_Detection/WioTerminal_EI_Anomaly_Detection_Blynk/OTA.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | String overTheAirURL; 7 | 8 | extern BlynkTimer timer; 9 | 10 | BLYNK_WRITE(InternalPinOTA) { 11 | overTheAirURL = param.asString(); 12 | 13 | timer.setTimeout(2000L, [](){ 14 | // Start OTA 15 | Blynk.logEvent("sys_ota", "OTA started"); 16 | 17 | // Disconnect, not to interfere with OTA process 18 | Blynk.disconnect(); 19 | 20 | BlynkState::set(MODE_OTA_UPGRADE); 21 | }); 22 | } 23 | 24 | void enterOTA() { 25 | BlynkState::set(MODE_OTA_UPGRADE); 26 | 27 | DEBUG_PRINT(String("Firmware update URL: ") + overTheAirURL); 28 | 29 | HTTPClient http; 30 | http.begin(overTheAirURL); 31 | 32 | int httpCode = http.GET(); 33 | if (httpCode != HTTP_CODE_OK) { 34 | DEBUG_PRINT("HTTP response should be 200"); 35 | BlynkState::set(MODE_ERROR); 36 | return; 37 | } 38 | int contentLength = http.getSize(); 39 | if (contentLength <= 0) { 40 | DEBUG_PRINT("Content-Length not defined"); 41 | BlynkState::set(MODE_ERROR); 42 | return; 43 | } 44 | 45 | bool canBegin = Update.begin(contentLength); 46 | if (!canBegin) { 47 | DEBUG_PRINT("Not enough space to begin OTA"); 48 | BlynkState::set(MODE_ERROR); 49 | return; 50 | } 51 | 52 | Client& client = http.getStream(); 53 | int written = Update.writeStream(client); 54 | if (written != contentLength) { 55 | DEBUG_PRINT(String("OTA written ") + written + " / " + contentLength + " bytes"); 56 | BlynkState::set(MODE_ERROR); 57 | return; 58 | } 59 | 60 | if (!Update.end()) { 61 | DEBUG_PRINT("Error #" + String(Update.getError())); 62 | BlynkState::set(MODE_ERROR); 63 | return; 64 | } 65 | 66 | if (!Update.isFinished()) { 67 | DEBUG_PRINT("Update failed."); 68 | BlynkState::set(MODE_ERROR); 69 | return; 70 | } 71 | 72 | DEBUG_PRINT("=== Update successfully completed. Rebooting."); 73 | restartMCU(); 74 | } 75 | 76 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_5_Anomaly_Detection/WioTerminal_EI_Anomaly_Detection_Blynk/ResetButton.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ResetButton.h 3 | * @author Blynk Inc. 4 | * @modified Dmitry Maslov (Seeed Studio) 5 | * @license This project is released under the MIT License (MIT) 6 | * @copyright Copyright (c) 2021 Blynk Inc. 7 | * @date May 2021 8 | * @brief 9 | * 10 | */ 11 | 12 | volatile bool g_buttonPressed = false; 13 | volatile uint32_t g_buttonPressTime = -1; 14 | 15 | void button_action(void) 16 | { 17 | BlynkState::set(MODE_RESET_CONFIG); 18 | } 19 | 20 | void button_change(void) 21 | { 22 | #if BOARD_BUTTON_ACTIVE_LOW 23 | bool buttonState = !digitalRead(BOARD_BUTTON_PIN); 24 | #else 25 | bool buttonState = digitalRead(BOARD_BUTTON_PIN); 26 | #endif 27 | 28 | if (buttonState && !g_buttonPressed) { 29 | g_buttonPressTime = millis(); 30 | g_buttonPressed = true; 31 | DEBUG_PRINT("Hold the button for 10 seconds to reset configuration..."); 32 | } else if (!buttonState && g_buttonPressed) { 33 | g_buttonPressed = false; 34 | uint32_t buttonHoldTime = millis() - g_buttonPressTime; 35 | if (buttonHoldTime >= BUTTON_HOLD_TIME_ACTION) { 36 | button_action(); 37 | } else { 38 | // User action 39 | } 40 | g_buttonPressTime = -1; 41 | } 42 | } 43 | 44 | void button_init() 45 | { 46 | #if BOARD_BUTTON_ACTIVE_LOW 47 | pinMode(BOARD_BUTTON_PIN, INPUT_PULLUP); 48 | #else 49 | pinMode(BOARD_BUTTON_PIN, INPUT_PULLDOWN); 50 | #endif 51 | attachInterrupt(BOARD_BUTTON_PIN, button_change, CHANGE); 52 | } 53 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_5_Anomaly_Detection/WioTerminal_EI_Anomaly_Detection_Blynk/Settings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * General options 3 | */ 4 | 5 | #define BOARD_HARDWARE_VERSION "1.0.0" 6 | 7 | /* 8 | * Board configuration (see examples below). 9 | */ 10 | 11 | // Custom board configuration 12 | #define BOARD_BUTTON_PIN WIO_KEY_A // Pin where user button is attached 13 | #define BOARD_BUTTON_ACTIVE_LOW true // true if button is "active-low" 14 | 15 | #define BOARD_LED_PIN LED_BUILTIN // Set LED pin - if you have a single-color LED attached 16 | #define BOARD_LED_INVERSE false // true if LED is common anode, false if common cathode 17 | #define BOARD_LED_BRIGHTNESS 255 // 0..255 brightness control 18 | 19 | /** 20 | * @file Settings.h 21 | * @author Blynk Inc. 22 | * @modified Dmitry Maslov (Seeed Studio) 23 | * @license This project is released under the MIT License (MIT) 24 | * @copyright Copyright (c) 2021 Blynk Inc. 25 | * @date May 2021 26 | * @brief 27 | * 28 | */ 29 | 30 | /* 31 | * Advanced options 32 | */ 33 | 34 | #define BUTTON_HOLD_TIME_INDICATION 3000 35 | #define BUTTON_HOLD_TIME_ACTION 10000 36 | 37 | #define BOARD_PWM_MAX 1023 38 | 39 | #define LEDC_CHANNEL_1 1 40 | #define LEDC_CHANNEL_2 2 41 | #define LEDC_CHANNEL_3 3 42 | #define LEDC_TIMER_BITS 10 43 | #define LEDC_BASE_FREQ 12000 44 | 45 | #define CONFIG_AP_URL "blynk.setup" 46 | #define CONFIG_DEFAULT_SERVER "blynk.cloud" 47 | #define CONFIG_DEFAULT_PORT 80 48 | 49 | 50 | #define WIFI_NET_CONNECT_TIMEOUT 30000 51 | #define WIFI_CLOUD_CONNECT_TIMEOUT 30000 52 | #define WIFI_AP_CONFIG_PORT 80 53 | #define WIFI_AP_IP IPAddress(192, 168, 4, 1) 54 | #define WIFI_AP_Subnet IPAddress(255, 255, 255, 0) 55 | #define WIFI_CAPTIVE_PORTAL_ENABLE 1 56 | 57 | //#define USE_TC3 58 | //#define USE_TCC0 59 | 60 | //#define BLYNK_NO_DEFAULT_BANNER 61 | 62 | #if defined(APP_DEBUG) 63 | #define DEBUG_PRINT(...) BLYNK_LOG1(__VA_ARGS__) 64 | #else 65 | #define DEBUG_PRINT(...) 66 | #endif 67 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_5_Anomaly_Detection/WioTerminal_EI_Anomaly_Detection_LCD/WioTerminal_EI_Anomaly_Detection_LCD.ino: -------------------------------------------------------------------------------- 1 | /* 2 | An example sketch for Edge Impulse trained model inference for Anomaly detection with Accelerometer and LCD indication 3 | 4 | Copyright (c) 2021 Seeed technology co., ltd. 5 | Author : Dmitry Maslov 6 | Create Time : May 2021 7 | Change Log : 8 | 9 | The MIT License (MIT) 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #define ANOMALY_THRESHOLD 0.5 31 | 32 | /* Includes ---------------------------------------------------------------- */ 33 | #include 34 | #include"LIS3DHTR.h" 35 | #include"TFT_eSPI.h" 36 | 37 | TFT_eSPI tft; 38 | LIS3DHTR lis; 39 | 40 | /* Constant defines -------------------------------------------------------- */ 41 | #define CONVERT_G_TO_MS2 9.80665f 42 | 43 | /* Private variables ------------------------------------------------------- */ 44 | static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal 45 | 46 | /** 47 | * @brief Arduino setup function 48 | */ 49 | void setup() 50 | { 51 | // put your setup code here, to run once: 52 | Serial.begin(115200); 53 | //while (!Serial) {delay(10);} 54 | 55 | Serial.println("Edge Impulse Inferencing Demo"); 56 | 57 | tft.begin(); 58 | tft.setRotation(3); 59 | 60 | lis.begin(Wire1); 61 | 62 | if (!lis.available()) { 63 | Serial.println("Failed to initialize IMU!"); 64 | while (1); 65 | } 66 | else { 67 | ei_printf("IMU initialized\r\n"); 68 | } 69 | lis.setOutputDataRate(LIS3DHTR_DATARATE_100HZ); // Setting output data rage to 25Hz, can be set up tp 5kHz 70 | lis.setFullScaleRange(LIS3DHTR_RANGE_16G); // Setting scale range to 2g, select from 2,4,8,16g 71 | 72 | 73 | if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != 3) { 74 | ei_printf("ERR: EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME should be equal to 3 (the 3 sensor axes)\n"); 75 | return; 76 | } 77 | } 78 | 79 | /** 80 | * @brief Printf function uses vsnprintf and output using Arduino Serial 81 | * 82 | * @param[in] format Variable argument list 83 | */ 84 | void ei_printf(const char *format, ...) { 85 | static char print_buf[1024] = { 0 }; 86 | 87 | va_list args; 88 | va_start(args, format); 89 | int r = vsnprintf(print_buf, sizeof(print_buf), format, args); 90 | va_end(args); 91 | 92 | if (r > 0) { 93 | Serial.write(print_buf); 94 | } 95 | } 96 | 97 | /** 98 | * @brief Get data and run inferencing 99 | * 100 | * @param[in] debug Get debug info if true 101 | */ 102 | void loop() 103 | { 104 | 105 | ei_printf("Sampling...\n"); 106 | 107 | // Allocate a buffer here for the values we'll read from the IMU 108 | float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 }; 109 | 110 | for (size_t ix = 0; ix < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; ix += 3) { 111 | // Determine the next tick (and then sleep later) 112 | uint64_t next_tick = micros() + (EI_CLASSIFIER_INTERVAL_MS * 1000); 113 | 114 | lis.getAcceleration(&buffer[ix], &buffer[ix+1], &buffer[ix + 2]); 115 | buffer[ix + 0] *= CONVERT_G_TO_MS2; 116 | buffer[ix + 1] *= CONVERT_G_TO_MS2; 117 | buffer[ix + 2] *= CONVERT_G_TO_MS2; 118 | 119 | delayMicroseconds(next_tick - micros()); 120 | } 121 | 122 | // Turn the raw buffer in a signal which we can the classify 123 | signal_t signal; 124 | int err = numpy::signal_from_buffer(buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal); 125 | if (err != 0) { 126 | ei_printf("Failed to create signal from buffer (%d)\n", err); 127 | return; 128 | } 129 | 130 | // Run the classifier 131 | ei_impulse_result_t result = { 0 }; 132 | 133 | err = run_classifier(&signal, &result, debug_nn); 134 | if (err != EI_IMPULSE_OK) { 135 | ei_printf("ERR: Failed to run classifier (%d)\n", err); 136 | return; 137 | } 138 | 139 | // print the predictions 140 | ei_printf("Predictions "); 141 | ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)", 142 | result.timing.dsp, result.timing.classification, result.timing.anomaly); 143 | ei_printf(": \n"); 144 | for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) { 145 | ei_printf(" %s: %.5f\n", result.classification[ix].label, result.classification[ix].value); 146 | } 147 | #if EI_CLASSIFIER_HAS_ANOMALY == 1 148 | ei_printf(" anomaly score: %.3f\n", result.anomaly); 149 | 150 | if (result.anomaly > ANOMALY_THRESHOLD) 151 | { 152 | tft.fillScreen(TFT_RED); 153 | tft.setFreeFont(&FreeSansBoldOblique12pt7b); 154 | tft.drawString("Anomaly detected", 20, 80); 155 | delay(1000); 156 | tft.fillScreen(TFT_WHITE); 157 | } 158 | 159 | #endif 160 | } 161 | 162 | #if !defined(EI_CLASSIFIER_SENSOR) || EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_ACCELEROMETER 163 | #error "Invalid model for current sensor" 164 | #endif 165 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_6_Speech_Recognition/README.md: -------------------------------------------------------------------------------- 1 | # TinyML Course 6 Speech Recognition (TensorFlow Micro) 2 | 3 | To run test on static data you will need sufficiently new version of Tensorflow Lite for Microcontrollers. Read on how to get it in [Seeed Wiki](https://wiki.seeedstudio.com/Wio-Terminal-TinyML-TFLM-1/#install-the-arduino-tensorflow-lite-library). 4 | 5 | To train your own model, have a look at [Speech-to-Intent-Micro](https://github.com/AIWintermuteAI/Speech-to-Intent-Micro) repository. 6 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_6_Speech_Recognition/Wio_Terminal_TF-MICRO_Speech_Recognition_Mic/dma_rec.h: -------------------------------------------------------------------------------- 1 | #ifndef REC 2 | #define REC 3 | 4 | #include "Arduino.h" 5 | 6 | #define SAMPLES 48000 7 | #define BUF_SIZE 320 8 | //#define DEBUG 9 | 10 | class FilterBuHp 11 | { 12 | public: 13 | FilterBuHp(); 14 | private: 15 | float v[2]; 16 | public: 17 | float step(float x); 18 | }; 19 | 20 | static void audio_rec_callback(uint16_t *buf, uint32_t buf_len); 21 | void DMAC_1_Handler(); 22 | void config_dma_adc(); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_6_Speech_Recognition/Wio_Terminal_TF-MICRO_Speech_Recognition_Mic/mfcc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Arm Limited or its affiliates. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the License); you may 7 | * not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT 14 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __KWS_MFCC_H__ 20 | #define __KWS_MFCC_H__ 21 | 22 | #include "arm_math.h" 23 | #include "string.h" 24 | 25 | #define SAMP_FREQ 16000 26 | #define NUM_FBANK_BINS 40 27 | #define MEL_LOW_FREQ 100 28 | #define MEL_HIGH_FREQ 8000 29 | 30 | #define M_2PI 6.283185307179586476925286766559005 31 | 32 | class MFCC{ 33 | private: 34 | int num_mfcc_features; 35 | int frame_len; 36 | int frame_len_padded; 37 | int mfcc_dec_bits; 38 | float * frame; 39 | float * buffer; 40 | float * mel_energies; 41 | float * window_func; 42 | int32_t * fbank_filter_first; 43 | int32_t * fbank_filter_last; 44 | float ** mel_fbank; 45 | float * dct_matrix; 46 | arm_rfft_fast_instance_f32 * rfft; 47 | float * create_dct_matrix(int32_t input_length, int32_t coefficient_count); 48 | float ** create_mel_fbank(); 49 | 50 | static inline float InverseMelScale(float mel_freq) { 51 | return 700.0f * (expf (mel_freq / 1127.0f) - 1.0f); 52 | } 53 | 54 | static inline float MelScale(float freq) { 55 | return 1127.0f * logf (1.0f + freq / 700.0f); 56 | } 57 | 58 | public: 59 | MFCC(int num_mfcc_features, int frame_len, int mfcc_dec_bits); 60 | ~MFCC(); 61 | void mfcc_compute(const int16_t* data, float* mfcc_out); 62 | }; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_6_Speech_Recognition/Wio_Terminal_TF-MICRO_Speech_Recognition_SD_card/mfcc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Arm Limited or its affiliates. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the License); you may 7 | * not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT 14 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __KWS_MFCC_H__ 20 | #define __KWS_MFCC_H__ 21 | 22 | #include "arm_math.h" 23 | #include "string.h" 24 | 25 | #define SAMP_FREQ 16000 26 | #define NUM_FBANK_BINS 40 27 | #define MEL_LOW_FREQ 100 28 | #define MEL_HIGH_FREQ 8000 29 | 30 | #define M_2PI 6.283185307179586476925286766559005 31 | 32 | class MFCC{ 33 | private: 34 | int num_mfcc_features; 35 | int frame_len; 36 | int frame_len_padded; 37 | int mfcc_dec_bits; 38 | float * frame; 39 | float * buffer; 40 | float * mel_energies; 41 | float * window_func; 42 | int32_t * fbank_filter_first; 43 | int32_t * fbank_filter_last; 44 | float ** mel_fbank; 45 | float * dct_matrix; 46 | arm_rfft_fast_instance_f32 * rfft; 47 | float * create_dct_matrix(int32_t input_length, int32_t coefficient_count); 48 | float ** create_mel_fbank(); 49 | 50 | static inline float InverseMelScale(float mel_freq) { 51 | return 700.0f * (expf (mel_freq / 1127.0f) - 1.0f); 52 | } 53 | 54 | static inline float MelScale(float freq) { 55 | return 1127.0f * logf (1.0f + freq / 700.0f); 56 | } 57 | 58 | public: 59 | MFCC(int num_mfcc_features, int frame_len, int mfcc_dec_bits); 60 | ~MFCC(); 61 | void mfcc_compute(const int16_t* data, float* mfcc_out); 62 | }; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_6_Speech_Recognition/Wio_Terminal_TF-MICRO_Speech_Recognition_SD_card/read_wav.cpp: -------------------------------------------------------------------------------- 1 | #include "read_wav.h" 2 | 3 | File sFile; 4 | 5 | void init_SD() { 6 | 7 | if (!SD.begin(SDCARD_SS_PIN, SDCARD_SPI)) { 8 | Serial.println("SD initialization failed!"); 9 | while (1); 10 | } 11 | Serial.println("SD initialization done."); 12 | 13 | } 14 | 15 | 16 | void open_wav(String filename) { 17 | sFile = SD.open(filename, FILE_READ); 18 | sFile.seek(44); 19 | } 20 | 21 | void read_wav(int16_t* audio_buffer) { 22 | sFile.read(audio_buffer, BUF_SIZE*2); 23 | 24 | //for (int i = 0; i < BUF_SIZE; i++) { 25 | //Serial.println(audio_buffer[i]); 26 | //} 27 | } 28 | 29 | void close_wav() { 30 | sFile.close(); 31 | } 32 | -------------------------------------------------------------------------------- /examples/WioTerminal_TinyML_6_Speech_Recognition/Wio_Terminal_TF-MICRO_Speech_Recognition_SD_card/read_wav.h: -------------------------------------------------------------------------------- 1 | #ifndef READ_WAV 2 | #define READ_WAV 3 | 4 | #include 5 | #include 6 | #include "SD/Seeed_SD.h" 7 | 8 | #define SAMPLES 48000 9 | #define BUF_SIZE 480 10 | 11 | void init_SD(); 12 | void open_wav(String filename); 13 | void read_wav(int16_t* audio_buffer); 14 | void close_wav(); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /examples/WioTerminal_USB2Serial_Burn8720/WioTerminal_USB2Serial_Burn8720.ino: -------------------------------------------------------------------------------- 1 | #include "TFT_eSPI.h" 2 | 3 | #include "Free_Fonts.h" //include the header file 4 | volatile byte state_a = LOW; 5 | volatile byte state_b = LOW; 6 | volatile byte state_c = LOW; 7 | volatile byte do_break = 0; 8 | TFT_eSPI tft; 9 | 10 | void key_a_input() 11 | { 12 | state_a = !state_a; 13 | do_break = 1; 14 | } 15 | void key_b_input() 16 | { 17 | state_b = !state_b; 18 | do_break = 1; 19 | } 20 | void key_c_input() 21 | { 22 | state_c = !state_c; 23 | do_break = 1; 24 | } 25 | 26 | void setup() 27 | { 28 | Serial.begin(115200); 29 | //Serial1.begin(115200); 30 | pinMode(WIO_KEY_A, INPUT_PULLUP); 31 | 32 | pinMode(WIO_KEY_B, INPUT_PULLUP); 33 | 34 | pinMode(WIO_KEY_C, INPUT_PULLUP); 35 | attachInterrupt(digitalPinToInterrupt(WIO_KEY_A), key_a_input, CHANGE); 36 | attachInterrupt(digitalPinToInterrupt(WIO_KEY_B), key_b_input, CHANGE); 37 | attachInterrupt(digitalPinToInterrupt(WIO_KEY_C), key_c_input, CHANGE); 38 | 39 | tft.begin(); 40 | tft.setRotation(3); 41 | tft.fillScreen(TFT_BLACK); //Black background 42 | tft.setFreeFont(FSSBO12); //select Free, Sans, Bold, Oblique, 12pt. 43 | } 44 | 45 | void loop() 46 | { 47 | 48 | if (state_a == LOW) 49 | { 50 | uint32_t baud; 51 | 52 | uint32_t old_baud; 53 | while (digitalRead(WIO_KEY_A) == LOW) 54 | ; 55 | tft.drawString("Burn RTL8720 fw", 70, 80); //prints string at (70,80) 56 | state_a = 1; 57 | // initialize both serial ports: 58 | pinMode(PIN_SERIAL2_RX, OUTPUT); 59 | pinMode(RTL8720D_CHIP_PU, OUTPUT); 60 | digitalWrite(PIN_SERIAL2_RX, LOW); 61 | digitalWrite(RTL8720D_CHIP_PU, LOW); 62 | delay(500); 63 | digitalWrite(RTL8720D_CHIP_PU, HIGH); 64 | delay(500); 65 | pinMode(PIN_SERIAL2_RX, INPUT); 66 | Serial.beginWithoutDTR(115200); 67 | // Serial.baud 68 | old_baud = Serial.baud(); 69 | RTL8720D.begin(old_baud); 70 | 71 | delay(500); 72 | while (1) 73 | { 74 | baud = Serial.baud(); 75 | if(baud != old_baud) 76 | { 77 | RTL8720D.begin(baud); 78 | old_baud = baud; 79 | } 80 | // read from port 1, send to port 0: 81 | 82 | if (Serial.available()) 83 | { 84 | 85 | int inbyte = Serial.read(); 86 | 87 | RTL8720D.write(inbyte); 88 | 89 | //Serial1.write(inbyte); 90 | } 91 | 92 | // read from port 1, send to port 0: 93 | 94 | if (RTL8720D.available()) 95 | { 96 | 97 | int inbyte = RTL8720D.read(); 98 | 99 | Serial.write(inbyte); 100 | 101 | //Serial1.write(inbyte); 102 | } 103 | 104 | if (do_break == 1) 105 | { 106 | do_break = 0; 107 | break; 108 | } 109 | } 110 | } 111 | else if (state_b == LOW) 112 | { 113 | while (digitalRead(WIO_KEY_B) == LOW) 114 | ; 115 | tft.drawString("USB to Serial ", 70, 80); //prints string at (70,80) 116 | state_b = 1; 117 | // put your setup code here, to run once: 118 | uint32_t baud; 119 | 120 | uint32_t old_baud; 121 | 122 | digitalWrite(RTL8720D_CHIP_PU, LOW); 123 | delay(500); 124 | digitalWrite(RTL8720D_CHIP_PU, HIGH); 125 | delay(500); 126 | 127 | Serial.begin(115200); 128 | 129 | baud = Serial.baud(); 130 | 131 | old_baud = baud; 132 | 133 | RTL8720D.begin(baud); 134 | while (1) 135 | { 136 | 137 | // put your main code here, to run repeatedly: 138 | baud = Serial.baud(); 139 | if (baud != old_baud) 140 | { 141 | RTL8720D.begin(baud); 142 | while (!Serial) 143 | ; 144 | old_baud = baud; 145 | // SerialUSB.println(baud); 146 | } 147 | if (Serial.available() > 0) 148 | { 149 | char c = Serial.read(); 150 | RTL8720D.write(c); 151 | } 152 | if (RTL8720D.available() > 0) 153 | { 154 | char c = RTL8720D.read(); 155 | Serial.write(c); 156 | } 157 | if (do_break == 1) 158 | { 159 | do_break = 0; 160 | break; 161 | } 162 | } 163 | } 164 | else if (state_c == LOW) 165 | { 166 | while (digitalRead(WIO_KEY_C) == LOW) 167 | ; 168 | tft.drawString("C Key pressed", 70, 80); //prints string at (70,80) 169 | state_c = 1; 170 | while (1) 171 | { 172 | if (do_break == 1) 173 | { 174 | do_break = 0; 175 | break; 176 | } 177 | } 178 | 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /examples/WioTerminal_WebBluetooth/WioTerminal_WebBluetooth.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define accelerometerService "19b10000-e8f2-537e-4f6c-d104768a1214" 6 | #define firstCharacteristic "19b10010-e8f2-537e-4f6c-d104768a1214" 7 | #define DESCRIPTOR_UUID "19b10010" 8 | 9 | LIS3DHTR lis; 10 | 11 | bool deviceConnected = false; 12 | bool oldDeviceConnected = false; 13 | 14 | BLEServer *pServer = NULL; 15 | BLECharacteristic * pCharacteristic; 16 | 17 | class MyServerCallbacks: public BLEServerCallbacks { 18 | void onConnect(BLEServer* pServer) { 19 | Serial.println("MyServerCallbacks onConnect "); 20 | deviceConnected = true; 21 | }; 22 | 23 | void onDisconnect(BLEServer* pServer) { 24 | deviceConnected = false; 25 | } 26 | }; 27 | 28 | class MyCallbacks: public BLECharacteristicCallbacks { 29 | void onWrite(BLECharacteristic *pCharacteristic) { 30 | std::string rxValue = pCharacteristic->getValue(); 31 | 32 | if (rxValue.length() > 0) { 33 | Serial.println("*********"); 34 | Serial.print("Received Value: "); 35 | for (int i = 0; i < rxValue.length(); i++) 36 | Serial.print(rxValue[i]); 37 | 38 | Serial.println(); 39 | Serial.println("*********"); 40 | } 41 | } 42 | }; 43 | 44 | void setup() { 45 | Serial.begin(115200); 46 | // while(!Serial){}; 47 | 48 | lis.begin(Wire1); 49 | if (!lis) { 50 | Serial.println("Accelerater Error!"); 51 | while(1); 52 | } 53 | lis.setOutputDataRate(LIS3DHTR_DATARATE_25HZ); //Data output rate 54 | lis.setFullScaleRange(LIS3DHTR_RANGE_2G); //Scale range set to 2g 55 | Serial.println("Accelerater Initialised!"); 56 | 57 | Serial.println("Starting BLE work!"); 58 | 59 | BLEDevice::init("Accelerometer"); 60 | pServer = BLEDevice::createServer(); 61 | pServer->setCallbacks(new MyServerCallbacks()); 62 | 63 | BLEService *pService = pServer->createService(accelerometerService); 64 | pCharacteristic = pService->createCharacteristic( 65 | firstCharacteristic, 66 | BLECharacteristic::PROPERTY_READ | 67 | BLECharacteristic::PROPERTY_WRITE 68 | ); 69 | pCharacteristic->setAccessPermissions(GATT_PERM_READ | GATT_PERM_WRITE); 70 | BLEDescriptor *pDescriptor = pCharacteristic->createDescriptor( 71 | DESCRIPTOR_UUID, 72 | ATTRIB_FLAG_VOID | ATTRIB_FLAG_ASCII_Z, 73 | GATT_PERM_READ | GATT_PERM_WRITE, 74 | 2 75 | ); 76 | pCharacteristic->setCallbacks(new MyCallbacks()); 77 | pService->start(); 78 | 79 | BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); 80 | pAdvertising->addServiceUUID(accelerometerService); 81 | pAdvertising->setScanResponse(true); 82 | pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue 83 | pAdvertising->setMinPreferred(0x12); 84 | BLEDevice::startAdvertising(); 85 | Serial.println("Characteristic defined! Now you can read it in your phone!"); 86 | } 87 | 88 | void loop() { 89 | if (deviceConnected) { 90 | updateAcceleration(); 91 | } 92 | // disconnecting 93 | if (!deviceConnected && oldDeviceConnected) { 94 | delay(500); // give the bluetooth stack the chance to get things ready 95 | pServer->startAdvertising(); // restart advertising 96 | Serial.println("start advertising"); 97 | oldDeviceConnected = deviceConnected; 98 | } 99 | // connecting 100 | if (deviceConnected && !oldDeviceConnected) { 101 | // do stuff here on connecting 102 | oldDeviceConnected = deviceConnected; 103 | } 104 | } 105 | 106 | void updateAcceleration() { 107 | float x_values, y_values, z_values; 108 | x_values = lis.getAccelerationX(); 109 | y_values = lis.getAccelerationY(); 110 | z_values = lis.getAccelerationZ(); 111 | 112 | String accelerometerData = String(x_values)+"|"+String(y_values)+"|"+String(z_values); 113 | Serial.println(accelerometerData); 114 | pCharacteristic->setValue(accelerometerData.c_str()); 115 | pCharacteristic->notify(); 116 | delay(20); 117 | } 118 | -------------------------------------------------------------------------------- /examples/jumper/rgb332/0.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/0.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/1.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/2.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/3.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/4.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/5.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/6.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/6.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/7.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/7.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/8.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/8.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/9.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/9.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/big_1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/big_1.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/big_2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/big_2.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/big_3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/big_3.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/big_block.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/big_block.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/breaking_out.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/breaking_out.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/cloud.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/cloud.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/failure.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/failure.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/fly0.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/fly0.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/fly1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/fly1.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/game_over.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/game_over.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/go.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/go.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/jump.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/jump.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/moon.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/moon.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/road.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/road.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/run0.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/run0.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/run1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/run1.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/setup.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/setup.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/small_block.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/small_block.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/wait_play.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/wait_play.bmp -------------------------------------------------------------------------------- /examples/jumper/rgb332/wire.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/examples/jumper/rgb332/wire.bmp -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Seeed Arduino Sketchbook 2 | version=1.0.2 3 | author=Seeed Studio 4 | maintainer=Seeed Studio 5 | sentence=Wio Terminal and Other Seeed Demos 6 | paragraph=This library provides many Wio Terminal demos and some other demos for Seeed products 7 | category=Other 8 | url=https://github.com/Seeed-Studio/Seeed_Arduino_Sketchbook 9 | architectures=* 10 | -------------------------------------------------------------------------------- /others/RawImage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | 6 | /* 7 | USAGE: 8 | 9 | // when use 8bit color. 10 | Raw8 * img8 = newImage("path to sd card image."); 11 | 12 | // when use 16bit color. 13 | Raw16 * img16 = newImage("path to sd card image."); 14 | 15 | // do some drawing. 16 | // img8->draw(); 17 | 18 | // remember release it 19 | img8->release(); 20 | img16->release(); 21 | */ 22 | 23 | extern TFT_eSPI tft; 24 | 25 | template 26 | struct RawImage{ 27 | type * ptr(){ 28 | return (type *)(this + 1); 29 | } 30 | type get(int16_t x, int16_t y){ 31 | return this->ptr()[y * width() + x]; 32 | } 33 | void draw(size_t x = 0, size_t y = 0){ 34 | tft.pushImage(x, y, width(), height(), ptr()); 35 | } 36 | void release(){ 37 | delete [] this; 38 | } 39 | int16_t width(){ return _width; } 40 | int16_t height(){ return _height; } 41 | private: 42 | int16_t _width; 43 | int16_t _height; 44 | }; 45 | 46 | typedef RawImage Raw8; 47 | typedef RawImage Raw16; 48 | 49 | template 50 | RawImage * newImage(const char * path){ 51 | typedef RawImage raw; 52 | File f = SD.open(path, FILE_READ); 53 | if (!f){ 54 | return nullptr; 55 | } 56 | int32_t size = f.size(); 57 | raw * mem = (raw *)new uint8_t[size]; 58 | if (mem == nullptr){ 59 | return nullptr; 60 | } 61 | f.read(mem, size); 62 | f.close(); 63 | return mem; 64 | } 65 | 66 | template 67 | void drawImage(const char * path, size_t x = 0, size_t y = 0){ 68 | auto img = newImage(path); 69 | img->draw(x, y); 70 | img->release(); 71 | } 72 | -------------------------------------------------------------------------------- /src/Seeed_Arduino_Sketchbook.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Seeed-Studio/Seeed_Arduino_Sketchbook/4f39ac4578267b5eeb1b6093f38b4efd02128c83/src/Seeed_Arduino_Sketchbook.h --------------------------------------------------------------------------------