diff --git a/Platforms.h b/Platforms.h index fe96241..31d39cd 100644 --- a/Platforms.h +++ b/Platforms.h @@ -27,6 +27,7 @@ //#pragma message "Using ESP32" #define DELAY_US(us) ets_delay_us(us) + #define DELAY_MS(ms) vTaskDelay(ms / portTICK_PERIOD_MS); #define IN_FLASH #elif (IS_ESP8266) @@ -63,7 +64,7 @@ //} #if IS_ESP8266 - #define sprintf os_sprintf + //#define sprintf os_sprintf extern "C" { // #include "ets_sys.h" // #include "c_types.h" diff --git a/ext/e-ink/Waveshare.h b/ext/e-ink/Waveshare.h index 8bdcb53..ec7dc93 100644 --- a/ext/e-ink/Waveshare.h +++ b/ext/e-ink/Waveshare.h @@ -5,7 +5,11 @@ #include "../../Debug.h" - +#ifndef usleep + void usleep(int val) { + vTaskDelay(val / 1000 / portTICK_PERIOD_MS); + } +#endif /** * base-class for Waveshare SPI E-Ink displays @@ -16,11 +20,11 @@ template class static constexpr const char* NAME = "E-Ink"; SPI& spi; - + public: Waveshare(SPI& spi) : spi(spi) { - debugMod4(NAME, "ctor() CS:%d BUSY:%d RST:%d DC:%d", PIN_CS, PIN_BUSY, PIN_RST, PIN_DC); + Log::addInfo(NAME, "ctor() CS:%d BUSY:%d RST:%d DC:%d", PIN_CS, PIN_BUSY, PIN_RST, PIN_DC); MyGPIO::setInput(PIN_BUSY); MyGPIO::setOutput(PIN_RST); MyGPIO::setOutput(PIN_DC); @@ -30,7 +34,7 @@ public: protected: void reset() { - debugMod(NAME, "reset()"); + Log::addInfo(NAME, "reset()"); MyGPIO::clear(PIN_RST); usleep(200*1000); MyGPIO::set(PIN_RST); @@ -54,9 +58,9 @@ protected: } void waitUntilIdle() { - debugMod(NAME, "waitUntilIdle()"); + Log::addInfo(NAME, "waitUntilIdle()"); while(MyGPIO::get(PIN_BUSY) == 0) {usleep(200*1000);} - debugMod(NAME, "OK"); + Log::addInfo(NAME, "OK"); } void lut(uint8_t c, uint8_t l, const uint8_t* p) { diff --git a/ext/e-ink/Waveshare_4_2.h b/ext/e-ink/Waveshare_4_2.h index d6c874e..76b3983 100644 --- a/ext/e-ink/Waveshare_4_2.h +++ b/ext/e-ink/Waveshare_4_2.h @@ -1,10 +1,52 @@ #include "Waveshare.h" +// www.waveshare.com/wiki/4.2inch_e-Paper_Module_(B) +// https://www.waveshare.com/wiki/4.2inch_e-Paper_Module_(B)_Manual#Overview + template class Waveshare_4_2 : public Waveshare { static constexpr const char* NAME = "E-Ink 4.2\""; + static constexpr const uint8_t PANEL_SETTING = 0x00; + static constexpr const uint8_t POWER_SETTING = 0x01; + static constexpr const uint8_t POWER_OFF = 0x02; + static constexpr const uint8_t POWER_OFF_SEQUENCE_SETTING = 0x03; + static constexpr const uint8_t POWER_ON = 0x04; + static constexpr const uint8_t POWER_ON_MEASURE = 0x05; + static constexpr const uint8_t BOOSTER_SOFT_START = 0x06; + static constexpr const uint8_t DEEP_SLEEP = 0x07; + static constexpr const uint8_t DATA_START_TRANSMISSION_1 = 0x10; + static constexpr const uint8_t DATA_STOP = 0x11; + static constexpr const uint8_t DISPLAY_REFRESH = 0x12; + static constexpr const uint8_t DATA_START_TRANSMISSION_2 = 0x13; + static constexpr const uint8_t LUT_FOR_VCOM = 0x20; + static constexpr const uint8_t LUT_WHITE_TO_WHITE = 0x21; + static constexpr const uint8_t LUT_BLACK_TO_WHITE = 0x22; + static constexpr const uint8_t LUT_WHITE_TO_BLACK = 0x23; + static constexpr const uint8_t LUT_BLACK_TO_BLACK = 0x24; + static constexpr const uint8_t PLL_CONTROL = 0x30; + static constexpr const uint8_t TEMPERATURE_SENSOR_COMMAND = 0x40; + static constexpr const uint8_t TEMPERATURE_SENSOR_SELECTION = 0x41; + static constexpr const uint8_t TEMPERATURE_SENSOR_WRITE = 0x42; + static constexpr const uint8_t TEMPERATURE_SENSOR_READ = 0x43; + static constexpr const uint8_t VCOM_AND_DATA_INTERVAL_SETTING = 0x50; + static constexpr const uint8_t LOW_POWER_DETECTION = 0x51; + static constexpr const uint8_t TCON_SETTING = 0x60; + static constexpr const uint8_t RESOLUTION_SETTING = 0x61; + static constexpr const uint8_t GSST_SETTING = 0x65; + static constexpr const uint8_t GET_STATUS = 0x71; + static constexpr const uint8_t AUTO_MEASUREMENT_VCOM = 0x80; + static constexpr const uint8_t READ_VCOM_VALUE = 0x81; + static constexpr const uint8_t VCM_DC_SETTING = 0x82; + static constexpr const uint8_t PARTIAL_WINDOW = 0x90; + static constexpr const uint8_t PARTIAL_IN = 0x91; + static constexpr const uint8_t PARTIAL_OUT = 0x92; + static constexpr const uint8_t PROGRAM_MODE = 0xA0; + static constexpr const uint8_t ACTIVE_PROGRAMMING = 0xA1; + static constexpr const uint8_t READ_OTP = 0xA2; + static constexpr const uint8_t POWER_SAVING = 0xE3; + public: enum class Mode { @@ -42,53 +84,55 @@ public: } void enableWindow() { - this->sendCommand(0x91); + this->sendCommand(PARTIAL_IN); } void disableWindow() { - this->sendCommand(0x92); + this->sendCommand(PARTIAL_OUT); } void init(Mode mode) { - debugMod(NAME, "init()"); + Log::addInfo(NAME, "init()"); this->reset(); - this->send3(0x06, 0x17, 0x17, 0x17); // BOOSTER_SOFT_START - this->sendCommand(0x04); // POWER_ON + this->send3(BOOSTER_SOFT_START, 0x17, 0x17, 0x17); + this->sendCommand(POWER_ON); this->waitUntilIdle(); uint8_t cfg = 0x0F; if (mode == Mode::BLACK_WHITE) {cfg |= (1<<4);} - this->send1(0x00, cfg); // PANEL_SETTING - this->send1(0x50, 0xF7); // VCOM_AND_DATA_INTERVAL_SETTING + this->send1(PANEL_SETTING, cfg); + this->send1(VCOM_AND_DATA_INTERVAL_SETTING, 0xF7); //this->sendCommand(0x10);//DATA_START_TRANSMISSION_1 //usleep(10*1000); - debugMod(NAME, "init() complete"); + Log::addInfo(NAME, "init() complete"); } + /** load black data, bit-set = black pixel, nullptr input = clear all */ void loadBlack(const uint8_t* black) { - this->sendCommand(0x10); + this->sendCommand(DATA_START_TRANSMISSION_1); if (black) { for (int i = 0; i < 400*300/8; ++i) {this->sendData(~reverse(black[i]));} } else { - for (int i = 0; i < 400*300/8; ++i) {this->sendData(~0x00);} + for (int i = 0; i < 400*300/8; ++i) {this->sendData(0);} // 0 = pixel not set (blank) } - this->sendCommand(0x11); + this->sendCommand(DATA_STOP); } + /** load black data, bit-set = red pixel, nullptr input = clear all */ void loadRed(const uint8_t* red) { - this->sendCommand(0x13); + this->sendCommand(DATA_START_TRANSMISSION_2); if (red) { for (int i = 0; i < 400*300/8; ++i) {this->sendData(~reverse(red[i]));} } else { - for (int i = 0; i < 400*300/8; ++i) {this->sendData(~0x00);} + for (int i = 0; i < 400*300/8; ++i) {this->sendData(0);} // 0 = pixel not set (blank) } - this->sendCommand(0x11); + this->sendCommand(DATA_STOP); } static uint8_t reverse(uint8_t a) { @@ -101,19 +145,19 @@ public: void show() { - debugMod(NAME, "refresh"); - this->sendCommand(0x12);//DISPLAY_REFRESH + Log::addInfo(NAME, "refresh"); + this->sendCommand(DISPLAY_REFRESH); usleep(100*1000); this->waitUntilIdle(); - debugMod(NAME, "refresh done"); + Log::addInfo(NAME, "refresh done"); - debugMod(NAME, "sleep"); - this->send1(0x50, 0x17);//VCOM_AND_DATA_INTERVAL_SETTING - this->send1(0x82, 0x00);//VCM_DC_SETTING_REGISTER, to solve Vcom drop - this->send4(0x01, 0x02, 0x00, 0x00, 0x00);//POWER_SETTING + Log::addInfo(NAME, "sleep"); + this->send1(VCOM_AND_DATA_INTERVAL_SETTING, 0x17); + this->send1(VCM_DC_SETTING, 0x00); //to solve Vcom drop + this->send4(POWER_SETTING, 0x02, 0x00, 0x00, 0x00); this->waitUntilIdle(); - this->sendCommand(0x02);//POWER_OFF - debugMod(NAME, "sleep done"); + this->sendCommand(POWER_OFF); + Log::addInfo(NAME, "sleep done"); } diff --git a/ext/lcd/SH1106.h b/ext/lcd/SH1106.h new file mode 100644 index 0000000..eddd9cc --- /dev/null +++ b/ext/lcd/SH1106.h @@ -0,0 +1,147 @@ +#pragma once + +#include "../../io/SoftI2C.h" + +// https://www.displayfuture.com/Display/datasheet/controller/SH1106.pdf +// Note: the SH1106 is almost the same as SSD1306, +// except for some addressing modes, when writing the whole display at once +// the device address is also the same + +template class SH1106 { + +private: + + static constexpr uint8_t ADDR7 = 0b0111100; + + static constexpr uint8_t CMD_COL_ADDR_LO = 0x00; + static constexpr uint8_t CMD_COL_ADDR_HI = 0x10; + static constexpr uint8_t CMD_PUMP_VOLTAGE = 0x30; + static constexpr uint8_t CMD_START_LINE = 0x40; + static constexpr uint8_t CMD_DISPLAY_OFF = 0xAE | 0; + static constexpr uint8_t CMD_DISPLAY_ON = 0xAE | 1; + static constexpr uint8_t CMD_PAGE_ADDR = 0xB0; + + +private: + + bool inited = false; + I2C& i2c; + +public: + + SH1106(I2C& i2c) : i2c(i2c) { + + } + + bool isPresent() { + return i2c.query(ADDR7); + } + + /** checks if LCD is present and initializes it once / when it was gone */ + bool isPresentAndInit() { + bool present = isPresent(); + if (!present) {inited = false;} + if ( present && !inited) {initOnce();} + return present; + } + + void initOnce() { + if (inited) {return;} + init(); + inited = true; + } + + + void flush(const uint8_t* data) { + + for (uint8_t y = 0; y < h/8; ++y) { + + sendCommand(CMD_COL_ADDR_LO | 0); + sendCommand(CMD_COL_ADDR_HI | 0); + sendCommand(CMD_PAGE_ADDR | y); + + startDataTransfer(); + for (uint8_t x = 0; x < w; ++x) { + writeData(*data); ++data; + } + stopDataTransfer(); + + } + + } + + +private: + + inline void startDataTransfer() { + i2c.startWrite(ADDR7); + i2c.writeByteAndCheck(0x40); + } + + inline void writeData(uint8_t val) { + i2c.writeByteAndCheck(val); + } + + inline void stopDataTransfer() { + i2c.stop(); + } + + void init() { + + sendCommand(CMD_DISPLAY_OFF); + + // Init + + sendCommand(CMD_DISPLAY_ON); + + } + +private: + + + + void sendCommand(uint8_t cmd) { + bool ok; + ok = i2c.startWrite(ADDR7); + if (!ok) {os_printf("failed start write\n");} + ok = i2c.writeByteAndCheck(0x00); // command + if (!ok) {os_printf("failed command mode\n");} + ok = i2c.writeByteAndCheck(cmd); + if (!ok) {os_printf("failed command\n");} + i2c.stop(); + } + + void sendCommand(uint8_t cmd, uint8_t v1) { + sendCommand(cmd); + sendCommand(v1); + } + + void sendCommand(uint8_t cmd, uint8_t v1, uint8_t v2) { + sendCommand(cmd); + sendCommand(v1); + sendCommand(v2); + } + + void sendCommand2(uint8_t cmd, uint8_t v1) { + i2c.startWrite(ADDR7); + i2c.writeByteAndCheck(0x00); + i2c.writeByteAndCheck(cmd); + //i2c.writeByteAndCheck(0x00); + i2c.writeByteAndCheck(v1); + i2c.stop(); + } + + void sendCommand2(uint8_t cmd, uint8_t v1, uint8_t v2) { + i2c.startWrite(ADDR7); + i2c.writeByteAndCheck(0x00); + i2c.writeByteAndCheck(cmd); + //i2c.writeByteAndCheck(0x00); + i2c.writeByteAndCheck(v1); + //i2c.writeByteAndCheck(0x00); + i2c.writeByteAndCheck(v2); + i2c.stop(); + } + +}; + + diff --git a/ext/lcd/SSD1306.h b/ext/lcd/SSD1306.h index 4f66896..e6166c0 100644 --- a/ext/lcd/SSD1306.h +++ b/ext/lcd/SSD1306.h @@ -3,6 +3,9 @@ #include "../../io/SoftI2C.h" +// NOTE: this is almost the same as SH1106 +// https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf + //#define SSD1306_128_64 1 //#define SSD1306_64_48 1 // https://github.com/mcauser/Adafruit_SSD1306/blob/esp8266-64x48/Adafruit_SSD1306.cpp @@ -88,6 +91,14 @@ public: bool isPresent() { return i2c.query(ADDR7); } + + /** checks if LCD is present and initializes it once / when it was gone */ + bool isPresentAndInit() { + bool present = isPresent(); + if (!present) {inited = false;} + if ( present && !inited) {initOnce();} + return present; + } void initOnce() { if (inited) {return;} @@ -98,20 +109,29 @@ public: void flush(const uint8_t* data) { - sendCommand(SSD1306_COLUMNADDR); + // special handling for 64x48 oled shield #if SSD1306_LCDWIDTH == 64 && SSD1306_LCDHEIGHT == 48 + sendCommand(SSD1306_COLUMNADDR); sendCommand(32); sendCommand(32 + SSD1306_LCDWIDTH - 1); #else - sendCommand(0); // Column start address (0 = reset) - sendCommand(SSD1306_LCDWIDTH-1); // Column end address (127 = reset) + sendCommand(SSD1306_COLUMNADDR, 0, SSD1306_LCDWIDTH-1); + //sendCommand(SSD1306_COLUMNADDR); + //sendCommand(0); // Column start address (0 = reset) + //sendCommand(SSD1306_LCDWIDTH-1); // Column end address (127 = reset) #endif - sendCommand(SSD1306_PAGEADDR); - sendCommand(0); // Page start address (0 = reset) - sendCommand( (SSD1306_LCDHEIGHT/8)-1 ); // Page end address + + sendCommand(SSD1306_PAGEADDR, 0, (SSD1306_LCDHEIGHT/8)-1); + //sendCommand(SSD1306_PAGEADDR); + //sendCommand(0); // Page start address (0 = reset) + //sendCommand( (SSD1306_LCDHEIGHT/8)-1 ); // Page end address + + + + // #if SSD1306_LCDHEIGHT == 64 // sendCommand(7); // Page end address // #endif @@ -147,7 +167,8 @@ public: bool ok = i2c.writeByteAndCheck(0x40); if (!ok) {os_printf("failed write data\n");} - for (uint16_t i=0; i < (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { + //for (uint16_t i=0; i < (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { + for (uint16_t i=0; i < 16; i++) { i2c.writeByteAndCheck(data[i]); } @@ -163,25 +184,32 @@ private: uint8_t vccstate = 0; sendCommand(SSD1306_DISPLAYOFF); // 0xAE + sendCommand(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 sendCommand(0x80); // the suggested ratio 0x80 - sendCommand(SSD1306_SETMULTIPLEX); // 0xA8 + sendCommand(SSD1306_SETMULTIPLEX); // 0xA8: multiplexer (31 == 32MUX, 63 == 64MUX) sendCommand(SSD1306_LCDHEIGHT - 1); - sendCommand(SSD1306_SETDISPLAYOFFSET); // 0xD3 + sendCommand(SSD1306_SETDISPLAYOFFSET); // 0xD3: vertical shift 0-63 sendCommand(0x0); // no offset + sendCommand(SSD1306_SETSTARTLINE | 0x0); // line #0 + sendCommand(SSD1306_CHARGEPUMP); // 0x8D if (vccstate == SSD1306_EXTERNALVCC) { sendCommand(0x10); } else { sendCommand(0x14); } - sendCommand(SSD1306_MEMORYMODE); // 0x20 - sendCommand(0x00); // 0x0 act like ks0108 - sendCommand(SSD1306_SEGREMAP | 0x1); + + //sendCommand(SSD1306_MEMORYMODE); // 0x20: memory mode: hor/ver/page + //sendCommand(0x02); // 0x0 act like ks0108 + sendCommand(SSD1306_MEMORYMODE, 0x00); // 0x20: memory mode: hor/ver/page + + sendCommand(SSD1306_SEGREMAP | 0x0); + //sendCommand(SSD1306_COMSCANINC); // rotate 0 sendCommand(SSD1306_COMSCANDEC); // rotate 180? // OLD @@ -244,6 +272,8 @@ private: private: + + void sendCommand(uint8_t cmd) { bool ok; ok = i2c.startWrite(ADDR7); @@ -254,6 +284,37 @@ private: if (!ok) {os_printf("failed command\n");} i2c.stop(); } + + void sendCommand(uint8_t cmd, uint8_t v1) { + bool ok; + ok = i2c.startWrite(ADDR7); + if (!ok) {os_printf("failed start write\n");} + ok = i2c.writeByteAndCheck(0x00); // command + if (!ok) {os_printf("failed command mode\n");} + ok = i2c.writeByteAndCheck(cmd); + if (!ok) {os_printf("failed command\n");} + ok = i2c.writeByteAndCheck(0x00); // command + ok = i2c.writeByteAndCheck(v1); + if (!ok) {os_printf("failed command\n");} + i2c.stop(); + } + + void sendCommand(uint8_t cmd, uint8_t v1, uint8_t v2) { + bool ok; + ok = i2c.startWrite(ADDR7); + if (!ok) {os_printf("failed start write\n");} + ok = i2c.writeByteAndCheck(0x00); // command + if (!ok) {os_printf("failed command mode\n");} + ok = i2c.writeByteAndCheck(cmd); + if (!ok) {os_printf("failed command\n");} + ok = i2c.writeByteAndCheck(0x00); // command + ok = i2c.writeByteAndCheck(v1); + if (!ok) {os_printf("failed command\n");} + ok = i2c.writeByteAndCheck(0x00); // command + ok = i2c.writeByteAndCheck(v2); + if (!ok) {os_printf("failed command\n");} + i2c.stop(); + } }; diff --git a/ext/lcd/SSD1306_old.h b/ext/lcd/SSD1306.h.old similarity index 100% rename from ext/lcd/SSD1306_old.h rename to ext/lcd/SSD1306.h.old diff --git a/ext/lcd/SSD1306.h.testing b/ext/lcd/SSD1306.h.testing new file mode 100644 index 0000000..aaaa98c --- /dev/null +++ b/ext/lcd/SSD1306.h.testing @@ -0,0 +1,324 @@ +#ifndef LCD_SSD1306 +#define LCD_SSD1306 + +#include "../../io/SoftI2C.h" + +// https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf + +//#define SSD1306_128_64 1 +//#define SSD1306_64_48 1 // https://github.com/mcauser/Adafruit_SSD1306/blob/esp8266-64x48/Adafruit_SSD1306.cpp + +#if defined SSD1306_128_64 + #define SSD1306_LCDWIDTH 128 + #define SSD1306_LCDHEIGHT 64 +#elif defined SSD1306_128_32 + #define SSD1306_LCDWIDTH 128 + #define SSD1306_LCDHEIGHT 32 +#elif defined SSD1306_96_16 + #define SSD1306_LCDWIDTH 96 + #define SSD1306_LCDHEIGHT 16 +#elif defined SSD1306_64_48 + #define SSD1306_LCDWIDTH 64 + #define SSD1306_LCDHEIGHT 48 +#else + #error "SSD1306 display size not defined" +#endif + +#define SSD1306_SETCONTRAST 0x81 +#define SSD1306_DISPLAYALLON_RESUME 0xA4 +#define SSD1306_DISPLAYALLON 0xA5 +#define SSD1306_NORMALDISPLAY 0xA6 +#define SSD1306_INVERTDISPLAY 0xA7 +#define SSD1306_DISPLAYOFF 0xAE +#define SSD1306_DISPLAYON 0xAF + +#define SSD1306_SETDISPLAYOFFSET 0xD3 +#define SSD1306_SETCOMPINS 0xDA + +#define SSD1306_SETVCOMDETECT 0xDB + +#define SSD1306_SETDISPLAYCLOCKDIV 0xD5 +#define SSD1306_SETPRECHARGE 0xD9 + +#define SSD1306_SETMULTIPLEX 0xA8 + +#define SSD1306_SETLOWCOLUMN 0x00 +#define SSD1306_SETHIGHCOLUMN 0x10 + +#define SSD1306_SETSTARTLINE 0x40 + +#define SSD1306_MEMORYMODE 0x20 +#define SSD1306_COLUMNADDR 0x21 +#define SSD1306_PAGEADDR 0x22 + +#define SSD1306_COMSCANINC 0xC0 +#define SSD1306_COMSCANDEC 0xC8 + +#define SSD1306_SEGREMAP 0xA0 + +#define SSD1306_CHARGEPUMP 0x8D + +#define SSD1306_EXTERNALVCC 0x1 +#define SSD1306_SWITCHCAPVCC 0x2 + +// Scrolling #defines +#define SSD1306_ACTIVATE_SCROLL 0x2F +#define SSD1306_DEACTIVATE_SCROLL 0x2E +#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 +#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26 +#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27 +#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29 +#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A + + + +template class SSD1306 { + +private: + + static constexpr uint8_t ADDR7 = 0b0111100; + bool inited = false; + + I2C& i2c; + +public: + + SSD1306(I2C& i2c) : i2c(i2c) { + + } + + bool isPresent() { + return i2c.query(ADDR7); + } + + /** checks if LCD is present and initializes it once / when it was gone */ + bool isPresentAndInit() { + bool present = isPresent(); + if (!present) {inited = false;} + if ( present && !inited) {initOnce();} + return present; + } + + void initOnce() { + if (inited) {return;} + init(); + inited = true; + } + + + void flush(const uint8_t* data) { + + + sendCommand(0xC0); + + sendCommand2(0x20, 0b11111100); + + // special handling for 64x48 oled shield + #if SSD1306_LCDWIDTH == 64 && SSD1306_LCDHEIGHT == 48 + sendCommand(SSD1306_COLUMNADDR); + sendCommand(32); + sendCommand(32 + SSD1306_LCDWIDTH - 1); + #else + //sendCommand2(SSD1306_COLUMNADDR, 0, SSD1306_LCDWIDTH-1); + sendCommand(SSD1306_COLUMNADDR); + sendCommand(0); // Column start address (0 = reset) + sendCommand(SSD1306_LCDWIDTH-1); // Column end address (127 = reset) + + #endif + + + //sendCommand2(SSD1306_PAGEADDR, 0, (SSD1306_LCDHEIGHT/8)-1); + + sendCommand(SSD1306_PAGEADDR); + sendCommand(0); // Page start address (0 = reset) + sendCommand( (SSD1306_LCDHEIGHT/8)-1 ); // Page end address + + + sendCommand(0x00 | 0x00); + sendCommand(0x10 | 0x00); + sendCommand(0xB0 | 0x02); + + + + + +// #if SSD1306_LCDHEIGHT == 64 +// sendCommand(7); // Page end address +// #endif +// #if SSD1306_LCDHEIGHT == 48 +// sendCommand(3); // Page end address +// #endif +// #if SSD1306_LCDHEIGHT == 32 +// sendCommand(3); // Page end address +// #endif +// #if SSD1306_LCDHEIGHT == 16 +// sendCommand(1); // Page end address +// #endif + + + + + +// for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { +// // send a bunch of data in one xmission +// i2c::startWrite(ADDR7); +// bool ok = i2c::writeByteAndCheck(0x40); +// if (!ok) {os_printf("failed line\n");} + +// for (uint8_t x = 0; x < 16; ++x) { +// i2c::writeByteAndCheck(data[i]); +// ++i; +// } +// i--; +// i2c::stop(); +// } + + i2c.startWrite(ADDR7); + bool ok = i2c.writeByteAndCheck(0x40); + if (!ok) {os_printf("failed write data\n");} + + //for (uint16_t i=0; i < (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { + for (uint16_t i=0; i < 16; i++) { + i2c.writeByteAndCheck(data[i]); + usleep(1000); + } + + i2c.stop(); + + } + + +private: + + void init() { + + uint8_t vccstate = 0; + + sendCommand(SSD1306_DISPLAYOFF); // 0xAE + + sendCommand(SSD1306_SETDISPLAYCLOCKDIV, 0x80); // 0xD5, the suggested ratio 0x80 + + sendCommand(SSD1306_SETMULTIPLEX, SSD1306_LCDHEIGHT-1); // 0xA8: multiplexer (31 == 32MUX, 63 == 64MUX) + + sendCommand(SSD1306_SETDISPLAYOFFSET, 0x00); // 0xD3: vertical shift 0-63, no offset + + sendCommand(SSD1306_SETSTARTLINE | 0x0); // line #0 + + if (vccstate == SSD1306_EXTERNALVCC) { + sendCommand(SSD1306_CHARGEPUMP, 0x10); // 0x8D + } else { + sendCommand(SSD1306_CHARGEPUMP, 0x14); // 0x8D + } + + sendCommand(SSD1306_MEMORYMODE, 0x00); // 0x20: memory mode(hor/ver/page) -> hor + + sendCommand(SSD1306_SEGREMAP | 0x0); + + //sendCommand(SSD1306_COMSCANINC); // rotate 0 + sendCommand(SSD1306_COMSCANDEC); // rotate 180? + + // OLD +// #if defined SSD1306_128_32 +// sendCommand(SSD1306_SETCOMPINS); // 0xDA +// sendCommand(0x02); +// sendCommand(SSD1306_SETCONTRAST); // 0x81 +// sendCommand(0x8F); + +// #elif defined SSD1306_128_64 +// sendCommand(SSD1306_SETCOMPINS); // 0xDA +// sendCommand(0x12); +// sendCommand(SSD1306_SETCONTRAST); // 0x81 +// if (vccstate == SSD1306_EXTERNALVCC) +// { sendCommand(0x9F); } +// else +// { sendCommand(0xCF); } + +// #elif defined SSD1306_96_16 +// sendCommand(SSD1306_SETCOMPINS); // 0xDA +// sendCommand(0x2); //ada x12 +// sendCommand(SSD1306_SETCONTRAST); // 0x81 +// if (vccstate == SSD1306_EXTERNALVCC) +// { sendCommand(0x10); } +// else +// { sendCommand(0xAF); } + +// #endif + + // NEW + sendCommand(SSD1306_SETCOMPINS, 0x12); // 0xDA + + if (vccstate == SSD1306_EXTERNALVCC) { + sendCommand(0x9F); + } else { + sendCommand(0xCF); + } + + + if (vccstate == SSD1306_EXTERNALVCC) { + sendCommand(SSD1306_SETPRECHARGE, 0x22); // 0xd9 + } else { + sendCommand(SSD1306_SETPRECHARGE, 0xF1); // 0xd9 + } + + sendCommand(SSD1306_SETVCOMDETECT, 0x40); // 0xDB + + sendCommand(SSD1306_DISPLAYALLON_RESUME); // 0xA4 + + sendCommand(SSD1306_NORMALDISPLAY); // 0xA6 + + sendCommand(SSD1306_DEACTIVATE_SCROLL); + + sendCommand(SSD1306_DISPLAYON); //--turn on oled panel + + } + +private: + + + + void sendCommand(uint8_t cmd) { + bool ok; + ok = i2c.startWrite(ADDR7); + if (!ok) {os_printf("failed start write\n");} + ok = i2c.writeByteAndCheck(0x00); // command + if (!ok) {os_printf("failed command mode\n");} + ok = i2c.writeByteAndCheck(cmd); + if (!ok) {os_printf("failed command\n");} + i2c.stop(); + } + + void sendCommand(uint8_t cmd, uint8_t v1) { + sendCommand(cmd); + sendCommand(v1); + } + + void sendCommand(uint8_t cmd, uint8_t v1, uint8_t v2) { + sendCommand(cmd); + sendCommand(v1); + sendCommand(v2); + } + + void sendCommand2(uint8_t cmd, uint8_t v1) { + i2c.startWrite(ADDR7); + i2c.writeByteAndCheck(0x00); + i2c.writeByteAndCheck(cmd); + //i2c.writeByteAndCheck(0x00); + i2c.writeByteAndCheck(v1); + i2c.stop(); + } + + void sendCommand2(uint8_t cmd, uint8_t v1, uint8_t v2) { + i2c.startWrite(ADDR7); + i2c.writeByteAndCheck(0x00); + i2c.writeByteAndCheck(cmd); + //i2c.writeByteAndCheck(0x00); + i2c.writeByteAndCheck(v1); + //i2c.writeByteAndCheck(0x00); + i2c.writeByteAndCheck(v2); + i2c.stop(); + } + +}; + + +#endif diff --git a/ext/sens/AHT2x.h b/ext/sens/AHT2x.h new file mode 100644 index 0000000..b145dcb --- /dev/null +++ b/ext/sens/AHT2x.h @@ -0,0 +1,98 @@ +#pragma once + +/** + * humidity and temperature sensor + * https://asairsensors.com/wp-content/uploads/2021/09/Data-Sheet-AHT21-Humidity-and-Temperature-Sensor-ASAIR-V1.0.03.pdf + */ +template class AHT2x { + +private: + + I2C& i2c; + static constexpr const uint8_t ADDR = 0x38; + static constexpr const char* NAME = "AHT2x"; + + static constexpr const uint8_t BIT_BUSY = 0x80; + static constexpr const uint8_t BIT_CALIBRATED = 0x08; + +public: + + struct Result { + float temp; + float humi; + }; + +public: + + AHT2x(I2C& i2c) : i2c(i2c) { + + } + + void init() { + softReset(); + int ok = calibrate(); + printf("aht calib: %d\n", ok); + } + + /** is the device present on the bus? */ + bool isPresent() { + return i2c.query(ADDR); + } + + void softReset() { + uint8_t cmd = 0xBA; + i2c.writeRaw(ADDR, 1, &cmd); + DELAY_MS(100); + } + + bool calibrate() { + uint8_t cmdCalibrate[3] = {0xBE, 0x08, 0x00}; + i2c.writeRaw(ADDR, 3, cmdCalibrate); + waitUntilDone(); + return readStatus() & BIT_CALIBRATED; + } + + void waitUntilDone() { + for (uint8_t i = 0; i < 200; ++i) { + printf("."); + if (!(readStatus() & BIT_BUSY)) {break;} + DELAY_MS(1); + } + printf("x\n"); + } + + uint8_t readStatus() { + uint8_t status = 0; + i2c.readRaw(ADDR, 1, &status); + return status; + } + + Result measure() { + + // trigger measurement + uint8_t cmdMeasure[3] = {0xAC, 0x33, 0x00}; + i2c.writeRaw(ADDR, 3, cmdMeasure); + + // fetch result, also waits until the busy-bit is cleared + uint8_t raw[6]; + for(uint8_t i = 0; i < 50; ++i) { + DELAY_MS(10); + i2c.readRaw(ADDR, 6, raw); + bool busy = (raw[0] & BIT_BUSY); + if (!busy) {break;} + } + + // calculate + Result res; + + uint32_t _humi = ((raw[1] << 16) | (raw[2] << 8) | (raw[3] << 0)) >> 4; + res.humi = _humi * 100 / 1048576.0f; + + uint32_t _temp = ((raw[3] & 0x0F) << 16) | (raw[4] << 8) | (raw[5] << 0); + res.temp = (_temp * 200 / 1048576.0f) - 50; + + return res; + + } + +}; diff --git a/ext/sens/BME280.h b/ext/sens/BME280.h index ea970f4..6bf966f 100644 --- a/ext/sens/BME280.h +++ b/ext/sens/BME280.h @@ -4,15 +4,29 @@ #include "../../Platforms.h" #include "../../Debug.h" +// https://www.mouser.com/datasheet/2/783/BST-BME280-DS002-1509607.pdf + template class BME280 { + I2C& i2c; + static constexpr const char* NAME = "BME280"; - static constexpr uint8_t ADDR7 = 0b1110110; + static constexpr uint8_t ADDR7_1 = 0b1110110; // 0x76 + static constexpr uint8_t ADDR7_2 = 0b1110111; // 0x77 + + static constexpr uint8_t MODE_SLEEP = 0b00; + static constexpr uint8_t MODE_FORCED = 0b01; // manual sampling + static constexpr uint8_t MODE_NORMAL = 0b11; // periodic background sampling + + + uint8_t ADDR7; + static constexpr uint8_t REG_CTRL1 = 0xF2; // humidity static constexpr uint8_t REG_CTRL2 = 0xF4; // temp, pressure, mode - + static constexpr uint8_t REG_CONFIG = 0xF5; + static constexpr uint8_t REG_STATUS = 0xF3; static constexpr uint8_t REG_PRESSURE = 0xF7; static constexpr uint8_t REG_TEMPERATURE= 0xFA; @@ -22,9 +36,6 @@ template class BME280 { static constexpr uint8_t REG_DIG_T2 = 0x8A; static constexpr uint8_t REG_DIG_T3 = 0x8C; - -public: - bool started = false; /** internal sensor calibration values */ @@ -52,24 +63,141 @@ public: int8_t dig_H6 = 0; } cal; + +public: + + struct Result { + float temp; + float humi; + float pres; + }; + + enum class Interval : uint8_t { + INT_500_US = 0b000, + INT_62_MS = 0b001, + INT_125_MS = 0b010, + INT_250_MS = 0b011, + INT_500_MS = 0b100, + INT_1000_MS = 0b101, + INT_10_MS = 0b110, + INT_20_MS = 0b111, + }; + enum class Oversample : uint8_t { + X1 = 0b001, + X2 = 0b010, + X4 = 0b011, + X8 = 0b100, + X16 = 0b101, + }; + +private: + + struct Config { + + Oversample temp = Oversample::X2; + Oversample pres = Oversample::X16; + Oversample humi = Oversample::X2; + + uint8_t mode = MODE_NORMAL; + Interval interval = Interval::INT_500_MS; + uint8_t fir = 0b000; // fir filter disabled + + } cfg; + +public: - I2C& i2c; - - BME280(I2C& i2c) : i2c(i2c) { + BME280(I2C& i2c, uint8_t addrOffset = 0) : i2c(i2c), ADDR7(ADDR7_1 + addrOffset) { } - - + bool isPresent() { return i2c.query(ADDR7); } + void init() { + readCalib(); + } + + void setSampling(Oversample temp, Oversample pres, Oversample humi) { + cfg.temp = temp; + cfg.pres = pres; + cfg.humi = humi; + } + + uint8_t getStatus() { + uint8_t res[1]; + i2c.readReg(ADDR7, REG_STATUS, 1, res); + return 0; + } + + /** start periodic background measurement (tends to sensor-self-heating??) */ + void measurePeriodic(Interval ival) { + cfg.mode = MODE_NORMAL; + cfg.interval = ival; + commitConfig(); + } + + /** measure only once, takes some time before NEW results are present (seems more stable in terms of temperature) */ + void measureOnce() { + cfg.mode = MODE_FORCED; + commitConfig(); + } + + /** get the most recent readings */ + Result getAll() { + Result res; + res.temp = getTemperature(); + res.humi = getHumidity(); + res.pres = getPressure(); + return res; + } + + /** get most recent pressure reading (hPa) */ + float getPressure() { + uint8_t res[3]; + i2c.readReg(ADDR7, REG_PRESSURE, 3, res); + //os_printf("res: %d - %d - %d \n", res[0], res[1], res[2]); + const uint32_t tmp = ((res[0] << 16) | (res[1] << 8) | (res[2] << 0)) >> 4; + const uint32_t pres = BME280_compensate_P_int64(tmp); + const float presF = pres / 256.0f / 100.0f; // convert from Q24.8 to float and from Pa to hPa + //const uint32_t p0 = pres / 256; + //const uint32_t p1 = (uint32_t) presF; + //const uint32_t p2 = (presF - p1) * 100000; + //Log::addInfo((NAME, "[pres] ADC: %d -> %d Pa | %d.%d hPa", tmp, p0, p1,p2); + return presF; + } + + /** get most recent temperature reading */ + float getTemperature() { + uint8_t res[3]; + i2c.readReg(ADDR7, REG_TEMPERATURE, 3, res); + const uint32_t tmp = ((res[0] << 16) | (res[1] << 8) | (res[2] << 0)) >> 4; + const int32_t temp = BME280_compensate_T_int32(tmp); + const float tempF = temp / 100.0f; + return tempF; + } + + /** get the most recent humidity reading */ + float getHumidity() { + uint8_t res[2]; + i2c.readReg(ADDR7, REG_HUMIDITY, 2, res); + //os_printf("res: %d - %d \n", res[0], res[1]); + const uint32_t tmp = (res[0] << 8) | (res[1] << 0); + const int32_t humi = bme280_compensate_H_int32(tmp); + const float humiF = humi / 1024.0f; + //const uint16_t h0 = humi / 1024; + //const uint16_t h1 = (uint16_t) humiF; + //const uint16_t h2 = (humiF - humi) * 10000; + //Log::addInfo((NAME, "[humi] ADC: %d -> %d -> %d.%d %%", tmp, h0, h1,h2); + return humiF; + } + private: void readCalib() { - debugMod(NAME, "readCalib()"); + Log::addInfo(NAME, "readCalib()"); // read all 24 calibration bytes for temperature and pressure uint8_t b1[24]; @@ -93,137 +221,33 @@ private: i2c.readReg(ADDR7, 0xA1, 1, &cal.dig_H1); i2c.readReg(ADDR7, 0xE1, 7, b1); cal.dig_H2 = (b1[1] << 8) | b1[0]; - cal.dig_H3 = b1[3]; - cal.dig_H4 = (b1[3] << 4) | (b1[4] & 0b000001111); - cal.dig_H5 = (b1[5] << 4) | ((b1[4] & 0b111100000) >> 4); + cal.dig_H3 = b1[2]; + cal.dig_H4 = (b1[3] << 4) | (b1[4] & 0b00001111); + cal.dig_H5 = (b1[5] << 4) | ((b1[4] & 0b11110000) >> 4); cal.dig_H6 = (b1[6]); //os_printf("calib temp: %d %d %d\n", cal.dig_T1, cal.dig_T2, cal.dig_T3); //os_printf("calib pres: %d %d %d %d %d %d %d %d %d\n", cal.dig_P1, cal.dig_P2, cal.dig_P3, cal.dig_P4, cal.dig_P5, cal.dig_P6, cal.dig_P7, cal.dig_P8, cal.dig_P9); //os_printf("calib humi: %d %d %d %d %d %d\n", cal.dig_H1, cal.dig_H2, cal.dig_H3, cal.dig_H4, cal.dig_H5, cal.dig_H6); - //debugMod3(NAME, "calTemp: %d %d %d", cal.dig_T1, cal.dig_T2, cal.dig_T3); - //debugMod9(NAME, "calPres: %d %d %d %d %d %d %d %d %d", cal.dig_P1, cal.dig_P2, cal.dig_P3, cal.dig_P4, cal.dig_P5, cal.dig_P6, cal.dig_P7, cal.dig_P8, cal.dig_P9); - //debugMod6(NAME, "calHumi: %d %d %d %d %d %d", cal.dig_H1, cal.dig_H2, cal.dig_H3, cal.dig_H4, cal.dig_H5, cal.dig_H6); + Log::addInfo(NAME, "calTemp: %d %d %d", cal.dig_T1, cal.dig_T2, cal.dig_T3); + Log::addInfo(NAME, "calPres: %d %d %d %d %d %d %d %d %d", cal.dig_P1, cal.dig_P2, cal.dig_P3, cal.dig_P4, cal.dig_P5, cal.dig_P6, cal.dig_P7, cal.dig_P8, cal.dig_P9); + Log::addInfo(NAME, "calHumi: %d %d %d %d %d %d", cal.dig_H1, cal.dig_H2, cal.dig_H3, cal.dig_H4, cal.dig_H5, cal.dig_H6); } - - void start() { - debugMod(NAME, "start()"); - const uint8_t cfgHumi = 0b101; // 16x oversampling - const uint8_t cfgPres = 0b101; // 16x oversampling - const uint8_t cfgTemp = 0b101; // 16x oversampling - const uint8_t cfgMode = 0b11; - const uint8_t cfg1 = (cfgHumi << 1); - const uint8_t cfg2 = (cfgTemp << 5) | (cfgPres << 2) | (cfgMode << 0); - i2c.writeReg(ADDR7, REG_CTRL1, 1, &cfg1); - i2c.writeReg(ADDR7, REG_CTRL2, 1, &cfg2); + + void commitConfig() { + + const uint8_t ctrl1 = (uint8_t(cfg.humi) << 0); + const uint8_t ctrl2 = (uint8_t(cfg.temp) << 5) | (uint8_t(cfg.pres) << 2) | (uint8_t(cfg.mode) << 0); + const uint8_t conf = (uint8_t(cfg.interval) << 5) | (cfg.fir << 2); + + i2c.writeReg8(ADDR7, REG_CTRL1, MODE_SLEEP); + i2c.writeReg8(ADDR7, REG_CTRL1, ctrl1); + i2c.writeReg8(ADDR7, REG_CTRL2, ctrl2); + i2c.writeReg8(ADDR7, REG_CONFIG, conf); + } - - -public: - - void startOnce() { - if (started) {return;} - debugMod(NAME, "startOnce()"); - readCalib(); - start(); - started = true; - } - - uint8_t getStatus() { - uint8_t res[1]; - i2c.readReg(ADDR7, REG_STATUS, 1, res); - //os_printf("Status: %d \n", res[0]); - return 0; - } - - /** get current pressure in hPa */ - float getPressure() { - uint8_t res[3]; - i2c.readReg(ADDR7, REG_PRESSURE, 3, res); - //os_printf("res: %d - %d - %d \n", res[0], res[1], res[2]); - const uint32_t tmp = ((res[0] << 16) | (res[1] << 8) | (res[2] << 0)) >> 4; - const uint32_t pres = BME280_compensate_P_int64(tmp); - const float presF = pres / 256.0f / 100.0f; // convert from Q24.8 to float and from Pa to hPa - //const uint32_t p0 = pres / 256; - //const uint32_t p1 = (uint32_t) presF; - //const uint32_t p2 = (presF - p1) * 100000; - //debugMod4(NAME, "[pres] ADC: %d -> %d Pa | %d.%d hPa", tmp, p0, p1,p2); - return presF; - } - - float getTemperature() { - uint8_t res[3]; - i2c.readReg(ADDR7, REG_TEMPERATURE, 3, res); - //os_printf("res: %d - %d - %d \n", res[0], res[1], res[2]); - const uint32_t tmp = ((res[0] << 16) | (res[1] << 8) | (res[2] << 0)) >> 4; - const int32_t temp = BME280_compensate_T_int32(tmp); - const float tempF = temp / 100.0f; - //debugMod2(NAME, "[temp] ADC: %d -> %d", tmp, temp); - return tempF; - } - - float getHumidity() { - uint8_t res[2]; - i2c.readReg(ADDR7, REG_HUMIDITY, 2, res); - //os_printf("res: %d - %d \n", res[0], res[1]); - const uint32_t tmp = (res[0] << 8) | (res[1] << 0); - const int32_t humi = bme280_compensate_H_int32(tmp); - const float humiF = humi / 1024.0f; - //const uint16_t h0 = humi / 1024; - //const uint16_t h1 = (uint16_t) humiF; - //const uint16_t h2 = (humiF - humi) * 10000; - //debugMod4(NAME, "[humi] ADC: %d -> %d -> %d.%d %%", tmp, h0, h1,h2); - return humiF; - } - - /* - bool readRegister(const uint8_t addr, uint8_t* dst, const uint8_t len) { - - bool ok; - - // address the slave in write mode and select the first register to read - ok = i2c.startWrite(ADDR7); - if (!ok) {printf("failed start write\n"); return false;} - ok = i2c.writeByteAndCheck(addr); - if (!ok) {printf("failed to select register %d\n", addr); return false;} - - //i2c::stop(); - - // address the slave in read mode and read [len] registers - ok = i2c.startRead(ADDR7); - if (!ok) {printf("failed start read\n"); return 0;} - i2c.readBytes(dst, len); - - // done - i2c.stop(); - return true; - - } - - bool writeRegister(const uint8_t addr, const uint8_t* src, const uint8_t len) { - - bool ok; - - // address the slave in write mode and select the first register to read - ok = i2c.startWrite(ADDR7); - if (!ok) {printf("failed start write\n"); return false;} - ok = i2c.writeByteAndCheck(addr); - if (!ok) {printf("failed to select register %d\n", addr); return false;} - ok = i2c.writeBytesAndCheck(src, len); - if (!ok) {printf("failed to write register contents \n"); return false;} - - // done - i2c.stop(); - return true; - - } - - */ - -private: - /** conversions from ADC values to real-world values. from Bosch BMP280 manual! */ using BME280_S32_t = int32_t; @@ -251,7 +275,7 @@ private: var2 = var2 + ((var1*(BME280_S64_t)cal.dig_P5)<<17); var2 = var2 + (((BME280_S64_t)cal.dig_P4)<<35); var1 = ((var1 * var1 * (BME280_S64_t)cal.dig_P3)>>8) + ((var1 * (BME280_S64_t)cal.dig_P2)<<12); - var1 = (((((BME280_S64_t)1)<<47)+var1))*((BME280_S64_t)cal.dig_P1)>>33; + var1 = (((((BME280_S64_t)1l)<<47)+var1))*((BME280_S64_t)cal.dig_P1)>>33; if (var1 == 0) {return 0;} // avoid exception caused by division by zero p = 1048576-adc_P; p = (((p<<31)-var2)*3125)/var1; diff --git a/ext/sens/CMPS10.h b/ext/sens/CMPS10.h new file mode 100644 index 0000000..e9b5e24 --- /dev/null +++ b/ext/sens/CMPS10.h @@ -0,0 +1,74 @@ +#pragma once + + +#include "../../Platforms.h" +#include "../../Debug.h" + +/** + * CMPS10 3-axis magnetometer/accelerometer module + * https://www.robot-electronics.co.uk/htm/cmps10i2c.htm + */ +template class CMPS10 { + + I2C& i2c; + + static constexpr const char* NAME = "CMPS10"; + + static constexpr uint8_t ADDR7 = 0xC0>>1; + + static constexpr uint8_t REG_MAG_X = 10; //10+11; + static constexpr uint8_t REG_MAG_Y = 12; //12+13; + static constexpr uint8_t REG_MAG_Z = 14; //14+15; + + static constexpr uint8_t REG_ACC_X = 16; //16+17; + static constexpr uint8_t REG_ACC_Y = 18; //18+19; + static constexpr uint8_t REG_ACC_Z = 20; //20+21; + + +public: + + struct Magnetometer { + int16_t x; + int16_t y; + int16_t z; + }; + + struct Acceleromter { + int16_t x; + int16_t y; + int16_t z; + }; + +public: + + CMPS10(I2C& i2c, uint8_t addrOffset = 0) : i2c(i2c){ + + } + + + bool isPresent() { + return i2c.query(ADDR7); + } + + Magnetometer getMagnetometer() { + uint8_t res[6]; + i2c.readReg(ADDR7, REG_MAG_X, 6, res); + Magnetometer mag; + mag.x = ((res[0] << 8) | (res[1] << 0)); + mag.y = ((res[2] << 8) | (res[3] << 0)); + mag.z = ((res[4] << 8) | (res[5] << 0)); + return mag; + } + + Acceleromter getAcceleromter() { + uint8_t res[6]; + i2c.readReg(ADDR7, REG_ACC_X, 6, res); + Acceleromter acc; + acc.x = ((res[0] << 8) | (res[1] << 0)); + acc.y = ((res[2] << 8) | (res[3] << 0)); + acc.z = ((res[4] << 8) | (res[5] << 0)); + return acc; + } + +}; + diff --git a/ext/sens/ENS160.h b/ext/sens/ENS160.h new file mode 100644 index 0000000..95b35ba --- /dev/null +++ b/ext/sens/ENS160.h @@ -0,0 +1,146 @@ +#pragma once + +/** + * a digital multi-gas sensor for indoor air quality monitoring + * https://www.sciosense.com/wp-content/uploads/documents/SC-001224-DS-7-ENS160-Datasheet.pdf + */ +template class ENS160 { + +private: + + I2C& i2c; + static constexpr const uint8_t ADDR1 = 0x52; + static constexpr const uint8_t ADDR2 = 0x53; + uint8_t ADDR; + + static constexpr const char* NAME = "ENS160"; + + static constexpr const uint8_t REG_PART_ID = 0x00; + static constexpr const uint8_t REG_OPMODE = 0x10; + static constexpr const uint8_t REG_TEMP_IN = 0x13; + static constexpr const uint8_t REG_RH_IN = 0x15; + static constexpr const uint8_t REG_DEVICE_STATUS = 0x20; + static constexpr const uint8_t REG_DATA_AQI = 0x21; + static constexpr const uint8_t REG_DATA_TVOC = 0x22; + static constexpr const uint8_t REG_DATA_ECO2 = 0x24; + + + +public: + + enum class Mode : uint8_t { + DEEP_SLEEP = 0x00, + IDLE = 0x01, + STANDARD = 0x02, + RESET = 0xF0, + }; + + union Status { + + uint8_t raw; + + struct { + uint8_t newgpr : 1; + uint8_t newdat : 1; + uint8_t valid : 2; + uint8_t dummy : 2; + uint8_t stater : 1; + uint8_t statas : 1; + } __attribute__((__packed__)); + + bool isNormal() const {return valid == 0;} + bool isWarmUp() const {return valid == 1;} + bool isStartUp() const {return valid == 2;} + bool isInvalid() const {return valid == 3;} + + } __attribute__((__packed__)); + + union Result { + + uint8_t raw[6]; + + struct { + Status status; + uint8_t aqi; + uint16_t tvoc; + uint16_t eco2; + } __attribute__((__packed__)); + + } __attribute__((__packed__)); + +public: + + ENS160(I2C& i2c, uint8_t addr = ADDR1) : i2c(i2c), ADDR(addr) { + + } + + /** always 0x01 0x60 */ + uint16_t getID() { + uint16_t res = 0; + i2c.readReg(ADDR, 0x00, 2, (uint8_t*)&res); + return res; + } + + /** switch the mode of operation */ + void setMode(Mode m) { + i2c.writeReg8(ADDR, REG_OPMODE, (uint8_t)m); + DELAY_MS(250); // not mentioned in the data-sheet but important? + } + + /** set the current ambient temperature - for compensation */ + void setTemp(float celsius) { + float kelvin = celsius + 273.15; + uint16_t tmp = (uint16_t) (kelvin * 64); + i2c.writeReg(ADDR, REG_TEMP_IN, 2, (uint8_t*)&tmp); + } + + /** set the current ambient humidity (in %) - for compensation */ + void setHumi(uint8_t humi) { + uint16_t tmp = humi * 512; + i2c.writeReg(ADDR, REG_RH_IN, 2, (uint8_t*)&tmp); + } + + /** status + aqi + tvoc + eco2 */ + Result getAll() { + Result res; + memset(res.raw, 0, 6); + i2c.readReg(ADDR, REG_DEVICE_STATUS, 6, res.raw); + res.status = getStatus(); + //res.aqi = getAQI(); + //res.tvoc = getTVOC(); + //res.eco2 = getECO2(); + return res; + } + + Status getStatus() { + Status res; + res.raw = i2c.readReg8(ADDR, REG_DEVICE_STATUS); + return res; + } + + uint8_t getAQI() { + uint8_t tmp = 0; + i2c.readReg(ADDR, REG_DATA_AQI, 1, &tmp); + return tmp & 0b111; + } + + uint16_t getTVOC() { + uint16_t tmp = 0; + i2c.readReg(ADDR, REG_DATA_TVOC, 2, (uint8_t*)&tmp); + return tmp; + } + + uint16_t getECO2() { + uint16_t tmp = 0; + i2c.readReg(ADDR, REG_DATA_ECO2, 2, (uint8_t*)&tmp); + return tmp; + } + + + + /** is the device present on the bus? */ + bool isPresent() { + return i2c.query(ADDR); + } + +}; diff --git a/ext/sens/HTU2x.h b/ext/sens/HTU2x.h new file mode 100644 index 0000000..cc95c0c --- /dev/null +++ b/ext/sens/HTU2x.h @@ -0,0 +1,101 @@ + + +#pragma once + +/** + * humidity and temperature sensor + * https://www.ttieurope.com/content/dam/tti-europe/manufacturers/te-connectivity/resources/ENG_DS_HPC199_6_A6.pdf + * + * this sensor seems to be a bit stubborn.. requiring active polling until it is finished + * just waiting some time does not seem to work + * + */ +template class HTU2x { + +private: + + I2C& i2c; + static constexpr const uint8_t ADDR = 0x40; + static constexpr const char* NAME = "HTU2x"; + + static constexpr const uint8_t CMD_QUERY_TEMP = 0xF3; + static constexpr const uint8_t CMD_QUERY_HUMI = 0xF5; + static constexpr const uint8_t CMD_READ_USER_REG = 0xE7; + static constexpr const uint8_t CMD_SOFT_RESET = 0xFE; + + + +public: + + HTU2x(I2C& i2c) : i2c(i2c) { + + } + + /** is the device present on the bus? */ + bool isPresent() { + return i2c.query(ADDR); + } + + struct Result { + float temp; + float humi; + float humiComp; + }; + + /** trigger a single measurement */ + Result singleMeasure() { + + uint8_t tmp[3]; // 2 bytes + checksum + Result res; + + sendCMD(CMD_QUERY_TEMP); + if (waitForStart()) { + i2c.readBytes(tmp, 3); + i2c.stop(); + uint16_t t = ((tmp[0]<<8)|(tmp[1]<<0)) & 0xFFFC; + //printf("a: %d\n", t); + res.temp = -46.85f + 175.72 * t / float(1<<16); + } + + sendCMD(CMD_QUERY_HUMI); + if (waitForStart()) { + i2c.readBytes(tmp, 3); + i2c.stop(); + uint16_t h = ((tmp[0]<<8)|(tmp[1]<<0)) & 0xFFFC; + //printf("b: %d\n", h); + res.humi = -6 + 125 * h / float(1<<16); + res.humiComp = res.humi + (-0.15 * (25 - res.temp)); + } + + return res; + + } + +private: + + bool waitForStart() { + for (int i = 0; i < 1024; ++i) { + if (i2c.startRead(ADDR)) {return true;} + } + return false; + } + + void sendCMD(uint8_t cmd) { + i2c.writeRaw(ADDR, 1, &cmd); + } + + void readUserRegister() { + + i2c.writeRaw(ADDR, 1, &CMD_SOFT_RESET); + + vTaskDelay(100 / portTICK_PERIOD_MS); + + uint8_t val = 0xaa; + i2c.readReg(ADDR, CMD_READ_USER_REG, 1, &val); + + printf("user: %d\n", val); + + } + + +}; diff --git a/ext/sens/LIS3MDL.h b/ext/sens/LIS3MDL.h new file mode 100644 index 0000000..9460a1e --- /dev/null +++ b/ext/sens/LIS3MDL.h @@ -0,0 +1,123 @@ +#pragma once + + +#include "../../Platforms.h" +#include "../../Debug.h" + +/** + * LIS3MDL 3-axis magnetometer module + * https://www.st.com/resource/en/datasheet/lis3mdl.pdf + */ +template class LIS3MDL { + + I2C& i2c; + + static constexpr const char* NAME = "LIS3MDL"; + + static constexpr uint8_t ADDR7 = 0b0011100; + + static constexpr uint8_t CTRL_REG1 = 0x20; + static constexpr uint8_t CTRL_REG2 = 0x21; + static constexpr uint8_t CTRL_REG3 = 0x22; + static constexpr uint8_t CTRL_REG4 = 0x23; + static constexpr uint8_t CTRL_REG5 = 0x24; + + static constexpr uint8_t REG_X = 0x28; //0x28(L= + 0x29(H) + static constexpr uint8_t REG_Y = 0x2A; //0x2A(L) + 0x2B(H) + static constexpr uint8_t REG_Z = 0x2C; //0x2C(L) + 0x2D(H) + + + +public: + + struct Magnetometer { + int16_t x; + int16_t y; + int16_t z; + }; + + struct Acceleromter { + int16_t x; + int16_t y; + int16_t z; + }; + + enum class Resolution : uint8_t { + GAUSS_4 = 0b00, + GAUSS_8 = 0b01, + GAUSS_12 = 0b10, + GAUSS_16 = 0b11, + }; + + enum class AxisMode : uint8_t { + LOW_POWER = 0b00, + MEDIUM_PERFORMANCE = 0b01, + HIGH_PERFORMANCE = 0b10, + ULTRA_HIGH_PERFORMANCE = 0b11, + }; + + enum class SamplingRate : uint8_t { + HZ_0_625, + HZ_1_25, + HZ_2_5, + HZ_5, + HZ_10, + HZ_20, + HZ_40, + HZ_80, + }; + + enum class OperationMode : uint8_t { + CONTINUOUS = 0b00, + SINGLE = 0b01, + OFF = 0b11, + }; + +public: + + LIS3MDL(I2C& i2c, uint8_t addrOffset = 0) : i2c(i2c){ + + } + + + bool isPresent() { + return i2c.query(ADDR7); + } + + + + void setResolution(Resolution res) { + getAndSet(CTRL_REG2, 0b01100000, (uint8_t)res << 5); + } + + void setAxisMode(AxisMode mode) { + getAndSet(CTRL_REG1, 0b01100000, (uint8_t)mode << 5); // x and y + getAndSet(CTRL_REG4, 0b00001100, (uint8_t)mode << 2); // z + } + + void setSamplingRate(SamplingRate rate) { + getAndSet(CTRL_REG1, 0b00011100, (uint8_t)rate << 2); + } + + void setOperationMode(OperationMode mode) { + getAndSet(CTRL_REG3, 0b00000011, (uint8_t)mode << 0); + } + + Magnetometer getMagnetometer() { + uint8_t res[6]; + i2c.readReg(ADDR7, REG_X, 6, res); + Magnetometer mag; + mag.x = ((res[0] << 0) | (res[1] << 8)); + mag.y = ((res[2] << 0) | (res[3] << 8)); + mag.z = ((res[4] << 0) | (res[5] << 8)); + return mag; + } + + void getAndSet(uint8_t reg, uint8_t setMask, uint8_t setVal) { + uint8_t tmp = i2c.readReg8(ADDR7, reg); + tmp = (tmp & ~setMask) | setVal; + i2c.writeReg8(ADDR7, reg, tmp); + } + +}; + diff --git a/ext/sens/SGP30.h b/ext/sens/SGP30.h new file mode 100644 index 0000000..87e3402 --- /dev/null +++ b/ext/sens/SGP30.h @@ -0,0 +1,109 @@ + +#pragma once + +/** + * air quality sensor + * https://sensirion.com/media/documents/984E0DD5/61644B8B/Sensirion_Gas_Sensors_Datasheet_SGP30.pdf + */ +template class SGP30 { + +private: + + I2C& i2c; + static constexpr const uint8_t ADDR = 0x58; + static constexpr const char* NAME = "SGP30"; + + static constexpr const uint16_t CMD_IAQ_INIT = 0x2003; + static constexpr const uint16_t CMD_IAQ_MEASURE = 0x2008; + static constexpr const uint16_t CMD_GET_SERIAL = 0x3682; + + +public: + + SGP30(I2C& i2c) : i2c(i2c) { + + } + + void init() { + sendCommand(CMD_IAQ_INIT); + } + + /** is the device present on the bus? */ + bool isPresent() { + return i2c.query(ADDR); + } + + + struct Result { + uint16_t co2e; + uint16_t tvoc; + }; + + /** should be called ~ every second */ + Result measure() { + + sendCommand(CMD_IAQ_MEASURE); + vTaskDelay(100 / portTICK_PERIOD_MS); + + uint8_t tmp[6]; + i2c.readRaw(ADDR, 6, tmp); + + Result res; + res.co2e = (tmp[0]<<8) | (tmp[1]<<0); + res.tvoc = (tmp[3]<<8) | (tmp[4]<<0); + return res; + + } + + void getSerial() { + + struct Serial { + uint8_t v1[2]; + uint8_t crc1; + uint8_t v2[2]; + uint8_t crc2; + uint8_t v3[2]; + uint8_t crc3; + } serial; + + sendCommand(CMD_GET_SERIAL); + uint8_t tmp[9]; + i2c.readRaw(ADDR, 9, &serial); + /* + uint8_t a = calcCRC(tmp+0, 2); + uint8_t b = calcCRC(tmp+3, 2); + uint8_t c = calcCRC(tmp+6, 2); + + printf("%d %d %d %d\n", tmp[0], tmp[1], tmp[2], a); + printf("%d %d %d %d\n", tmp[3], tmp[4], tmp[5], b); + printf("%d %d %d %d\n", tmp[6], tmp[7], tmp[8], c); + */ + } + + +private: + + void sendCommand(uint16_t cmd) { + uint8_t tmp[2]; + tmp[0] = cmd >> 8; + tmp[1] = cmd >> 0; + i2c.writeRaw(ADDR, 2, tmp); + } + + static uint8_t calcCRC(const uint8_t* data, uint8_t len) { + uint8_t crc = 0xff; + for (uint8_t i = 0; i < len; i++) { + crc ^= data[i]; + for (uint8_t j = 0; j < 8; j++) { + if ((crc & 0x80) != 0) { + crc = (uint8_t)((crc << 1) ^ 0x31); + } else { + crc <<= 1; + } + } + } + return crc; + } + + +}; diff --git a/ext/sens/SHT3x.h b/ext/sens/SHT3x.h new file mode 100644 index 0000000..434d027 --- /dev/null +++ b/ext/sens/SHT3x.h @@ -0,0 +1,93 @@ + +#pragma once + +/** + * humidity and temperature sensor + * https://www.mouser.com/datasheet/2/682/Sensirion_Humidity_Sensors_SHT3x_Datasheet_digital-971521.pdf + * + * sensor seems to be really good! and very easy to use! + * + */ +template class SHT3x { + +private: + + I2C& i2c; + static constexpr const uint8_t ADDR = 0x44; + static constexpr const char* NAME = "SHT3x"; + + +public: + + SHT3x(I2C& i2c) : i2c(i2c) { + + } + + /** is the device present on the bus? */ + bool isPresent() { + return i2c.query(ADDR); + } + + struct Result { + float temp; + float humi; + }; + + /** trigger a single measurement */ + Result singleMeasure() { + + uint16_t cmd = 0x2400; // high quality, no clock stretching + sendCommand(cmd); + vTaskDelay(100 / portTICK_PERIOD_MS); + + return readResult(); + + } + + void startPeriodicMeasure() { + uint16_t cmd = 0x2130; // high quality, 1 measurement per second + sendCommand(cmd); + } + + Result getLastResult() { + return readResult(); + } + +private: + + Result readResult() { + + uint8_t tmp[6]; + i2c.readRaw(ADDR, 6, (uint8_t*)&tmp); + + Result res; + res.temp = -45 + 175 * ((tmp[0]<<8) | (tmp[1]<<0)) / float((1<<16)-1); + res.humi = 100 * ((tmp[3]<<8) | (tmp[4]<<0)) / float((1<<16)-1); + return res; + + } + + void sendCommand(uint16_t cmd) { + uint8_t tmp[2]; + tmp[0] = cmd >> 8; + tmp[1] = cmd >> 0; + i2c.writeRaw(ADDR, 2, tmp); + } + + static uint8_t calcCRC(const uint8_t* data, uint8_t len) { + uint8_t crc = 0xff; + for (uint8_t i = 0; i < len; i++) { + crc ^= data[i]; + for (uint8_t j = 0; j < 8; j++) { + if ((crc & 0x80) != 0) { + crc = (uint8_t)((crc << 1) ^ 0x31); + } else { + crc <<= 1; + } + } + } + return crc; + } + + +}; diff --git a/io/GPIO.h b/io/GPIO.h index 385cce7..cfc8b2e 100644 --- a/io/GPIO.h +++ b/io/GPIO.h @@ -100,6 +100,7 @@ #include "driver/gpio.h" #include "esp8266/gpio_struct.h" + struct MyGPIO { static inline bool get(const uint8_t num) { @@ -166,6 +167,11 @@ ESP_ERROR_CHECK(gpio_config(&io_conf)); } + static void setBuiltInLED(bool on) { + setOutput(GPIO_NUM_2); + if (on) {clear(GPIO_NUM_2);} else {set(GPIO_NUM_2);} + } + static void toggleBuiltInLED() { static bool level = false; setOutput(GPIO_NUM_2); @@ -179,6 +185,7 @@ #elif IS_ESP32 #include "driver/gpio.h" + #include "soc/gpio_reg.h" // NOTE from the manual // GPIO 6-11 are usually used for SPI flash. diff --git a/io/SoftI2C.h b/io/SoftI2C.h index b7d4ba8..22d6688 100644 --- a/io/SoftI2C.h +++ b/io/SoftI2C.h @@ -157,7 +157,7 @@ public: Log::addInfo(NAME, "found %d", i); } waitLong(); - if (i%16 == 0) {delay(10);} + //if (i%16 == 0) {DELAY_MS(10);} } } @@ -219,6 +219,44 @@ public: +public: + + /** similar to readReg() but without actually selecting a register */ + bool readRaw(const uint8_t addr, const uint8_t len, uint8_t* dst) { + + bool ok; + + ok = startWrite(addr); + if (!ok) {Log::addInfo(NAME, "failed start read(1)"); return false;} + stop(); + + ok = startRead(addr); + if (!ok) {Log::addInfo(NAME, "failed start read(2)"); return false;} + readBytes(dst, len); + stop(); + + return true; + + } + + + /** similar to writeReg() but without actually selecting a register */ + bool writeRaw(const uint8_t addr, const uint8_t len, const uint8_t* src) { + + bool ok; + + // address the slave in write mode and select the first register to read + ok = startWrite(addr); + if (!ok) {Log::addInfo(NAME, "failed start write"); return false;} + ok = writeBytesAndCheck(src, len); + if (!ok) {Log::addInfo(NAME, "failed to write register contents"); return false;} + + stop(); + return true; + + } + + diff --git a/tools/PixelFontGen/FontBuilder.h b/tools/PixelFontGen/FontBuilder.h index 97f20af..ec6d96b 100644 --- a/tools/PixelFontGen/FontBuilder.h +++ b/tools/PixelFontGen/FontBuilder.h @@ -18,6 +18,8 @@ struct FontBuilder { + uint8_t spaceBetween = 1; + /** resulting font */ struct Result { @@ -33,6 +35,8 @@ struct FontBuilder { void dump(const char* name) const { + std::cout << "#include " << std::endl; + std::cout << "static const uint8_t " << name << "_data[] = {"; for (uint8_t i : data) { std::cout << (int) i << ","; @@ -76,6 +80,10 @@ struct FontBuilder { } + void setSpaceBetween(uint8_t space) { + this->spaceBetween = space; + } + void addDummy() { // update res.offsets.push_back(curX); @@ -202,7 +210,7 @@ struct FontBuilder { std::cout << " " << c << " : " << rect.width() << " cur: " << curX << std::endl; p.drawText(curX+drawOffsetX, atHeight, str); - curX += std::ceil(rect.width()) + 1; // 1 pixel space between chars + curX += std::ceil(rect.width()) + spaceBetween; // 1 pixel space between chars } p.end(); diff --git a/tools/PixelFontGen/MainWindow.cpp b/tools/PixelFontGen/MainWindow.cpp index 31d9705..1afb87d 100644 --- a/tools/PixelFontGen/MainWindow.cpp +++ b/tools/PixelFontGen/MainWindow.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include "../../ext/lcd/Draw.h" #include #include @@ -26,13 +26,13 @@ MainWindow::~MainWindow() { void MainWindow::paintEvent(QPaintEvent* e) { - QString fontPath="/apps/ESP8266lib/tools/PixelFontGen/fonts/"; + QString fontPath="/storage/vm/workspace/house/ESP8266lib/tools/PixelFontGen/fonts/"; //FontBuilder::Result res = fb.build("/apps/esp/test/04B_03__.TTF"); //FontBuilder fb(10); fb.addChars("/apps/esp/PixelFont/PixelOperator.ttf", 16, 9, 32, 126); //FontBuilder fb(8); fb.addChars("/apps/esp/PixelFont/04B_03__.TTF", 8, 6, 32, 126); // OK //FontBuilder fb(8); fb.addChars("/apps/esp/PixelFont/Minecraft.ttf", 7.5, 6, 32, 126); // ugly - //FontBuilder fb(10); fb.addChars("/apps/esp/PixelFont/EnterCommand.ttf", 15, 8, 32, 126); + //FontBuilder fb(10); fb.addChars(fontPath+"/EnterCommand.ttf", 15, 8, 32, 126); //FontBuilder fb(10); fb.addChars("/apps/esp/PixelFont/PIXELADE.TTF", 13, 8, 32, 126); //FontBuilder fb(10); fb.addChars("/apps/esp/PixelFont/C&C Red Alert [LAN].ttf", 110, 8, 32, 126); // ugly //FontBuilder fb(11); fb.addChars("/apps/esp/PixelFont/LeviWindows.ttf", 21, 9, 32, 126); @@ -51,8 +51,24 @@ void MainWindow::paintEvent(QPaintEvent* e) { //FontBuilder fb(7); fb.addChars(fontPath+"/RNTG Larger.ttf", 7, 7, 32, 126, [](char c, QRect& r) {if(c=='1'){r.setX(0); r.setWidth(5);}}); //FontBuilder fb(8); fb.addChars(fontPath+"/Bonni-Africa.ttf", 8, 7, 32, 126); + //FontBuilder fb(14); fb.addChars(fontPath+"/rainyhearts.ttf", 16, 11, 32, 126); + //FontBuilder fb(16); fb.addChars(fontPath+"/Pixellari.ttf", 16, 7, 32, 126); + //FontBuilder fb(13); fb.addChars(fontPath+"/PixelOperator.ttf", 16, 10, 32, 126); + + + //FontBuilder fb(16); fb.setSpaceBetween(2); fb.addChars(fontPath+"/gameovercre1.ttf", 16, 12, 32, 126); + FontBuilder fb(13); fb.setSpaceBetween(2); fb.addChars(fontPath+"/monaco.ttf", 16, 11, 32, 126); + + + + + //FontBuilder fb(16); fb.addChars(fontPath+"/VCR_OSD_MONO_1.001.ttf", 21, 17, 32, 126); + + + //FontBuilder fb(8); fb.addCharsMonoFromImage("/apps/esp/PixelFont/res/fnt1.png", 3, 32, 126); + /* // test for icons FontBuilder fb(9); // for (int i = 0; i < 10; ++i) { @@ -62,10 +78,11 @@ void MainWindow::paintEvent(QPaintEvent* e) { fb.addIcon("/apps/esp32/BoatRemote/icon/boat.svg", 12, 9, 0); fb.addDummy(); // } + */ const FontBuilder::Result& res = fb.get(); //res.dump("f1"); - res.dump("fIcon"); + res.dump("f1"); diff --git a/tools/PixelFontGen/PixelFontGen.pro.user b/tools/PixelFontGen/PixelFontGen.pro.user index 60754c4..c57bb36 100644 --- a/tools/PixelFontGen/PixelFontGen.pro.user +++ b/tools/PixelFontGen/PixelFontGen.pro.user @@ -1,10 +1,10 @@ - + EnvironmentId - {662356ad-536e-4e17-8869-ff649e71cb1a} + {09bd03a1-b3d4-445c-b477-faca8ef547ef} ProjectExplorer.Project.ActiveTarget @@ -37,6 +37,7 @@ true true 1 + false true false 0 @@ -45,20 +46,38 @@ 0 8 true - 1 + false + 2 true true true + *.md, *.MD, Makefile false + true ProjectExplorer.Project.PluginSettings + + true + false + true + true + true + true + + + 0 + true + + true + Builtin.BuildSystem + true true Builtin.DefaultTidyAndClazy - 4 + 12 @@ -69,33 +88,27 @@ ProjectExplorer.Project.Target.0 + Desktop Desktop Desktop - {fe56f1ef-f99a-4240-b10b-b3bde6dd50d2} + {d62f8679-f200-4a85-9392-dac2dc9931cd} 0 0 0 - true 0 - /apps/ESP8266lib/tools/build-PixelFontGen-Desktop-Debug - /apps/ESP8266lib/tools/build-PixelFontGen-Desktop-Debug + /storage/vm/workspace/house/ESP8266lib/tools/build-PixelFontGen-Desktop-Debug + /storage/vm/workspace/house/ESP8266lib/tools/build-PixelFontGen-Desktop-Debug true QtProjectManager.QMakeBuildStep - false true Qt4ProjectManager.MakeStep - - false - - - false 2 Build @@ -106,11 +119,7 @@ true Qt4ProjectManager.MakeStep - - true clean - - false 1 Clean @@ -119,34 +128,26 @@ 2 false + + false Debug Qt4ProjectManager.Qt4BuildConfiguration 2 - 2 - 2 - true - 2 - /apps/ESP8266lib/tools/build-PixelFontGen-Desktop-Release - /apps/ESP8266lib/tools/build-PixelFontGen-Desktop-Release + /storage/vm/workspace/house/ESP8266lib/tools/build-PixelFontGen-Desktop-Release + /storage/vm/workspace/house/ESP8266lib/tools/build-PixelFontGen-Desktop-Release true QtProjectManager.QMakeBuildStep - false true Qt4ProjectManager.MakeStep - - false - - - false 2 Build @@ -157,11 +158,7 @@ true Qt4ProjectManager.MakeStep - - true clean - - false 1 Clean @@ -170,34 +167,28 @@ 2 false + + false Release Qt4ProjectManager.Qt4BuildConfiguration 0 0 - 2 - true 0 - /apps/ESP8266lib/tools/build-PixelFontGen-Desktop-Profile - /apps/ESP8266lib/tools/build-PixelFontGen-Desktop-Profile + /storage/vm/workspace/house/ESP8266lib/tools/build-PixelFontGen-Desktop-Profile + /storage/vm/workspace/house/ESP8266lib/tools/build-PixelFontGen-Desktop-Profile true QtProjectManager.QMakeBuildStep - false true Qt4ProjectManager.MakeStep - - false - - - false 2 Build @@ -208,11 +199,7 @@ true Qt4ProjectManager.MakeStep - - true clean - - false 1 Clean @@ -221,6 +208,8 @@ 2 false + + false Profile Qt4ProjectManager.Qt4BuildConfiguration @@ -242,80 +231,19 @@ ProjectExplorer.DefaultDeployConfiguration 1 - - dwarf - - cpu-cycles - - - 250 - - -e - cpu-cycles - --call-graph - dwarf,4096 - -F - 250 - - -F - true - 4096 - false - false - 1000 - - true - - false - false - false - false - true - 0.01 - 10 - true - kcachegrind - 1 - 25 - - 1 true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - + 2 - Qt4ProjectManager.Qt4RunConfiguration:/apps/ESP8266lib/tools/PixelFontGen/PixelFontGen.pro - /apps/ESP8266lib/tools/PixelFontGen/PixelFontGen.pro - - false - + Qt4ProjectManager.Qt4RunConfiguration:/storage/vm/workspace/house/ESP8266lib/tools/PixelFontGen/PixelFontGen.pro + /storage/vm/workspace/house/ESP8266lib/tools/PixelFontGen/PixelFontGen.pro false true true - false false true - - /apps/ESP8266lib/tools/build-PixelFontGen-Desktop-Debug + /storage/vm/workspace/house/ESP8266lib/tools/build-PixelFontGen-Desktop-Debug 1 diff --git a/tools/PixelFontGen/main.cpp b/tools/PixelFontGen/main.cpp index 8d41aaa..b70f27a 100644 --- a/tools/PixelFontGen/main.cpp +++ b/tools/PixelFontGen/main.cpp @@ -1,8 +1,6 @@ #include "MainWindow.h" #include -#include - int main(int argc, char *argv[]) { QApplication a(argc, argv);