├── library.properties ├── .github ├── workflows │ ├── Arduino-Lint-Check.yml │ ├── clang-format-check.yml │ └── arduino-action-coreink-compile.yml ├── ISSUE_TEMPLATE │ └── bug-report.yml └── actions │ ├── action.yml │ └── arduino-test-compile.sh ├── library.json ├── src ├── utility │ ├── config.h │ ├── i2c_device.h │ ├── Speaker.h │ ├── Ink_eSPI.h │ ├── Ink_Sprite.h │ ├── Ink_eSPI.cpp │ ├── BM8563.h │ ├── Button.h │ ├── i2c_device.cpp │ ├── Speaker.cpp │ ├── WFT0154CZB3_INIT.h │ ├── Ink_Sprite.cpp │ ├── M5Timer.h │ ├── Button.cpp │ ├── M5Timer.cpp │ └── BM8563.cpp ├── M5CoreInk.h └── M5CoreInk.cpp ├── LICENSE ├── examples ├── Advanced │ ├── MultSerial │ │ └── MultSerial.ino │ ├── I2C_Tester │ │ └── I2C_Tester.ino │ ├── Counter │ │ └── Counter.ino │ ├── MultiTask │ │ └── MultiTask.ino │ ├── EzData │ │ └── EzData.ino │ ├── EEPROM │ │ └── EEPROM.ino │ └── MQTT │ │ └── MQTT.ino ├── Unit │ ├── LIMIT │ │ └── LIMIT.ino │ └── KEY │ │ └── KEY.ino ├── Basics │ ├── HelloWorld │ │ └── HelloWorld.ino │ ├── FactoryTest │ │ ├── icon.h │ │ ├── Num18x29.cpp │ │ ├── FactoryTest.ino │ │ └── Num_55x40.cpp │ ├── RTC_WakeUp │ │ └── RTC_WakeUp.ino │ ├── RTC_BM8563 │ │ └── RTC_BM8563.ino │ ├── Button │ │ └── Button.ino │ ├── Simple_Clock │ │ └── Simple_Clock.ino │ └── RTC_Clock │ │ └── RTC_Clock.ino └── KIT │ └── SCALES_KIT │ └── SCALES_KIT.ino ├── README_cn.md ├── README.md └── .clang-format /library.properties: -------------------------------------------------------------------------------- 1 | name=M5Core-Ink 2 | version=1.0.0 3 | author=M5Stack 4 | maintainer=M5Stack 5 | sentence=Library for M5CoreInk development kit 6 | paragraph=See more on https://docs.m5stack.com/en/core/coreink 7 | category=Device Control 8 | url=https://github.com/m5stack/M5Core-Ink.git 9 | architectures=esp32 10 | includes=M5CoreInk.h 11 | depends=M5GFX,M5Family 12 | -------------------------------------------------------------------------------- /.github/workflows/Arduino-Lint-Check.yml: -------------------------------------------------------------------------------- 1 | name: Arduino Lint 2 | on: 3 | push: 4 | pull_request: 5 | jobs: 6 | lint: 7 | name: Lint Check 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: arduino/arduino-lint-action@v1 12 | with: 13 | library-manager: update 14 | compliance: strict 15 | project-type: all -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "M5Core-Ink", 3 | "description": "M5Stack CoreInk development board", 4 | "keywords": "M5Stack CoreInk", 5 | "authors": { 6 | "name": "M5Stack", 7 | "url": "http://www.m5stack.com" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/m5stack/M5Core-Ink.git" 12 | }, 13 | "version": "1.0.0", 14 | "frameworks": "arduino", 15 | "platforms": "espressif32" 16 | } -------------------------------------------------------------------------------- /src/utility/config.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG_H_ 2 | #define _CONFIG_H_ 3 | 4 | #define INK_SPI_CS 9 5 | #define INK_SPI_SCK 18 6 | #define INK_SPI_MOSI 23 7 | #define INK_SPI_DC 15 8 | #define INK_SPI_BUSY 4 9 | #define INK_SPI_RST 0 10 | 11 | #define BUTTON_UP_PIN 37 12 | #define BUTTON_DOWN_PIN 39 13 | #define BUTTON_MID_PIN 38 14 | #define BUTTON_EXT_PIN 5 15 | #define BUTTON_PWR_PIN 27 16 | 17 | #define LED_EXT_PIN 10 18 | 19 | #define SPEAKER_PIN 2 20 | #define TONE_PIN_CHANNEL 0 21 | 22 | #define POWER_HOLD_PIN 12 23 | 24 | #endif -------------------------------------------------------------------------------- /src/utility/i2c_device.h: -------------------------------------------------------------------------------- 1 | #ifndef _I2C_DEVICE_BUS_ 2 | #define _I2C_DEVICE_BUS_ 3 | 4 | #include "Arduino.h" 5 | #include "Wire.h" 6 | 7 | class I2C_DEVICE { 8 | private: 9 | TwoWire* _wire; 10 | uint8_t _scl; 11 | uint8_t _sda; 12 | uint8_t _freq; 13 | 14 | public: 15 | void begin(TwoWire* wire, uint8_t sda, uint8_t scl, long freq = 100000); 16 | bool writeBytes(uint8_t addr, uint8_t reg, uint8_t* buffer, uint8_t length); 17 | bool readBytes(uint8_t addr, uint8_t reg, uint8_t* buffer, uint8_t length); 18 | bool writeByte(uint8_t addr, uint8_t reg, uint8_t data); 19 | uint8_t readByte(uint8_t addr, uint8_t reg); 20 | bool writeBitOn(uint8_t addr, uint8_t reg, uint8_t data); 21 | bool writeBitOff(uint8_t addr, uint8_t reg, uint8_t data); 22 | }; 23 | 24 | #endif -------------------------------------------------------------------------------- /.github/workflows/clang-format-check.yml: -------------------------------------------------------------------------------- 1 | name: clang-format Check 2 | on: [push, pull_request] 3 | jobs: 4 | formatting-check: 5 | name: Formatting Check 6 | runs-on: ubuntu-latest 7 | strategy: 8 | matrix: 9 | path: 10 | - check: './' # path to include 11 | exclude: '(MahonyAHRS)' # path to exclude 12 | # - check: 'src' 13 | # exclude: '(Fonts)' # Exclude file paths containing "Fonts" 14 | # - check: 'examples' 15 | # exclude: '' 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Run clang-format style check for C/C++/Protobuf programs. 19 | uses: jidicula/clang-format-action@v4.8.0 20 | with: 21 | clang-format-version: '13' 22 | check-path: ${{ matrix.path['check'] }} 23 | exclude-regex: ${{ matrix.path['exclude'] }} 24 | -------------------------------------------------------------------------------- /src/utility/Speaker.h: -------------------------------------------------------------------------------- 1 | #ifndef _SPEAKER_H_ 2 | #define _SPEAKER_H_ 3 | 4 | #include "Arduino.h" 5 | #include "config.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif /* __cplusplus */ 10 | #include "esp32-hal-dac.h" 11 | #ifdef __cplusplus 12 | } 13 | #endif /* __cplusplus */ 14 | 15 | class SPEAKER { 16 | public: 17 | SPEAKER(void); 18 | 19 | void begin(); 20 | void end(); 21 | void mute(); 22 | void tone(uint16_t frequency); 23 | void tone(uint16_t frequency, uint32_t duration); 24 | void beep(); 25 | void setBeep(uint16_t frequency, uint16_t duration); 26 | void update(); 27 | 28 | void write(uint8_t value); 29 | void setVolume(uint8_t volume); 30 | void playMusic(const uint8_t *music_data, uint16_t sample_rate); 31 | 32 | private: 33 | uint32_t _count; 34 | uint8_t _volume; 35 | uint16_t _beep_duration; 36 | uint16_t _beep_freq; 37 | bool _begun; 38 | bool speaker_on; 39 | }; 40 | #endif 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 M5Stack 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. -------------------------------------------------------------------------------- /src/utility/Ink_eSPI.h: -------------------------------------------------------------------------------- 1 | #ifndef _INK_ESPI_H_ 2 | #define _INK_ESPI_H_ 3 | 4 | #include 5 | #include 6 | #include "soc/spi_reg.h" 7 | #include "config.h" 8 | #include "WFT0154CZB3_INIT.h" 9 | #include "M5GFX.h" 10 | 11 | // #define SPI_PORT VSPI 12 | 13 | // #define INK_SPI_FREQUENCY 10000000 14 | 15 | #define INK_FULL_MODE 0x00 16 | #define INK_PARTIAL_MODE 0x01 17 | 18 | #define INK_CLENR_MODE0 0 19 | #define INK_CLEAR_MODE1 1 20 | 21 | class Ink_eSPI : public M5GFX { 22 | public: 23 | Ink_eSPI() 24 | : M5GFX(){ 25 | 26 | }; 27 | void begin(); 28 | bool isInit(); 29 | 30 | int clear(int mode = INK_CLENR_MODE0); 31 | int clearDSRAM(); 32 | 33 | int drawBuff(uint8_t* buff, bool bitMode = true); 34 | int drawBuff(uint8_t* lastbuff, uint8_t* buff, size_t size); 35 | 36 | void switchMode(epd_mode_t mode); 37 | epd_mode_t getMode() { 38 | return _mode; 39 | } 40 | 41 | void deepSleep(); 42 | void powerHVON(); 43 | void powerHVOFF(); 44 | 45 | private: 46 | bool _isInit = false; 47 | int32_t _width, _height; 48 | epd_mode_t _mode = epd_text; 49 | }; 50 | 51 | #endif -------------------------------------------------------------------------------- /examples/Advanced/MultSerial/MultSerial.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2021 by M5Stack 4 | * Equipped with M5Core2 sample source code 5 | * 配套 M5Core2 示例源代码 6 | * Visit for more information: https://docs.m5stack.com/en/core/core2 7 | * 获取更多资料请访问:https://docs.m5stack.com/zh_CN/core/core2 8 | * 9 | * Describe: MultSerial. 多串口 10 | * Date: 2021/8/5 11 | ****************************************************************************** 12 | */ 13 | #include 14 | 15 | void setup() { 16 | M5.begin(); // Init M5Core2. 初始化 M5Core2 17 | // Serial2.begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t 18 | // txPin, bool invert) 19 | Serial2.begin(115200, SERIAL_8N1, 13, 20 | 14); // Init serial port 2. 初始化串口2 21 | } 22 | 23 | void loop() { 24 | if (Serial 25 | .available()) { // If the serial port reads data. 如果串口读到数据 26 | int ch = Serial.read(); // Copy the data read from the serial port to 27 | // the CH. 把串口读取到的数据复制给ch 28 | Serial2.write( 29 | ch); // Serial port 2 Outputs the CH content. 串口2输出ch的内容 30 | } 31 | 32 | if (Serial2.available()) { 33 | int ch = Serial2.read(); 34 | Serial.write(ch); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/M5CoreInk.h: -------------------------------------------------------------------------------- 1 | #ifndef _M5COREINK_H_ 2 | #define _M5COREINK_H_ 3 | 4 | #include 5 | 6 | #include "utility/config.h" 7 | 8 | #include "utility/BM8563.h" 9 | #include "utility/Ink_Sprite.h" 10 | #include "utility/Button.h" 11 | #include "utility/Ink_eSPI.h" 12 | #include "utility/Ink_Sprite.h" 13 | #include "utility/Speaker.h" 14 | 15 | class M5CoreInk { 16 | private: 17 | /* data */ 18 | // WFT0154CZB3 19 | public: 20 | M5CoreInk(/* args */); 21 | ~M5CoreInk(); 22 | 23 | int begin(bool InkEnable = true, bool wireEnable = false, 24 | bool SpeakerEnable = false); 25 | void update(); 26 | 27 | void shutdown(); 28 | int shutdown(int seconds); 29 | int shutdown(const RTC_TimeTypeDef &RTC_TimeStruct); 30 | int shutdown(const RTC_DateTypeDef &RTC_DateStruct, 31 | const RTC_TimeTypeDef &RTC_TimeStruct); 32 | 33 | #define DEBOUNCE_MS 10 34 | Button BtnUP = Button(BUTTON_UP_PIN, true, DEBOUNCE_MS); 35 | Button BtnDOWN = Button(BUTTON_DOWN_PIN, true, DEBOUNCE_MS); 36 | Button BtnMID = Button(BUTTON_MID_PIN, true, DEBOUNCE_MS); 37 | Button BtnEXT = Button(BUTTON_EXT_PIN, true, DEBOUNCE_MS); 38 | Button BtnPWR = Button(BUTTON_PWR_PIN, true, DEBOUNCE_MS); 39 | 40 | SPEAKER Speaker; 41 | RTC rtc; 42 | Ink_eSPI M5Ink; 43 | }; 44 | 45 | extern M5CoreInk M5; 46 | #define Rtc rtc 47 | #endif -------------------------------------------------------------------------------- /examples/Unit/LIMIT/LIMIT.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2022 by M5Stack 4 | * Equipped with M5CoreInk sample source code 5 | * 配套 M5CoreInk 示例源代码 6 | * Visit the website for more information: 7 | * 获取更多资料请访问: 8 | * 9 | * Product: Limit. 10 | * Date: 2022/6/1 11 | ******************************************************************************* 12 | */ 13 | 14 | #include 15 | 16 | Ink_Sprite InkPageSprite(&M5.M5Ink); 17 | 18 | #define KEY_PIN 33 // Define Limit Pin. 定义Limit连接引脚 19 | 20 | void setup() { 21 | M5.begin(); // Init M5Stack 初始化M5Stack 22 | M5.M5Ink.isInit(); // Init E-INK screen. 初始化E-INK屏幕驱动 23 | M5.M5Ink.clear(); 24 | delay(1000); 25 | if (InkPageSprite.creatSprite(0, 0, 200, 200, true) != 26 | 0) { // creat ink refresh Sprite. 创建画布. 27 | Serial.printf("Ink Sprite creat faild"); 28 | } else { 29 | Serial.printf("creatSprite success\n"); 30 | } 31 | InkPageSprite.drawString(30, 50, "UNIT-LIMIT Example"); 32 | InkPageSprite.drawString(8, 70, "Beep when limit was hit"); 33 | InkPageSprite.pushSprite(); 34 | 35 | pinMode(KEY_PIN, INPUT_PULLUP); // Init Limit pin. 初始化Limit引脚. 36 | } 37 | 38 | void loop() { 39 | if (!digitalRead(KEY_PIN)) { // If Limit was hit. 如果触碰了Limit. 40 | M5.Speaker.beep(); 41 | } else { 42 | M5.Speaker.mute(); 43 | } 44 | delay(100); 45 | } 46 | -------------------------------------------------------------------------------- /examples/Basics/HelloWorld/HelloWorld.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2021 by M5Stack 4 | * Equipped with CoreInk sample source code 5 | * 配套 CoreInk 示例源代码 6 | * Visit for more information: https://docs.m5stack.com/en/core/coreink 7 | * 获取更多资料请访问:https://docs.m5stack.com/zh_CN/core/coreink 8 | * 9 | * Describe: Hello World 10 | * Date: 2021/11/14 11 | ******************************************************************************* 12 | */ 13 | #include "M5CoreInk.h" 14 | 15 | Ink_Sprite InkPageSprite(&M5.M5Ink); //创建 M5Ink实例 16 | 17 | /* After CoreInk is started or reset 18 | the program in the setUp () function will be run, and this part will only be 19 | run once. 在 CoreInk 20 | 启动或者复位后,即会开始执行setup()函数中的程序,该部分只会执行一次。 */ 21 | void setup() { 22 | M5.begin(); // Initialize CoreInk. 初始化 CoreInk 23 | if (!M5.M5Ink.isInit()) { // check if the initialization is successful. 24 | // 检查初始化是否成功 25 | Serial.printf("Ink Init faild"); 26 | while (1) delay(100); 27 | } 28 | M5.M5Ink.clear(); // clear the screen. 清屏 29 | delay(1000); 30 | // creat ink Sprite. 创建图像区域 31 | if (InkPageSprite.creatSprite(0, 0, 200, 200, true) != 0) { 32 | Serial.printf("Ink Sprite creat faild"); 33 | } 34 | InkPageSprite.drawString(35, 50, "Hello World!"); // draw string. 35 | // 绘制字符串 36 | InkPageSprite.pushSprite(); // push the sprite. 推送图片 37 | } 38 | 39 | void loop() { 40 | } -------------------------------------------------------------------------------- /src/utility/Ink_Sprite.h: -------------------------------------------------------------------------------- 1 | #ifndef _INK_SPRITE_H_ 2 | #define _INK_SPRITE_H_ 3 | 4 | #include "Ink_eSPI.h" 5 | #include "M5GFX.h" 6 | 7 | #define CLEAR_DRAWBUFF 0x01 8 | #define CLEAR_LASTBUFF 0x02 9 | 10 | class Ink_Sprite : public M5Canvas { 11 | public: 12 | Ink_Sprite() : M5Canvas() { 13 | } 14 | Ink_Sprite(LovyanGFX* parent) : M5Canvas(parent) { 15 | } 16 | int creatSprite(uint16_t posX = 0, uint16_t posY = 0, uint16_t width = 200, 17 | uint16_t height = 200, bool copyFromMem = true); 18 | int pushSprite(); 19 | int deleteSprite(); 20 | 21 | void clear(int cleanFlag = CLEAR_DRAWBUFF); 22 | void drawPix(uint16_t posX, uint16_t posY, uint8_t pixBit); 23 | void FillRect(uint16_t posX, uint16_t posY, uint16_t width, uint16_t height, 24 | uint8_t pixBit); 25 | 26 | void drawFullBuff(uint8_t* buff, bool bitMode = true); 27 | void drawBuff(uint16_t posX, uint16_t posY, uint16_t width, uint16_t height, 28 | uint8_t* imageDataptr); 29 | 30 | void drawChar(uint16_t posX, uint16_t posY, char charData, 31 | const lgfx::FixedBMPfont* fontPtr = &fonts::AsciiFont24x48); 32 | void drawString(uint16_t posX, uint16_t posY, const char* charData, 33 | const lgfx::FixedBMPfont* fontPtr = &fonts::AsciiFont8x16); 34 | 35 | uint8_t* getSpritePtr() { 36 | return _spriteBuff; 37 | } 38 | 39 | uint16_t width() { 40 | return _width; 41 | } 42 | uint16_t height() { 43 | return _height; 44 | } 45 | uint16_t posX() { 46 | return _posX; 47 | } 48 | uint16_t posY() { 49 | return _posY; 50 | } 51 | 52 | private: 53 | bool isCreat = false; 54 | uint16_t _posX, _posY; 55 | uint16_t _width, _height; 56 | uint16_t _pixSize; 57 | 58 | uint8_t* _spriteBuff = nullptr; 59 | uint8_t* _lastBuff = nullptr; 60 | }; 61 | 62 | #endif -------------------------------------------------------------------------------- /src/utility/Ink_eSPI.cpp: -------------------------------------------------------------------------------- 1 | #include "Ink_eSPI.h" 2 | 3 | void Ink_eSPI::begin() { 4 | M5GFX::begin(); 5 | M5GFX::setEpdMode(epd_mode_t::epd_text); 6 | M5GFX::invertDisplay(true); 7 | M5GFX::clear(TFT_BLACK); 8 | _isInit = true; 9 | _width = 200; 10 | _height = 200; 11 | } 12 | 13 | int Ink_eSPI::clear(int mode) { 14 | M5GFX::clear(TFT_BLACK); 15 | M5GFX::fillScreen(TFT_BLACK); 16 | return 0; 17 | } 18 | 19 | [[deprecated("clearDSRAM is deprecated")]] int Ink_eSPI::clearDSRAM() { 20 | M5GFX::clear(); 21 | return 0; 22 | } 23 | 24 | int Ink_eSPI::drawBuff(uint8_t *buff, bool bitMode) { 25 | if (bitMode) { 26 | size_t _pixsize = _width * _height; 27 | size_t _bitsize = _pixsize / 8; 28 | uint8_t *data = (uint8_t *)malloc(_pixsize); 29 | if (!data) { 30 | return -1; 31 | } 32 | for (size_t i = 0; i < _bitsize; i++) { 33 | uint8_t _byte = buff[i]; 34 | for (size_t j = 0; j < 8; j++) { 35 | size_t index = i * 8 + j; 36 | if (((_byte << j) & 0x80) == 0x80) { 37 | data[index] = 0x00; 38 | } else { 39 | data[index] = 0xff; 40 | } 41 | } 42 | } 43 | M5GFX::pushImage(0, 0, _width, _height, data); 44 | free(data); 45 | } else { 46 | M5GFX::pushImage(0, 0, _width, _height, buff); 47 | } 48 | 49 | return 0; 50 | } 51 | 52 | int Ink_eSPI::drawBuff(uint8_t *lastbuff, uint8_t *buff, size_t size) { 53 | M5GFX::pushImage(0, 0, _width, _height, buff); 54 | return 0; 55 | } 56 | 57 | bool Ink_eSPI::isInit() { 58 | return _isInit; 59 | } 60 | 61 | void Ink_eSPI::switchMode(epd_mode_t mode) { 62 | M5GFX::setEpdMode(epd_mode_t::epd_quality); 63 | } 64 | 65 | void Ink_eSPI::deepSleep() { 66 | M5GFX::sleep(); 67 | } 68 | 69 | void Ink_eSPI::powerHVON() { 70 | M5GFX::powerSaveOff(); 71 | } 72 | 73 | void Ink_eSPI::powerHVOFF() { 74 | M5GFX::powerSaveOn(); 75 | } -------------------------------------------------------------------------------- /src/utility/BM8563.h: -------------------------------------------------------------------------------- 1 | #ifndef __BM8563_H__ 2 | #define __BM8563_H__ 3 | 4 | #include 5 | #include "i2c_device.h" 6 | 7 | #define BM8563_I2C_ADDR 0x51 8 | 9 | typedef struct RTC_Time { 10 | int8_t Hours; 11 | int8_t Minutes; 12 | int8_t Seconds; 13 | bool VLFlag; 14 | RTC_Time() : Hours(), Minutes(), Seconds() { 15 | } 16 | RTC_Time(int8_t h, int8_t m, int8_t s) : Hours(h), Minutes(m), Seconds(s) { 17 | } 18 | } RTC_TimeTypeDef; 19 | 20 | typedef struct RTC_Date { 21 | int8_t WeekDay; 22 | int8_t Month; 23 | int8_t Date; 24 | int16_t Year; 25 | RTC_Date() : WeekDay(), Month(), Date(), Year() { 26 | } 27 | RTC_Date(int8_t w, int8_t m, int8_t d, int16_t y) 28 | : WeekDay(w), Month(m), Date(d), Year(y) { 29 | } 30 | } RTC_DateTypeDef; 31 | 32 | class RTC { 33 | public: 34 | RTC(); 35 | 36 | void begin(void); 37 | 38 | void GetBm8563Time(void); 39 | 40 | void SetTime(RTC_TimeTypeDef *RTC_TimeStruct); 41 | void SetDate(RTC_DateTypeDef *RTC_DateStruct); 42 | 43 | void GetTime(RTC_TimeTypeDef *RTC_TimeStruct); 44 | void GetDate(RTC_DateTypeDef *RTC_DateStruct); 45 | 46 | int SetAlarmIRQ(int afterSeconds); 47 | int SetAlarmIRQ(const RTC_TimeTypeDef &RTC_TimeStruct); 48 | int SetAlarmIRQ(const RTC_DateTypeDef &RTC_DateStruct, 49 | const RTC_TimeTypeDef &RTC_TimeStruct); 50 | 51 | void clearIRQ(); 52 | void disableIRQ(); 53 | 54 | public: 55 | uint8_t Second; 56 | uint8_t Minute; 57 | uint8_t Hour; 58 | uint8_t Week; 59 | uint8_t Day; 60 | uint8_t Month; 61 | uint8_t Year; 62 | uint8_t DateString[9]; 63 | uint8_t TimeString[9]; 64 | 65 | uint8_t asc[14]; 66 | 67 | private: 68 | void Bcd2asc(void); 69 | void DataMask(); 70 | void Str2Time(void); 71 | 72 | uint8_t bcd2ToByte(uint8_t value); 73 | uint8_t byteToBcd2(uint8_t value); 74 | 75 | I2C_DEVICE _i2c; 76 | 77 | private: 78 | /*定义数组用来存储读取的时间数据 */ 79 | uint8_t trdata[7]; 80 | /*定义数组用来存储转换的 asc 码时间数据*/ 81 | // uint8_t asc[14]; 82 | }; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /src/utility/Button.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------* 2 | * Arduino Button Library v1.0 * 3 | * Jack Christensen Mar 2012 * 4 | * * 5 | * This work is licensed under the Creative Commons Attribution- * 6 | * ShareAlike 3.0 Unported License. To view a copy of this license, * 7 | * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * 8 | * letter to Creative Commons, 171 Second Street, Suite 300, * 9 | * San Francisco, California, 94105, USA. * 10 | *----------------------------------------------------------------------*/ 11 | #ifndef Button_h 12 | #define Button_h 13 | // #if ARDUINO >= 100 14 | #include 15 | // #else 16 | // #include 17 | // #endif 18 | class Button { 19 | public: 20 | Button(uint8_t pin, uint8_t invert, uint32_t dbTime); 21 | uint8_t read(); 22 | uint8_t isPressed(); 23 | uint8_t isReleased(); 24 | uint8_t wasPressed(); 25 | uint8_t wasReleased(); 26 | uint8_t pressedFor(uint32_t ms); 27 | uint8_t releasedFor(uint32_t ms); 28 | uint8_t wasReleasefor(uint32_t ms); 29 | uint32_t lastChange(); 30 | 31 | private: 32 | uint8_t _pin; // arduino pin number 33 | uint8_t _puEnable; // internal pullup resistor enabled 34 | uint8_t _invert; // if 0, interpret high state as pressed, else interpret 35 | // low state as pressed 36 | uint8_t _state; // current button state 37 | uint8_t _lastState; // previous button state 38 | uint8_t _changed; // state changed since last read 39 | uint32_t _time; // time of current state (all times are in ms) 40 | uint32_t _lastTime; // time of previous state 41 | uint32_t _lastChange; // time of last state change 42 | uint32_t _dbTime; // debounce time 43 | uint32_t _pressTime; // press time 44 | uint32_t _hold_time; // hold time call wasreleasefor 45 | }; 46 | #endif 47 | -------------------------------------------------------------------------------- /examples/Basics/FactoryTest/icon.h: -------------------------------------------------------------------------------- 1 | #ifndef _ICON_H_ 2 | #define _ICON_H_ 3 | 4 | #include "utility/Ink_Sprite.h" 5 | 6 | extern unsigned char image_CoreInkWelcome[5000]; 7 | extern unsigned char image_CoreInkTime[5000]; 8 | extern unsigned char image_CoreInkWifi[5000]; 9 | extern unsigned char image_CoreInkWWellcome[5000]; 10 | extern unsigned char image_coreInkMain[5000]; 11 | 12 | typedef enum { 13 | kRGBImage, 14 | } ImangePixMode_t; 15 | 16 | typedef struct { 17 | int width; 18 | int height; 19 | int bitCount; 20 | unsigned char *ptr; 21 | } image_t; 22 | 23 | // Num40x55 24 | extern unsigned char image_num_01[275]; //"0" W:40 H:55 25 | extern unsigned char image_num_02[275]; //"1" W:40 H:55 26 | extern unsigned char image_num_03[275]; //"2" W:40 H:55 27 | extern unsigned char image_num_04[275]; //"3" W:40 H:55 28 | extern unsigned char image_num_05[275]; //"4" W:40 H:55 29 | extern unsigned char image_num_06[275]; //"5" W:40 H:55 30 | extern unsigned char image_num_07[275]; //"6" W:40 H:55 31 | extern unsigned char image_num_08[275]; //"7" W:40 H:55 32 | extern unsigned char image_num_09[275]; //"8" W:40 H:55 33 | extern unsigned char image_num_10[275]; //"9" W:40 H:55 34 | extern unsigned char image_num_11[165]; //":" W:24 H:55 35 | 36 | // Num18x29 37 | extern unsigned char image_num_29_01[66]; //"0" W:18 H:29 38 | extern unsigned char image_num_29_02[66]; //"1" W:18 H:29 39 | extern unsigned char image_num_29_03[66]; //"2" W:18 H:29 40 | extern unsigned char image_num_29_04[66]; //"3" W:18 H:29 41 | extern unsigned char image_num_29_05[66]; //"4" W:18 H:29 42 | extern unsigned char image_num_29_06[66]; //"5" W:18 H:29 43 | extern unsigned char image_num_29_07[66]; //"6" W:18 H:29 44 | extern unsigned char image_num_29_08[66]; //"7" W:18 H:29 45 | extern unsigned char image_num_29_09[66]; //"8" W:18 H:29 46 | extern unsigned char image_num_29_10[66]; //"9" W:18 H:29 47 | extern unsigned char image_num_29_11[66]; //"/" W:18 H:29 48 | 49 | extern image_t warningImage; 50 | extern image_t wifiScanImage; 51 | 52 | extern image_t num55[11]; 53 | extern image_t num18x29[11]; 54 | 55 | #endif -------------------------------------------------------------------------------- /src/utility/i2c_device.cpp: -------------------------------------------------------------------------------- 1 | #include "i2c_device.h" 2 | 3 | void I2C_DEVICE::begin(TwoWire *wire, uint8_t sda, uint8_t scl, long freq) { 4 | _wire = wire; 5 | _sda = sda; 6 | _scl = scl; 7 | _freq = freq; 8 | _wire->begin(sda, scl, freq); 9 | } 10 | 11 | bool I2C_DEVICE::writeBytes(uint8_t addr, uint8_t reg, uint8_t *buffer, 12 | uint8_t length) { 13 | _wire->beginTransmission(addr); 14 | _wire->write(reg); 15 | _wire->write(buffer, length); 16 | if (_wire->endTransmission() == 0) return true; 17 | return false; 18 | } 19 | 20 | bool I2C_DEVICE::readBytes(uint8_t addr, uint8_t reg, uint8_t *buffer, 21 | uint8_t length) { 22 | uint8_t index = 0; 23 | _wire->beginTransmission(addr); 24 | _wire->write(reg); 25 | _wire->endTransmission(); 26 | if (_wire->requestFrom(addr, length)) { 27 | for (uint8_t i = 0; i < length; i++) { 28 | buffer[index++] = _wire->read(); 29 | } 30 | return true; 31 | } 32 | return false; 33 | } 34 | 35 | bool I2C_DEVICE::writeByte(uint8_t addr, uint8_t reg, uint8_t data) { 36 | _wire->beginTransmission(addr); 37 | _wire->write(reg); 38 | _wire->write(data); 39 | if (_wire->endTransmission() == 0) return true; 40 | return false; 41 | } 42 | 43 | uint8_t I2C_DEVICE::readByte(uint8_t addr, uint8_t reg) { 44 | _wire->beginTransmission(addr); 45 | _wire->write(reg); 46 | _wire->endTransmission(); 47 | 48 | if (_wire->requestFrom(addr, 1)) { 49 | return _wire->read(); 50 | } 51 | return 0; 52 | } 53 | 54 | bool I2C_DEVICE::writeBitOn(uint8_t addr, uint8_t reg, uint8_t data) { 55 | uint8_t temp; 56 | uint8_t write_back; 57 | temp = readByte(addr, reg); 58 | write_back = (temp | data); 59 | return (writeByte(addr, reg, write_back)); 60 | } 61 | 62 | bool I2C_DEVICE::writeBitOff(uint8_t addr, uint8_t reg, uint8_t data) { 63 | uint8_t temp; 64 | uint8_t write_back; 65 | temp = readByte(addr, reg); 66 | write_back = (temp & (~data)); 67 | return (writeByte(addr, reg, write_back)); 68 | } 69 | -------------------------------------------------------------------------------- /examples/Basics/RTC_WakeUp/RTC_WakeUp.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2021 by M5Stack 4 | * Equipped with CoreInk sample source code 5 | * 配套 CoreInk 示例源代码 6 | * Visit for more information:https://docs.m5stack.com/en/core/coreink 7 | * 获取更多资料请访问:https://docs.m5stack.com/zh_CN/core/coreink 8 | * 9 | * Describe: RTC example. RTC示例 10 | * Date: 2022/6/30 11 | ******************************************************************************* 12 | */ 13 | #include "M5CoreInk.h" 14 | 15 | Ink_Sprite InkPageSprite(&M5.M5Ink); //创建 M5Ink实例 16 | 17 | void setup() { 18 | M5.begin(); // Initialize CoreInk. 初始化 CoreInk 19 | digitalWrite(LED_EXT_PIN, LOW); //设置 LED_EXT_PIN 为低电平 20 | if (!M5.M5Ink.isInit()) { //判断 M5Ink 是否初始化成功 21 | Serial.printf("Ink Init failed"); 22 | while (1) delay(100); 23 | } 24 | M5.M5Ink.clear(); // clear the screen. 清屏 25 | delay(1000); 26 | // creat ink Sprite. 创建图像区域 27 | if (InkPageSprite.creatSprite(0, 0, 200, 200, true) != 0) { 28 | Serial.printf("Ink Sprite create failed"); 29 | } 30 | InkPageSprite.drawString( 31 | 10, 50, "Press PWR Btn for sleep"); //在图像区域内绘制字符串 32 | InkPageSprite.drawString(15, 80, "after 5 sec wakeup."); 33 | InkPageSprite.pushSprite(); //将图像区域内的内容推送到屏幕上 34 | } 35 | 36 | void loop() { 37 | // Press PWR Btn for sleep , after 5 sec wakeup. 38 | // Press POWER Button for sleep, after 5 sec wake up. 39 | if (M5.BtnPWR.wasPressed()) { 40 | Serial.printf("Btn %d was pressed \r\n", BUTTON_PWR_PIN); 41 | M5.shutdown(5); // Turn off the power and wake up the device through 42 | // RTC after the delay of 5 seconds. 43 | // 关闭电源,在延时5秒结束后通过RTC唤醒设备。 44 | // M5.shutdown(RTC_TimeTypeDef(0, 0, 5)); 45 | } 46 | M5.update(); // Refresh device button. 刷新设备按键 47 | if (M5.BtnUP.wasPressed()) { // The program continues to execute after 5 48 | // seconds 49 | Serial.printf("Btn %d was pressed \r\n", BUTTON_UP_PIN); 50 | } 51 | } -------------------------------------------------------------------------------- /src/utility/Speaker.cpp: -------------------------------------------------------------------------------- 1 | #include "Speaker.h" 2 | 3 | SPEAKER::SPEAKER(void) { 4 | _volume = 8; 5 | _begun = false; 6 | } 7 | 8 | void SPEAKER::begin() { 9 | _begun = true; 10 | ledcSetup(TONE_PIN_CHANNEL, 0, 13); 11 | ledcAttachPin(SPEAKER_PIN, TONE_PIN_CHANNEL); 12 | setBeep(1000, 100); 13 | } 14 | 15 | void SPEAKER::end() { 16 | mute(); 17 | ledcDetachPin(SPEAKER_PIN); 18 | _begun = false; 19 | } 20 | 21 | void SPEAKER::tone(uint16_t frequency) { 22 | if (!_begun) begin(); 23 | ledcWriteTone(TONE_PIN_CHANNEL, frequency); 24 | } 25 | 26 | void SPEAKER::tone(uint16_t frequency, uint32_t duration) { 27 | tone(frequency); 28 | _count = millis() + duration; 29 | speaker_on = 1; 30 | } 31 | 32 | void SPEAKER::beep() { 33 | if (!_begun) begin(); 34 | tone(_beep_freq, _beep_duration); 35 | } 36 | 37 | void SPEAKER::setBeep(uint16_t frequency, uint16_t duration) { 38 | _beep_freq = frequency; 39 | _beep_duration = duration; 40 | } 41 | 42 | void SPEAKER::setVolume(uint8_t volume) { 43 | _volume = 11 - volume; 44 | } 45 | 46 | void SPEAKER::mute() { 47 | ledcWriteTone(TONE_PIN_CHANNEL, 0); 48 | digitalWrite(SPEAKER_PIN, 0); 49 | } 50 | 51 | void SPEAKER::update() { 52 | if (speaker_on) { 53 | if (millis() > _count) { 54 | speaker_on = 0; 55 | mute(); 56 | } 57 | } 58 | } 59 | 60 | void SPEAKER::write(uint8_t value) { 61 | dacWrite(SPEAKER_PIN, value); 62 | } 63 | 64 | void SPEAKER::playMusic(const uint8_t *music_data, uint16_t sample_rate) { 65 | uint32_t length = strlen((char *)music_data); 66 | uint16_t delay_interval = ((uint32_t)1000000 / sample_rate); 67 | if (_volume != 11) { 68 | for (int i = 0; i < length; i++) { 69 | dacWrite(SPEAKER_PIN, music_data[i] / _volume); 70 | delayMicroseconds(delay_interval); 71 | } 72 | 73 | for (int t = music_data[length - 1] / _volume; t >= 0; t--) { 74 | dacWrite(SPEAKER_PIN, t); 75 | delay(2); 76 | } 77 | } 78 | // ledcSetup(TONE_PIN_CHANNEL, 0, 13); 79 | ledcAttachPin(SPEAKER_PIN, TONE_PIN_CHANNEL); 80 | } 81 | -------------------------------------------------------------------------------- /examples/Basics/RTC_BM8563/RTC_BM8563.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2021 by M5Stack 4 | * Equipped with CoreInk sample source code 5 | * 配套 CoreInk 示例源代码 6 | * Visit for more information:https://docs.m5stack.com/en/core/coreink 7 | * 获取更多资料请访问:https://docs.m5stack.com/zh_CN/core/coreink 8 | * 9 | * Describe: RTC example. RTC示例 10 | * Date: 2022/6/30 11 | ******************************************************************************* 12 | */ 13 | #include "M5CoreInk.h" 14 | 15 | Ink_Sprite InkPageSprite(&M5.M5Ink); //创建 M5Ink实例 16 | 17 | RTC_TimeTypeDef RTCtime; 18 | RTC_DateTypeDef RTCDate; 19 | 20 | char timeStrbuff[64]; 21 | 22 | void flushTime() { 23 | M5.rtc.GetTime(&RTCtime); // Get RTC time. 获取RTC时间 24 | M5.rtc.GetDate(&RTCDate); // Get RTC date. 获取RTC日期 25 | sprintf(timeStrbuff, "%d/%02d/%02d %02d:%02d:%02d", RTCDate.Year, 26 | RTCDate.Month, RTCDate.Date, RTCtime.Hours, RTCtime.Minutes, 27 | RTCtime.Seconds); 28 | InkPageSprite.drawString(10, 100, timeStrbuff); // Draw time. 绘制时间 29 | InkPageSprite.pushSprite(); // push the sprite. 推送图片 30 | } 31 | 32 | void setupTime() { 33 | RTCtime.Hours = 23; 34 | RTCtime.Minutes = 33; 35 | RTCtime.Seconds = 33; 36 | M5.rtc.SetTime(&RTCtime); // Set RTC time. 设置RTC时间 37 | 38 | RTCDate.Year = 2020; 39 | RTCDate.Month = 11; 40 | RTCDate.Date = 6; 41 | M5.rtc.SetDate(&RTCDate); // Set RTC date. 设置RTC日期 42 | } 43 | 44 | void setup() { 45 | M5.begin(); // Initialize CoreInk. 初始化 CoreInk 46 | if (!M5.M5Ink.isInit()) { // check if the initialization is successful. 47 | // 检查初始化是否成功 48 | Serial.printf("Ink Init failed"); 49 | while (1) delay(100); 50 | } 51 | M5.M5Ink.clear(); // clear the screen. 清屏 52 | delay(1000); 53 | // creat ink Sprite. 创建图像区域 54 | if (InkPageSprite.creatSprite(0, 0, 200, 200, true) != 0) { 55 | Serial.printf("Ink Sprite create failed"); 56 | } 57 | setupTime(); 58 | } 59 | 60 | void loop() { 61 | flushTime(); 62 | delay(15000); 63 | } -------------------------------------------------------------------------------- /examples/Advanced/I2C_Tester/I2C_Tester.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2021 by M5Stack 4 | * Equipped with CoreInk sample source code 5 | * 配套 CoreInk 示例源代码 6 | * Visit for more information: https://docs.m5stack.com/en/core/coreink 7 | * 获取更多资料请访问:https://docs.m5stack.com/zh_CN/core/coreink 8 | * 9 | * Describe: I2C Scanner. I2C探测 10 | * Date: 2021/11/27 11 | ******************************************************************************* 12 | */ 13 | /* 14 | This program scans the addresses 1-127 continuosly and shows the devices found 15 | on the TFT. 该程序连续扫描地址 1-127 并显示在外部(内部)I2C发现的设备。 16 | */ 17 | #include 18 | 19 | void setup() { 20 | M5.begin(false, true, 21 | false); // Init M5Core2(Initialization of external I2C is also 22 | // included). 初始化M5Core2(初始化外部I2C也包含在内) 23 | // Wire.begin(21, 22); //Detect internal I2C, if this sentence is not added, 24 | // it will detect external I2C. 检测内部I2C,若不加此句为检测外部I2C 25 | Serial.println("M5Core2 I2C Tester"); // Print a string on the screen. 26 | // 在屏幕上打印字符串 27 | delay(3000); 28 | } 29 | 30 | void loop() { 31 | int address; 32 | int error; 33 | Serial.println("scanning Address [HEX]"); 34 | for (address = 1; address < 127; address++) { 35 | Wire.beginTransmission( 36 | address); // Data transmission to the specified device address 37 | // starts. 开始向指定的设备地址进行传输数据 38 | error = Wire.endTransmission(); /*Stop data transmission with the slave. 39 | 停止与从机的数据传输 0: success. 成功 1: The amount of data 40 | exceeds the transmission buffer capacity limit. 41 | 数据量超过传送缓存容纳限制 return value: 2: 42 | Received NACK when sending address. 传送地址时收到 NACK 3: 43 | Received NACK when transmitting data. 传送数据时收到 NACK 44 | 4: Other errors. 其它错误 */ 45 | if (error == 0) { 46 | Serial.print(address, HEX); 47 | Serial.print(" "); 48 | } else 49 | Serial.print("."); 50 | 51 | delay(10); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/M5CoreInk.cpp: -------------------------------------------------------------------------------- 1 | #include "M5CoreInk.h" 2 | 3 | M5CoreInk::M5CoreInk(/* args */) { 4 | } 5 | 6 | M5CoreInk::~M5CoreInk() { 7 | } 8 | 9 | int M5CoreInk::begin(bool InkEnable, bool wireEnable, bool SpeakerEnable) { 10 | pinMode(POWER_HOLD_PIN, OUTPUT); 11 | digitalWrite(POWER_HOLD_PIN, HIGH); // Hold power 12 | 13 | #if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 4, 6)) 14 | // pinMode(1, OUTPUT); 15 | #else 16 | pinMode(1, OUTPUT); 17 | #endif 18 | pinMode(LED_EXT_PIN, OUTPUT); 19 | 20 | Serial.begin(115200); 21 | Serial.printf("initializing.....OK\n"); 22 | 23 | if (wireEnable) { 24 | Wire.begin(32, 33, 100000UL); 25 | } 26 | 27 | if (SpeakerEnable) { 28 | Speaker.begin(); 29 | } 30 | 31 | rtc.begin(); 32 | rtc.disableIRQ(); 33 | 34 | if (InkEnable) { 35 | M5Ink.begin(); 36 | // if (!M5.M5Ink.isInit()) { 37 | // Serial.printf("Ink initializ is faild\n"); 38 | // return -1; 39 | // } 40 | } 41 | 42 | return 0; 43 | } 44 | 45 | void M5CoreInk::update() { 46 | BtnUP.read(); 47 | BtnDOWN.read(); 48 | BtnMID.read(); 49 | BtnEXT.read(); 50 | BtnPWR.read(); 51 | Speaker.update(); 52 | } 53 | 54 | void M5CoreInk::shutdown() { 55 | M5Ink.deepSleep(); 56 | delay(50); 57 | esp_deep_sleep_start(); 58 | digitalWrite(POWER_HOLD_PIN, LOW); 59 | } 60 | int M5CoreInk::shutdown(int seconds) { 61 | rtc.disableIRQ(); 62 | rtc.SetAlarmIRQ(seconds); 63 | gpio_wakeup_enable(GPIO_NUM_19, gpio_int_type_t::GPIO_INTR_LOW_LEVEL); 64 | esp_sleep_enable_gpio_wakeup(); 65 | shutdown(); 66 | 67 | return 0; 68 | } 69 | int M5CoreInk::shutdown(const RTC_TimeTypeDef &RTC_TimeStruct) { 70 | rtc.disableIRQ(); 71 | rtc.SetAlarmIRQ(RTC_TimeStruct); 72 | gpio_wakeup_enable(GPIO_NUM_19, gpio_int_type_t::GPIO_INTR_LOW_LEVEL); 73 | esp_sleep_enable_gpio_wakeup(); 74 | shutdown(); 75 | return 0; 76 | } 77 | int M5CoreInk::shutdown(const RTC_DateTypeDef &RTC_DateStruct, 78 | const RTC_TimeTypeDef &RTC_TimeStruct) { 79 | rtc.disableIRQ(); 80 | rtc.SetAlarmIRQ(RTC_DateStruct, RTC_TimeStruct); 81 | gpio_wakeup_enable(GPIO_NUM_19, gpio_int_type_t::GPIO_INTR_LOW_LEVEL); 82 | esp_sleep_enable_gpio_wakeup(); 83 | shutdown(); 84 | return 0; 85 | } 86 | 87 | M5CoreInk M5; -------------------------------------------------------------------------------- /README_cn.md: -------------------------------------------------------------------------------- 1 | # M5CoreInk Library 2 | 3 | [![Arduino Compile](https://github.com/m5stack/M5Core-Ink/actions/workflows/arduino-action-coreink-compile.yml/badge.svg)](https://github.com/m5stack/M5Core-Ink/actions/workflows/arduino-action-paper-compile.yml) 4 | [![Arduino Lint](https://github.com/m5stack/M5Core-Ink/actions/workflows/Arduino-Lint-Check.yml/badge.svg)](https://github.com/m5stack/M5Core-Ink/actions/workflows/Arduino-Lint-Check.yml) 5 | [![Clang Format](https://github.com/m5stack/M5Core-Ink/actions/workflows/clang-format-check.yml/badge.svg)](https://github.com/m5stack/M5Core-Ink/actions/workflows/clang-format-check.yml) 6 | 7 | [English](README.md) | 中文 8 | 9 | CoreInk_Pic_01 10 | 11 | ## 描述 12 | 13 | **CoreInk** 是M5Stack推出的一款带有电子墨水屏(E-Ink)的主控设备,控制器采用ESP32-PICO-D4。正面嵌入了一块分辨率为200x200 @ 1.54"的电子墨水屏,支持黑/白显示。相对于普通的LCD的屏幕,电子墨水屏能够提供用户更好的文本阅读体验, 同时具有低功耗,掉电图像保持等特性。人机交互方面提供了拨轮开关,与物理按键, 集成LED指示灯与蜂鸣器。内置了390mAh锂电池,结合内部的RTC(BM8563)可实现定时休眠与唤醒功能,能够为设备提供较为优秀的续航能力。在机身的左侧和底部配有独立的电源按键与复位(RST)按键,方便使用与调试。开放了丰富的外设接口(HY2.0-4P、M-BUS、HAT模块接口)能够拓展各式各样的传感器设备,为后续的应用功能开发提供无限可能。 14 | 15 | **注意事项**: 使用时请注意避免长时间高频刷新,建议刷新间隔为(15s/次), 请勿长时间暴露在紫外线下, 否则有可能对墨水屏造成不可逆的损害。 16 | 17 | * **如果想要购买 CoreInk 的话,[点击这里](https://item.taobao.com/item.htm?spm=a1z10.5-c-s.w4002-22404213529.11.5d80e428hIJBNY&id=631373978142)** 18 | 19 | CoreInk_Pic_01 20 | 21 | ## 产品特性 22 | 23 | - 基于 ESP32 开发,支持WiFi,蓝牙 24 | - 内置4M Flash 25 | - 低功耗显示面板 26 | - 近180度可视角 27 | - 人机交互接口 28 | - 背面磁吸设计 29 | - 内置锂电池 30 | - 丰富的拓展接口 31 | 32 | ## 更多信息 33 | 34 | - **API** 35 | 36 | - [CoreInk Arduino API](http://docs.m5stack.com/zh_CN/api/coreink/system_api) 37 | 38 | - **Document** 39 | - [Arduino Quick Start](http://docs.m5stack.com/zh_CN/quick_start/coreink/arduino) 40 | - [Product Document](https://docs.m5stack.com/zh_CN/core/coreink) 41 | 42 | ## 相关链接 43 | 44 | - **Datasheet** 45 | - [ESP32](https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/esp32_datasheet_cn.pdf) 46 | - [BM8563](https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/BM8563_V1.1_cn.pdf) 47 | - [SY7088](https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/SY7088-Silergy.pdf) 48 | - [GDEW0154M09](https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/CoreInk-K048-GDEW0154M09%20V2.0%20Specification.pdf) 49 | 50 | -------------------------------------------------------------------------------- /examples/Advanced/Counter/Counter.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2021 by M5Stack 4 | * Equipped with CoreInk sample source code 5 | * 配套 CoreInk 示例源代码 6 | * Visit for more information: https://docs.m5stack.com/en/core/coreink 7 | * 获取更多资料请访问:https://docs.m5stack.com/zh_CN/core/coreink 8 | * 9 | * Describe: Counter. 10 | * Date: 2021/11/28 11 | ******************************************************************************* 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | Preferences preferences; 18 | Ink_Sprite InkPageSprite(&M5.M5Ink); //创建 M5Ink实例 19 | 20 | char Strbuff[64]; 21 | 22 | void setup() { 23 | M5.begin(); 24 | digitalWrite(LED_EXT_PIN, LOW); //设置 LED_EXT_PIN 为低电平 25 | if (!M5.M5Ink.isInit()) { //判断 M5Ink 是否初始化成功 26 | Serial.printf("Ink Init faild"); 27 | while (1) delay(100); 28 | } 29 | M5.M5Ink.clear(); // clear the screen. 清屏 30 | delay(1000); 31 | // creat ink Sprite. 创建图像区域 32 | if (InkPageSprite.creatSprite(0, 0, 200, 200, true) != 0) { 33 | Serial.printf("Ink Sprite creat faild"); 34 | } 35 | InkPageSprite.drawString(10, 10, "Counter"); //在图像区域内绘制字符串 36 | preferences.begin( 37 | "my-app", 38 | false); // We will open storage in RW-mode (second parameter has to be 39 | // false). 40 | // 在perferences中创建叫my-app的空间,并以rw模式打开存储(第二个参数必须为false) 41 | 42 | // preferences.clear(); // Remove all preferences under the opened 43 | // namespace.清除preferences中所有的空间 preferences.remove("counter"); // 44 | // Or remove the counter key only. 只清除counter中的值 45 | 46 | unsigned int counter = preferences.getUInt( 47 | "counter", 48 | 0); // Get the counter value in current sapce, if the key does not 49 | // exist, return a default value of 0. 50 | // 在当前空间中读取counter的值(若不存在为0),并赋值给counter 51 | counter++; // Increase counter by 1. 使计数器的值加一 52 | sprintf(Strbuff, "Current counter value:%u", counter); 53 | InkPageSprite.drawString(5, 40, Strbuff); 54 | preferences.putUInt( 55 | "counter", 56 | counter); // Store the counter to the Preferences. 存储计数器的值 57 | preferences.end(); // Close the Preferences. 关闭Preferences 58 | InkPageSprite.drawString(10, 75, "Restart in 15 s"); 59 | InkPageSprite.pushSprite(); //将图像区域内的内容推送到屏幕上 60 | delay(15000); // delay 10. 延迟10s 61 | ESP.restart(); // Restart. 重启 62 | } 63 | void loop() { 64 | } 65 | -------------------------------------------------------------------------------- /src/utility/WFT0154CZB3_INIT.h: -------------------------------------------------------------------------------- 1 | #ifndef _WFT0154CZB3_INIT_H_ 2 | #define _WFT0154CZB3_INIT_H_ 3 | 4 | const unsigned char WFT0154CZB3_LIST[] = { 5 | 11, // 11 commands in list: 6 | 0x00, 2, 0xdf, 0x0e, // panel setting 7 | 0x4D, 1, 0x55, // FITIinternal code 8 | 0xaa, 1, 0x0f, 0xe9, 1, 0x02, 0xb6, 1, 0x11, 9 | 0xf3, 1, 0x0a, 0x61, 3, 0xc8, 0x00, 0xc8, // resolution setting 10 | 0x60, 1, 0x00, // Tcon setting 11 | 0x50, 1, 0xd7, 0xe3, 1, 0x00, 0x04, 0 // Power on 12 | }; 13 | 14 | const unsigned char lut_vcomDC1[] PROGMEM = { 15 | 0x01, 0x04, 0x04, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 16 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 17 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 18 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 19 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 20 | }; 21 | 22 | const unsigned char lut_ww1[] PROGMEM = { 23 | 0x01, 0x04, 0x04, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 25 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 26 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 27 | }; 28 | 29 | const unsigned char lut_bw1[] PROGMEM = { 30 | 0x01, 0x84, 0x84, 0x83, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 35 | }; 36 | 37 | const unsigned char lut_wb1[] PROGMEM = { 38 | 0x01, 0x44, 0x44, 0x43, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 | }; 44 | 45 | const unsigned char lut_bb1[] PROGMEM = { 46 | 0x01, 0x04, 0x04, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 | }; 52 | 53 | #endif -------------------------------------------------------------------------------- /examples/Basics/Button/Button.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2021 by M5Stack 4 | * Equipped with CoreInk sample source code 5 | * 配套 CoreInk 示例源代码 6 | * Visit for more information:https://docs.m5stack.com/en/core/coreink 7 | * 获取更多资料请访问:https://docs.m5stack.com/zh_CN/core/coreink 8 | * 9 | * Product: Button example. 按键示例 10 | * Date: 2022/6/30 11 | ******************************************************************************* 12 | */ 13 | #include "M5CoreInk.h" 14 | 15 | Ink_Sprite InkPageSprite(&M5.M5Ink); //创建 M5Ink实例 16 | 17 | void ButtonTest(char* str) { 18 | InkPageSprite.clear(); // clear the screen. 清屏 19 | InkPageSprite.drawString(35, 59, str); // draw the string. 绘制字符串 20 | InkPageSprite.pushSprite(); // push the sprite. 推送图片 21 | delay(2000); 22 | } 23 | 24 | /* After CoreInk is started or reset 25 | the program in the setUp () function will be run, and this part will only be 26 | run once. 在 CoreInk 27 | 启动或者复位后,即会开始执行setup()函数中的程序,该部分只会执行一次。 */ 28 | void setup() { 29 | M5.begin(); // Initialize CoreInk. 初始化 CoreInk 30 | if (!M5.M5Ink.isInit()) { // check if the initialization is successful. 31 | // 检查初始化是否成功 32 | Serial.printf("Ink Init faild"); 33 | } 34 | M5.M5Ink.clear(); // Clear the screen. 清屏 35 | delay(1000); 36 | // creat ink Sprite. 创建图像区域 37 | if (InkPageSprite.creatSprite(0, 0, 200, 200, true) != 0) { 38 | Serial.printf("Ink Sprite create faild"); 39 | } 40 | InkPageSprite.drawString(20, 20, "Hello Core-INK"); 41 | } 42 | 43 | /* After the program in setup() runs, it runs the program in loop() 44 | The loop() function is an infinite loop in which the program runs repeatedly 45 | 在setup()函数中的程序执行完后,会接着执行loop()函数中的程序 46 | loop()函数是一个死循环,其中的程序会不断的重复运行 */ 47 | void loop() { 48 | if (M5.BtnUP.wasPressed()) 49 | ButtonTest("Btn UP Pressed"); // Scroll wheel up. 拨轮向上滚动 50 | if (M5.BtnDOWN.wasPressed()) 51 | ButtonTest("Btn DOWN Pressed"); // Trackwheel scroll down. 拨轮向下滚动 52 | if (M5.BtnMID.wasPressed()) 53 | ButtonTest("Btn MID Pressed"); // Dial down. 拨轮按下 54 | if (M5.BtnEXT.wasPressed()) 55 | ButtonTest("Btn EXT Pressed"); // Top button press. 顶部按键按下 56 | if (M5.BtnPWR.wasPressed()) { // Right button press. 右侧按键按下 57 | ButtonTest("Btn PWR Pressed"); 58 | M5.shutdown(); // Turn off the power, restart it, you need to wake up 59 | // through the PWR button. 60 | // 关闭电源,再次启动需要通过PWR按键唤醒 61 | } 62 | M5.update(); // Refresh device button. 刷新设备按键 63 | } 64 | -------------------------------------------------------------------------------- /examples/Basics/Simple_Clock/Simple_Clock.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2021 by M5Stack 4 | * Equipped with CoreInk sample source code 5 | * 配套 CoreInk 示例源代码 6 | * Visit for more information:https://docs.m5stack.com/en/core/coreink 7 | * 获取更多资料请访问:https://docs.m5stack.com/zh_CN/core/coreink 8 | * 9 | * Describe: Simple Clock. 简易时钟 10 | * Date: 2022/8/30 11 | ******************************************************************************* 12 | A simple clock based on M5CoreInk. 13 | Libraries: 14 | - [M5Unified](https://github.com/m5stack/M5Unified) 15 | - [M5GFX](https://github.com/m5stack/M5GFX) 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #define WIFI_SSID "YOUR WIFI SSID" 23 | #define WIFI_PASSWORD "YOUR WIFI PASSWD" 24 | #define NTP_TIMEZONE "JST-8" 25 | #define NTP_SERVER1 "ntp.aliyun.com" 26 | #define NTP_SERVER2 "ntp1.aliyun.com" 27 | #define NTP_SERVER3 "ntp2.aliyun.com" 28 | 29 | void setup(void) { 30 | auto cfg = M5.config(); 31 | 32 | cfg.external_rtc = true; 33 | cfg.clear_display = false; 34 | 35 | M5.begin(cfg); 36 | 37 | if (!M5.Rtc.getIRQstatus()) { 38 | WiFi.begin(WIFI_SSID, WIFI_PASSWORD); 39 | configTzTime(NTP_TIMEZONE, NTP_SERVER1, NTP_SERVER2, NTP_SERVER3); 40 | 41 | while (WiFi.status() != WL_CONNECTED) { 42 | Serial.print('.'); 43 | delay(500); 44 | } 45 | Serial.println("\r\n WiFi Connected."); 46 | 47 | while (sntp_get_sync_status() != SNTP_SYNC_STATUS_COMPLETED) { 48 | Serial.print('.'); 49 | delay(500); 50 | } 51 | Serial.println("\r\n NTP Connected."); 52 | 53 | time_t t = time(nullptr) + 1; 54 | while (t > time(nullptr)) 55 | ; 56 | 57 | M5.Rtc.setDateTime(localtime(&t)); 58 | } 59 | 60 | auto dt = M5.Rtc.getDateTime(); 61 | 62 | while (dt.time.seconds != 0) { 63 | dt = M5.Rtc.getDateTime(); 64 | delay(500); 65 | } 66 | 67 | M5.Display.setFreeFont(&Orbitron_Light_24); 68 | if (dt.time.minutes == 30) { 69 | M5.Display.clear(TFT_WHITE); 70 | M5.Display.setTextSize(2.5); 71 | M5.Display.drawCenterString("Clock", 100, 120); 72 | } 73 | 74 | char buf[32] = {0}; 75 | M5.Display.setTextSize(2); 76 | M5.Display.fillRect(0, 0, 200, 100); 77 | sprintf(buf, "%02d:%02d", dt.time.hours, dt.time.minutes); 78 | M5.Display.drawCenterString(buf, 100, 10); 79 | M5.Display.setTextSize(1); 80 | sprintf(buf, "%02d-%02d-%04d", dt.date.date, dt.date.month, dt.date.year); 81 | M5.Display.drawCenterString(buf, 100, 70); 82 | 83 | M5.Display.sleep(); 84 | M5.Rtc.clearIRQ(); 85 | M5.Rtc.setAlarmIRQ(55); 86 | M5.Power.powerOff(); 87 | } 88 | 89 | void loop(void) { 90 | delay(100); 91 | } -------------------------------------------------------------------------------- /src/utility/Ink_Sprite.cpp: -------------------------------------------------------------------------------- 1 | #include "Ink_Sprite.h" 2 | 3 | int Ink_Sprite::creatSprite(uint16_t posX, uint16_t posY, uint16_t width, 4 | uint16_t height, bool copyFromMem) { 5 | // if ((posX % 8 != 0) || (width % 8 != 0)) return -1; 6 | 7 | _posX = posX; 8 | _posY = posY; 9 | _width = width; 10 | _height = height; 11 | if (M5Canvas::createSprite(width, height)) { 12 | Serial.println("createSprite success"); 13 | } else { 14 | Serial.println("createSprite failed"); 15 | }; 16 | return 0; 17 | } 18 | 19 | void Ink_Sprite::clear(int cleanFlag) { 20 | M5Canvas::clear(); 21 | } 22 | 23 | void Ink_Sprite::drawPix(uint16_t posX, uint16_t posY, uint8_t pixBit) { 24 | M5Canvas::drawPixel(posX, posY, pixBit ? 0x0000 : 0xFFFF); 25 | } 26 | 27 | void Ink_Sprite::FillRect(uint16_t posX, uint16_t posY, uint16_t width, 28 | uint16_t height, uint8_t pixBit) { 29 | fillRect(posX, posY, width, height, pixBit); 30 | } 31 | 32 | void Ink_Sprite::drawFullBuff(uint8_t *buff, bool bitMode) { 33 | if (bitMode) { 34 | size_t _pixsize = _width * _height; 35 | size_t _bitsize = _pixsize / 8; 36 | uint8_t *data = (uint8_t *)malloc(_pixsize); 37 | if (!data) { 38 | return; 39 | } 40 | for (size_t i = 0; i < _bitsize; i++) { 41 | uint8_t _byte = buff[i]; 42 | for (size_t j = 0; j < 8; j++) { 43 | size_t index = i * 8 + j; 44 | if (((_byte << j) & 0x80) == 0x80) { 45 | data[index] = 0x00; 46 | } else { 47 | data[index] = 0xff; 48 | } 49 | } 50 | } 51 | M5Canvas::pushImage(0, 0, _width, _height, data); 52 | free(data); 53 | } else { 54 | M5Canvas::pushImage(0, 0, _width, _height, buff); 55 | } 56 | } 57 | 58 | void Ink_Sprite::drawChar(uint16_t posX, uint16_t posY, char charData, 59 | const lgfx::FixedBMPfont *fontPtr) { 60 | M5Canvas::drawChar(charData, posX, posY); 61 | } 62 | 63 | void Ink_Sprite::drawString(uint16_t posX, uint16_t posY, const char *charData, 64 | const lgfx::FixedBMPfont *fontPtr) { 65 | M5Canvas::drawString(charData, posX, posY, fontPtr); 66 | } 67 | 68 | void Ink_Sprite::drawBuff(uint16_t posX, uint16_t posY, uint16_t width, 69 | uint16_t height, uint8_t *imageDataptr) { 70 | for (int y = 0; y < height; y++) { 71 | for (int x = 0; x < width; x++) { 72 | uint8_t mark = 0x80 >> (y * width + x) % 8; 73 | if ((imageDataptr[(y * width + x) / 8]) & mark) { 74 | drawPix(x + posX, y + posY, 1); 75 | } else { 76 | drawPix(x + posX, y + posY, 0); 77 | } 78 | } 79 | } 80 | } 81 | 82 | int Ink_Sprite::pushSprite() { 83 | M5Canvas::pushSprite(_posX, _posY); 84 | return 0; 85 | } 86 | 87 | int Ink_Sprite::deleteSprite() { 88 | return 0; 89 | } -------------------------------------------------------------------------------- /examples/Advanced/MultiTask/MultiTask.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2021 by M5Stack 4 | * Equipped with CoreInk sample source code 5 | * 配套 CoreInk 示例源代码 6 | * Visit for more information: https://docs.m5stack.com/en/core/coreink 7 | * 获取更多资料请访问:https://docs.m5stack.com/zh_CN/core/coreink 8 | * 9 | * Describe: MultiTask. 10 | * Date: 2021/11/28 11 | ******************************************************************************* 12 | */ 13 | 14 | #include 15 | 16 | Ink_Sprite InkPageSprite(&M5.M5Ink); //创建 M5Ink实例 17 | 18 | void task1(void* pvParameters) { // Define the tasks to be executed in 19 | // thread 1. 定义线程1内要执行的任务 20 | while (1) { // Keep the thread running. 使线程一直运行 21 | Serial.print("task1 Uptime (ms): "); 22 | Serial.println(millis()); // The running time of the serial port 23 | // printing program. 串口打印程序运行的时间 24 | delay( 25 | 100); // With a delay of 100ms, it can be seen in the serial 26 | // monitor that every 100ms, thread 1 will be executed once. 27 | // 延迟100ms,在串口监视器内可看到每隔100ms,线程1就会被执行一次 28 | } 29 | } 30 | 31 | void task2(void* pvParameters) { 32 | while (1) { 33 | Serial.print("task2 Uptime (ms): "); 34 | Serial.println(millis()); 35 | delay(200); 36 | } 37 | } 38 | 39 | void task3(void* pvParameters) { 40 | while (1) { 41 | Serial.print("task3 Uptime (ms): "); 42 | Serial.println(millis()); 43 | delay(1000); 44 | } 45 | } 46 | 47 | void setup() { 48 | M5.begin(); 49 | digitalWrite(LED_EXT_PIN, LOW); //设置 LED_EXT_PIN 为低电平 50 | if (!M5.M5Ink.isInit()) { //判断 M5Ink 是否初始化成功 51 | Serial.printf("Ink Init faild"); 52 | while (1) delay(100); 53 | } 54 | M5.M5Ink.clear(); // clear the screen. 清屏 55 | delay(1000); 56 | // creat ink Sprite. 创建图像区域 57 | if (InkPageSprite.creatSprite(0, 0, 200, 200, true) != 0) { 58 | Serial.printf("Ink Sprite creat faild"); 59 | } 60 | InkPageSprite.drawString(10, 10, "MultiTask"); //在图像区域内绘制字符串 61 | InkPageSprite.drawString(10, 25, "Please see the serial"); 62 | 63 | InkPageSprite.pushSprite(); //将图像区域内的内容推送到屏幕上 64 | // Creat Task1. 创建线程1 65 | xTaskCreatePinnedToCore( 66 | task1, // Function to implement the task. 67 | // 线程对应函数名称(不能有返回值) 68 | "task1", //线程名称 69 | 4096, // The size of the task stack specified as the number of * 70 | // bytes.任务堆栈的大小(字节) 71 | NULL, // Pointer that will be used as the parameter for the task * 72 | // being created. 创建作为任务输入参数的指针 73 | 1, // Priority of the task. 任务的优先级 74 | NULL, // Task handler. 任务句柄 75 | 0); // Core where the task should run. 将任务挂载到指定内核 76 | 77 | // Task 2 78 | xTaskCreatePinnedToCore(task2, "task2", 4096, NULL, 2, NULL, 0); 79 | 80 | // Task 3 81 | xTaskCreatePinnedToCore(task3, "task3", 4096, NULL, 3, NULL, 0); 82 | } 83 | 84 | void loop() { 85 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | # Source: 2 | # https://github.com/Tinyu-Zhao/M5-Depends/blob/main/.github/ISSUE_TEMPLATE/bug-report.yml 3 | # See: 4 | # https://docs.github.com/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms 5 | 6 | name: Bug report 7 | description: Report a problem with the code in this repository. 8 | labels: 9 | - "type: bug" 10 | body: 11 | - type: markdown 12 | attributes: 13 | value: "Thank you for opening an issue on an M5Stack Arduino library repository.\n\ 14 | To improve the speed of resolution please review the following guidelines and common troubleshooting steps below before creating the issue:\n\ 15 | Do not use GitHub issues for troubleshooting projects and issues. Instead use the forums at https://community.m5stack.com to ask questions and troubleshoot why something isn't working as expected. In many cases the problem is a common issue that you will more quickly receive help from the forum community. GitHub issues are meant for known defects in the code. If you don't know if there is a defect in the code then start with troubleshooting on the forum first." 16 | - type: textarea 17 | id: description 18 | attributes: 19 | label: Describe the bug 20 | description: A clear and concise description of what the bug is. 21 | validations: 22 | required: true 23 | - type: textarea 24 | id: reproduce 25 | attributes: 26 | label: To reproduce 27 | description: Provide the specific set of steps we can follow to reproduce the problem. 28 | placeholder: | 29 | 1. In this environment... 30 | 2. With this config... 31 | 3. Run '...' 32 | 4. See error... 33 | validations: 34 | required: true 35 | - type: textarea 36 | id: expected 37 | attributes: 38 | label: Expected behavior 39 | description: What would you expect to happen after following those instructions? 40 | validations: 41 | required: true 42 | - type: textarea 43 | id: screenshots 44 | attributes: 45 | label: Screenshots 46 | description: If applicable, add screenshots to help explain your problem. 47 | validations: 48 | required: false 49 | - type: textarea 50 | id: information 51 | attributes: 52 | label: Environment 53 | description: | 54 | If applicable, add screenshots to help explain your problem. 55 | examples: 56 | - **OS**: Ubuntu 20.04 57 | - **IDE & IDE Version**: Arduino 1.8.19 Or Platform IO v2.5.0 58 | - **Repository Version**: 0.4.0 59 | value: | 60 | - OS: 61 | - IDE &IDE Version: 62 | - Repository Version: 63 | validations: 64 | required: false 65 | - type: textarea 66 | id: additional 67 | attributes: 68 | label: Additional context 69 | description: Add any additional information here. 70 | validations: 71 | required: false 72 | - type: checkboxes 73 | id: checklist 74 | attributes: 75 | label: Issue checklist 76 | description: Please double-check that you have done each of the following things before submitting the issue. 77 | options: 78 | - label: I searched for previous reports in [the issue tracker](https://github.com/m5stack/M5Core-Ink/issues?q=) 79 | required: true 80 | - label: My report contains all necessary details 81 | required: true 82 | -------------------------------------------------------------------------------- /examples/Unit/KEY/KEY.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2022 by M5Stack 4 | * Equipped with M5CoreInk sample source code 5 | * 配套 M5CoreInk 示例源代码 6 | * Visit the website for more information: 7 | * 获取更多资料请访问: 8 | * 9 | * Please follow the steps below to add FastLED library: 10 | * - Arduino menu --> Manage Libraries... --> FastLED --> install 11 | * 在烧录前请按以下步骤添加 FastLED 库: 12 | * - Arduino menu --> Manage Libraries... --> FastLED --> install 13 | * 14 | * Product: KEY. 按键. 15 | * Date: 2022/6/1 16 | ******************************************************************************* 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | Ink_Sprite InkPageSprite(&M5.M5Ink); 23 | 24 | uint8_t ledColor = 0; 25 | 26 | #define KEY_PIN 33 // Define Key Pin. 定义Key引脚 27 | #define DATA_PIN 32 // Define LED pin. 定义LED引脚. 28 | CRGB leds[1]; // Define the array of leds. 定义LED阵列. 29 | 30 | void LED(void *parameter); 31 | void changeLedColor(); 32 | 33 | void setup() { 34 | M5.begin(); // Init M5Stack 初始化M5Stack 35 | M5.M5Ink.isInit(); // Init E-INK screen. 初始化E-INK屏幕驱动 36 | M5.M5Ink.clear(); 37 | delay(1000); 38 | if (InkPageSprite.creatSprite(0, 0, 200, 200, true) != 39 | 0) { // creat ink refresh Sprite. 创建画布. 40 | Serial.printf("Ink Sprite creat faild"); 41 | } else { 42 | Serial.printf("creatSprite success\n"); 43 | } 44 | InkPageSprite.drawString(35, 50, "UNIT-KEY Example"); 45 | InkPageSprite.pushSprite(); 46 | 47 | pinMode(KEY_PIN, INPUT_PULLUP); // Init Key pin. 初始化Key引脚. 48 | 49 | FastLED.addLeds(leds, 50 | 1); // Init FastLED. 初始化FastLED. 51 | 52 | xTaskCreate( 53 | LED, "led", 1000, NULL, 0, 54 | NULL); // Create a thread for breathing LED. 创建一个线程用于LED呼吸灯. 55 | } 56 | 57 | void loop() { 58 | if (!digitalRead(KEY_PIN)) { // If Key was pressed. 如果按键按下. 59 | changeLedColor(); // Change LED color. 更换LED呼吸灯颜色. 60 | while (!digitalRead( 61 | KEY_PIN)) // Hold until the key released. 在松开按键前保持状态. 62 | ; 63 | } 64 | delay(100); 65 | } 66 | 67 | void LED(void *parameter) { 68 | leds[0] = CRGB::Red; 69 | for (;;) { 70 | for (int i = 0; i < 255; 71 | i++) { // Set LED brightness from 0 to 255. 设置LED亮度从0到255. 72 | FastLED.setBrightness(i); 73 | FastLED.show(); 74 | delay(5); 75 | } 76 | for (int i = 255; i > 0; 77 | i--) { // Set LED brightness from 255 to 0. 设置LED亮度从255到0. 78 | FastLED.setBrightness(i); 79 | FastLED.show(); 80 | delay(5); 81 | } 82 | } 83 | vTaskDelete(NULL); 84 | } 85 | 86 | void changeLedColor() { 87 | ledColor++; 88 | if (ledColor > 2) ledColor = 0; 89 | switch ( 90 | ledColor) { // Change LED colors between R,G,B. 在红绿蓝中切换LED颜色. 91 | case 0: 92 | leds[0] = CRGB::Red; 93 | break; 94 | case 1: 95 | leds[0] = CRGB::Green; 96 | break; 97 | case 2: 98 | leds[0] = CRGB::Blue; 99 | break; 100 | default: 101 | break; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🚫 Deprecated — Use M5GFX & M5Unified 2 | 3 | - **M5GFX** 4 | High-performance, lightweight graphics and display driver library for M5 devices. 5 | 6 | 7 | - **M5Unified** 8 | Unified base library for M5 devices (IO/peripherals, power management, audio, etc.). 9 | 10 | 11 | 12 | # M5CoreInk Library 13 | 14 | [![Arduino Compile](https://github.com/m5stack/M5Core-Ink/actions/workflows/arduino-action-coreink-compile.yml/badge.svg)](https://github.com/m5stack/M5Core-Ink/actions/workflows/arduino-action-paper-compile.yml) 15 | [![Arduino Lint](https://github.com/m5stack/M5Core-Ink/actions/workflows/Arduino-Lint-Check.yml/badge.svg)](https://github.com/m5stack/M5Core-Ink/actions/workflows/Arduino-Lint-Check.yml) 16 | [![Clang Format](https://github.com/m5stack/M5Core-Ink/actions/workflows/clang-format-check.yml/badge.svg)](https://github.com/m5stack/M5Core-Ink/actions/workflows/clang-format-check.yml) 17 | 18 | 19 | English | [中文](README_cn.md) 20 | 21 | CoreInk_Pic_01 22 | 23 | ## Description 24 | 25 | **CoreInk** is a brand new E-ink display in the M5Stack cores range. Controlled by the ESP32-PICO-D4 This new device includes a 200x200 1.54" Black and White E-Ink Display. Compared to a regular LCD,E-ink displays are easier on the eyes, which makes them a great choice for reading or viewing for longer periods. Other benefits are the low power consumption and the ability to retain the image even if power to the display is terminated。For control the CoreInk integrates an multi-function button,A physical button, integrated status LED and buzzer.The device also includes a 390mAh Lipo,RTC(BM8563)for controlling accurate timing and deep sleep funcionality. CoreInk features independent reset and power buttons,expansion ports(HY2.0-4P、M-BUS、HAT expansion)for attaching external sensors to expand functionailty,for unlimited possibilities。 26 | 27 | **Warning**: Please avoid using high refresh rates,reccommended refresh rate is(15s/per refresh), Do not expose to ultraviolet rays for a long time, otherwise it may cause irreversible damage to the ink screen. 28 | 29 | CoreInk_Pic_01 30 | 31 | ## Product Features 32 | 33 | - ESP32 Standard wireless functions Wi-Fi,Bluetooth 34 | - Internal 4M Flash 35 | - Low Power Display 36 | - 180 degree viewing angle 37 | - Expansion ports 38 | - Built-in Magnet 39 | - Internal Battery 40 | - Expandable 41 | 42 | * **In order to buy Core-Ink, please [Click here](https://shop.m5stack.com/products/m5stack-esp32-core-ink-development-kit1-54-elnk-display)** 43 | 44 | 45 | ## More Information 46 | - **API** 47 | - [Arduino API](http://docs.m5stack.com/#/en/arduino/arduino_home_page) 48 | 49 | - **Document** 50 | - [Arduino Quick Start](http://docs.m5stack.com/en/quick_start/coreink/arduino) 51 | - [Product Document](https://docs.m5stack.com/en/core/coreink) 52 | ## Related Link 53 | 54 | - **Datasheet** 55 | - [ESP32](https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/esp32_datasheet_cn.pdf) 56 | - [BM8563](https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/BM8563_V1.1_cn.pdf) 57 | - [SY7088](https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/SY7088-Silergy.pdf) 58 | - [GDEW0154M09](https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/CoreInk-K048-GDEW0154M09%20V2.0%20Specification.pdf) 59 | -------------------------------------------------------------------------------- /.github/workflows/arduino-action-coreink-compile.yml: -------------------------------------------------------------------------------- 1 | # arduino-test-compile-ActionTest.yml 2 | # Github workflow script for testing the arduino-test-compile action development. 3 | # 4 | # Copyright (C) 2020 Armin Joachimsmeyer 5 | # https://github.com/ArminJo/Github-Actions 6 | # License: MIT 7 | # 8 | 9 | # This is the name of the workflow, visible on GitHub UI. 10 | name: Arduino Compile 11 | on: 12 | push: # see: https://help.github.com/en/actions/reference/events-that-trigger-workflows#pull-request-event-pull_request 13 | paths: 14 | - '**.ino' 15 | - '**.cpp' 16 | - '**.h' 17 | - 'arduino-test-compile.sh' 18 | - '*.yml' 19 | workflow_dispatch: 20 | jobs: 21 | build: 22 | name: ${{ matrix.arduino-boards-fqbn }} - test compiling examples 23 | 24 | runs-on: ubuntu-latest # ubuntu-latest # I picked Ubuntu to use shell scripts. 25 | 26 | env: 27 | # Comma separated list without double quotes around the list. 28 | CLI_VERSION: latest 29 | 30 | strategy: 31 | matrix: 32 | # The matrix will produce one job for each configuration parameter of type `arduino-boards-fqbn` 33 | # In the Arduino IDE, the fqbn is printed in the first line of the verbose output for compilation as parameter -fqbn=... for the "arduino-builder -dump-prefs" command 34 | # 35 | # Examples: arduino:avr:uno, arduino:avr:leonardo, arduino:avr:nano, arduino:avr:mega 36 | # arduino:sam:arduino_due_x, arduino:samd:arduino_zero_native" 37 | # ATTinyCore:avr:attinyx5:chip=85,clock=1internal, digistump:avr:digispark-tiny, digistump:avr:digispark-pro 38 | # STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103C8 39 | # esp8266:esp8266:huzzah:eesz=4M3M,xtal=80, esp32:esp32:featheresp32:FlashFreq=80 40 | # You may add a suffix behind the fqbn with "|" to specify one board for e.g. different compile options like arduino:avr:uno|trace 41 | ############################################################################################################# 42 | arduino-boards-fqbn: 43 | - m5stack:esp32:coreink 44 | 45 | # Specify parameters for each board. 46 | ############################################################################################################# 47 | include: 48 | - arduino-boards-fqbn: m5stack:esp32:coreink 49 | platform-url: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/arduino/package_m5stack_index.json 50 | sketches-exclude: WhistleSwitch,50Hz,SimpleFrequencyDetector 51 | 52 | # Do not cancel all jobs / architectures if one job fails 53 | fail-fast: false 54 | 55 | steps: 56 | - name: Checkout 57 | uses: actions/checkout@v3 58 | 59 | - name: Checkout custom library 60 | uses: actions/checkout@v3 61 | with: 62 | repository: ArminJo/ATtinySerialOut 63 | ref: master 64 | path: CustomLibrary # must match the pattern *Custom* 65 | 66 | # Test of the arduino-test-compile action 67 | - name: Compile all examples using the arduino-test-compile action 68 | # uses: ArminJo/arduino-test-compile@master 69 | uses: ./.github/actions 70 | with: 71 | arduino-board-fqbn: ${{ matrix.arduino-boards-fqbn }} 72 | arduino-platform: ${{ matrix.arduino-platform }} 73 | platform-url: ${{ matrix.platform-url }} 74 | required-libraries: ${{ env.REQUIRED_LIBRARIES }} 75 | sketches-exclude: ${{ matrix.sketches-exclude }} 76 | build-properties: ${{ toJson(matrix.build-properties) }} 77 | sketch-names: "*.ino" 78 | sketch-names-find-start: "examples/*" 79 | debug-compile: true 80 | debug-install: true 81 | -------------------------------------------------------------------------------- /examples/Advanced/EzData/EzData.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2021 by M5Stack 4 | * Equipped with CoreInk sample source code 5 | * 配套 CoreInk 示例源代码 6 | * Visit for more information: https://docs.m5stack.com/en/core/coreink 7 | * 获取更多资料请访问:https://docs.m5stack.com/zh_CN/core/coreink 8 | * 9 | * Describe: EzData 10 | * Date: 2021/11/27 11 | ******************************************************************************* 12 | */ 13 | #include "M5CoreInk.h" 14 | #include "M5_EzData.h" 15 | 16 | Ink_Sprite InkPageSprite(&M5.M5Ink); //创建 M5Ink实例 17 | 18 | // Configure the name and password of the connected wifi and your token. 19 | // 配置所连接wifi的名称、密码以及你的token 20 | const char* ssid = "Explore-F"; 21 | const char* password = "xingchentansuo123"; 22 | const char* token = "JT8H8eSd0A0pKajNzGm2tDL2H6mjIVLc"; 23 | 24 | void setup() { 25 | M5.begin(); 26 | digitalWrite(LED_EXT_PIN, LOW); //设置 LED_EXT_PIN 为低电平 27 | if (!M5.M5Ink.isInit()) { //判断 M5Ink 是否初始化成功 28 | Serial.printf("Ink Init faild"); 29 | while (1) delay(100); 30 | } 31 | M5.M5Ink.clear(); // clear the screen. 清屏 32 | delay(1000); 33 | // creat ink Sprite. 创建图像区域 34 | if (InkPageSprite.creatSprite(0, 0, 200, 200, true) != 0) { 35 | Serial.printf("Ink Sprite creat faild"); 36 | } 37 | if (setupWifi(ssid, password)) { // Connect to wifi. 连接到wifi 38 | InkPageSprite.drawString( 39 | 10, 10, "Success connecting to "); //在图像区域内绘制字符串 40 | InkPageSprite.drawString(10, 25, ssid); //在图像区域内绘制字符串 41 | } else { 42 | InkPageSprite.drawString(10, 10, 43 | "Connecting failed"); //在图像区域内绘制字符串 44 | } 45 | InkPageSprite.pushSprite(); //将图像区域内的内容推送到屏幕上 46 | } 47 | 48 | void loop() { 49 | // Save the data 20 to the top of the testData topic queue. 保存数据20至 50 | // testData 队列首位 51 | if (setData(token, "testData", 20)) { 52 | InkPageSprite.drawString(10, 50, "Success sending data"); 53 | } else { 54 | InkPageSprite.drawString(10, 50, "Fail to save data"); 55 | } 56 | delay(10000); 57 | InkPageSprite.pushSprite(); //将图像区域内的内容推送到屏幕上 58 | 59 | // Save 3 data in sequence to the first place of testList. 依次保存3个数据至 60 | // testList首位 61 | for (int i = 0; i < 3; i++) { 62 | if (addToList(token, "testList", i)) { 63 | InkPageSprite.drawString(10, 65, "Success sending data"); 64 | } else { 65 | InkPageSprite.drawString(10, 65, "Fail to save data"); 66 | } 67 | delay(100); 68 | } 69 | delay(10000); 70 | InkPageSprite.pushSprite(); //将图像区域内的内容推送到屏幕上 71 | // Get a piece of data from a topic and store the value in result. 从一个 72 | // topic中获取一个数据,并将值存储在 result 73 | int result = 0; 74 | if (getData(token, "testData", result)) { 75 | InkPageSprite.drawString(10, 80, "Success get data"); 76 | } else { 77 | InkPageSprite.drawString(10, 80, "Fail to get data"); 78 | } 79 | delay(10000); 80 | InkPageSprite.pushSprite(); //将图像区域内的内容推送到屏幕上 81 | 82 | // Remove data 83 | if (removeData(token, "testData")) 84 | InkPageSprite.drawString(10, 95, "Success remove data"); 85 | else 86 | InkPageSprite.drawString(10, 95, "Fail to remove data"); 87 | 88 | if (removeData(token, "testList")) 89 | InkPageSprite.drawString(10, 110, "Success remove data"); 90 | else 91 | InkPageSprite.drawString(10, 110, "Fail to remove data"); 92 | delay(10000); 93 | InkPageSprite.pushSprite(); //将图像区域内的内容推送到屏幕上 94 | delay(10000); 95 | InkPageSprite.clear(); // clear the screen. 清屏 96 | } 97 | -------------------------------------------------------------------------------- /src/utility/M5Timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * M5Timer.h 3 | * 4 | * M5Timer - A timer library for Arduino. 5 | * Author: mromani@ottotecnica.com 6 | * Copyright (c) 2010 OTTOTECNICA Italy 7 | * 8 | * This library is free software; you can redistribute it 9 | * and/or modify it under the terms of the GNU Lesser 10 | * General Public License as published by the Free Software 11 | * Foundation; either version 2.1 of the License, or (at 12 | * your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will 15 | * be useful, but WITHOUT ANY WARRANTY; without even the 16 | * implied warranty of MERCHANTABILITY or FITNESS FOR A 17 | * PARTICULAR PURPOSE. See the GNU Lesser General Public 18 | * License for more details. 19 | * 20 | * You should have received a copy of the GNU Lesser 21 | * General Public License along with this library; if not, 22 | * write to the Free Software Foundation, Inc., 23 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | * 25 | */ 26 | 27 | #ifndef M5Timer_H 28 | #define M5Timer_H 29 | 30 | #include 31 | #include 32 | 33 | typedef std::function timer_callback; 34 | 35 | class M5Timer { 36 | public: 37 | // maximum number of timers 38 | const static int MAX_TIMERS = 10; 39 | 40 | // setTimer() constants 41 | const static int RUN_FOREVER = 0; 42 | const static int RUN_ONCE = 1; 43 | 44 | // constructor 45 | M5Timer(); 46 | 47 | // this function must be called inside loop() 48 | void run(); 49 | 50 | // call function f every d milliseconds 51 | int setInterval(long d, timer_callback f); 52 | 53 | // call function f once after d milliseconds 54 | int setTimeout(long d, timer_callback f); 55 | 56 | // call function f every d milliseconds for n times 57 | int setTimer(long d, timer_callback f, int n); 58 | 59 | // destroy the specified timer 60 | void deleteTimer(int numTimer); 61 | 62 | // restart the specified timer 63 | void restartTimer(int numTimer); 64 | 65 | // returns true if the specified timer is enabled 66 | boolean isEnabled(int numTimer); 67 | 68 | // enables the specified timer 69 | void enable(int numTimer); 70 | 71 | // disables the specified timer 72 | void disable(int numTimer); 73 | 74 | // enables the specified timer if it's currently disabled, 75 | // and vice-versa 76 | void toggle(int numTimer); 77 | 78 | // returns the number of used timers 79 | int getNumTimers(); 80 | 81 | // returns the number of available timers 82 | int getNumAvailableTimers() { 83 | return MAX_TIMERS - numTimers; 84 | }; 85 | 86 | private: 87 | // deferred call constants 88 | const static int DEFCALL_DONTRUN = 0; // don't call the callback function 89 | const static int DEFCALL_RUNONLY = 90 | 1; // call the callback function but don't delete the timer 91 | const static int DEFCALL_RUNANDDEL = 92 | 2; // call the callback function and delete the timer 93 | 94 | // find the first available slot 95 | int findFirstFreeSlot(); 96 | 97 | // value returned by the millis() function 98 | // in the previous run() call 99 | unsigned long prev_millis[MAX_TIMERS]; 100 | 101 | // pointers to the callback functions 102 | timer_callback callbacks[MAX_TIMERS]; 103 | 104 | // delay values 105 | long delays[MAX_TIMERS]; 106 | 107 | // number of runs to be executed for each timer 108 | int maxNumRuns[MAX_TIMERS]; 109 | 110 | // number of executed runs for each timer 111 | int numRuns[MAX_TIMERS]; 112 | 113 | // which timers are enabled 114 | boolean enabled[MAX_TIMERS]; 115 | 116 | // deferred function call (sort of) - N.B.: this array is only used in run() 117 | int toBeCalled[MAX_TIMERS]; 118 | 119 | // actual number of timers in use 120 | int numTimers; 121 | }; 122 | 123 | #endif 124 | -------------------------------------------------------------------------------- /examples/Advanced/EEPROM/EEPROM.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2021 by M5Stack 4 | * Equipped with CoreInk sample source code 5 | * 配套 CoreInk 示例源代码 6 | * Visit for more information: https://docs.m5stack.com/en/core/coreink 7 | * 获取更多资料请访问:https://docs.m5stack.com/zh_CN/core/coreink 8 | * 9 | * Describe: EEPROM Write. 10 | * Date: 2021/11/28 11 | ******************************************************************************* 12 | The values stored in the EEPROM will remain in the EEPROM even after the 13 | CoreInk is disconnected. When a new program is uploaded to the CoreInk, the 14 | values stored in the EEPROM can still be called or modified by the new program. 15 | 储存于EEPROM的数值即使在断开 CoreInk开发板电源后仍会保存在EEPROM中 16 | 当新程序上传到 CoreInk后,储存于EEPROM中的数值仍然可以被新的程序调用或者修改 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | Ink_Sprite InkPageSprite(&M5.M5Ink); //创建 M5Ink实例 23 | 24 | int addr = 0; // EEPROM Start number of an ADDRESS. EEPROM地址起始编号 25 | #define SIZE 32 // define the size of EEPROM(Byte). 定义EEPROM的大小(字节) 26 | 27 | void setup() { 28 | M5.begin(); // Init CoreInk. 初始化 CoreInk 29 | digitalWrite(LED_EXT_PIN, LOW); //设置 LED_EXT_PIN 为低电平 30 | if (!M5.M5Ink.isInit()) { //判断 M5Ink 是否初始化成功 31 | Serial.printf("Ink Init faild"); 32 | while (1) delay(100); 33 | } 34 | M5.M5Ink.clear(); // clear the screen. 清屏 35 | delay(1000); 36 | // creat ink Sprite. 创建图像区域 37 | if (InkPageSprite.creatSprite(0, 0, 200, 200, true) != 0) { 38 | Serial.printf("Ink Sprite creat faild"); 39 | } 40 | InkPageSprite.drawString(10, 10, "EEPROM"); //在图像区域内绘制字符串 41 | if (!EEPROM.begin(SIZE)) { // Request storage of SIZE size(success return 42 | // 1). 申请SIZE大小的存储(成功返回1) 43 | Serial.println( 44 | "\nFailed to initialise EEPROM!"); //串口输出格式化字符串. Serial 45 | // output format string 46 | delay(1000000); 47 | } 48 | Serial.println("\nRead data from EEPROM. Values are:"); 49 | for (int i = 0; i < SIZE; i++) { 50 | Serial.printf("%d ", 51 | EEPROM.read(i)); // Reads data from 0 to SIZE in EEPROM. 52 | // 读取EEPROM中从0到SIZE中的数据 53 | } 54 | Serial.println("\n\nPress BtnA to Write EEPROM"); 55 | } 56 | 57 | void loop() { 58 | M5.update(); // Check button down state. 检测按键按下状态 59 | if (M5.BtnEXT.isPressed()) { // if the button.A is Pressed. 如果按键A按下 60 | Serial.printf("\n%d Bytes datas written on EEPROM.\nValues are:\n", 61 | SIZE); 62 | for (int i = 0; i < SIZE; i++) { 63 | int val = random( 64 | 256); // Integer values to be stored in the EEPROM (EEPROM can 65 | // store one byte per memory address, and can only store 66 | // numbers from 0 to 255. Therefore, if you want to use 67 | // EEPROM to store the numeric value read by the analog 68 | // input pin, divide the numeric value by 4. 69 | //将要存储于EEPROM的整数数值(EEPROM每一个存储地址可以储存一个字节,只能存储0-255的数.故如果要使用EEPROM存储模拟输入引脚所读取到的数值需要将该数值除以4) 70 | EEPROM.write(addr, 71 | val); // Writes the specified data to the specified 72 | // address. 向指定地址写入指定数据 73 | Serial.printf("%d ", val); 74 | addr += 1; // Go to the next storage address. 转入下一存储地址 75 | } 76 | // When the storage address sequence number reaches the end of the 77 | // storage space of the EEPROM, return to. 78 | // 当存储地址序列号达到EEPROM的存储空间结尾,返回到EEPROM开始地址 79 | addr = 0; 80 | Serial.println("\n\nRead form EEPROM. Values are:"); 81 | for (int i = 0; i < SIZE; i++) { 82 | Serial.printf("%d ", EEPROM.read(i)); 83 | } 84 | Serial.println("\n-------------------------------------\n"); 85 | } 86 | delay(150); 87 | } -------------------------------------------------------------------------------- /examples/KIT/SCALES_KIT/SCALES_KIT.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2022 by M5Stack 4 | * Equipped with M5CoreInk sample source code 5 | * 配套 M5CoreInk 示例源代码 6 | * Visit the website for more 7 | information:https://docs.m5stack.com/en/app/scales_kit 8 | * 获取更多资料请访问:https://docs.m5stack.com/zh_CN/app/scales_kit 9 | * 10 | * Product: SCALES KIT WEIGHT UNIT EXAMPLE. 11 | * Date: 2022/02/23 12 | ******************************************************************************* 13 | Connect WEIGHT UNIT to port A (G32/33) 14 | Calibration Instructions: Push the roller switch to tare up (0g calibration) 15 | when there is no load. Press the middle button of the wheel switch, push left 16 | and right to switch the standard weight value and put down the corresponding 17 | weight, and press the middle button of the wheel to confirm to calibrate. 18 | confirm for calibration. 19 | 将WEIGHT UNIT连接至端口A(G32/33) 20 | 校准说明:无负重情况下推动滚轮开关向上去皮重(0g 校准), 21 | 按下滚轮开关中间按键,左右推动切换标准重量值并放下对应重量砝码,按下滚轮中间按键comfirm进行校准。 22 | Libraries: 23 | - [HX711](https://github.com/bogde/HX711) 24 | 25 | */ 26 | 27 | #include 28 | #include 29 | #include "HX711.h" 30 | 31 | M5GFX display; 32 | M5Canvas canvas(&display); 33 | 34 | // HX711 related pin Settings. HX711 相关引脚设置 35 | #define LOADCELL_DOUT_PIN 33 36 | #define LOADCELL_SCK_PIN 32 37 | 38 | HX711 scale; 39 | 40 | void setup() { 41 | M5.begin(); 42 | 43 | display.begin(); 44 | 45 | if (display.isEPD()) { 46 | display.setEpdMode(epd_mode_t::epd_fastest); 47 | display.invertDisplay(true); 48 | display.clear(TFT_BLACK); 49 | } 50 | if (display.width() < display.height()) { 51 | display.setRotation(display.getRotation() ^ 1); 52 | } 53 | 54 | canvas.createSprite(display.width(), display.height()); 55 | canvas.setTextDatum(MC_DATUM); 56 | canvas.setTextSize(1); 57 | canvas.setFont(&fonts::lgfxJapanGothic_16); 58 | canvas.drawString("Calibration sensor....", 100, 100); 59 | canvas.pushSprite(0, 0); 60 | scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN); 61 | // The scale value is the adc value corresponding to 1g 62 | scale.set_scale(27.61f); // set scale 63 | scale.tare(); // auto set offset 64 | } 65 | 66 | char info[100]; 67 | 68 | float last_weight = 0; 69 | 70 | void loop() { 71 | float weight = scale.get_units(20) / 1000.0; 72 | if (weight != last_weight) { 73 | canvas.clear(); 74 | canvas.setTextSize(1); 75 | canvas.drawString("press MID calibration mode", 100, 20); 76 | canvas.drawString("press EXT 0g calibration", 100, 40); 77 | canvas.setTextSize(2); 78 | if (weight >= 0) { 79 | Serial.printf("%.2f", weight); 80 | sprintf(info, "%.2f", weight); 81 | canvas.drawString(String(info) + "kg", 100, 100); 82 | } else { 83 | canvas.drawString("0.00kg", 100, 100); 84 | } 85 | canvas.pushSprite(0, 0); 86 | last_weight = weight; 87 | delay(500); 88 | } 89 | M5.update(); 90 | if (M5.BtnEXT.wasPressed()) { 91 | canvas.clear(); 92 | canvas.setTextSize(1); 93 | scale.tare(); 94 | canvas.drawString("0g calibration!", 100, 100); 95 | canvas.pushSprite(0, 0); 96 | delay(500); 97 | } 98 | if (M5.BtnMID.wasPressed()) { 99 | long kg = 5; 100 | while (1) { 101 | M5.update(); 102 | canvas.clear(); 103 | canvas.setTextSize(1); 104 | canvas.drawString("calibration:" + String(kg) + "kg", 100, 100); 105 | canvas.drawString("press MID comfirm", 100, 20); 106 | canvas.drawString("press UP/DOWN change calibration value", 100, 107 | 40); 108 | canvas.pushSprite(0, 0); 109 | if (M5.BtnDOWN.isPressed()) { 110 | kg--; 111 | } 112 | if (M5.BtnUP.isPressed()) { 113 | kg++; 114 | } 115 | if (M5.BtnMID.wasPressed()) { 116 | break; 117 | } 118 | delay(100); 119 | } 120 | long kg_adc = scale.read_average(20); 121 | kg_adc = kg_adc - scale.get_offset(); 122 | scale.set_scale(kg_adc / (kg * 1000.0)); 123 | canvas.drawString("Set Scale: " + String(kg_adc / (kg * 1000.0)), 100, 124 | 100); 125 | canvas.pushSprite(0, 0); 126 | delay(500); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /examples/Advanced/MQTT/MQTT.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ******************************************************************************* 3 | * Copyright (c) 2021 by M5Stack 4 | * Equipped with CoreInk sample source code 5 | * 配套 CoreInk 示例源代码 6 | * Visit for more information: https://docs.m5stack.com/en/core/coreink 7 | * 获取更多资料请访问:https://docs.m5stack.com/zh_CN/core/coreink 8 | * 9 | * Describe: MQTT. 10 | * Date: 2021/11/28 11 | ******************************************************************************* 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | WiFiClient espClient; 19 | PubSubClient client(espClient); 20 | Ink_Sprite InkPageSprite(&M5.M5Ink); 21 | 22 | // Configure the name and password of the connected wifi and your MQTT Serve 23 | // host. 配置所连接wifi的名称、密码以及你MQTT服务器域名 24 | const char* ssid = "Explore-F"; 25 | const char* password = "xingchentansuo123"; 26 | const char* mqtt_server = "mqtt.m5stack.com"; 27 | 28 | #define MSG_BUFFER_SIZE (50) 29 | unsigned long lastMsg = 0; 30 | char msg[MSG_BUFFER_SIZE]; 31 | int value = 0; 32 | 33 | void setupWifi(); 34 | void callback(char* topic, byte* payload, unsigned int length); 35 | void reConnect(); 36 | 37 | void setup() { 38 | M5.begin(); 39 | digitalWrite(LED_EXT_PIN, LOW); //设置 LED_EXT_PIN 为低电平 40 | if (!M5.M5Ink.isInit()) { //判断 M5Ink 是否初始化成功 41 | Serial.printf("Ink Init faild"); 42 | while (1) delay(100); 43 | } 44 | M5.M5Ink.clear(); // clear the screen. 清屏 45 | delay(1000); 46 | // creat ink Sprite. 创建图像区域 47 | if (InkPageSprite.creatSprite(0, 0, 200, 200, true) != 0) { 48 | Serial.printf("Ink Sprite creat faild"); 49 | } 50 | InkPageSprite.drawString(10, 10, "MQTT"); //在图像区域内绘制字符串 51 | setupWifi(); 52 | client.setServer(mqtt_server, 53 | 1883); // Sets the server details. 配置所连接的服务器 54 | client.setCallback( 55 | callback); // Sets the message callback function. 设置消息回调函数 56 | InkPageSprite.pushSprite(); //将图像区域内的内容推送到屏幕上 57 | } 58 | 59 | void loop() { 60 | if (!client.connected()) { 61 | reConnect(); 62 | } 63 | client.loop(); // This function is called periodically to allow clients to 64 | // process incoming messages and maintain connections to the 65 | // server. 66 | //定期调用此函数,以允许主机处理传入消息并保持与服务器的连接 67 | 68 | unsigned long now = 69 | millis(); // Obtain the host startup duration. 获取主机开机时长 70 | if (now - lastMsg > 2000) { 71 | lastMsg = now; 72 | ++value; 73 | snprintf(msg, MSG_BUFFER_SIZE, "hello world #%d", 74 | value); // Format to the specified string and store it in MSG. 75 | // 格式化成指定字符串并存入msg中 76 | Serial.print("Publish message: "); 77 | Serial.println(msg); 78 | client.publish("M5Stack", msg); // Publishes a message to the specified 79 | // topic. 发送一条消息至指定话题 80 | } 81 | } 82 | 83 | void setupWifi() { 84 | delay(10); 85 | Serial.printf("Connecting to %s", ssid); 86 | WiFi.mode( 87 | WIFI_STA); // Set the mode to WiFi station mode. 设置模式为WIFI站模式 88 | WiFi.begin(ssid, password); // Start Wifi connection. 开始wifi连接 89 | 90 | while (WiFi.status() != WL_CONNECTED) { 91 | delay(500); 92 | Serial.print("."); 93 | } 94 | Serial.printf("\nSuccess\n"); 95 | InkPageSprite.drawString( 96 | 10, 25, "Success connecting wifi "); //在图像区域内绘制字符串 97 | InkPageSprite.drawString(10, 40, 98 | "Please see the serial"); //在图像区域内绘制字符串 99 | } 100 | 101 | void callback(char* topic, byte* payload, unsigned int length) { 102 | Serial.print("Message arrived ["); 103 | Serial.print(topic); 104 | Serial.print("] "); 105 | for (int i = 0; i < length; i++) { 106 | Serial.print((char)payload[i]); 107 | } 108 | Serial.println(); 109 | } 110 | 111 | void reConnect() { 112 | while (!client.connected()) { 113 | Serial.print("Attempting MQTT connection..."); 114 | // Create a random client ID. 创建一个随机的客户端ID 115 | String clientId = "M5Stack-"; 116 | clientId += String(random(0xffff), HEX); 117 | // Attempt to connect. 尝试重新连接 118 | if (client.connect(clientId.c_str())) { 119 | Serial.printf("\nSuccess\n"); 120 | // Once connected, publish an announcement to the topic. 121 | // 一旦连接,发送一条消息至指定话题 122 | client.publish("M5Stack", "hello world"); 123 | // ... and resubscribe. 重新订阅话题 124 | client.subscribe("M5Stack"); 125 | } else { 126 | Serial.print("failed, rc="); 127 | Serial.print(client.state()); 128 | Serial.println("try again in 5 seconds"); 129 | delay(5000); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: Google 4 | AccessModifierOffset: -1 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveMacros: true 7 | AlignConsecutiveAssignments: true 8 | AlignConsecutiveDeclarations: false 9 | AlignEscapedNewlines: Left 10 | AlignOperands: true 11 | AlignTrailingComments: true 12 | AllowAllArgumentsOnNextLine: true 13 | AllowAllConstructorInitializersOnNextLine: true 14 | AllowAllParametersOfDeclarationOnNextLine: true 15 | AllowShortBlocksOnASingleLine: Never 16 | AllowShortCaseLabelsOnASingleLine: false 17 | AllowShortFunctionsOnASingleLine: false 18 | AllowShortLambdasOnASingleLine: All 19 | AllowShortIfStatementsOnASingleLine: WithoutElse 20 | AllowShortLoopsOnASingleLine: true 21 | AlwaysBreakAfterDefinitionReturnType: None 22 | AlwaysBreakAfterReturnType: None 23 | AlwaysBreakBeforeMultilineStrings: true 24 | AlwaysBreakTemplateDeclarations: Yes 25 | BinPackArguments: true 26 | BinPackParameters: true 27 | BraceWrapping: 28 | AfterCaseLabel: false 29 | AfterClass: false 30 | AfterControlStatement: false 31 | AfterEnum: false 32 | AfterFunction: false 33 | AfterNamespace: false 34 | AfterObjCDeclaration: false 35 | AfterStruct: false 36 | AfterUnion: false 37 | AfterExternBlock: false 38 | BeforeCatch: false 39 | BeforeElse: false 40 | IndentBraces: false 41 | SplitEmptyFunction: true 42 | SplitEmptyRecord: true 43 | SplitEmptyNamespace: true 44 | BreakBeforeBinaryOperators: None 45 | BreakBeforeBraces: Attach 46 | BreakBeforeInheritanceComma: false 47 | BreakInheritanceList: BeforeColon 48 | BreakBeforeTernaryOperators: true 49 | BreakConstructorInitializersBeforeComma: false 50 | BreakConstructorInitializers: BeforeColon 51 | BreakAfterJavaFieldAnnotations: false 52 | BreakStringLiterals: true 53 | ColumnLimit: 80 54 | CommentPragmas: '^ IWYU pragma:' 55 | CompactNamespaces: false 56 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 57 | ConstructorInitializerIndentWidth: 4 58 | ContinuationIndentWidth: 4 59 | Cpp11BracedListStyle: true 60 | DeriveLineEnding: true 61 | DerivePointerAlignment: true 62 | DisableFormat: false 63 | ExperimentalAutoDetectBinPacking: false 64 | FixNamespaceComments: true 65 | ForEachMacros: 66 | - foreach 67 | - Q_FOREACH 68 | - BOOST_FOREACH 69 | IncludeBlocks: Regroup 70 | IncludeCategories: 71 | - Regex: '^' 72 | Priority: 2 73 | SortPriority: 0 74 | - Regex: '^<.*\.h>' 75 | Priority: 1 76 | SortPriority: 0 77 | - Regex: '^<.*' 78 | Priority: 2 79 | SortPriority: 0 80 | - Regex: '.*' 81 | Priority: 3 82 | SortPriority: 0 83 | IncludeIsMainRegex: '([-_](test|unittest))?$' 84 | IncludeIsMainSourceRegex: '' 85 | IndentCaseLabels: true 86 | IndentGotoLabels: true 87 | IndentPPDirectives: None 88 | IndentWidth: 4 89 | IndentWrappedFunctionNames: false 90 | JavaScriptQuotes: Leave 91 | JavaScriptWrapImports: true 92 | KeepEmptyLinesAtTheStartOfBlocks: false 93 | MacroBlockBegin: '' 94 | MacroBlockEnd: '' 95 | MaxEmptyLinesToKeep: 1 96 | NamespaceIndentation: None 97 | ObjCBinPackProtocolList: Never 98 | ObjCBlockIndentWidth: 2 99 | ObjCSpaceAfterProperty: false 100 | ObjCSpaceBeforeProtocolList: true 101 | PenaltyBreakAssignment: 2 102 | PenaltyBreakBeforeFirstCallParameter: 1 103 | PenaltyBreakComment: 300 104 | PenaltyBreakFirstLessLess: 120 105 | PenaltyBreakString: 1000 106 | PenaltyBreakTemplateDeclaration: 10 107 | PenaltyExcessCharacter: 1000000 108 | PenaltyReturnTypeOnItsOwnLine: 200 109 | PointerAlignment: Left 110 | RawStringFormats: 111 | - Language: Cpp 112 | Delimiters: 113 | - cc 114 | - CC 115 | - cpp 116 | - Cpp 117 | - CPP 118 | - 'c++' 119 | - 'C++' 120 | CanonicalDelimiter: '' 121 | BasedOnStyle: google 122 | - Language: TextProto 123 | Delimiters: 124 | - pb 125 | - PB 126 | - proto 127 | - PROTO 128 | EnclosingFunctions: 129 | - EqualsProto 130 | - EquivToProto 131 | - PARSE_PARTIAL_TEXT_PROTO 132 | - PARSE_TEST_PROTO 133 | - PARSE_TEXT_PROTO 134 | - ParseTextOrDie 135 | - ParseTextProtoOrDie 136 | CanonicalDelimiter: '' 137 | BasedOnStyle: google 138 | ReflowComments: true 139 | SortIncludes: false 140 | SortUsingDeclarations: true 141 | SpaceAfterCStyleCast: false 142 | SpaceAfterLogicalNot: false 143 | SpaceAfterTemplateKeyword: true 144 | SpaceBeforeAssignmentOperators: true 145 | SpaceBeforeCpp11BracedList: false 146 | SpaceBeforeCtorInitializerColon: true 147 | SpaceBeforeInheritanceColon: true 148 | SpaceBeforeParens: ControlStatements 149 | SpaceBeforeRangeBasedForLoopColon: true 150 | SpaceInEmptyBlock: false 151 | SpaceInEmptyParentheses: false 152 | SpacesBeforeTrailingComments: 2 153 | SpacesInAngles: false 154 | SpacesInConditionalStatement: false 155 | SpacesInContainerLiterals: true 156 | SpacesInCStyleCastParentheses: false 157 | SpacesInParentheses: false 158 | SpacesInSquareBrackets: false 159 | SpaceBeforeSquareBrackets: false 160 | Standard: Auto 161 | StatementMacros: 162 | - Q_UNUSED 163 | - QT_REQUIRE_VERSION 164 | TabWidth: 4 165 | UseCRLF: false 166 | UseTab: Never 167 | ... 168 | -------------------------------------------------------------------------------- /examples/Basics/FactoryTest/Num18x29.cpp: -------------------------------------------------------------------------------- 1 | #include "icon.h" 2 | 3 | unsigned char image_num_29_01[66] = { 4 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xf8, 0x0f, 5 | 0xf8, 0x00, 0xfe, 0x3e, 0x3e, 0x0f, 0x83, 0x8f, 0xf8, 0xe3, 0xf8, 6 | 0x38, 0xfe, 0x0e, 0x3e, 0x03, 0x8f, 0x88, 0xe3, 0x82, 0x38, 0xe3, 7 | 0x8e, 0x20, 0xe3, 0x88, 0xf8, 0xe0, 0x3e, 0x38, 0x3f, 0x8e, 0x0f, 8 | 0xe3, 0x8f, 0xf8, 0xe0, 0xf8, 0x3e, 0x3e, 0x3f, 0x80, 0x0f, 0xf8, 9 | 0x0f, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 10 | }; 11 | unsigned char image_num_29_02[66] = { 12 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x7f, 0xf0, 0x1f, 13 | 0xfc, 0x07, 0xff, 0xf1, 0xff, 0xfc, 0x7f, 0xff, 0x1f, 0xff, 0xc7, 14 | 0xff, 0xf1, 0xff, 0xfc, 0x7f, 0xff, 0x1f, 0xff, 0xc7, 0xff, 0xf1, 15 | 0xff, 0xfc, 0x7f, 0xff, 0x1f, 0xff, 0xc7, 0xff, 0xf1, 0xff, 0xfc, 16 | 0x7f, 0xff, 0x1f, 0xff, 0xc7, 0xff, 0xf1, 0xff, 0xfc, 0x7f, 0xff, 17 | 0x1f, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 18 | }; 19 | unsigned char image_num_29_03[66] = { 20 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xf8, 0x0f, 21 | 0xf8, 0x00, 0xfe, 0x3e, 0x3e, 0x0f, 0x83, 0x8f, 0xf8, 0xe3, 0xfe, 22 | 0x3f, 0xff, 0x8f, 0xff, 0x83, 0xff, 0xe3, 0xff, 0xe0, 0xff, 0xf8, 23 | 0xff, 0xf8, 0x3f, 0xfe, 0x3f, 0xfe, 0x0f, 0xff, 0x8f, 0xff, 0x83, 24 | 0xff, 0xe3, 0xff, 0xe0, 0xff, 0xf8, 0xff, 0xfe, 0x00, 0x03, 0x80, 25 | 0x00, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 26 | }; 27 | unsigned char image_num_29_04[66] = { 28 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xf8, 0x0f, 29 | 0xf8, 0x00, 0xfe, 0x3e, 0x3e, 0x0f, 0x83, 0x8f, 0xf8, 0xe3, 0xfe, 30 | 0x3f, 0xff, 0x8f, 0xff, 0x83, 0xff, 0xe3, 0xfe, 0x00, 0xff, 0x80, 31 | 0xff, 0xe0, 0x0f, 0xff, 0xe3, 0xff, 0xf8, 0x3f, 0xff, 0x8e, 0x3f, 32 | 0xe3, 0x8f, 0xf8, 0xe0, 0xf8, 0x3e, 0x3e, 0x3f, 0x80, 0x0f, 0xf8, 33 | 0x0f, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 34 | }; 35 | unsigned char image_num_29_05[66] = { 36 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0x0f, 37 | 0xff, 0xc3, 0xff, 0xe0, 0xff, 0xf0, 0x3f, 0xfc, 0x0f, 0xfe, 0x03, 38 | 0xff, 0x88, 0xff, 0xc6, 0x3f, 0xe1, 0x8f, 0xf8, 0xe3, 0xfc, 0x38, 39 | 0xff, 0x1e, 0x3f, 0x87, 0x8f, 0xe0, 0x00, 0x38, 0x00, 0x0e, 0x00, 40 | 0x03, 0xff, 0x8f, 0xff, 0xe3, 0xff, 0xf8, 0xff, 0xfe, 0x3f, 0xff, 41 | 0x8f, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 42 | }; 43 | unsigned char image_num_29_06[66] = { 44 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x03, 0x80, 0x00, 45 | 0xe0, 0x00, 0x38, 0xff, 0xfe, 0x3f, 0xff, 0x8f, 0xff, 0xe3, 0xff, 46 | 0xf8, 0xff, 0xfe, 0x00, 0x3f, 0x80, 0x0f, 0xe0, 0x00, 0xff, 0xfe, 47 | 0x3f, 0xff, 0x83, 0xff, 0xf8, 0xff, 0xfe, 0x3f, 0xff, 0x8e, 0x3f, 48 | 0xe3, 0x8f, 0xf8, 0xe0, 0xf8, 0x3e, 0x3e, 0x3f, 0x80, 0x0f, 0xf8, 49 | 0x0f, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 50 | }; 51 | unsigned char image_num_29_07[66] = { 52 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xf8, 0x0f, 53 | 0xf8, 0x00, 0xfe, 0x3e, 0x3e, 0x0f, 0x83, 0x8f, 0xf8, 0xe3, 0xfe, 54 | 0x38, 0xff, 0xfe, 0x20, 0x3f, 0x88, 0x0f, 0xe0, 0x00, 0xf8, 0x3e, 55 | 0x3e, 0x0f, 0x83, 0x8f, 0xf8, 0xe3, 0xfe, 0x38, 0xff, 0x8e, 0x3f, 56 | 0xe3, 0x8f, 0xf8, 0xe0, 0xf8, 0x3e, 0x3e, 0x3f, 0x80, 0x0f, 0xf8, 57 | 0x0f, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 58 | }; 59 | unsigned char image_num_29_08[66] = { 60 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x03, 0x80, 0x00, 61 | 0xe0, 0x00, 0x3f, 0xff, 0x8f, 0xff, 0xe3, 0xff, 0xf8, 0xff, 0xf8, 62 | 0x3f, 0xfe, 0x3f, 0xff, 0x8f, 0xff, 0xe3, 0xff, 0xe0, 0xff, 0xf8, 63 | 0xff, 0xfe, 0x3f, 0xff, 0x8f, 0xff, 0x83, 0xff, 0xe3, 0xff, 0xf8, 64 | 0xff, 0xfe, 0x3f, 0xfe, 0x0f, 0xff, 0x8f, 0xff, 0xe3, 0xff, 0xf8, 65 | 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 66 | }; 67 | unsigned char image_num_29_09[66] = { 68 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xf8, 0x0f, 69 | 0xf8, 0x00, 0xfe, 0x3e, 0x3e, 0x0f, 0x83, 0x8f, 0xf8, 0xe3, 0xfe, 70 | 0x38, 0xff, 0x8e, 0x0f, 0x83, 0xe3, 0xe3, 0xf8, 0x00, 0xff, 0x80, 71 | 0xff, 0x80, 0x0f, 0xe3, 0xe3, 0xe0, 0xf8, 0x38, 0xff, 0x8e, 0x3f, 72 | 0xe3, 0x8f, 0xf8, 0xe0, 0xf8, 0x3e, 0x3e, 0x3f, 0x80, 0x0f, 0xf8, 73 | 0x0f, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 74 | }; 75 | unsigned char image_num_29_10[66] = { 76 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xf8, 0x0f, 77 | 0xf8, 0x00, 0xfe, 0x3e, 0x3e, 0x0f, 0x83, 0x8f, 0xf8, 0xe3, 0xfe, 78 | 0x38, 0xff, 0x8e, 0x3f, 0xe3, 0x8f, 0xf8, 0xe0, 0xf8, 0x3e, 0x3e, 79 | 0x0f, 0x80, 0x03, 0xf8, 0x08, 0xfe, 0x02, 0x3f, 0xff, 0x8e, 0x3f, 80 | 0xe3, 0x8f, 0xf8, 0xe0, 0xf8, 0x3e, 0x3e, 0x3f, 0x80, 0x0f, 0xf8, 81 | 0x0f, 0xfe, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 82 | }; 83 | unsigned char image_num_29_11[66] = { 84 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xe3, 85 | 0xff, 0xf8, 0xff, 0xfe, 0x3f, 0xfe, 0x0f, 0xff, 0x8f, 0xff, 0xe3, 86 | 0xff, 0xf8, 0xff, 0xf8, 0x3f, 0xfe, 0x3f, 0xff, 0x8f, 0xff, 0xe3, 87 | 0xff, 0xe0, 0xff, 0xf8, 0xff, 0xfe, 0x3f, 0xff, 0x8f, 0xff, 0x83, 88 | 0xff, 0xe3, 0xff, 0xf8, 0xff, 0xfe, 0x3f, 0xfe, 0x0f, 0xff, 0x8f, 89 | 0xff, 0xe3, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 90 | }; 91 | -------------------------------------------------------------------------------- /.github/actions/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Test compile for Arduino' 2 | description: 'Compile sketches or Arduino library examples for one board type using arduino-cli and check for errors' 3 | author: 'Armin Joachimsmeyer' 4 | inputs: 5 | cli-version: 6 | description: 'Version of arduino-cli to use when building. Current (8/2022) one is 0.26.0.' 7 | default: 'latest' 8 | required: false 9 | 10 | sketch-names: 11 | description: 'Comma sepatated list of patterns or filenames (without path) of the sketch(es) to test compile. Useful if the sketch is a *.cpp or *.c file or only one sketch in the repository should be compiled.' 12 | default: '*.ino' 13 | required: false 14 | 15 | sketch-names-find-start: 16 | description: 'The start directory to look for the sketch-names to test compile. Can be a path like "digistump-avr/libraries/*/examples/C*/" .' 17 | default: '.' 18 | required: false 19 | 20 | arduino-board-fqbn: 21 | #In the Arduino IDE, the fqbn is printed in the first line of the verbose output for compilation as parameter -fqbn=... for the "arduino-builder -dump-prefs" command 22 | description: 'Fully Qualified Board Name of the Arduino board. You may add a suffix behind the fqbn with "|" to specify one board for e.g. different compile options like arduino:avr:uno|trace.' 23 | default: 'arduino:avr:uno' 24 | required: false 25 | 26 | arduino-platform: 27 | description: 'Comma separated list of platform specifiers, if you require a fixed version like "arduino:avr@1.8.2" or do not want the specifier derived from the 2 first elements of the arduino-board-fqbn or need more than one core. The suffix "@latest" is always removed.' 28 | default: '' 29 | required: false 30 | 31 | platform-default-url: 32 | description: 'The platform URL for the required board description if arduino-board-fqbn does not start with "arduino:" and not explicitly specified by platform-url.' 33 | default: '' 34 | required: false 35 | 36 | platform-url: 37 | description: 'The platform URL for the required board description if arduino-board-fqbn does not start with "arduino:".' 38 | default: '' 39 | required: false 40 | 41 | required-libraries: 42 | description: 'Comma separated list of arduino library names required for compiling the sketches / examples for this board.' 43 | default: '' 44 | required: false 45 | 46 | sketches-exclude: 47 | description: 'Comma or space separated list of complete names of all sketches / examples to be excluded in the build for this board.' 48 | default: '' 49 | required: false 50 | 51 | build-properties: 52 | description: | 53 | Build parameter like -DDEBUG for each example specified or for all examples, if example name is "All". In json format. 54 | For example: build-properties: '{ "WhistleSwitch": "-DDEBUG -DFREQUENCY_RANGE_LOW", "SimpleFrequencyDetector": "-DINFO" }' 55 | default: '' 56 | required: false 57 | 58 | extra-arduino-cli-args: 59 | description: | 60 | This string is passed verbatim without double quotes to the arduino-cli compile commandline as last argument before the filename. 61 | See https://arduino.github.io/arduino-cli/commands/arduino-cli_compile/ for compile parameters. 62 | default: '' 63 | required: false 64 | 65 | extra-arduino-lib-install-args: 66 | description: | 67 | This string is passed verbatim without double quotes to the arduino-cli lib install commandline as last argument before the library names. 68 | It can be used e.g. to suppress dependency resolving for libraries by using --no-deps as argument string. 69 | default: '' 70 | required: false 71 | 72 | set-build-path: 73 | description: 'Flag to set the build directory (arduino-cli paramer --build-path) to /build subdirectory of compiled sketches.' 74 | default: 'false' 75 | required: false 76 | 77 | debug-compile: 78 | description: 'If set to "true" the action logs verbose compile output even during successful builds' 79 | default: '' 80 | required: false 81 | 82 | debug-install: 83 | description: 'If set to "true" the action logs verbose arduino-cli output during installation' 84 | default: '' 85 | required: false 86 | 87 | runs: 88 | using: 'composite' 89 | steps: 90 | - name: Compile all sketches / examples using the bash script arduino-test-compile.sh 91 | env: 92 | # Passing parameters to the script by setting the appropriate ENV_* variables. 93 | # Direct passing as arguments is not possible because of blanks in the arguments. 94 | ENV_CLI_VERSION: ${{ inputs.cli-version }} 95 | ENV_SKETCH_NAMES: ${{ inputs.sketch-names }} 96 | ENV_SKETCH_NAMES_FIND_START: ${{ inputs.sketch-names-find-start }} 97 | ENV_ARDUINO_BOARD_FQBN: ${{ inputs.arduino-board-fqbn }} 98 | ENV_ARDUINO_PLATFORM: ${{ inputs.arduino-platform }} 99 | ENV_PLATFORM_DEFAULT_URL: ${{ inputs.platform-default-url }} 100 | ENV_PLATFORM_URL: ${{ inputs.platform-url }} 101 | ENV_REQUIRED_LIBRARIES: ${{ inputs.required-libraries }} 102 | ENV_SKETCHES_EXCLUDE: ${{ inputs.sketches-exclude }} 103 | ENV_BUILD_PROPERTIES: ${{ inputs.build-properties }} 104 | ENV_EXTRA_ARDUINO_CLI_ARGS: ${{ inputs.extra-arduino-cli-args }} 105 | ENV_EXTRA_ARDUINO_LIB_INSTALL_ARGS: ${{ inputs.extra-arduino-lib-install-args }} 106 | ENV_SET_BUILD_PATH: ${{ inputs.set-build-path }} 107 | ENV_DEBUG_COMPILE: ${{ inputs.debug-compile }} 108 | ENV_DEBUG_INSTALL: ${{ inputs.debug-install }} 109 | 110 | run: ${{ github.action_path }}/arduino-test-compile.sh 111 | shell: bash 112 | 113 | branding: 114 | icon: 'eye' 115 | color: 'red' -------------------------------------------------------------------------------- /src/utility/Button.cpp: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------* 2 | * Arduino Button Library v1.0 * 3 | * Jack Christensen May 2011, published Mar 2012 * 4 | * * 5 | * Library for reading momentary contact switches like tactile button * 6 | * switches. Intended for use in state machine constructs. * 7 | * Use the read() function to read all buttons in the main loop, * 8 | * which should execute as fast as possible. * 9 | * * 10 | * This work is licensed under the Creative Commons Attribution- * 11 | * ShareAlike 3.0 Unported License. To view a copy of this license, * 12 | * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * 13 | * letter to Creative Commons, 171 Second Street, Suite 300, * 14 | * San Francisco, California, 94105, USA. * 15 | *----------------------------------------------------------------------*/ 16 | 17 | #include "Button.h" 18 | 19 | /*----------------------------------------------------------------------* 20 | * Button(pin, puEnable, invert, dbTime) instantiates a button object. * 21 | * pin Is the Arduino pin the button is connected to. * 22 | * puEnable Enables the AVR internal pullup resistor if != 0 (can also * 23 | * use true or false). * 24 | * invert If invert == 0, interprets a high state as pressed, low as * 25 | * released. If invert != 0, interprets a high state as * 26 | * released, low as pressed (can also use true or false). * 27 | * dbTime Is the debounce time in milliseconds. * 28 | * * 29 | * (Note that invert cannot be implied from puEnable since an external * 30 | * pullup could be used.) * 31 | *----------------------------------------------------------------------*/ 32 | Button::Button(uint8_t pin, uint8_t invert, uint32_t dbTime) { 33 | _pin = pin; 34 | _invert = invert; 35 | _dbTime = dbTime; 36 | pinMode(_pin, INPUT_PULLUP); 37 | _state = digitalRead(_pin); 38 | if (_invert != 0) _state = !_state; 39 | _time = millis(); 40 | _lastState = _state; 41 | _changed = 0; 42 | _hold_time = -1; 43 | _lastTime = _time; 44 | _lastChange = _time; 45 | _pressTime = _time; 46 | } 47 | 48 | /*----------------------------------------------------------------------* 49 | * read() returns the state of the button, 1==pressed, 0==released, * 50 | * does debouncing, captures and maintains times, previous states, etc. * 51 | *----------------------------------------------------------------------*/ 52 | uint8_t Button::read(void) { 53 | static uint32_t ms; 54 | static uint8_t pinVal; 55 | 56 | ms = millis(); 57 | pinVal = digitalRead(_pin); 58 | if (_invert != 0) pinVal = !pinVal; 59 | if (ms - _lastChange < _dbTime) { 60 | _lastTime = _time; 61 | _time = ms; 62 | _changed = 0; 63 | return _state; 64 | } else { 65 | _lastTime = _time; 66 | _time = ms; 67 | _lastState = _state; 68 | _state = pinVal; 69 | if (_state != _lastState) { 70 | _lastChange = ms; 71 | _changed = 1; 72 | if (_state) { 73 | _pressTime = _time; 74 | } 75 | } else { 76 | _changed = 0; 77 | } 78 | return _state; 79 | } 80 | } 81 | 82 | /*----------------------------------------------------------------------* 83 | * isPressed() and isReleased() check the button state when it was last * 84 | * read, and return false (0) or true (!=0) accordingly. * 85 | * These functions do not cause the button to be read. * 86 | *----------------------------------------------------------------------*/ 87 | uint8_t Button::isPressed(void) { 88 | return _state == 0 ? 0 : 1; 89 | } 90 | 91 | uint8_t Button::isReleased(void) { 92 | return _state == 0 ? 1 : 0; 93 | } 94 | 95 | /*----------------------------------------------------------------------* 96 | * wasPressed() and wasReleased() check the button state to see if it * 97 | * changed between the last two reads and return false (0) or * 98 | * true (!=0) accordingly. * 99 | * These functions do not cause the button to be read. * 100 | *----------------------------------------------------------------------*/ 101 | uint8_t Button::wasPressed(void) { 102 | return _state && _changed; 103 | } 104 | 105 | uint8_t Button::wasReleased(void) { 106 | return !_state && _changed && millis() - _pressTime < _hold_time; 107 | } 108 | 109 | uint8_t Button::wasReleasefor(uint32_t ms) { 110 | _hold_time = ms; 111 | return !_state && _changed && millis() - _pressTime >= ms; 112 | } 113 | /*----------------------------------------------------------------------* 114 | * pressedFor(ms) and releasedFor(ms) check to see if the button is * 115 | * pressed (or released), and has been in that state for the specified * 116 | * time in milliseconds. Returns false (0) or true (1) accordingly. * 117 | * These functions do not cause the button to be read. * 118 | *----------------------------------------------------------------------*/ 119 | uint8_t Button::pressedFor(uint32_t ms) { 120 | return (_state == 1 && _time - _lastChange >= ms) ? 1 : 0; 121 | } 122 | 123 | uint8_t Button::releasedFor(uint32_t ms) { 124 | return (_state == 0 && _time - _lastChange >= ms) ? 1 : 0; 125 | } 126 | /*----------------------------------------------------------------------* 127 | * lastChange() returns the time the button last changed state, * 128 | * in milliseconds. * 129 | *----------------------------------------------------------------------*/ 130 | uint32_t Button::lastChange(void) { 131 | return _lastChange; 132 | } 133 | -------------------------------------------------------------------------------- /examples/Basics/RTC_Clock/RTC_Clock.ino: -------------------------------------------------------------------------------- 1 | // This RTC clock example keeps the system mostly in shutdown mode and 2 | // only wakes up every 58 seconds for a brief period of time during 3 | // which the time and date are updated on the ink display. 4 | // 5 | // When started initially or via power button a full ink display refresh 6 | // is executed to clear the display. 7 | // The current time and date are fetched via NTP and shown on the ink display. 8 | // After waiting for the full minute the system is put into shutdown 9 | // mode for about 58 seconds. 10 | // When the RTC timer expires (just befor the next minute change) the 11 | // system is powered on. 12 | // The ink display is updated with the current time and date. 13 | // Then the system goes back into shutdown mode for about 58 seconds and 14 | // the cycle begins anew. 15 | // Every hour a full ink display refresh is executed to keep the ink 16 | // display crisp. 17 | // 18 | // Note: If WiFi connection fails - some fantasy time and date are used. 19 | // Note: System will not enter shutdown mode while USB is connected. 20 | 21 | #include "M5CoreInk.h" 22 | #include 23 | #include "time.h" 24 | 25 | const char* ssid = "YOUR_SSID"; 26 | const char* password = "YOUR_PASSWORD"; 27 | const char* ntpServer = "pool.ntp.org"; 28 | const long gmtOffset_sec = 3600; 29 | const int daylightOffset_sec = 3600; 30 | 31 | // every hour at minute 45 do a full ink display refresh 32 | #define FULL_REFRESH_MINUTE (45) 33 | 34 | Ink_Sprite TimePageSprite(&M5.M5Ink); 35 | 36 | void printLocalTimeAndSetRTC() { 37 | struct tm timeinfo; 38 | 39 | if (getLocalTime(&timeinfo) == false) { 40 | Serial.println("Failed to obtain time"); 41 | return; 42 | } 43 | Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S"); 44 | 45 | RTC_TimeTypeDef time; 46 | time.Hours = timeinfo.tm_hour; 47 | time.Minutes = timeinfo.tm_min; 48 | time.Seconds = timeinfo.tm_sec; 49 | M5.rtc.SetTime(&time); 50 | 51 | RTC_DateTypeDef date; 52 | date.Date = timeinfo.tm_mday; 53 | date.Month = timeinfo.tm_mon + 1; 54 | date.Year = timeinfo.tm_year + 1900; 55 | M5.rtc.SetDate(&date); 56 | } 57 | 58 | void getNTPTime() { 59 | // Try to connect for 10 seconds 60 | uint32_t connect_timeout = millis() + 10000; 61 | 62 | Serial.printf("Connecting to %s ", ssid); 63 | WiFi.begin(ssid, password); 64 | while ((WiFi.status() != WL_CONNECTED) && (millis() < connect_timeout)) { 65 | delay(500); 66 | Serial.print("."); 67 | } 68 | if (WiFi.status() != WL_CONNECTED) { 69 | // WiFi connection failed - set fantasy time and date 70 | RTC_TimeTypeDef time; 71 | time.Hours = 6; 72 | time.Minutes = 43; 73 | time.Seconds = 50; 74 | M5.rtc.SetTime(&time); 75 | 76 | RTC_DateTypeDef date; 77 | date.Date = 4; 78 | date.Month = 12; 79 | date.Year = 2020; 80 | M5.rtc.SetDate(&date); 81 | return; 82 | } 83 | 84 | Serial.println("Connected"); 85 | 86 | configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); 87 | printLocalTimeAndSetRTC(); 88 | 89 | WiFi.disconnect(true); 90 | WiFi.mode(WIFI_OFF); 91 | } 92 | 93 | void drawTimeAndDate(RTC_TimeTypeDef time, RTC_DateTypeDef date) { 94 | char buf[20] = {0}; 95 | sprintf(buf, "%02d:%02d", time.Hours, time.Minutes); 96 | TimePageSprite.drawString(40, 20, buf, &AsciiFont24x48); 97 | memset(buf, 0, 20); 98 | sprintf(buf, "%02d.%02d.%02d", date.Date, date.Month, date.Year - 2000); 99 | TimePageSprite.drawString(4, 70, buf, &AsciiFont24x48); 100 | } 101 | 102 | void setup() { 103 | // Check power on reason before calling M5.begin() 104 | // which calls Rtc.begin() which clears the timer flag. 105 | uint8_t data = 0; 106 | Wire1.begin(21, 22); 107 | Wire1.beginTransmission(0x51); 108 | Wire1.write(0x01); 109 | Wire1.endTransmission(); 110 | if (Wire1.requestFrom(0x51, 1)) { 111 | data = Wire1.read(); 112 | } 113 | 114 | M5.begin(); 115 | // Green LED - indicates ESP32 is running 116 | digitalWrite(LED_EXT_PIN, LOW); 117 | 118 | if (M5.M5Ink.isInit() == false) { 119 | Serial.printf("Ink Init failed"); 120 | while (1) delay(100); 121 | } 122 | 123 | RTC_TimeTypeDef time; 124 | RTC_DateTypeDef date; 125 | 126 | // Check timer flag 127 | if ((data & 0b00000100) == 0b00000100) { 128 | Serial.println("Power on by: RTC timer"); 129 | M5.rtc.GetTime(&time); 130 | M5.rtc.GetDate(&date); 131 | // Full refresh once per hour 132 | if (time.Minutes == FULL_REFRESH_MINUTE - 1) { 133 | M5.M5Ink.clear(); 134 | } 135 | } else { 136 | Serial.println("Power on by: power button"); 137 | M5.M5Ink.clear(); 138 | // Fetch current time from Internet 139 | getNTPTime(); 140 | M5.rtc.GetTime(&time); 141 | M5.rtc.GetDate(&date); 142 | } 143 | 144 | // After every shutdown the sprite is created anew. 145 | // But the sprite doesn't know about the current image on the 146 | // ink display therefore the same time and date, as have been 147 | // drawn before the shutdown, are redrawn. 148 | // This is required, else drawing new time and date only adds 149 | // pixels to the already drawn pixels instead of clearing the 150 | // previous time and date and then draw the new time and date. 151 | TimePageSprite.creatSprite(0, 0, 200, 200); 152 | 153 | drawTimeAndDate(time, date); 154 | TimePageSprite.pushSprite(); 155 | 156 | // Wait until full minute, e.g. seconds are 0 157 | while ((time.Seconds != 0)) { 158 | M5.rtc.GetTime(&time); 159 | delay(200); 160 | } 161 | M5.rtc.GetDate(&date); 162 | 163 | // Draw new time and date 164 | drawTimeAndDate(time, date); 165 | TimePageSprite.pushSprite(); 166 | 167 | Serial.printf("Shutdown...\n"); 168 | Serial.flush(); 169 | 170 | // Full refresh once per hour 171 | if (time.Minutes == FULL_REFRESH_MINUTE - 1) { 172 | // Allow extra time for full ink refresh 173 | // Shutdown for 55 seconds only 174 | M5.shutdown(55); 175 | return; 176 | } 177 | // Shutdown for 58 seconds 178 | M5.shutdown(58); 179 | } 180 | 181 | void loop() { 182 | } 183 | -------------------------------------------------------------------------------- /src/utility/M5Timer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * M5Timer.cpp 3 | * 4 | * M5Timer - A timer library for Arduino. 5 | * Author: mromani@ottotecnica.com 6 | * Copyright (c) 2010 OTTOTECNICA Italy 7 | * 8 | * This library is free software; you can redistribute it 9 | * and/or modify it under the terms of the GNU Lesser 10 | * General Public License as published by the Free Software 11 | * Foundation; either version 2.1 of the License, or (at 12 | * your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will 15 | * be useful, but WITHOUT ANY WARRANTY; without even the 16 | * implied warranty of MERCHANTABILITY or FITNESS FOR A 17 | * PARTICULAR PURPOSE. See the GNU Lesser General Public 18 | * License for more details. 19 | * 20 | * You should have received a copy of the GNU Lesser 21 | * General Public License along with this library; if not, 22 | * write to the Free Software Foundation, Inc., 23 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | */ 25 | 26 | #include "M5Timer.h" 27 | 28 | // Select time function: 29 | // static inline unsigned long elapsed() { return micros(); } 30 | static inline unsigned long elapsed() { 31 | return millis(); 32 | } 33 | 34 | M5Timer::M5Timer() { 35 | unsigned long current_millis = elapsed(); 36 | 37 | for (int i = 0; i < MAX_TIMERS; i++) { 38 | enabled[i] = false; 39 | callbacks[i] = 0; // if the callback pointer is zero, the slot is free, 40 | // i.e. doesn't "contain" any timer 41 | prev_millis[i] = current_millis; 42 | numRuns[i] = 0; 43 | } 44 | numTimers = 0; 45 | } 46 | 47 | void M5Timer::run() { 48 | int i; 49 | unsigned long current_millis; 50 | 51 | // get current time 52 | current_millis = elapsed(); 53 | 54 | for (i = 0; i < MAX_TIMERS; i++) { 55 | toBeCalled[i] = DEFCALL_DONTRUN; 56 | 57 | // no callback == no timer, i.e. jump over empty slots 58 | if (callbacks[i] != 0) { 59 | // is it time to process this timer ? 60 | // see 61 | // http://arduino.cc/forum/index.php/topic,124048.msg932592.html#msg932592 62 | 63 | if (current_millis - prev_millis[i] >= delays[i]) { 64 | // update time 65 | // prev_millis[i] = current_millis; 66 | prev_millis[i] += delays[i]; 67 | 68 | // check if the timer callback has to be executed 69 | if (enabled[i] == true) { 70 | // "run forever" timers must always be executed 71 | if (maxNumRuns[i] == RUN_FOREVER) { 72 | toBeCalled[i] = DEFCALL_RUNONLY; 73 | } else if (numRuns[i] < maxNumRuns[i]) { 74 | // other timers get executed the specified number of 75 | // times 76 | toBeCalled[i] = DEFCALL_RUNONLY; 77 | numRuns[i]++; 78 | // after the last run, delete the timer 79 | if (numRuns[i] >= maxNumRuns[i]) { 80 | toBeCalled[i] = DEFCALL_RUNANDDEL; 81 | } 82 | } 83 | } 84 | } 85 | } 86 | } 87 | for (i = 0; i < MAX_TIMERS; i++) { 88 | switch (toBeCalled[i]) { 89 | case DEFCALL_DONTRUN: 90 | break; 91 | 92 | case DEFCALL_RUNONLY: 93 | callbacks[i](); 94 | break; 95 | 96 | case DEFCALL_RUNANDDEL: 97 | callbacks[i](); 98 | deleteTimer(i); 99 | break; 100 | } 101 | } 102 | } 103 | 104 | // find the first available slot 105 | // return -1 if none found 106 | int M5Timer::findFirstFreeSlot() { 107 | int i; 108 | 109 | // all slots are used 110 | if (numTimers >= MAX_TIMERS) { 111 | return -1; 112 | } 113 | 114 | // return the first slot with no callback (i.e. free) 115 | for (i = 0; i < MAX_TIMERS; i++) { 116 | if (callbacks[i] == 0) { 117 | return i; 118 | } 119 | } 120 | // no free slots found 121 | return -1; 122 | } 123 | 124 | int M5Timer::setTimer(long d, timer_callback f, int n) { 125 | int freeTimer; 126 | 127 | freeTimer = findFirstFreeSlot(); 128 | if (freeTimer < 0) { 129 | return -1; 130 | } 131 | 132 | if (f == NULL) { 133 | return -1; 134 | } 135 | 136 | delays[freeTimer] = d; 137 | callbacks[freeTimer] = f; 138 | maxNumRuns[freeTimer] = n; 139 | enabled[freeTimer] = true; 140 | prev_millis[freeTimer] = elapsed(); 141 | 142 | numTimers++; 143 | 144 | return freeTimer; 145 | } 146 | 147 | int M5Timer::setInterval(long d, timer_callback f) { 148 | return setTimer(d, f, RUN_FOREVER); 149 | } 150 | 151 | int M5Timer::setTimeout(long d, timer_callback f) { 152 | return setTimer(d, f, RUN_ONCE); 153 | } 154 | 155 | void M5Timer::deleteTimer(int timerId) { 156 | if (timerId >= MAX_TIMERS) { 157 | return; 158 | } 159 | 160 | // nothing to delete if no timers are in use 161 | if (numTimers == 0) { 162 | return; 163 | } 164 | 165 | // don't decrease the number of timers if the 166 | // specified slot is already empty 167 | if (callbacks[timerId] != NULL) { 168 | callbacks[timerId] = 0; 169 | enabled[timerId] = false; 170 | toBeCalled[timerId] = DEFCALL_DONTRUN; 171 | delays[timerId] = 0; 172 | numRuns[timerId] = 0; 173 | 174 | // update number of timers 175 | numTimers--; 176 | } 177 | } 178 | 179 | // function contributed by code@rowansimms.com 180 | void M5Timer::restartTimer(int numTimer) { 181 | if (numTimer >= MAX_TIMERS) { 182 | return; 183 | } 184 | 185 | prev_millis[numTimer] = elapsed(); 186 | } 187 | 188 | boolean M5Timer::isEnabled(int numTimer) { 189 | if (numTimer >= MAX_TIMERS) { 190 | return false; 191 | } 192 | 193 | return enabled[numTimer]; 194 | } 195 | 196 | void M5Timer::enable(int numTimer) { 197 | if (numTimer >= MAX_TIMERS) { 198 | return; 199 | } 200 | 201 | enabled[numTimer] = true; 202 | } 203 | 204 | void M5Timer::disable(int numTimer) { 205 | if (numTimer >= MAX_TIMERS) { 206 | return; 207 | } 208 | 209 | enabled[numTimer] = false; 210 | } 211 | 212 | void M5Timer::toggle(int numTimer) { 213 | if (numTimer >= MAX_TIMERS) { 214 | return; 215 | } 216 | 217 | enabled[numTimer] = !enabled[numTimer]; 218 | } 219 | 220 | int M5Timer::getNumTimers() { 221 | return numTimers; 222 | } 223 | -------------------------------------------------------------------------------- /src/utility/BM8563.cpp: -------------------------------------------------------------------------------- 1 | #include "BM8563.h" 2 | 3 | RTC::RTC() { 4 | } 5 | 6 | void RTC::begin(void) { 7 | _i2c.begin(&Wire1, 21, 22); 8 | _i2c.writeByte(BM8563_I2C_ADDR, 0x00, 0x00); 9 | _i2c.writeByte(BM8563_I2C_ADDR, 0x0E, 0x03); 10 | } 11 | 12 | void RTC::GetBm8563Time(void) { 13 | if (_i2c.readBytes(BM8563_I2C_ADDR, 0x02, trdata, 7)) { 14 | DataMask(); 15 | Bcd2asc(); 16 | Str2Time(); 17 | } 18 | } 19 | 20 | void RTC::Str2Time(void) { 21 | Second = (asc[0] - 0x30) * 10 + asc[1] - 0x30; 22 | Minute = (asc[2] - 0x30) * 10 + asc[3] - 0x30; 23 | Hour = (asc[4] - 0x30) * 10 + asc[5] - 0x30; 24 | /* 25 | uint8_t Hour; 26 | uint8_t Week; 27 | uint8_t Day; 28 | uint8_t Month; 29 | uint8_t Year; 30 | */ 31 | } 32 | 33 | void RTC::DataMask() { 34 | trdata[0] = trdata[0] & 0x7f; // 秒 35 | trdata[1] = trdata[1] & 0x7f; // 分 36 | trdata[2] = trdata[2] & 0x3f; // 时 37 | 38 | trdata[3] = trdata[3] & 0x3f; // 日 39 | trdata[4] = trdata[4] & 0x07; // 星期 40 | trdata[5] = trdata[5] & 0x1f; // 月 41 | 42 | trdata[6] = trdata[6] & 0xff; // 年 43 | } 44 | /******************************************************************** 45 | 函 数 名: void Bcd2asc(void) 46 | 功 能: bcd 码转换成 asc 码,供Lcd显示用 47 | 说 明: 48 | 调 用: 49 | 入口参数: 50 | 返 回 值:无 51 | ***********************************************************************/ 52 | void RTC::Bcd2asc(void) { 53 | uint8_t i, j; 54 | for (j = 0, i = 0; i < 7; i++) { 55 | asc[j++] = 56 | (trdata[i] & 0xf0) >> 4 | 0x30; /*格式为: 秒 分 时 日 月 星期 年 */ 57 | asc[j++] = (trdata[i] & 0x0f) | 0x30; 58 | } 59 | } 60 | 61 | uint8_t RTC::bcd2ToByte(uint8_t value) { 62 | return ((value >> 4) * 10) + (value & 0x0F); 63 | } 64 | 65 | uint8_t RTC::byteToBcd2(uint8_t value) { 66 | std::uint_fast8_t bcdhigh = value / 10; 67 | return (bcdhigh << 4) | (value - (bcdhigh * 10)); 68 | } 69 | 70 | void RTC::GetTime(RTC_TimeTypeDef *RTC_TimeStruct) { 71 | uint8_t buf[3] = {0}; 72 | if (_i2c.readBytes(BM8563_I2C_ADDR, 0x02, buf, 3)) { 73 | RTC_TimeStruct->VLFlag = (buf[0] & 0x80) >> 7; 74 | RTC_TimeStruct->Seconds = bcd2ToByte(buf[0] & 0x7f); // 秒 75 | RTC_TimeStruct->Minutes = bcd2ToByte(buf[1] & 0x7f); // 分 76 | RTC_TimeStruct->Hours = bcd2ToByte(buf[2] & 0x3f); // 时 77 | } 78 | } 79 | 80 | void RTC::SetTime(RTC_TimeTypeDef *RTC_TimeStruct) { 81 | if (RTC_TimeStruct == NULL) return; 82 | 83 | uint8_t buf[] = {byteToBcd2(RTC_TimeStruct->Seconds), 84 | byteToBcd2(RTC_TimeStruct->Minutes), 85 | byteToBcd2(RTC_TimeStruct->Hours)}; 86 | 87 | _i2c.writeBytes(BM8563_I2C_ADDR, 0x02, buf, sizeof(buf)); 88 | } 89 | 90 | void RTC::GetDate(RTC_DateTypeDef *RTC_DateStruct) { 91 | uint8_t buf[4] = {0}; 92 | if (_i2c.readBytes(BM8563_I2C_ADDR, 0x05, buf, 4)) { 93 | RTC_DateStruct->Date = bcd2ToByte(buf[0] & 0x3f); 94 | RTC_DateStruct->WeekDay = bcd2ToByte(buf[1] & 0x07); 95 | RTC_DateStruct->Month = bcd2ToByte(buf[2] & 0x1f); 96 | RTC_DateStruct->Year = 97 | bcd2ToByte(buf[3] & 0xff) + ((0x80 & buf[2]) ? 1900 : 2000); 98 | } 99 | } 100 | 101 | void RTC::SetDate(RTC_DateTypeDef *RTC_DateStruct) { 102 | if (RTC_DateStruct == NULL) return; 103 | 104 | uint8_t buf[] = {byteToBcd2(RTC_DateStruct->Date), 105 | byteToBcd2(RTC_DateStruct->WeekDay), 106 | (std::uint8_t)(byteToBcd2(RTC_DateStruct->Month) + 107 | (RTC_DateStruct->Year < 2000 ? 0x80 : 0)), 108 | byteToBcd2(RTC_DateStruct->Year % 100)}; 109 | 110 | _i2c.writeBytes(BM8563_I2C_ADDR, 0x05, buf, sizeof(buf)); 111 | } 112 | 113 | int RTC::SetAlarmIRQ(int afterSeconds) { 114 | std::uint8_t reg_value = _i2c.readByte(BM8563_I2C_ADDR, 0x01) & ~0x0C; 115 | 116 | if (afterSeconds < 0) { // disable timer 117 | _i2c.writeByte(BM8563_I2C_ADDR, 0x01, reg_value & ~0x01); 118 | _i2c.writeByte(BM8563_I2C_ADDR, 0x0E, 0x03); 119 | return -1; 120 | } 121 | 122 | std::size_t div = 1; 123 | std::uint8_t type_value = 0x82; 124 | if (afterSeconds < 270) { 125 | if (afterSeconds > 255) { 126 | afterSeconds = 255; 127 | } 128 | } else { 129 | div = 60; 130 | afterSeconds = (afterSeconds + 30) / div; 131 | if (afterSeconds > 255) { 132 | afterSeconds = 255; 133 | } 134 | type_value = 0x83; 135 | } 136 | 137 | _i2c.writeByte(BM8563_I2C_ADDR, 0x0E, type_value); 138 | _i2c.writeByte(BM8563_I2C_ADDR, 0x0F, afterSeconds); 139 | _i2c.writeByte(BM8563_I2C_ADDR, 0x01, (reg_value | 0x01) & ~0x80); 140 | return afterSeconds * div; 141 | } 142 | 143 | int RTC::SetAlarmIRQ(const RTC_TimeTypeDef &RTC_TimeStruct) { 144 | uint8_t irq_enable = false; 145 | uint8_t out_buf[4] = {0x80, 0x80, 0x80, 0x80}; 146 | 147 | if (RTC_TimeStruct.Minutes >= 0) { 148 | irq_enable = true; 149 | out_buf[0] = byteToBcd2(RTC_TimeStruct.Minutes) & 0x7f; 150 | } 151 | 152 | if (RTC_TimeStruct.Hours >= 0) { 153 | irq_enable = true; 154 | out_buf[1] = byteToBcd2(RTC_TimeStruct.Hours) & 0x3f; 155 | } 156 | 157 | out_buf[2] = 0x80; 158 | out_buf[3] = 0x80; 159 | 160 | uint8_t reg_value = _i2c.readByte(BM8563_I2C_ADDR, 0x01); 161 | 162 | if (irq_enable) { 163 | reg_value |= (1 << 1); 164 | } else { 165 | reg_value &= ~(1 << 1); 166 | } 167 | 168 | for (int i = 0; i < 4; i++) { 169 | _i2c.writeByte(BM8563_I2C_ADDR, 0x09 + i, out_buf[i]); 170 | } 171 | _i2c.writeByte(BM8563_I2C_ADDR, 0x01, reg_value); 172 | 173 | return irq_enable ? 1 : 0; 174 | } 175 | 176 | int RTC::SetAlarmIRQ(const RTC_DateTypeDef &RTC_DateStruct, 177 | const RTC_TimeTypeDef &RTC_TimeStruct) { 178 | uint8_t irq_enable = false; 179 | uint8_t out_buf[4] = {0x80, 0x80, 0x80, 0x80}; 180 | 181 | if (RTC_TimeStruct.Minutes >= 0) { 182 | irq_enable = true; 183 | out_buf[0] = byteToBcd2(RTC_TimeStruct.Minutes) & 0x7f; 184 | } 185 | 186 | if (RTC_TimeStruct.Hours >= 0) { 187 | irq_enable = true; 188 | out_buf[1] = byteToBcd2(RTC_TimeStruct.Hours) & 0x3f; 189 | } 190 | 191 | if (RTC_DateStruct.Date >= 0) { 192 | irq_enable = true; 193 | out_buf[2] = byteToBcd2(RTC_DateStruct.Date) & 0x3f; 194 | } 195 | 196 | if (RTC_DateStruct.WeekDay >= 0) { 197 | irq_enable = true; 198 | out_buf[3] = byteToBcd2(RTC_DateStruct.WeekDay) & 0x07; 199 | } 200 | 201 | uint8_t reg_value = _i2c.readByte(BM8563_I2C_ADDR, 0x01); 202 | 203 | if (irq_enable) { 204 | reg_value |= (1 << 1); 205 | } else { 206 | reg_value &= ~(1 << 1); 207 | } 208 | 209 | for (int i = 0; i < 4; i++) { 210 | _i2c.writeByte(BM8563_I2C_ADDR, 0x09 + i, out_buf[i]); 211 | } 212 | _i2c.writeByte(BM8563_I2C_ADDR, 0x01, reg_value); 213 | 214 | return irq_enable ? 1 : 0; 215 | } 216 | 217 | void RTC::clearIRQ() { 218 | _i2c.writeBitOff(BM8563_I2C_ADDR, 0x01, 0x0C); 219 | } 220 | 221 | void RTC::disableIRQ() { 222 | // disable alerm (bit7:1=disabled) 223 | static constexpr const std::uint8_t buf[4] = {0x80, 0x80, 0x80, 0x80}; 224 | _i2c.writeBytes(BM8563_I2C_ADDR, 0x09, (uint8_t *)buf, 4); 225 | 226 | // disable timer (bit7:0=disabled) 227 | _i2c.writeByte(BM8563_I2C_ADDR, 0x0E, 0); 228 | 229 | // clear flag and INT enable bits 230 | _i2c.writeByte(BM8563_I2C_ADDR, 0x01, 0x00); 231 | } 232 | -------------------------------------------------------------------------------- /examples/Basics/FactoryTest/FactoryTest.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "M5CoreInk.h" 4 | #include "esp_adc_cal.h" 5 | #include "icon.h" 6 | 7 | Ink_Sprite TimePageSprite(&M5.M5Ink); 8 | 9 | RTC_TimeTypeDef RTCtime, RTCTimeSave; 10 | RTC_DateTypeDef RTCDate; 11 | uint8_t second = 0, minutes = 0; 12 | 13 | bool testMode = false; 14 | 15 | void set_led(bool status) { 16 | digitalWrite(LED_EXT_PIN, !status); 17 | } 18 | 19 | void timer_wakeup_test() { 20 | M5.M5Ink.setEpdMode(epd_mode_t::epd_quality); 21 | M5.M5Ink.clear(); // clear the screen. 清屏 22 | TimePageSprite.clear(); 23 | // // creat ink Sprite. 创建图像区域 24 | TimePageSprite.drawString(10, 50, 25 | "Click EXT Btn Sleep 5s"); // draw string. 26 | TimePageSprite.pushSprite(); 27 | 28 | while (1) { 29 | M5.update(); 30 | if (M5.BtnEXT.wasPressed()) { 31 | set_led(false); 32 | Serial.println("Sleep 5s..."); 33 | M5.shutdown(5); 34 | } 35 | } 36 | } 37 | 38 | void drawImageToSprite(int posX, int posY, image_t *imagePtr, 39 | Ink_Sprite *sprite) { 40 | sprite->drawBuff(posX, posY, imagePtr->width, imagePtr->height, 41 | imagePtr->ptr); 42 | } 43 | 44 | void drawTime(RTC_TimeTypeDef *time) { 45 | drawImageToSprite(10, 48, &num55[time->Hours / 10], &TimePageSprite); 46 | drawImageToSprite(50, 48, &num55[time->Hours % 10], &TimePageSprite); 47 | drawImageToSprite(90, 48, &num55[10], &TimePageSprite); 48 | drawImageToSprite(110, 48, &num55[time->Minutes / 10], &TimePageSprite); 49 | drawImageToSprite(150, 48, &num55[time->Minutes % 10], &TimePageSprite); 50 | } 51 | 52 | void drawDate(RTC_DateTypeDef *date) { 53 | int posX = 15, num = 0; 54 | for (int i = 0; i < 4; i++) { 55 | num = (date->Year / int(pow(10, 3 - i)) % 10); 56 | drawImageToSprite(posX, 124, &num18x29[num], &TimePageSprite); 57 | posX += 17; 58 | } 59 | drawImageToSprite(posX, 124, &num18x29[10], &TimePageSprite); 60 | posX += 17; 61 | 62 | drawImageToSprite(posX, 124, &num18x29[date->Month / 10 % 10], 63 | &TimePageSprite); 64 | posX += 17; 65 | drawImageToSprite(posX, 124, &num18x29[date->Month % 10], &TimePageSprite); 66 | posX += 17; 67 | 68 | drawImageToSprite(posX, 124, &num18x29[10], &TimePageSprite); 69 | posX += 17; 70 | 71 | drawImageToSprite(posX, 124, &num18x29[date->Date / 10 % 10], 72 | &TimePageSprite); 73 | posX += 17; 74 | drawImageToSprite(posX, 124, &num18x29[date->Date % 10], &TimePageSprite); 75 | posX += 17; 76 | } 77 | 78 | float getBatVoltage() { 79 | analogSetPinAttenuation(35, ADC_11db); 80 | esp_adc_cal_characteristics_t *adc_chars = 81 | (esp_adc_cal_characteristics_t *)calloc( 82 | 1, sizeof(esp_adc_cal_characteristics_t)); 83 | esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 84 | 3600, adc_chars); 85 | uint16_t ADCValue = analogRead(35); 86 | 87 | uint32_t BatVolmV = esp_adc_cal_raw_to_voltage(ADCValue, adc_chars); 88 | float BatVol = float(BatVolmV) * 25.1 / 5.1 / 1000; 89 | free(adc_chars); 90 | return BatVol; 91 | } 92 | 93 | void drawScanWifi() { 94 | M5.M5Ink.clear(); 95 | TimePageSprite.clear(); 96 | } 97 | 98 | void drawWarning(const char *str) { 99 | M5.M5Ink.clear(); 100 | TimePageSprite.clear(CLEAR_DRAWBUFF | CLEAR_LASTBUFF); 101 | drawImageToSprite(76, 40, &warningImage, &TimePageSprite); 102 | TimePageSprite.drawString(30, 100, str, &fonts::AsciiFont8x16); 103 | TimePageSprite.pushSprite(); 104 | } 105 | 106 | void drawTimePage() { 107 | M5.rtc.GetTime(&RTCtime); 108 | drawTime(&RTCtime); 109 | minutes = RTCtime.Minutes; 110 | M5.rtc.GetDate(&RTCDate); 111 | drawDate(&RTCDate); 112 | TimePageSprite.pushSprite(); 113 | } 114 | 115 | void testPage() { 116 | M5.M5Ink.setEpdMode(epd_mode_t::epd_quality); 117 | uint8_t buttonMark = 0x00, buttonMarkSave = 0; 118 | WiFi.mode(WIFI_STA); 119 | WiFi.disconnect(); 120 | WiFi.scanNetworks(true); 121 | 122 | M5.M5Ink.clear(); 123 | TimePageSprite.clear(); 124 | TimePageSprite.drawString(10, 41, "wifi scanning...", 125 | &fonts::AsciiFont8x16); 126 | TimePageSprite.pushSprite(); 127 | TimePageSprite.clear(); 128 | M5.M5Ink.setEpdMode(epd_mode_t::epd_text); 129 | 130 | const char BtnUPStr[] = "Btn UP Pressed"; 131 | const char BtnDOWNStr[] = "Btn DOWN Pressed"; 132 | const char BtnMIDStr[] = "Btn MID Pressed"; 133 | const char BtnEXTStr[] = "Btn EXT Pressed"; 134 | const char BtnPWRStr[] = "Btn PWR Pressed"; 135 | 136 | const char *strPtrBuff[5] = {BtnUPStr, BtnDOWNStr, BtnMIDStr, BtnEXTStr, 137 | BtnPWRStr}; 138 | 139 | char timeStrbuff[64]; 140 | M5.rtc.GetTime(&RTCtime); 141 | M5.rtc.GetDate(&RTCDate); 142 | 143 | sprintf(timeStrbuff, "%d/%02d/%02d %02d:%02d:%02d", RTCDate.Year, 144 | RTCDate.Month, RTCDate.Date, RTCtime.Hours, RTCtime.Minutes, 145 | RTCtime.Seconds); 146 | 147 | TimePageSprite.drawString(10, 5, timeStrbuff); 148 | 149 | // char batteryStrBuff[64]; 150 | // sprintf(batteryStrBuff,"Battery:%.2fV",getBatVoltage()); 151 | // TimePageSprite.drawString(10,23,batteryStrBuff,&AsciiFont8x16); 152 | 153 | char wifiStrBuff[64]; 154 | 155 | Wire.begin(32, 33, 100000UL); 156 | int groveCheck = 0; 157 | 158 | Wire.beginTransmission(0x76); 159 | Wire.write(0xD0); 160 | if (Wire.endTransmission() != 0) { 161 | groveCheck = -1; 162 | } else { 163 | Wire.requestFrom(0x76, 1); 164 | uint8_t chipID = Wire.read(); 165 | Serial.printf("Read ID = %02X\r\n", chipID); 166 | if (chipID != 0x58) { 167 | groveCheck = -1; 168 | } 169 | } 170 | 171 | if (groveCheck != 0) { 172 | drawWarning("GROVE Check Error"); 173 | while (1) { 174 | delay(10); 175 | } 176 | } 177 | 178 | while (1) { 179 | int WifiRes = WiFi.scanComplete(); 180 | if (WifiRes == -2) { 181 | } else if (WifiRes == -1) { 182 | } else if (WifiRes == 0) { 183 | TimePageSprite.drawString(10, 41, "no networks found", 184 | &fonts::AsciiFont8x16); 185 | break; 186 | } else { 187 | String SSIDStr = WiFi.SSID(0); 188 | if (SSIDStr.length() > 11) { 189 | SSIDStr = SSIDStr.substring(0, 8); 190 | SSIDStr += "..."; 191 | } 192 | int32_t rssi = (WiFi.RSSI(0) < -100) ? -100 : WiFi.RSSI(0); 193 | sprintf(wifiStrBuff, "wifi %s r:%d", SSIDStr.c_str(), rssi); 194 | TimePageSprite.drawString(10, 41, wifiStrBuff, 195 | &fonts::AsciiFont8x16); 196 | break; 197 | } 198 | delay(100); 199 | } 200 | M5.M5Ink.clear(); 201 | TimePageSprite.pushSprite(); 202 | 203 | Wire1.begin(-1, -1); 204 | pinMode(21, OUTPUT); 205 | pinMode(22, OUTPUT); 206 | 207 | digitalWrite(21, HIGH); 208 | digitalWrite(22, HIGH); 209 | 210 | while (1) { 211 | if (buttonMark != buttonMarkSave) { 212 | uint8_t mark = buttonMarkSave ^ buttonMark; 213 | int index = 0; 214 | while (!((mark >> index) & 0x01)) index++; 215 | Serial.printf("index = %d\r\n", index); 216 | TimePageSprite.drawString(10, 59 + (index * 18), strPtrBuff[index], 217 | &fonts::AsciiFont8x16); 218 | TimePageSprite.pushSprite(); 219 | buttonMarkSave = buttonMark; 220 | // digitalWrite(21,(pinFlag)?HIGH:LOW); 221 | // digitalWrite(22,(pinFlag)?HIGH:LOW); 222 | // pinFlag = !pinFlag; 223 | } 224 | 225 | if (M5.BtnUP.wasPressed()) buttonMark |= 0x01; 226 | if (M5.BtnDOWN.wasPressed()) buttonMark |= 0x02; 227 | if (M5.BtnMID.wasPressed()) buttonMark |= 0x04; 228 | if (M5.BtnEXT.wasPressed()) buttonMark |= 0x08; 229 | if (M5.BtnPWR.wasPressed()) buttonMark |= 0x10; 230 | 231 | M5.update(); 232 | if (buttonMarkSave == 0x1f) { 233 | Wire1.begin(21, 22); 234 | break; 235 | } 236 | } 237 | 238 | uint8_t pinCheckMark = 0; 239 | 240 | uint8_t testWritPinMap[4] = {13, 18, 26, 23}; 241 | uint8_t testReadPinMap[4] = {14, 36, 34, 25}; 242 | 243 | SPI.end(); 244 | 245 | for (int i = 0; i < 4; i++) { 246 | pinMode(testWritPinMap[i], OUTPUT); 247 | pinMode(testReadPinMap[i], INPUT); 248 | 249 | digitalWrite(testWritPinMap[i], HIGH); 250 | delay(2); 251 | if (digitalRead(testReadPinMap[i]) == HIGH) { 252 | pinCheckMark |= (1 << i); 253 | } 254 | 255 | digitalWrite(testWritPinMap[i], LOW); 256 | delay(2); 257 | if (digitalRead(testReadPinMap[i]) == LOW) { 258 | pinCheckMark |= (1 << (i + 4)); 259 | } 260 | } 261 | Serial.printf("EXT Check Mark %02X\r\n", pinCheckMark); 262 | 263 | SPI.begin(INK_SPI_SCK, -1, INK_SPI_MOSI, -1); 264 | 265 | // ink_spi.begin(INK_SPI_SCK, -1, INK_SPI_MOSI, -1); 266 | 267 | char pinStrBuff[64]; 268 | if (pinCheckMark != 0xff) { 269 | sprintf(pinStrBuff, "EXT PIN check %02X Error", pinCheckMark); 270 | } else { 271 | sprintf(pinStrBuff, "EXT PIN check %02X Ok", pinCheckMark); 272 | } 273 | M5.Speaker.tone(2700); 274 | TimePageSprite.drawString(10, 149, pinStrBuff, &fonts::AsciiFont8x16); 275 | TimePageSprite.pushSprite(); 276 | M5.Speaker.mute(); 277 | 278 | if (pinCheckMark != 0xff) { 279 | while (1) { 280 | delay(100); 281 | } 282 | } 283 | while (1) { 284 | delay(10); 285 | M5.update(); 286 | if (M5.BtnDOWN.wasPressed() || M5.BtnUP.wasPressed()) break; 287 | } 288 | 289 | M5.Speaker.tone(2700); 290 | delay(100); 291 | M5.Speaker.mute(); 292 | 293 | for (int i = 0; i < 4; i++) { 294 | testWritPinMap[i] = (i % 2 == 0) ? 26 : 25; 295 | testReadPinMap[i] = 36; 296 | } 297 | pinCheckMark = 0; 298 | for (int i = 0; i < 4; i++) { 299 | pinMode(testWritPinMap[i], OUTPUT); 300 | pinMode(testReadPinMap[i], INPUT); 301 | 302 | digitalWrite(testWritPinMap[i], HIGH); 303 | delay(2); 304 | if (digitalRead(testReadPinMap[i]) == HIGH) { 305 | pinCheckMark |= (1 << i); 306 | } 307 | 308 | digitalWrite(testWritPinMap[i], LOW); 309 | delay(2); 310 | if (digitalRead(testReadPinMap[i]) == LOW) { 311 | pinCheckMark |= (1 << (i + 4)); 312 | } 313 | } 314 | Serial.printf("HAT Check Mark %02X\r\n", pinCheckMark); 315 | 316 | if (pinCheckMark != 0xff) { 317 | sprintf(pinStrBuff, "HAT PIN check %02X Error", pinCheckMark); 318 | } else { 319 | sprintf(pinStrBuff, "HAT PIN check %02X Ok", pinCheckMark); 320 | } 321 | 322 | TimePageSprite.drawString(10, 167, pinStrBuff, &fonts::AsciiFont8x16); 323 | TimePageSprite.pushSprite(); 324 | 325 | if (pinCheckMark != 0xff) { 326 | while (1) { 327 | delay(100); 328 | } 329 | } 330 | 331 | M5.M5Ink.clear(); 332 | TimePageSprite.clear(CLEAR_DRAWBUFF | CLEAR_LASTBUFF); 333 | } 334 | 335 | void WifiScanPage() { 336 | M5.M5Ink.setEpdMode(epd_mode_t::epd_quality); 337 | WiFi.mode(WIFI_STA); 338 | WiFi.disconnect(); 339 | WiFi.scanNetworks(true); 340 | M5.M5Ink.clear(); 341 | TimePageSprite.clear(CLEAR_DRAWBUFF | CLEAR_LASTBUFF); 342 | drawImageToSprite(0, 0, &wifiScanImage, &TimePageSprite); 343 | TimePageSprite.pushSprite(); 344 | 345 | char wifiStrBuff[64]; 346 | int flushCount = 1000; 347 | bool wifiReadyFlag = false; 348 | M5.M5Ink.setEpdMode(epd_mode_t::epd_text); 349 | while (1) { 350 | int WifiRes = WiFi.scanComplete(); 351 | if (WifiRes == -2) { 352 | } else if (WifiRes == -1) { 353 | } else if (WifiRes == 0) { 354 | TimePageSprite.drawString(10, 41, "no networks found", 355 | &fonts::AsciiFont8x16); 356 | break; 357 | } else { 358 | TimePageSprite.clear(); 359 | drawImageToSprite(0, 0, &wifiScanImage, &TimePageSprite); 360 | WifiRes = (WifiRes > 8) ? 8 : WifiRes; 361 | for (int i = 0; i < WifiRes; i++) { 362 | String SSIDStr = WiFi.SSID(i); 363 | if (SSIDStr.length() > 11) { 364 | SSIDStr = SSIDStr.substring(0, 8); 365 | SSIDStr += "..."; 366 | } 367 | int32_t rssi = (WiFi.RSSI(i) < -100) ? -100 : WiFi.RSSI(i); 368 | sprintf(wifiStrBuff, "SSID:%s", SSIDStr.c_str()); 369 | TimePageSprite.drawString(10, 50 + i * 18, wifiStrBuff, 370 | &fonts::AsciiFont8x16); 371 | 372 | sprintf(wifiStrBuff, "%02ddb", rssi); 373 | TimePageSprite.drawString(150, 50 + i * 18, wifiStrBuff, 374 | &fonts::AsciiFont8x16); 375 | } 376 | wifiReadyFlag = true; 377 | WiFi.scanDelete(); 378 | WiFi.scanNetworks(true); 379 | } 380 | delay(10); 381 | if ((flushCount > 1000) && (wifiReadyFlag == true)) { 382 | TimePageSprite.pushSprite(); 383 | 384 | flushCount = 0; 385 | } 386 | flushCount++; 387 | M5.update(); 388 | if (M5.BtnPWR.wasPressed()) { 389 | digitalWrite(LED_EXT_PIN, LOW); 390 | M5.shutdown(); 391 | } 392 | if (M5.BtnDOWN.wasPressed() || M5.BtnUP.wasPressed()) break; 393 | } 394 | M5.M5Ink.clear(); 395 | TimePageSprite.clear(CLEAR_DRAWBUFF | CLEAR_LASTBUFF); 396 | } 397 | 398 | void flushTimePage() { 399 | M5.M5Ink.setEpdMode(epd_mode_t::epd_quality); 400 | M5.M5Ink.clear(); 401 | TimePageSprite.clear(CLEAR_DRAWBUFF | CLEAR_LASTBUFF); 402 | drawTimePage(); 403 | M5.M5Ink.setEpdMode(epd_mode_t::epd_text); 404 | while (1) { 405 | M5.rtc.GetTime(&RTCtime); 406 | if (minutes != RTCtime.Minutes) { 407 | M5.rtc.GetTime(&RTCtime); 408 | M5.rtc.GetDate(&RTCDate); 409 | 410 | if (RTCtime.Minutes % 10 == 0) { 411 | M5.M5Ink.clear(); 412 | TimePageSprite.clear(CLEAR_DRAWBUFF | CLEAR_LASTBUFF); 413 | } 414 | drawTime(&RTCtime); 415 | drawDate(&RTCDate); 416 | TimePageSprite.pushSprite(); 417 | minutes = RTCtime.Minutes; 418 | } 419 | 420 | delay(10); 421 | M5.update(); 422 | if (M5.BtnPWR.wasPressed()) { 423 | digitalWrite(LED_EXT_PIN, LOW); 424 | M5.shutdown(); 425 | } 426 | if (M5.BtnDOWN.wasPressed() || M5.BtnUP.wasPressed()) break; 427 | } 428 | M5.M5Ink.clear(); 429 | TimePageSprite.clear(CLEAR_DRAWBUFF | CLEAR_LASTBUFF); 430 | } 431 | 432 | void checkBatteryVoltage(bool powerDownFlag) { 433 | float batVol = getBatVoltage(); 434 | Serial.printf("Bat Voltage %.2f\r\n", batVol); 435 | 436 | if (batVol > 3.2) return; 437 | 438 | drawWarning("Battery voltage is low"); 439 | if (powerDownFlag == true) { 440 | M5.shutdown(); 441 | } 442 | while (1) { 443 | batVol = getBatVoltage(); 444 | if (batVol > 3.2) return; 445 | } 446 | } 447 | 448 | void checkRTC() { 449 | M5.rtc.GetTime(&RTCtime); 450 | if (RTCtime.Seconds == RTCTimeSave.Seconds) { 451 | drawWarning("RTC Error"); 452 | while (1) { 453 | if (M5.BtnMID.wasPressed()) return; 454 | delay(10); 455 | M5.update(); 456 | } 457 | } 458 | } 459 | 460 | void setup() { 461 | M5.begin(); 462 | 463 | digitalWrite(LED_EXT_PIN, LOW); 464 | 465 | Serial.println(__TIME__); 466 | 467 | M5.rtc.GetTime(&RTCTimeSave); 468 | M5.update(); 469 | if (M5.BtnMID.isPressed()) { 470 | M5.Speaker.tone(2700, 200); 471 | delay(100); 472 | testMode = true; 473 | M5.Speaker.mute(); 474 | } 475 | 476 | M5.M5Ink.clear(); 477 | M5.M5Ink.drawBuff((uint8_t *)image_CoreInkWWellcome); 478 | delay(500); 479 | 480 | checkRTC(); 481 | checkBatteryVoltage(false); 482 | 483 | TimePageSprite.creatSprite(0, 0, 200, 200); 484 | // TimePageSprite.clear( CLEAR_DRAWBUFF | CLEAR_LASTBUFF ); 485 | 486 | // timer_wakeup_test(); 487 | 488 | if (testMode) { 489 | testPage(); 490 | timer_wakeup_test(); 491 | } 492 | drawTimePage(); 493 | M5.Speaker.tone(2700, 200); 494 | delay(200); 495 | M5.Speaker.mute(); 496 | } 497 | 498 | void loop() { 499 | flushTimePage(); 500 | WifiScanPage(); 501 | 502 | /* 503 | if( M5.BtnUP.wasPressed()) 504 | { 505 | 506 | } 507 | if( M5.BtnDOWN.wasPressed()) 508 | { 509 | 510 | } 511 | if( M5.BtnMID.wasPressed()) 512 | { 513 | 514 | */ 515 | if (M5.BtnPWR.wasPressed()) { 516 | Serial.printf("Btn %d was pressed \r\n", BUTTON_EXT_PIN); 517 | digitalWrite(LED_EXT_PIN, LOW); 518 | M5.shutdown(); 519 | } 520 | M5.update(); 521 | } -------------------------------------------------------------------------------- /examples/Basics/FactoryTest/Num_55x40.cpp: -------------------------------------------------------------------------------- 1 | #include "icon.h" 2 | unsigned char image_num_01[275] = { 3 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, 4 | 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 5 | 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 6 | 0x01, 0xff, 0xc0, 0x7f, 0xff, 0x01, 0x00, 0x40, 0x7f, 0xff, 0x01, 0xff, 7 | 0x40, 0x7f, 0xf0, 0x01, 0xff, 0x40, 0x07, 0xf0, 0x3f, 0xff, 0x7e, 0x07, 8 | 0xd0, 0x3f, 0xff, 0x02, 0x07, 0xd0, 0x3f, 0xff, 0xfe, 0x07, 0xd0, 0x3f, 9 | 0xff, 0xc0, 0x07, 0xd0, 0x3f, 0xff, 0xc0, 0x07, 0xd0, 0x3f, 0xff, 0xc0, 10 | 0x07, 0xd0, 0x3f, 0xff, 0xc0, 0x07, 0xd0, 0x3f, 0xff, 0xc0, 0x07, 0xd0, 11 | 0x3f, 0xfc, 0x00, 0x07, 0xd0, 0x3f, 0xfc, 0x0e, 0x07, 0xd0, 0x3f, 0xfc, 12 | 0x0a, 0x07, 0xd0, 0x3f, 0xfc, 0x0a, 0x07, 0xd0, 0x3f, 0x80, 0x0a, 0x07, 13 | 0xd0, 0x3f, 0x80, 0xfa, 0x07, 0xd0, 0x3f, 0x80, 0xfa, 0x07, 0xd0, 0x3f, 14 | 0x80, 0xfa, 0x07, 0xd0, 0x3f, 0x80, 0xfa, 0x07, 0xd0, 0x38, 0x00, 0xfa, 15 | 0x07, 0xd0, 0x38, 0x1f, 0xfa, 0x07, 0xd0, 0x38, 0x1f, 0xfa, 0x07, 0xd0, 16 | 0x38, 0x1f, 0xfa, 0x07, 0xd0, 0x00, 0x1f, 0xfa, 0x07, 0xd0, 0x01, 0xff, 17 | 0xfa, 0x07, 0xd0, 0x01, 0xff, 0xfa, 0x07, 0xd0, 0x01, 0xff, 0xfa, 0x07, 18 | 0xd0, 0x01, 0xff, 0xfa, 0x07, 0xd0, 0x01, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 19 | 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfe, 20 | 0x07, 0xd0, 0x01, 0xff, 0xc0, 0x07, 0xdf, 0x01, 0xff, 0xc0, 0x7f, 0xc1, 21 | 0x01, 0xff, 0xc0, 0x7f, 0xfd, 0x01, 0xff, 0xc0, 0x7f, 0xfd, 0x01, 0xff, 22 | 0xc0, 0x7f, 0xfd, 0x00, 0x00, 0x00, 0x7f, 0xfd, 0xf8, 0x00, 0x0f, 0xff, 23 | 0xfc, 0x08, 0x00, 0x0f, 0xff, 0xff, 0xe8, 0x00, 0x0f, 0xff, 0xff, 0xe8, 24 | 0x00, 0x0f, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 25 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 26 | }; 27 | unsigned char image_num_02[275] = { 28 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xc0, 29 | 0x00, 0x7f, 0xff, 0xff, 0x40, 0x00, 0x7f, 0xff, 0xff, 0x40, 0x00, 0x7f, 30 | 0xff, 0xff, 0x40, 0x00, 0x7f, 0xff, 0xff, 0x40, 0x00, 0x7f, 0xff, 0xff, 31 | 0x7f, 0xe0, 0x7f, 0xff, 0xff, 0x00, 0x20, 0x7f, 0xff, 0xff, 0xff, 0xa0, 32 | 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 33 | 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 34 | 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 35 | 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 36 | 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 37 | 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 38 | 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 39 | 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 40 | 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 41 | 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 42 | 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 43 | 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 44 | 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 45 | 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 46 | 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 47 | 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 48 | 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xa0, 0x7f, 0xff, 0xff, 0xff, 49 | 0xa0, 0x7f, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 50 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 51 | }; 52 | unsigned char image_num_03[275] = { 53 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, 54 | 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 55 | 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 56 | 0x01, 0xff, 0xc0, 0x7f, 0xff, 0x01, 0x00, 0x40, 0x7f, 0xff, 0x01, 0xff, 57 | 0x40, 0x7f, 0xf0, 0x01, 0xff, 0x40, 0x07, 0xf0, 0x3f, 0xff, 0x7e, 0x07, 58 | 0xd0, 0x3f, 0xff, 0x02, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 59 | 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xdf, 0xff, 0xff, 0xfa, 60 | 0x07, 0xc0, 0xff, 0xff, 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 61 | 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0xff, 62 | 0xc0, 0x7f, 0xff, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0xfc, 0x00, 0x7f, 63 | 0xff, 0xff, 0xfc, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x0f, 0xff, 0xff, 0xff, 64 | 0xfc, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x0f, 0xff, 0xff, 0xff, 0x80, 0x0f, 65 | 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 66 | 0xff, 0x80, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xf8, 0x1f, 67 | 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 68 | 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x01, 69 | 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 70 | 0xff, 0xf0, 0x01, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xd0, 71 | 0x3f, 0xff, 0xff, 0xff, 0xd0, 0x3f, 0xff, 0xff, 0xff, 0xd0, 0x3f, 0xff, 72 | 0xff, 0xff, 0xd0, 0x00, 0x00, 0x00, 0x07, 0xd0, 0x00, 0x00, 0x00, 0x07, 73 | 0xd0, 0x00, 0x00, 0x00, 0x07, 0xd0, 0x00, 0x00, 0x00, 0x07, 0xd0, 0x00, 74 | 0x00, 0x00, 0x07, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 75 | 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 76 | }; 77 | unsigned char image_num_04[275] = { 78 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xfc, 79 | 0x00, 0x07, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xfc, 0x00, 0x07, 80 | 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f, 0xff, 81 | 0x80, 0xff, 0xe0, 0x3f, 0xff, 0x80, 0x80, 0x20, 0x3f, 0xff, 0x80, 0xff, 82 | 0xa0, 0x3f, 0xf8, 0x00, 0xff, 0xa0, 0x03, 0xf8, 0x1f, 0xff, 0xbf, 0x03, 83 | 0xe8, 0x1f, 0xff, 0x81, 0x03, 0xe8, 0x1f, 0xff, 0xfd, 0x03, 0xe8, 0x1f, 84 | 0xff, 0xfd, 0x03, 0xe8, 0x1f, 0xff, 0xfd, 0x03, 0xef, 0xff, 0xff, 0xfd, 85 | 0x03, 0xe0, 0x7f, 0xff, 0xfd, 0x03, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 86 | 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 87 | 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xfc, 0x00, 0x00, 0x3f, 88 | 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xf4, 0x00, 0x07, 0xff, 0xff, 0xf4, 89 | 0x00, 0x07, 0xff, 0xff, 0xf4, 0x00, 0x07, 0xff, 0xff, 0xf4, 0x00, 0x00, 90 | 0x3f, 0xff, 0xf7, 0xff, 0xe0, 0x3f, 0xff, 0xf0, 0x00, 0x20, 0x3f, 0xff, 91 | 0xff, 0xff, 0xa0, 0x3f, 0xff, 0xff, 0xff, 0xa0, 0x03, 0xff, 0xff, 0xff, 92 | 0xbf, 0x03, 0xff, 0xff, 0xff, 0x81, 0x03, 0xff, 0xff, 0xff, 0xfd, 0x03, 93 | 0xff, 0xff, 0xff, 0xfd, 0x03, 0xf8, 0x1f, 0xff, 0xfd, 0x03, 0xf8, 0x1f, 94 | 0xff, 0xfd, 0x03, 0xe8, 0x1f, 0xff, 0xfd, 0x03, 0xe8, 0x1f, 0xff, 0xff, 95 | 0x03, 0xe8, 0x00, 0xff, 0xe0, 0x03, 0xef, 0x80, 0xff, 0xe0, 0x3f, 0xe0, 96 | 0x80, 0xff, 0xe0, 0x3f, 0xfe, 0x80, 0xff, 0xe0, 0x3f, 0xfe, 0x80, 0xff, 97 | 0xe0, 0x3f, 0xfe, 0x80, 0x00, 0x00, 0x3f, 0xfe, 0xfc, 0x00, 0x07, 0xff, 98 | 0xfe, 0x04, 0x00, 0x07, 0xff, 0xff, 0xf4, 0x00, 0x07, 0xff, 0xff, 0xf4, 99 | 0x00, 0x07, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x1f, 100 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 101 | }; 102 | unsigned char image_num_05[275] = { 103 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 104 | 0xfe, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x07, 105 | 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 106 | 0xff, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xf0, 107 | 0x07, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 108 | 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xfc, 109 | 0x00, 0x07, 0xff, 0xff, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xfc, 0x0e, 0x07, 110 | 0xff, 0xff, 0xfc, 0x0a, 0x07, 0xff, 0xff, 0xe0, 0x0a, 0x07, 0xff, 0xff, 111 | 0xe0, 0x0a, 0x07, 0xff, 0xff, 0xe0, 0x7a, 0x07, 0xff, 0xff, 0xe0, 0x7a, 112 | 0x07, 0xff, 0xff, 0x00, 0x7a, 0x07, 0xff, 0xff, 0x00, 0x7a, 0x07, 0xff, 113 | 0xff, 0x03, 0xfa, 0x07, 0xff, 0xff, 0x03, 0xfa, 0x07, 0xff, 0xe8, 0x03, 114 | 0xfa, 0x07, 0xff, 0xe8, 0x03, 0xfa, 0x07, 0xff, 0xe8, 0x1f, 0xfa, 0x07, 115 | 0xff, 0xe8, 0x1f, 0xfe, 0x07, 0xff, 0xe8, 0x00, 0x00, 0x00, 0x07, 0xe8, 116 | 0x00, 0x00, 0x00, 0x07, 0xe8, 0x00, 0x00, 0x00, 0x07, 0xe8, 0x00, 0x00, 117 | 0x00, 0x07, 0xe8, 0x00, 0x00, 0x00, 0x07, 0xe8, 0x00, 0x00, 0x00, 0x07, 118 | 0xef, 0xff, 0xfe, 0x07, 0xff, 0xe0, 0x00, 0x02, 0x04, 0x1f, 0xff, 0xff, 119 | 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfa, 0x07, 120 | 0xff, 0xff, 0xff, 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfa, 0x07, 0xff, 0xff, 121 | 0xff, 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfa, 122 | 0x07, 0xff, 0xff, 0xff, 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfa, 0x07, 0xff, 123 | 0xff, 0xff, 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfa, 0x07, 0xff, 0xff, 0xff, 124 | 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 125 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 126 | }; 127 | unsigned char image_num_06[275] = { 128 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x00, 129 | 0x00, 0x00, 0x07, 0xd0, 0x00, 0x00, 0x00, 0x07, 0xd0, 0x00, 0x00, 0x00, 130 | 0x07, 0xd0, 0x00, 0x00, 0x00, 0x07, 0xd0, 0x00, 0x00, 0x00, 0x07, 0xd0, 131 | 0x3f, 0xff, 0xff, 0xff, 0xd0, 0x20, 0x00, 0x00, 0x1f, 0xd0, 0x3f, 0xff, 132 | 0xff, 0xff, 0xd0, 0x3f, 0xff, 0xff, 0xff, 0xd0, 0x3f, 0xff, 0xff, 0xff, 133 | 0xd0, 0x3f, 0xff, 0xff, 0xff, 0xd0, 0x3f, 0xff, 0xff, 0xff, 0xd0, 0x3f, 134 | 0xff, 0xff, 0xff, 0xd0, 0x3f, 0xff, 0xff, 0xff, 0xd0, 0x3f, 0xff, 0xff, 135 | 0xff, 0xd0, 0x3f, 0xff, 0xff, 0xff, 0xd0, 0x3f, 0xff, 0xff, 0xff, 0xd0, 136 | 0x00, 0x00, 0x0f, 0xff, 0xd0, 0x00, 0x00, 0x0f, 0xff, 0xd0, 0x00, 0x00, 137 | 0x0f, 0xff, 0xd0, 0x00, 0x00, 0x0f, 0xff, 0xd0, 0x00, 0x00, 0x00, 0x7f, 138 | 0xdf, 0xff, 0xff, 0xc0, 0x7f, 0xc0, 0x00, 0x00, 0x40, 0x7f, 0xff, 0xff, 139 | 0xff, 0x40, 0x7f, 0xff, 0xff, 0xff, 0x40, 0x7f, 0xff, 0xff, 0xff, 0x40, 140 | 0x07, 0xff, 0xff, 0xff, 0x7e, 0x07, 0xff, 0xff, 0xff, 0x02, 0x07, 0xff, 141 | 0xff, 0xff, 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfa, 0x07, 0xff, 0xff, 0xff, 142 | 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfa, 0x07, 143 | 0xff, 0xff, 0xff, 0xfa, 0x07, 0xf0, 0x3f, 0xff, 0xfa, 0x07, 0xf0, 0x3f, 144 | 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfe, 145 | 0x07, 0xd0, 0x01, 0xff, 0xc0, 0x07, 0xdf, 0x01, 0xff, 0xc0, 0x7f, 0xc1, 146 | 0x01, 0xff, 0xc0, 0x7f, 0xfd, 0x01, 0xff, 0xc0, 0x7f, 0xfd, 0x01, 0xff, 147 | 0xc0, 0x7f, 0xfd, 0x00, 0x00, 0x00, 0x7f, 0xfd, 0xf8, 0x00, 0x0f, 0xff, 148 | 0xfc, 0x08, 0x00, 0x0f, 0xff, 0xff, 0xe8, 0x00, 0x0f, 0xff, 0xff, 0xe8, 149 | 0x00, 0x0f, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 150 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 151 | }; 152 | unsigned char image_num_07[275] = { 153 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, 154 | 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 155 | 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 156 | 0x01, 0xff, 0xc0, 0x7f, 0xff, 0x01, 0x00, 0x40, 0x7f, 0xff, 0x01, 0xff, 157 | 0x40, 0x7f, 0xf0, 0x01, 0xff, 0x40, 0x07, 0xf0, 0x3f, 0xff, 0x7e, 0x07, 158 | 0xd0, 0x3f, 0xff, 0x02, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 159 | 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfb, 160 | 0xff, 0xd0, 0x3f, 0xff, 0xf8, 0x1f, 0xd0, 0x3f, 0xff, 0xff, 0xff, 0xd0, 161 | 0x38, 0x00, 0x0f, 0xff, 0xd0, 0x38, 0x00, 0x0f, 0xff, 0xd0, 0x38, 0x00, 162 | 0x0f, 0xff, 0xd0, 0x38, 0x00, 0x0f, 0xff, 0xd0, 0x00, 0x00, 0x00, 0x7f, 163 | 0xd0, 0x01, 0xff, 0xc0, 0x7f, 0xd0, 0x01, 0x00, 0x40, 0x7f, 0xd0, 0x01, 164 | 0xff, 0x40, 0x7f, 0xd0, 0x01, 0xff, 0x40, 0x7f, 0xd0, 0x01, 0xff, 0x40, 165 | 0x07, 0xd0, 0x3f, 0xff, 0x7e, 0x07, 0xd0, 0x3f, 0xff, 0x02, 0x07, 0xd0, 166 | 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 167 | 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 168 | 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 169 | 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfe, 170 | 0x07, 0xd0, 0x01, 0xff, 0xc0, 0x07, 0xdf, 0x01, 0xff, 0xc0, 0x7f, 0xc1, 171 | 0x01, 0xff, 0xc0, 0x7f, 0xfd, 0x01, 0xff, 0xc0, 0x7f, 0xfd, 0x01, 0xff, 172 | 0xc0, 0x7f, 0xfd, 0x00, 0x00, 0x00, 0x7f, 0xfd, 0xf8, 0x00, 0x0f, 0xff, 173 | 0xfc, 0x08, 0x00, 0x0f, 0xff, 0xff, 0xe8, 0x00, 0x0f, 0xff, 0xff, 0xe8, 174 | 0x00, 0x0f, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 175 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 176 | }; 177 | unsigned char image_num_08[275] = { 178 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x00, 179 | 0x00, 0x00, 0x07, 0xd0, 0x00, 0x00, 0x00, 0x07, 0xd0, 0x00, 0x00, 0x00, 180 | 0x07, 0xd0, 0x00, 0x00, 0x00, 0x07, 0xd0, 0x00, 0x00, 0x00, 0x07, 0xdf, 181 | 0xff, 0xff, 0xfe, 0x07, 0xc0, 0x00, 0x00, 0x02, 0x07, 0xff, 0xff, 0xff, 182 | 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfa, 0x07, 183 | 0xff, 0xff, 0xff, 0xfa, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 184 | 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0x40, 185 | 0x7f, 0xff, 0xff, 0xff, 0x40, 0x7f, 0xff, 0xff, 0xff, 0x40, 0x7f, 0xff, 186 | 0xff, 0xff, 0x40, 0x7f, 0xff, 0xff, 0xff, 0x40, 0x7f, 0xff, 0xff, 0xff, 187 | 0x40, 0x7f, 0xff, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0xfc, 0x00, 0x7f, 188 | 0xff, 0xff, 0xfc, 0x0f, 0xff, 0xff, 0xff, 0xf4, 0x0f, 0xff, 0xff, 0xff, 189 | 0xf4, 0x0f, 0xff, 0xff, 0xff, 0xf4, 0x0f, 0xff, 0xff, 0xff, 0xf4, 0x0f, 190 | 0xff, 0xff, 0xff, 0xf4, 0x0f, 0xff, 0xff, 0xff, 0xf4, 0x0f, 0xff, 0xff, 191 | 0xff, 0xfc, 0x0f, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0x80, 192 | 0xff, 0xff, 0xff, 0xfe, 0x80, 0xff, 0xff, 0xff, 0xfe, 0x80, 0xff, 0xff, 193 | 0xff, 0xfe, 0x80, 0xff, 0xff, 0xff, 0xfe, 0x80, 0xff, 0xff, 0xff, 0xfe, 194 | 0x80, 0xff, 0xff, 0xff, 0xfe, 0x80, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 195 | 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 196 | 0xe8, 0x1f, 0xff, 0xff, 0xff, 0xe8, 0x1f, 0xff, 0xff, 0xff, 0xe8, 0x1f, 197 | 0xff, 0xff, 0xff, 0xe8, 0x1f, 0xff, 0xff, 0xff, 0xe8, 0x1f, 0xff, 0xff, 198 | 0xff, 0xe8, 0x1f, 0xff, 0xff, 0xff, 0xe8, 0x1f, 0xff, 0xff, 0xff, 0xe8, 199 | 0x1f, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, 200 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 201 | }; 202 | unsigned char image_num_09[275] = { 203 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, 204 | 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 205 | 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 206 | 0x01, 0xff, 0xc0, 0x7f, 0xff, 0x01, 0x00, 0x40, 0x7f, 0xff, 0x01, 0xff, 207 | 0x40, 0x7f, 0xf0, 0x01, 0xff, 0x40, 0x07, 0xf0, 0x3f, 0xff, 0x7e, 0x07, 208 | 0xd0, 0x3f, 0xff, 0x02, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 209 | 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 210 | 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfe, 0x07, 0xd0, 211 | 0x01, 0xff, 0xc0, 0x07, 0xdf, 0x01, 0xff, 0xc0, 0x7f, 0xc1, 0x01, 0xff, 212 | 0xc0, 0x7f, 0xfd, 0x01, 0xff, 0xc0, 0x7f, 0xfd, 0x00, 0x00, 0x00, 0x7f, 213 | 0xfd, 0xf8, 0x00, 0x0f, 0xff, 0xfc, 0x08, 0x00, 0x0f, 0xff, 0xff, 0xe8, 214 | 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 215 | 0x7f, 0xff, 0x01, 0xff, 0xc0, 0x7f, 0xff, 0x01, 0x00, 0x40, 0x7f, 0xff, 216 | 0x01, 0xff, 0x40, 0x7f, 0xf0, 0x01, 0xff, 0x40, 0x07, 0xf0, 0x3f, 0xff, 217 | 0x7e, 0x07, 0xd0, 0x3f, 0xff, 0x02, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 218 | 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 219 | 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfe, 220 | 0x07, 0xd0, 0x01, 0xff, 0xc0, 0x07, 0xdf, 0x01, 0xff, 0xc0, 0x7f, 0xc1, 221 | 0x01, 0xff, 0xc0, 0x7f, 0xfd, 0x01, 0xff, 0xc0, 0x7f, 0xfd, 0x01, 0xff, 222 | 0xc0, 0x7f, 0xfd, 0x00, 0x00, 0x00, 0x7f, 0xfd, 0xf8, 0x00, 0x0f, 0xff, 223 | 0xfc, 0x08, 0x00, 0x0f, 0xff, 0xff, 0xe8, 0x00, 0x0f, 0xff, 0xff, 0xe8, 224 | 0x00, 0x0f, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 225 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 226 | }; 227 | unsigned char image_num_10[275] = { 228 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, 229 | 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 230 | 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 231 | 0x01, 0xff, 0xc0, 0x7f, 0xff, 0x01, 0x00, 0x40, 0x7f, 0xff, 0x01, 0xff, 232 | 0x40, 0x7f, 0xf0, 0x01, 0xff, 0x40, 0x07, 0xf0, 0x3f, 0xff, 0x7e, 0x07, 233 | 0xd0, 0x3f, 0xff, 0x02, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 234 | 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 235 | 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 236 | 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 237 | 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfe, 0x07, 0xd0, 0x01, 0xff, 0xc0, 0x07, 238 | 0xdf, 0x01, 0xff, 0xc0, 0x07, 0xc1, 0x01, 0xff, 0xc0, 0x07, 0xfd, 0x01, 239 | 0xff, 0xc0, 0x07, 0xfd, 0x01, 0xff, 0xc0, 0x07, 0xfd, 0x00, 0x00, 0x00, 240 | 0x07, 0xfd, 0xf8, 0x00, 0x0e, 0x07, 0xfc, 0x08, 0x00, 0x0a, 0x07, 0xff, 241 | 0xe8, 0x00, 0x0a, 0x07, 0xff, 0xe8, 0x00, 0x0a, 0x07, 0xff, 0xef, 0xff, 242 | 0xfa, 0x07, 0xff, 0xe0, 0x00, 0x3a, 0x07, 0xff, 0xff, 0xff, 0xfa, 0x07, 243 | 0xff, 0xff, 0xff, 0xfa, 0x07, 0xf0, 0x3f, 0xff, 0xfa, 0x07, 0xf0, 0x3f, 244 | 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfa, 0x07, 0xd0, 0x3f, 0xff, 0xfe, 245 | 0x07, 0xd0, 0x01, 0xff, 0xc0, 0x07, 0xdf, 0x01, 0xff, 0xc0, 0x7f, 0xc1, 246 | 0x01, 0xff, 0xc0, 0x7f, 0xfd, 0x01, 0xff, 0xc0, 0x7f, 0xfd, 0x01, 0xff, 247 | 0xc0, 0x7f, 0xfd, 0x00, 0x00, 0x00, 0x7f, 0xfd, 0xf8, 0x00, 0x0f, 0xff, 248 | 0xfc, 0x08, 0x00, 0x0f, 0xff, 0xff, 0xe8, 0x00, 0x0f, 0xff, 0xff, 0xe8, 249 | 0x00, 0x0f, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 250 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 251 | }; 252 | unsigned char image_num_11[165] = { 253 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 254 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 255 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xfe, 0x07, 0xff, 256 | 0xfa, 0x07, 0xff, 0xfa, 0x07, 0xff, 0xfa, 0x07, 0xff, 0xfa, 0x07, 0xff, 257 | 0xfb, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 258 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 259 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 260 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 261 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 262 | 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xfe, 0x07, 0xff, 0xfa, 0x07, 0xff, 263 | 0xfa, 0x07, 0xff, 0xfa, 0x07, 0xff, 0xfb, 0xff, 0xff, 0xf8, 0x1f, 0xff, 264 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 265 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 266 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 267 | }; 268 | -------------------------------------------------------------------------------- /.github/actions/arduino-test-compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # arduino-test-compile.sh 4 | # Bash script to do a test-compile of one or more Arduino programs in a repository each with different compile parameters. 5 | # 6 | # Copyright (C) 2020-2022 Armin Joachimsmeyer 7 | # https://github.com/ArminJo/Github-Actions 8 | # License: MIT 9 | # 10 | 11 | # Input parameter, which is normally not used for Githup actions 12 | CLI_VERSION="$1" 13 | SKETCH_NAMES="$2" 14 | SKETCH_NAMES_FIND_START="$3" 15 | ARDUINO_BOARD_FQBN="$4" 16 | ARDUINO_PLATFORM="$5" 17 | PLATFORM_DEFAULT_URL="$6" 18 | PLATFORM_URL="$7" 19 | REQUIRED_LIBRARIES="$8" 20 | SKETCHES_EXCLUDE="$9" 21 | EXAMPLES_EXCLUDE="${10}" 22 | BUILD_PROPERTIES="${11}" 23 | EXAMPLES_BUILD_PROPERTIES="${12}" 24 | EXTRA_ARDUINO_CLI_ARGS="${13}" 25 | EXTRA_ARDUINO_LIB_INSTALL_ARGS="${14}" 26 | SET_BUILD_PATH="${15}" 27 | DEBUG_COMPILE="${16}" 28 | DEBUG_INSTALL="${17}" 29 | 30 | readonly RED='\033[0;31m' 31 | readonly GREEN='\033[0;32m' 32 | readonly YELLOW='\033[1;33m' 33 | readonly BLUE='\033[0;34m' 34 | 35 | # 36 | # Get env parameter from action run with higher priority, which enables the script to run directly in a step 37 | # 38 | if [[ -n $ENV_CLI_VERSION ]]; then CLI_VERSION=$ENV_CLI_VERSION; fi 39 | if [[ -n $ENV_SKETCH_NAMES ]]; then SKETCH_NAMES=$ENV_SKETCH_NAMES; fi 40 | if [[ -n $ENV_SKETCH_NAMES_FIND_START ]]; then SKETCH_NAMES_FIND_START=$ENV_SKETCH_NAMES_FIND_START; fi 41 | if [[ -n $ENV_ARDUINO_BOARD_FQBN ]]; then ARDUINO_BOARD_FQBN=$ENV_ARDUINO_BOARD_FQBN; fi 42 | if [[ -n $ENV_ARDUINO_PLATFORM ]]; then ARDUINO_PLATFORM=$ENV_ARDUINO_PLATFORM; fi 43 | if [[ -n $ENV_PLATFORM_DEFAULT_URL ]]; then PLATFORM_DEFAULT_URL=$ENV_PLATFORM_DEFAULT_URL; fi 44 | if [[ -n $ENV_PLATFORM_URL ]]; then PLATFORM_URL=$ENV_PLATFORM_URL; fi 45 | if [[ -n $ENV_REQUIRED_LIBRARIES ]]; then REQUIRED_LIBRARIES=$ENV_REQUIRED_LIBRARIES; fi 46 | if [[ -n $ENV_SKETCHES_EXCLUDE ]]; then SKETCHES_EXCLUDE=$ENV_SKETCHES_EXCLUDE; fi 47 | if [[ -n $ENV_EXAMPLES_EXCLUDE ]]; then EXAMPLES_EXCLUDE=$ENV_EXAMPLES_EXCLUDE; fi #deprecated 48 | if [[ -n $ENV_BUILD_PROPERTIES ]]; then BUILD_PROPERTIES=$ENV_BUILD_PROPERTIES; fi 49 | if [[ -n $ENV_EXAMPLES_BUILD_PROPERTIES ]]; then EXAMPLES_BUILD_PROPERTIES=$ENV_EXAMPLES_BUILD_PROPERTIES; fi #deprecated 50 | if [[ -n $ENV_EXTRA_ARDUINO_CLI_ARGS ]]; then EXTRA_ARDUINO_CLI_ARGS=$ENV_EXTRA_ARDUINO_CLI_ARGS; fi 51 | if [[ -n $ENV_EXTRA_ARDUINO_LIB_INSTALL_ARGS ]]; then EXTRA_ARDUINO_LIB_INSTALL_ARGS=$ENV_EXTRA_ARDUINO_LIB_INSTALL_ARGS; fi 52 | if [[ -n $ENV_SET_BUILD_PATH ]]; then SET_BUILD_PATH=$ENV_SET_BUILD_PATH; fi 53 | 54 | if [[ -n $ENV_DEBUG_COMPILE ]]; then DEBUG_COMPILE=$ENV_DEBUG_COMPILE; fi 55 | if [[ -n $ENV_DEBUG_INSTALL ]]; then DEBUG_INSTALL=$ENV_DEBUG_INSTALL; fi 56 | 57 | # 58 | # Handle deprecated names 59 | # 60 | if [[ -z $SKETCHES_EXCLUDE && -n $EXAMPLES_EXCLUDE ]]; then 61 | echo "Please change parameter name from \"examples-exclude\" to \"sketches-exclude\"" 62 | SKETCHES_EXCLUDE=${EXAMPLES_EXCLUDE} 63 | fi 64 | if [[ -z $BUILD_PROPERTIES && -n $EXAMPLES_BUILD_PROPERTIES ]]; then 65 | echo "Please change parameter name from \"examples-build-properties\" to \"build-properties\"" 66 | BUILD_PROPERTIES=${EXAMPLES_BUILD_PROPERTIES} 67 | fi 68 | 69 | # 70 | # Enforce defaults. Required at least for script version. !!! MUST be equal the defaults in action.yml !!! 71 | # 72 | echo -e "\r\n${YELLOW}Set defaults" 73 | if [[ -z $ARDUINO_BOARD_FQBN ]]; then 74 | echo "Set ARDUINO_BOARD_FQBN to default value: \"arduino:avr:uno\"" 75 | ARDUINO_BOARD_FQBN='arduino:avr:uno' 76 | fi 77 | if [[ -z $PLATFORM_URL && -n $PLATFORM_DEFAULT_URL ]]; then 78 | echo -e "Set PLATFORM_URL to default value: \"${PLATFORM_DEFAULT_URL}\"" 79 | PLATFORM_URL=$PLATFORM_DEFAULT_URL 80 | fi 81 | if [[ -z $CLI_VERSION ]]; then 82 | echo "Set CLI_VERSION to default value: \"latest\"" 83 | CLI_VERSION='latest' 84 | fi 85 | if [[ -z $SKETCH_NAMES ]]; then 86 | echo -e "Set SKETCH_NAMES to default value: \"*.ino\"" 87 | SKETCH_NAMES='*.ino' 88 | fi 89 | if [[ -z $SKETCH_NAMES_FIND_START ]]; then 90 | echo -e "Set SKETCH_NAMES_FIND_START to default value: \".\" (root of repository)" 91 | SKETCH_NAMES_FIND_START='.' 92 | fi 93 | if [[ -z $SET_BUILD_PATH ]]; then 94 | echo -e "Set SET_BUILD_PATH to default value: \"false\"" 95 | SET_BUILD_PATH='false' 96 | fi 97 | 98 | # 99 | # Echo input parameter 100 | # 101 | echo -e "\r\n${YELLOW}Echo input parameter" 102 | echo CLI_VERSION=$CLI_VERSION 103 | echo SKETCH_NAMES=$SKETCH_NAMES 104 | echo SKETCH_NAMES_FIND_START=$SKETCH_NAMES_FIND_START 105 | echo ARDUINO_BOARD_FQBN=$ARDUINO_BOARD_FQBN 106 | echo ARDUINO_PLATFORM=$ARDUINO_PLATFORM 107 | echo PLATFORM_DEFAULT_URL=$PLATFORM_DEFAULT_URL 108 | echo PLATFORM_URL=$PLATFORM_URL 109 | echo REQUIRED_LIBRARIES=$REQUIRED_LIBRARIES 110 | echo SKETCHES_EXCLUDE=$SKETCHES_EXCLUDE 111 | echo BUILD_PROPERTIES=$BUILD_PROPERTIES 112 | echo EXTRA_ARDUINO_CLI_ARGS=$EXTRA_ARDUINO_CLI_ARGS 113 | echo EXTRA_ARDUINO_LIB_INSTALL_ARGS=$EXTRA_ARDUINO_LIB_INSTALL_ARGS 114 | echo SET_BUILD_PATH=$SET_BUILD_PATH 115 | 116 | echo DEBUG_COMPILE=$DEBUG_COMPILE 117 | echo DEBUG_INSTALL=$DEBUG_INSTALL 118 | 119 | VERBOSE_PARAMETER= 120 | if [[ $DEBUG_INSTALL == true ]]; then 121 | VERBOSE_PARAMETER=--verbose 122 | echo 123 | echo HOME=$HOME # /home/runner 124 | echo PWD=$PWD # *** 125 | echo GITHUB_WORKSPACE=$GITHUB_WORKSPACE # /home/runner/work// 126 | #set 127 | #ls -lR $GITHUB_WORKSPACE 128 | fi 129 | 130 | # Show calling parameters 131 | declare -p BASH_ARGV 132 | 133 | # 134 | # Download and install arduino IDE, if not already cached 135 | # 136 | echo -n -e "\r\n${YELLOW}arduino-cli " 137 | if [[ -f $HOME/arduino_ide/arduino-cli ]]; then 138 | echo -e "cached: ${GREEN}\xe2\x9c\x93" # never seen :-( 139 | else 140 | echo -n "downloading: " 141 | wget --quiet https://downloads.arduino.cc/arduino-cli/arduino-cli_${CLI_VERSION}_Linux_64bit.tar.gz 142 | if [[ $? -ne 0 ]]; then 143 | echo -e "${RED}\xe2\x9c\x96" 144 | echo "::error:: Unable to download arduino-cli_${CLI_VERSION}_Linux_64bit.tar.gz" 145 | exit 3 146 | else 147 | echo -e "${GREEN}\xe2\x9c\x93" 148 | fi 149 | echo -n "Upacking arduino-cli to ${HOME}/arduino_ide: " 150 | if [[ ! -d $HOME/arduino_ide/ ]]; then 151 | mkdir $HOME/arduino_ide 152 | fi 153 | tar xf arduino-cli_${CLI_VERSION}_Linux_64bit.tar.gz -C $HOME/arduino_ide/ 154 | if [[ $? -ne 0 ]]; then 155 | echo -e "${RED}\xe2\x9c\x96" 156 | else 157 | echo -e "${GREEN}\xe2\x9c\x93" 158 | fi 159 | # ls -l $HOME/arduino_ide/* # LICENSE.txt + arduino-cli 160 | # ls -l $HOME # only arduino_ide 161 | fi 162 | 163 | # add the arduino CLI to our PATH 164 | export PATH="$HOME/arduino_ide:$PATH" 165 | 166 | #print version 167 | arduino-cli version 168 | 169 | # 170 | # Add *Custom* directories to Arduino library directory 171 | # 172 | # if ls $GITHUB_WORKSPACE/*Custom* >/dev/null 2>&1; then 173 | # echo -e "\r\n${YELLOW}Add *Custom* as Arduino library" 174 | # mkdir --parents $HOME/Arduino/libraries 175 | # rm --force --recursive $GITHUB_WORKSPACE/*Custom*/.git # do not want to move the whole .git directory 176 | # # mv to avoid the library examples to be test compiled 177 | # echo mv --no-clobber $VERBOSE_PARAMETER $GITHUB_WORKSPACE/\*Custom\* $HOME/Arduino/libraries/ 178 | # mv --no-clobber $VERBOSE_PARAMETER $GITHUB_WORKSPACE/*Custom* $HOME/Arduino/libraries/ 179 | # fi 180 | 181 | echo "Download Depends Arduino library" 182 | mkdir --parents $HOME/Arduino/libraries 183 | 184 | if [[ -f $GITHUB_WORKSPACE/library.properties ]]; then 185 | OLD_IFS="$IFS" 186 | IFS=$'\n' 187 | for line in $(cat $GITHUB_WORKSPACE/library.properties); do 188 | result=$(echo $line | grep "depends=") 189 | if [[ "$result" != "" ]]; then 190 | depends_str=${line##*depends=} 191 | IFS="," 192 | for lib in ${depends_str[@]}; do 193 | echo "download $lib" 194 | arduino-cli lib install $lib 195 | done 196 | fi 197 | done 198 | IFS="$OLD_IFS" 199 | fi 200 | 201 | echo "Check Arduino library" 202 | repo_name="${GITHUB_WORKSPACE##*/}" 203 | if [[ -d $HOME/Arduino/libraries/$repo_name ]]; then 204 | rm -r $HOME/Arduino/libraries/$repo_name 205 | echo "Same Arduino library: ${repo_name}, replace this repository" 206 | fi 207 | 208 | cp -r $GITHUB_WORKSPACE $HOME/Arduino/libraries/ 209 | ls $HOME/Arduino/libraries/$repo_name 210 | 211 | # Link this repository as Arduino library 212 | # 213 | # Check if repo is an Arduino library 214 | # if [[ -f $GITHUB_WORKSPACE/library.properties ]]; then 215 | # echo -e "\r\n${YELLOW}Link this repository as Arduino library" 216 | # mkdir --parents $HOME/Arduino/libraries 217 | # repo_name="${GITHUB_WORKSPACE##*/}" 218 | # if [[ -d $HOME/Arduino/libraries/$repo_name ]]; then 219 | # rm -r $HOME/Arduino/libraries/$repo_name 220 | # echo -e "\r\nSame Arduino library: ${repo_name}, replace this repository" 221 | # fi 222 | # ln --symbolic $GITHUB_WORKSPACE $HOME/Arduino/libraries/. 223 | # if [[ $DEBUG_INSTALL == true ]]; then 224 | # echo ln --symbolic $GITHUB_WORKSPACE $HOME/Arduino/libraries/. 225 | # rm --force --recursive $HOME/Arduino/libraries/*/.git # do not want to list the whole .git directory 226 | # echo ls -l --dereference --recursive --all $HOME/Arduino/libraries/ 227 | # ls -l --dereference --recursive --all $HOME/Arduino/libraries/ 228 | # fi 229 | # fi 230 | 231 | # 232 | # Update index and install the required board platform 233 | # 234 | echo -e "\r\n${YELLOW}Update index and install the required board platform" 235 | if [[ -z $ARDUINO_PLATFORM ]]; then 236 | # ARDUINO_PLATFORM is empty -> derive platform from the 2 first elements of the arduino-board-fqbn 237 | remainder=${ARDUINO_BOARD_FQBN#*:} 238 | provider=${ARDUINO_BOARD_FQBN%%:*} 239 | PLATFORM=${provider}:${remainder%%:*} 240 | else 241 | # Remove @latest from specified platform 242 | PLATFORM=${ARDUINO_PLATFORM%@latest} 243 | fi 244 | echo PLATFORM=${PLATFORM} # e.g. digistump:avr 245 | if [[ ${PLATFORM} != *arduino* && -z $PLATFORM_URL ]]; then 246 | # check if the requested platform is manually installed 247 | if [[ ! -d $HOME/.arduino15/packages/${provider} ]]; then 248 | echo -e "::error::Non Arduino platform $PLATFORM requested, but \"platform-url\" parameter is missing." 249 | exit 1 250 | fi 251 | fi 252 | 253 | if [[ -n $PLATFORM_URL ]]; then 254 | PLATFORM_URL=${PLATFORM_URL// /,} # replace space by comma to enable multiple urls which are space separated 255 | PLATFORM_URL_COMMAND="--additional-urls" 256 | fi 257 | 258 | PLATFORM=${PLATFORM//,/ } # replace all comma by space to enable multiple platforms which are comma separated 259 | declare -a PLATFORM_ARRAY=($PLATFORM) 260 | if [[ $DEBUG_INSTALL == true ]]; then 261 | declare -p PLATFORM_ARRAY # print properties of PLATFORM_ARRAY 262 | fi 263 | for single_platform in "${PLATFORM_ARRAY[@]}"; do # Loop over all platforms specified 264 | if [[ $DEBUG_INSTALL == true ]]; then 265 | echo -e "arduino-cli core update-index $PLATFORM_URL_COMMAND $PLATFORM_URL --verbose" 266 | arduino-cli core update-index $PLATFORM_URL_COMMAND $PLATFORM_URL --verbose # must specify --additional-urls here 267 | if [[ $? -ne 0 ]]; then 268 | echo "::error::Updating index of $PLATFORM_URL failed" 269 | exit 1 270 | fi 271 | echo -e "arduino-cli core install $single_platform $PLATFORM_URL_COMMAND $PLATFORM_URL -v" 272 | arduino-cli core install $single_platform $PLATFORM_URL_COMMAND $PLATFORM_URL --verbose 273 | else 274 | echo -e "arduino-cli core update-index $PLATFORM_URL_COMMAND $PLATFORM_URL > /dev/null" 275 | arduino-cli core update-index $PLATFORM_URL_COMMAND $PLATFORM_URL >/dev/null # must specify --additional-urls here 276 | if [[ $? -ne 0 ]]; then 277 | echo "::error::Updating index of $PLATFORM_URL failed" 278 | exit 1 279 | fi 280 | echo -e "arduino-cli core install $single_platform $PLATFORM_URL_COMMAND $PLATFORM_URL > /dev/null" 281 | arduino-cli core install $single_platform $PLATFORM_URL_COMMAND $PLATFORM_URL >/dev/null 282 | fi 283 | if [[ $? -ne 0 ]]; then 284 | echo "::error::Install core for $single_platform failed" 285 | exit 1 286 | fi 287 | done 288 | 289 | # 290 | # Special esp8266 and esp32 platform handling 291 | # 292 | echo -e "\r\n${YELLOW}Special esp8266 and esp32 platform handling" 293 | if [[ ${PLATFORM} == esp8266:esp8266 && ! -f /usr/bin/python3 ]]; then 294 | # python3 is a link in the esp8266 package: /github/home/.arduino15/packages/esp8266/tools/python3/3.7.2-post1/python3 -> /usr/bin/python3 295 | echo -e "\r\n${YELLOW}install python3 for ESP8266" 296 | apt-get install -qq python3 >/dev/null 297 | fi 298 | 299 | if [[ $PLATFORM == esp32:esp32 ]]; then 300 | if [[ ! -f /usr/bin/pip && ! -f /usr/bin/python ]]; then 301 | echo -e "\r\n${YELLOW}install python and pip for ESP32" 302 | # Here we would get the warning: The directory '/github/home/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. 303 | # Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag. 304 | apt-get install -qq python-pip >/dev/null 2>&1 # this installs also python 305 | fi 306 | pip install pyserial 307 | fi 308 | 309 | # 310 | # List installed boards with their FQBN 311 | # 312 | echo -e "\r\n${YELLOW}List installed boards with their FQBN" 313 | if [[ $DEBUG_INSTALL == true ]]; then 314 | echo arduino-cli board listall --verbose 315 | arduino-cli board listall --verbose 316 | else 317 | echo arduino-cli board listall 318 | arduino-cli board listall 319 | fi 320 | 321 | # 322 | # Install required libraries 323 | # 324 | echo -e "\n${YELLOW}Install required libraries" 325 | if [[ -z $REQUIRED_LIBRARIES ]]; then 326 | echo No additional libraries to install 327 | else 328 | echo Install libraries $REQUIRED_LIBRARIES 329 | BACKUP_IFS="$IFS" 330 | # Split comma separated library list 331 | IFS=$',' 332 | declare -a REQUIRED_LIBRARIES_ARRAY=($REQUIRED_LIBRARIES) 333 | IFS="$BACKUP_IFS" 334 | if [[ $DEBUG_INSTALL == true ]]; then 335 | arduino-cli lib install "${REQUIRED_LIBRARIES_ARRAY[@]}" $EXTRA_ARDUINO_LIB_INSTALL_ARGS 336 | else 337 | arduino-cli lib install "${REQUIRED_LIBRARIES_ARRAY[@]}" $EXTRA_ARDUINO_LIB_INSTALL_ARGS >/dev/null 2>&1 338 | fi 339 | if [[ $? -ne 0 ]]; then 340 | echo "::error::Installation of $REQUIRED_LIBRARIES failed" 341 | exit 1 342 | fi 343 | fi 344 | 345 | # Save generated files to the build subfolder of the sketch 346 | export ARDUINO_SKETCH_ALWAYS_EXPORT_BINARIES=true 347 | 348 | # 349 | # Get the build property map 350 | # 351 | echo -e "\n${YELLOW}Compiling sketches / examples for board $ARDUINO_BOARD_FQBN\n" 352 | 353 | # If matrix.build-properties are specified, create an associative shell array 354 | # Input example: { "WhistleSwitch": "-DINFO -DFREQUENCY_RANGE_LOW", "SimpleFrequencyDetector": "-DINFO" } 355 | # Converted to: [All]="-DDEBUG -DINFO" [WhistleSwitch]="-DDEBUG -DINFO" 356 | if [[ -n $BUILD_PROPERTIES && $BUILD_PROPERTIES != "null" ]]; then # contains "null", if passed as environment variable 357 | echo BUILD_PROPERTIES=$BUILD_PROPERTIES 358 | BUILD_PROPERTIES=${BUILD_PROPERTIES#\{} # remove the "{". The "}" is required as end token 359 | # (\w*): * first token before the colon and spaces, ([^,}]*) token after colon and spaces up to "," or "}", [,}] trailing characters 360 | if [[ $DEBUG_COMPILE == true ]]; then 361 | echo BUILD_PROPERTIES is converted to:$(echo $BUILD_PROPERTIES | sed -E 's/"(\w*)": *([^,}]*)[,}]/\[\1\]=\2/g') 362 | fi 363 | declare -A PROP_MAP="( $(echo $BUILD_PROPERTIES | sed -E 's/"(\w*)": *([^,}]*)[,}]/\[\1\]=\2/g') )" 364 | declare -p PROP_MAP # print properties of PROP_MAP 365 | else 366 | declare -A PROP_MAP=([dummy]=dummy) # declare an accociative array 367 | fi 368 | 369 | # 370 | # Finally, we compile all examples 371 | # 372 | # Split comma separated sketch name list 373 | BACKUP_IFS="$IFS" 374 | IFS=$',' 375 | SKETCH_NAMES=${SKETCH_NAMES// /} # replace all spaces 376 | GLOBIGNORE=*:?:[ # Disable filename expansion (globbing) of *.ino to abc.ino if abc.ino is a file in the directory 377 | declare -a SKETCH_NAMES_ARRAY=($SKETCH_NAMES) # declare an indexed array 378 | GLOBIGNORE= # Enable it for cp command below 379 | if [[ $DEBUG_COMPILE == true ]]; then 380 | declare -p SKETCH_NAMES_ARRAY # print properties of SKETCH_NAMES_ARRAY 381 | fi 382 | IFS="$BACKUP_IFS" 383 | COMPILED_SKETCHES= 384 | for sketch_name in "${SKETCH_NAMES_ARRAY[@]}"; do # Loop over all sketch names 385 | if [[ $SET_BUILD_PATH == true ]]; then 386 | # must use $GITHUB_WORKSPACE/$SKETCH_NAMES_FIND_START, since arduino-cli does not support relative path for --build-path 387 | declare -a SKETCHES=($(find ${GITHUB_WORKSPACE}/${SKETCH_NAMES_FIND_START} -type f -name "$sketch_name")) # only search for files 388 | else 389 | declare -a SKETCHES=($(find ${SKETCH_NAMES_FIND_START} -type f -name "$sketch_name")) # only search for files 390 | fi 391 | if [[ $DEBUG_COMPILE == true ]]; then 392 | declare -p SKETCHES 393 | fi 394 | 395 | # Check if find command found a file 396 | if [[ -z ${SKETCHES[0]} ]]; then 397 | GLOBIGNORE=*:?:[ # Disable filename expansion (globbing) of *.ino to abc.ino if abc.ino is a file in the directory 398 | echo -e "::error::\nNo files found to compile with sketch_name=${sketch_name}." 399 | echo "sketch-names=${SKETCH_NAMES} and sketch-names-find-start=${SKETCH_NAMES_FIND_START}" 400 | GLOBIGNORE= 401 | # No files found -> list start directory and execute find command to see what we did 402 | echo -e "find command is: find ${GITHUB_WORKSPACE}/${SKETCH_NAMES_FIND_START} -type f -name \"$sketch_name\"" 403 | echo "\"sketch-names-find-start\" directory content listing with: ls -l ${GITHUB_WORKSPACE}/${SKETCH_NAMES_FIND_START}" 404 | ls -l ${GITHUB_WORKSPACE}/${SKETCH_NAMES_FIND_START} 405 | echo 406 | fi 407 | 408 | for sketch in "${SKETCHES[@]}"; do # Loop over all sketch files 409 | SKETCH_PATH=$(dirname $sketch) # complete path to sketch 410 | SKETCH_DIR=${SKETCH_PATH##*/} # directory of sketch, must match sketch basename 411 | SKETCH_FILENAME=$(basename $sketch) # complete name of sketch 412 | SKETCH_EXTENSION=${SKETCH_FILENAME##*.} # extension of sketch 413 | SKETCH_BASENAME=${SKETCH_FILENAME%%.$SKETCH_EXTENSION} # name without extension / basename of sketch, must match directory name 414 | if [[ $DEBUG_COMPILE == true ]]; then 415 | echo -n "Process $sketch with filename $SKETCH_FILENAME and extension $SKETCH_EXTENSION" 416 | fi 417 | echo -e "\n" 418 | if [[ $SKETCHES_EXCLUDE == *"$SKETCH_BASENAME"* ]]; then 419 | echo -e "Skipping $SKETCH_PATH \xe2\x9e\x9e" # Right arrow 420 | else 421 | # If sketch name does not end with .ino, rename it locally 422 | if [[ $SKETCH_EXTENSION != ino ]]; then 423 | echo "Rename ${SKETCH_PATH}/${SKETCH_FILENAME} to ${SKETCH_PATH}/${SKETCH_BASENAME}.ino" 424 | mv ${SKETCH_PATH}/${SKETCH_FILENAME} ${SKETCH_PATH}/${SKETCH_BASENAME}.ino 425 | fi 426 | # If directory name does not match sketch name, create an appropriate directory, copy the files recursively and compile 427 | if [[ $SKETCH_DIR != $SKETCH_BASENAME ]]; then 428 | mkdir $HOME/$SKETCH_BASENAME 429 | echo "Creating directory $HOME/$SKETCH_BASENAME and copy ${SKETCH_PATH}/* to it" 430 | cp --recursive ${SKETCH_PATH}/* $HOME/$SKETCH_BASENAME 431 | SKETCH_PATH=$HOME/$SKETCH_BASENAME 432 | fi 433 | if [[ $SET_BUILD_PATH == true ]]; then 434 | BUILD_PATH_PARAMETER="--build-path $SKETCH_PATH/build/" 435 | fi 436 | # Check if there is an entry in the associative array and create compile parameter to put in compiler.*.extra_flags 437 | # This flags are also defined in platform.txt as empty, to be overwritten by a platform.local.txt definition. 438 | # But I never saw a distribution using this fature, so we can go on here :-) 439 | echo -n "Compiling $SKETCH_BASENAME " 440 | if [[ -n ${PROP_MAP[$SKETCH_BASENAME]} ]]; then 441 | GCC_EXTRA_FLAGS=${PROP_MAP[$SKETCH_BASENAME]} 442 | echo -n "with $GCC_EXTRA_FLAGS " 443 | elif [[ -n ${PROP_MAP[All]} ]]; then 444 | GCC_EXTRA_FLAGS=${PROP_MAP[All]} 445 | echo -n "with $GCC_EXTRA_FLAGS " 446 | else 447 | GCC_EXTRA_FLAGS= 448 | fi 449 | if [[ -z $GCC_EXTRA_FLAGS ]]; then 450 | build_stdout=$(arduino-cli compile -e --verbose --warnings all --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH 2>&1) 451 | # build_stdout=$(arduino-cli compile -e --log-level error --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH 2>&1) 452 | else 453 | build_stdout=$(arduino-cli compile -e --verbose --warnings all --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags="${GCC_EXTRA_FLAGS}" --build-property compiler.c.extra_flags="${GCC_EXTRA_FLAGS}" --build-property compiler.S.extra_flags="${GCC_EXTRA_FLAGS}" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH 2>&1) 454 | # build_stdout=$(arduino-cli compile -e --log-level error --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags="${GCC_EXTRA_FLAGS}" --build-property compiler.c.extra_flags="${GCC_EXTRA_FLAGS}" --build-property compiler.S.extra_flags="${GCC_EXTRA_FLAGS}" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH 2>&1) 455 | fi 456 | if [[ $? -ne 0 ]]; then 457 | echo -e ""${RED}"\xe2\x9c\x96" # If ok output a green checkmark else a red X and the command output. 458 | if [[ -z $GCC_EXTRA_FLAGS ]]; then 459 | echo "arduino-cli compile -e --verbose --warnings all --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 460 | # echo "arduino-cli compile -e --log-level error --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 461 | else 462 | echo "arduino-cli compile -e --verbose --warnings all --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.c.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.S.extra_flags=\"${GCC_EXTRA_FLAGS}\" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 463 | # echo "arduino-cli compile -e --log-level error --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.c.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.S.extra_flags=\"${GCC_EXTRA_FLAGS}\" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 464 | fi 465 | echo "::error::Compile of $SKETCH_BASENAME ${GCC_EXTRA_FLAGS} failed" 466 | echo -e "$build_stdout \n" 467 | # repeat the info after hundred lines of output :-) 468 | echo "Compile of $SKETCH_BASENAME ${GCC_EXTRA_FLAGS} failed" 469 | exit_code=1 470 | else 471 | echo -e "${GREEN}\xe2\x9c\x93" 472 | if [[ -z $GCC_EXTRA_FLAGS ]]; then 473 | echo "arduino-cli compile -e --verbose --warnings all --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 474 | # echo "arduino-cli compile -e --log-level error --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 475 | else 476 | echo "arduino-cli compile -e --verbose --warnings all --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.c.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.S.extra_flags=\"${GCC_EXTRA_FLAGS}\" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 477 | # echo "arduino-cli compile -e --log-level error --fqbn ${ARDUINO_BOARD_FQBN%|*} $BUILD_PATH_PARAMETER --build-property compiler.cpp.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.c.extra_flags=\"${GCC_EXTRA_FLAGS}\" --build-property compiler.S.extra_flags=\"${GCC_EXTRA_FLAGS}\" $EXTRA_ARDUINO_CLI_ARGS $SKETCH_PATH" 478 | fi 479 | if [[ $DEBUG_COMPILE == true || $SET_BUILD_PATH == true ]]; then 480 | echo "Debug mode enabled => compile output will be printed also for successful compilation and sketch directory is listed after compilation" 481 | echo -e "$build_stdout \n" 482 | echo -e "\nls -l --recursive $SKETCH_PATH/build/" 483 | ls -l --recursive $SKETCH_PATH/build/ 484 | echo -e "\r\n" 485 | fi 486 | fi 487 | COMPILED_SKETCHES="$COMPILED_SKETCHES $SKETCH_NAME" 488 | fi 489 | done 490 | done 491 | if [ -z "$COMPILED_SKETCHES" ]; then 492 | echo "::error::Did not find any sketches to compile, probably misconfigured or used checkout twice without \"path:\" parameter?" 493 | exit_code=2 494 | fi 495 | 496 | echo "compiled all example, export bin file..." 497 | pwd 498 | find . -name "*.bin" 499 | 500 | exit $exit_code 501 | --------------------------------------------------------------------------------