many updates..

new sensors.. display.. led.. drawing.. stuff..
This commit is contained in:
kazu
2019-01-17 23:12:01 +01:00
parent 90e9fee101
commit 5cb02880b3
30 changed files with 5305 additions and 97 deletions

45
Debug.h
View File

@@ -34,16 +34,28 @@ extern "C" {
#define debugMod1(module, str, val)
#define debugMod2(module, str, v1, v2)
#define debugMod3(module, str, v1, v2, v3)
#define debugMod4(module, str, v1, v2, v3, v4)
#define debugMod5(module, str, v1, v2, v3, v4, v5)
#define debugMod6(module, str, v1, v2, v3, v4, v5, v6)
#define debugMod7(module, str, v1, v2, v3, v4, v5, v6, v7)
#define debugMod8(module, str, v1, v2, v3, v4, v5, v6, v7, v8)
#define debugMod9(module, str, v1, v2, v3, v4, v5, v6, v7, v8, v9)
#define IF_DEBUG(a)
#define debugShow(a, b)
#elif (PLATFORM == WEMOS_D1_MINI) || (PLATFORM == NODE_MCU)
#elif ESP8266
#define debug(str) os_printf(str)
#define debugMod(module, str) os_printf("[%s] %s\n", module, str)
#define debugMod1(module, str, val) os_printf("[%s] ", module); os_printf(str, val); os_printf("\n");
#define debugMod2(module, str, v1, v2) os_printf("[%s] ", module); os_printf(str, v1, v2); os_printf("\n");
#define debugMod3(module, str, v1, v2, v3) os_printf("[%s] ", module); os_printf(str, v1, v2, v3); os_printf("\n");
#define debug(str) os_printf(str)
#define debugMod(module, str) os_printf("[%s] %s\n", module, str)
#define debugMod1(module, str, val) os_printf("[%s] ", module); os_printf(str, val); os_printf("\n");
#define debugMod2(module, str, v1, v2) os_printf("[%s] ", module); os_printf(str, v1, v2); os_printf("\n");
#define debugMod3(module, str, v1, v2, v3) os_printf("[%s] ", module); os_printf(str, v1, v2, v3); os_printf("\n");
#define debugMod4(module, str, v1, v2, v3, v4) os_printf("[%s] ", module); os_printf(str, v1, v2, v3, v4); os_printf("\n");
#define debugMod5(module, str, v1, v2, v3, v4, v5) os_printf("[%s] ", module); os_printf(str, v1, v2, v3, v4, v5); os_printf("\n");
#define debugMod6(module, str, v1, v2, v3, v4, v5, v6) os_printf("[%s] ", module); os_printf(str, v1, v2, v3, v4, v5, v6); os_printf("\n");
#define debugMod7(module, str, v1, v2, v3, v4, v5, v6, v7) os_printf("[%s] ", module); os_printf(str, v1, v2, v3, v4, v5, v6, v7); os_printf("\n");
#define debugMod8(module, str, v1, v2, v3, v4, v5, v6, v7, v8) os_printf("[%s] ", module); os_printf(str, v1, v2, v3, v4, v5, v6, v7, v8); os_printf("\n");
#define debugMod9(module, str, v1, v2, v3, v4, v5, v6, v7, v8, v9) os_printf("[%s] ", module); os_printf(str, v1, v2, v3, v4, v5, v6, v7, v8, v9); os_printf("\n");
#define IF_DEBUG(a) a
#define debugShow(buf, len) hexdump(buf,len)
@@ -56,13 +68,20 @@ extern "C" {
#elif (PLATFORM == WROOM32_DEVKIT)
#define debug(str) ESP_LOGI("", str);
#define debugMod(module, str) ESP_LOGI(module, str);
#define debugMod1(module, str, val) ESP_LOGI(module, str, val);
#define debugMod2(module, str, v1, v2) ESP_LOGI(module, str, v1, v2);
#define debugMod3(module, str, v1, v2, v3) ESP_LOGI(module, str, v1, v2, v3);
#define IF_DEBUG(a) a
#define debugShow(buf, len) hexdump(buf,len)
#ifndef CONFIG_LOG_DEFAULT_LEVEL
#define CONFIG_LOG_DEFAULT_LEVEL 3
#endif
#include "esp_log.h"
#define debug(str) ESP_LOGI("", str);
#define debugMod(module, str) ESP_LOGI(module, str);
#define debugMod1(module, str, val) ESP_LOGI(module, str, val);
#define debugMod2(module, str, v1, v2) ESP_LOGI(module, str, v1, v2);
#define debugMod3(module, str, v1, v2, v3) ESP_LOGI(module, str, v1, v2, v3);
#define debugMod4(module, str, v1, v2, v3, v4) ESP_LOGI(module, str, v1, v2, v3, v4);
#define IF_DEBUG(a) a
#define debugShow(buf, len) hexdump(buf,len)
#else
#error "unsupported platform"

View File

@@ -1,3 +1,9 @@
#ifndef COLOR_H
#define COLOR_H
#include <cstdint>
struct Color {
uint8_t r;
@@ -40,6 +46,15 @@ public:
Color c; c.setHSV(h,s,v); return c;
}
/** get color with new brightness (0..255) */
Color brightness(const uint8_t brightness) const {
return Color(
((uint16_t)r)*brightness/255,
((uint16_t)g)*brightness/255,
((uint16_t)b)*brightness/255
);
}
void setHSV(const uint8_t h, const uint8_t s, const uint8_t v) {
uint8_t region, remainder, p, q, t;
@@ -97,3 +112,5 @@ public:
}
};
#endif // COLOR_H

35
data/Vector.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef DATA_VECTOR_H
#define DATA_VECTOR_H
#include <cstdint>
template <typename T> class Vector {
private:
T* data = nullptr;
size_t nextIdx = 0;
size_t total = 8;
public:
Vector() {
data = (T*) malloc(total*sizeof(T));
}
void push_back(T elem) {
data[nextIdx] = elem;
++nextIdx;
}
T& operator[] (const size_t idx) {
return data[idx];
}
size_t size() const {
return nextIdx;
}
};
#endif // DATA_VECTOR_H

190
ext/lcd/Draw.h Normal file
View File

@@ -0,0 +1,190 @@
#ifndef LCD_DRAW
#define LCD_DRAW
#include <cmath>
#include <cstdint>
#include "../../data/Color.h"
//struct RGB {
// uint8_t r;
// uint8_t g;
// uint8_t b;
// RGB() : r(0), g(0), b(0) {;}
// RGB(uint8_t r, uint8_t g, uint8_t b) : r(r), g(g), b(b) {;}
// uint16_t toRGB565() const {
// return
// ((r >> 3) << 11) |
// ((g >> 2) << 5) |
// ((b >> 3) << 0);
// }
//};
class FontWrap {
uint16_t w;
uint16_t h;
const uint8_t* data;
const uint16_t* offsets;
static constexpr uint8_t off = 32;
public:
/** ctor */
FontWrap(const uint16_t w, const uint16_t h, const uint8_t* data, const uint16_t* offsets) : w(w), h(h), data(data), offsets(offsets) {
;
}
/** get the pixel-width of the given char */
uint8_t getCharWidht(char c) const {
if (c == 32) {return 3;} // whitespace
return offsets[c-off+1] - offsets[c-off];
}
uint8_t getHeight() const {
return h;
}
uint16_t getWidth(const char* txt) const {
uint16_t sum = 0;
while(*txt) {
sum += getCharWidht(*txt);
++txt;
}
return sum;
}
/** draw the given char at the given position */
template <typename Scalar, typename Destination> void draw(const char* c, Scalar dx, Scalar dy, Destination& dst) {
while(*c) {
draw(*c, dx, dy, dst);
dx += getCharWidht(*c);// + 1;
++c;
}
}
/** draw the given char at the given position */
template <typename Scalar, typename Destination> void draw(unsigned char c, Scalar dx, Scalar dy, Destination& dst) {
if (c == 32) {return;} // skip whitespace
const uint16_t x1 = offsets[c-off];
const uint16_t x2 = offsets[c-off+1];
const uint16_t y1 = 0;
const uint16_t y2 = h;
for (uint16_t y = y1; y < y2; ++y) {
for (uint16_t x = x1; x < x2; ++x) {
const uint16_t idx = (x/8) + (y*this->w/8);
const uint8_t pixel = data[idx] & (1<<(x&7));
if (pixel) {
dst.setPixel(dx+x-x1, dy+y);
}
}
}
}
};
template <typename Scalar, typename Destination> class Draw {
Destination& dst;
public:
Draw(Destination& dst) : dst(dst) {
}
void set(const Scalar x1, const Scalar y1) {
dst.set(x1, y1);
}
void setColor(const Color color) {
dst.setColor(color);
}
/** draw a line from (x0,y0) to (x1,y1) */
void drawLine(Scalar x1, Scalar y1, const Scalar x2, const Scalar y2) {
// int dx, dy, p, x, y;
// dx=x1-x0;
// dy=y1-y0;
// x=x0;
// y=y0;
// p=2*dy-dx;
// while(x < x1) {
// if(p >= 0) {
// dst.set(x,y);
// y=y+1;
// p=p+2*dy-2*dx;
// } else {
// dst.set(x,y);
// p=p+2*dy;
// }
// x=x+1;
// }
Scalar dx = abs(x2-x1);
Scalar sx = (x1<x2 ? 1 : -1);
Scalar dy = -abs(y2-y1);
Scalar sy = (y1<y2 ? 1 : -1);
Scalar err = dx+dy;
Scalar e2;
while( (x1!=x2) || (y1!=y2) ) {
dst.setPixel(x1,y1);
e2 = 2*err;
if (e2 > dy) { err += dy; x1 += sx; }
if (e2 < dx) { err += dx; y1 += sy; }
}
}
void fillRect(const Scalar x, const Scalar y, const Scalar w, const Scalar h) {
dst.fillRect(x,y,w,h);
}
void drawLineHor(const Scalar x1, const Scalar x2, const Scalar y) {
dst.fillRect(x1,y,x2-x1,1);
}
void drawLineVer(const Scalar y1, const Scalar y2, const Scalar x) {
dst.fillRect(x,y1,1,y2-y1);
}
void drawRect(const Scalar x, const Scalar y, const Scalar w, const Scalar h) {
drawLineHor(x,x+w, y); // top
drawLineHor(x,x+w, y+h); // bottom
drawLineVer(y,y+h, x); // left
drawLineVer(y,y+h, x+w); // right
}
// void drawRect(const Scalar x1, const Scalar y1, const Scalar x2, const Scalar y2) {
// for (Scalar s = x1; s <= x2; ++s) {dst.set(s, y1);}
// for (Scalar s = x1; s <= x2; ++s) {dst.set(s, y2);}
// for (Scalar s = y1+1; s < y2; ++s) {dst.set(x1, s);}
// for (Scalar s = y1+1; s < y2; ++s) {dst.set(x2, s);}
// }
Scalar abs(Scalar v) const {
if (v >= 0) {return v;}
return -v;
}
};
#endif

365
ext/lcd/ILI9341.h Normal file
View File

@@ -0,0 +1,365 @@
#ifndef LCD_ILI9341
#define LCD_ILI9341
#include "../../Debug.h"
// https://github.com/adafruit/Adafruit_ILI9341/blob/master/Adafruit_ILI9341.cpp
// https://github.com/adafruit/Adafruit_ILI9341/blob/master/Adafruit_ILI9341.h
// http://datasheets.gpio.dk/dl/ILI9341.pdf
// e.g.
// TJCTM24024-SPI
// http://play.fallows.ca/wp/projects/electronics-projects/tjctm24024-mystery-modules-china/
// http://datasheets.gpio.dk/dl/2.4inch-tft-touch/2.4%25e4%25b8%25b2%25e5%258f%25a3_TJC-024-9341/Module_SCH.pdf
// http://datasheets.gpio.dk/dl/ILI9341.pdf
#define ILI9341_TFTWIDTH 240 ///< ILI9341 max TFT width
#define ILI9341_TFTHEIGHT 320 ///< ILI9341 max TFT height
#define ILI9341_NOP 0x00 ///< No-op register
#define ILI9341_SWRESET 0x01 ///< Software reset register
#define ILI9341_RDDID 0x04 ///< Read display identification information
#define ILI9341_RDDST 0x09 ///< Read Display Status
#define ILI9341_SLPIN 0x10 ///< Enter Sleep Mode
#define ILI9341_SLPOUT 0x11 ///< Sleep Out
#define ILI9341_PTLON 0x12 ///< Partial Mode ON
#define ILI9341_NORON 0x13 ///< Normal Display Mode ON
#define ILI9341_RDMODE 0x0A ///< Read Display Power Mode
#define ILI9341_RDMADCTL 0x0B ///< Read Display MADCTL
#define ILI9341_RDPIXFMT 0x0C ///< Read Display Pixel Format
#define ILI9341_RDIMGFMT 0x0D ///< Read Display Image Format
#define ILI9341_RDSELFDIAG 0x0F ///< Read Display Self-Diagnostic Result
#define ILI9341_INVOFF 0x20 ///< Display Inversion OFF
#define ILI9341_INVON 0x21 ///< Display Inversion ON
#define ILI9341_GAMMASET 0x26 ///< Gamma Set
#define ILI9341_DISPOFF 0x28 ///< Display OFF
#define ILI9341_DISPON 0x29 ///< Display ON
#define ILI9341_CASET 0x2A ///< Column Address Set
#define ILI9341_PASET 0x2B ///< Page Address Set
#define ILI9341_RAMWR 0x2C ///< Memory Write
#define ILI9341_RAMRD 0x2E ///< Memory Read
#define ILI9341_PTLAR 0x30 ///< Partial Area
#define ILI9341_MADCTL 0x36 ///< Memory Access Control
#define ILI9341_VSCRSADD 0x37 ///< Vertical Scrolling Start Address
#define ILI9341_PIXFMT 0x3A ///< COLMOD: Pixel Format Set
#define ILI9341_FRMCTR1 0xB1 ///< Frame Rate Control (In Normal Mode/Full Colors)
#define ILI9341_FRMCTR2 0xB2 ///< Frame Rate Control (In Idle Mode/8 colors)
#define ILI9341_FRMCTR3 0xB3 ///< Frame Rate control (In Partial Mode/Full Colors)
#define ILI9341_INVCTR 0xB4 ///< Display Inversion Control
#define ILI9341_DFUNCTR 0xB6 ///< Display Function Control
#define ILI9341_PWCTR1 0xC0 ///< Power Control 1
#define ILI9341_PWCTR2 0xC1 ///< Power Control 2
#define ILI9341_PWCTR3 0xC2 ///< Power Control 3
#define ILI9341_PWCTR4 0xC3 ///< Power Control 4
#define ILI9341_PWCTR5 0xC4 ///< Power Control 5
#define ILI9341_VMCTR1 0xC5 ///< VCOM Control 1
#define ILI9341_VMCTR2 0xC7 ///< VCOM Control 2
#define ILI9341_RDID1 0xDA ///< Read ID 1
#define ILI9341_RDID2 0xDB ///< Read ID 2
#define ILI9341_RDID3 0xDC ///< Read ID 3
#define ILI9341_RDID4 0xDD ///< Read ID 4
#define ILI9341_GMCTRP1 0xE0 ///< Positive Gamma Correction
#define ILI9341_GMCTRN1 0xE1 ///< Negative Gamma Correction
//#define ILI9341_PWCTR6 0xFC
#include "../../io/SoftSPI.h"
#include "../../io/HardSPI.h"
static constexpr const uint8_t initcmd[] = {
0xEF, 3, 0x03, 0x80, 0x02,
0xCF, 3, 0x00, 0xC1, 0x30,
0xED, 4, 0x64, 0x03, 0x12, 0x81,
0xE8, 3, 0x85, 0x00, 0x78,
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
0xF7, 1, 0x20,
0xEA, 2, 0x00, 0x00,
ILI9341_PWCTR1, 1, 0x23, // Power control VRH[5:0]
ILI9341_PWCTR2, 1, 0x10, // Power control SAP[2:0];BT[3:0]
ILI9341_VMCTR1, 2, 0x3e, 0x28, // VCM control
ILI9341_VMCTR2, 1, 0x86, // VCM control2
ILI9341_MADCTL, 1, 0x48, // Memory Access Control
ILI9341_VSCRSADD, 1, 0x00, // Vertical scroll zero
ILI9341_PIXFMT, 1, 0x55,
ILI9341_FRMCTR1, 2, 0x00, 0x18,
ILI9341_DFUNCTR, 3, 0x08, 0x82, 0x27, // Display Function Control
0xF2, 1, 0x00, // 3Gamma Function Disable
ILI9341_GAMMASET, 1, 0x01, // Gamma curve selected
ILI9341_GMCTRP1, 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
ILI9341_GMCTRN1, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, // Set Gamma
//ILI9341_SLPOUT, 0x80, // Exit Sleep
//ILI9341_DISPON, 0x80, // Display on
0x00 // End of list
};
//template <int PIN_CS, int PIN_MISO, int PIN_MOSI, int PIN_CLK, int PIN_DATA_COMMAND> class ILI9341 {
template <int PIN_CS, int PIN_DATA_COMMAND, typename SPI> class ILI9341 {
private:
int w = 240;
int h = 320;
static constexpr const char* MOD = "ILI9341";
//HardSPI<PIN_MISO, PIN_MOSI, PIN_CLK> spi;
//SoftSPI<PIN_MISO, PIN_MOSI, PIN_CLK, true> spi;
SPI& spi;
public:
ILI9341(SPI& spi) : spi(spi) {
GPIO::setOutput(PIN_DATA_COMMAND);
GPIO::setOutput(PIN_CS);
//spi.init();
}
void setPixel(const uint16_t x, const uint16_t y, const uint16_t color) {
chipSelect();
setAddrWindow(x,y,1,1);
sendWord(color);
chipDeselect();
}
void setPixel(const uint16_t x, const uint16_t y, const uint8_t w, const uint16_t color) {
chipSelect();
setAddrWindow(x-w/2,y-w/2,w,w);
for (int i = 0; i < w*w; ++i) {
sendWord(color);
}
chipDeselect();
}
/** perform display software reset and initialization */
void init() {
chipSelect();
// send reset command
wait();
sendCommand(ILI9341_SWRESET);
wait();
// send init sequence
const uint8_t* bytes = initcmd;
while(*bytes) {
const uint8_t cmd = *bytes; ++bytes;
uint8_t numArgs = *bytes; ++bytes;
debugMod2(MOD, "send command %d (%d bytes)", cmd, numArgs);
sendCommand(cmd);
while(numArgs--) {
sendByte(*bytes);
++bytes;
}
}
// finalize init sequence
sendCommand(ILI9341_SLPOUT); wait();
sendCommand(ILI9341_DISPON); wait();
// done
chipDeselect();
}
uint32_t getID() {
chipSelect();
sendCommand16(ILI9341_RDDID);
uint32_t res = 0xFFFFFFFF;
readBytes(reinterpret_cast<uint8_t*>(&res), 4); // dummy-byte + 3 data bytes
chipDeselect();
return res;
}
void getStatus() {
chipSelect();
uint8_t buf[5];
sendCommand16(ILI9341_RDDID);
uint32_t res = 0xFFFFFFFF;
readBytes(buf, 5); // dummy-byte + 4 data bytes
chipDeselect();
ESP_LOGI(MOD, "%d %d %d %d", buf[1],buf[2],buf[3],buf[4]);
read();
}
void read() {
chipSelect();
setAddrWindow(0,0,100,100);
sendCommand(ILI9341_RAMRD);
uint8_t buf[32];
readBytes(buf, 32);
for (int i = 0; i < 32; ++i) {
printf("%d ", buf[i]);
}
printf("\n");
chipDeselect();
}
void draw(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint16_t* data) {
chipSelect();
setAddrWindow(x,y,w,h);
const int len = w*h;
// for (int i = 0; i < len; ++i) {
// spi::writeWord(data[i]);
// }
spi.write((const uint8_t*)data, w*h*2);
chipDeselect();
}
void fillRand() {
// chipSelect();
// setAddrWindow(0,0,w,h);
// for (int i = 0; i < w*h/2; ++i) {
// sendQuad(rand());
// }
// chipDeselect();
chipSelect();
setAddrWindow(0,0,w,h);
for (int y = 0; y < h; ++y) {
uint16_t buf[w];
for (int x = 0; x < w; ++x) {buf[x] = rand();}
sendBytes(reinterpret_cast<uint8_t*>(buf), w*2);
}
chipDeselect();
}
void fill(const uint16_t color) {
chipSelect();
setAddrWindow(0,0,w,h);
for (int y = 0; y < h; ++y) {
uint16_t buf[w];
for (int x = 0; x < w; ++x) {buf[x] = color;}
sendBytes(reinterpret_cast<uint8_t*>(buf), w*2);
}
chipDeselect();
}
void fillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint16_t color) {
chipSelect();
setAddrWindow(x,y,w,h);
for (int i = 0; i < w*h; ++i) {
sendWord(color);
}
chipDeselect();
}
private:
void setAddrWindow(const uint16_t x, const uint16_t y, const uint16_t w, const uint16_t h) {
const uint32_t xa = ((uint32_t)x << 16) | (x+w-1);
const uint32_t ya = ((uint32_t)y << 16) | (y+h-1);
sendCommand(ILI9341_CASET); // Column addr set
sendQuad(xa);
sendCommand(ILI9341_PASET); // Row addr set
sendQuad(ya);
sendCommand(ILI9341_RAMWR); // write to RAM
// transmit data now
}
void wait() {
vTaskDelay(100 / portTICK_PERIOD_MS);
}
/** select the display (CS=0) */
inline void chipSelect() {
//spi::chipSelect();
GPIO::clear(PIN_CS);
}
/** send the given command to the display */
void sendCommand(const uint8_t cmd) {
modeCMD();
spi.writeByte(cmd);
modeDATA();
}
/** send the given command to the display */
void sendCommand16(const uint8_t cmd) {
modeCMD();
spi.writeByte(cmd);
spi.writeByte(0x00);
modeDATA();
}
/** send the given data byte to the display */
void sendByte(const uint8_t data) {
spi.writeByte(data);
}
/** send the given data word to the display */
void sendWord(const uint16_t data) {
spi.writeWord(data);
}
/** send the given data quad to the display */
void sendQuad(const uint32_t data) {
spi.writeQuad(data);
}
/** send the given data to the display */
void sendBytes(const uint8_t* data, const size_t len) {
spi.write(data, len);
}
/** read the given data from the display */
void readBytes(uint8_t* data, const size_t len) {
spi.read(data, len);
}
/** unselect the display (CS=1) */
inline void chipDeselect() {
//spi::chipDeselect();
GPIO::set(PIN_CS);
}
/** switch to command-mode */
inline void modeCMD() {
//gpio_set_level((gpio_num_t)PIN_DATA_COMMAND, 0);
GPIO::clear(PIN_DATA_COMMAND);
}
/** switch to data-mode */
inline void modeDATA() {
//gpio_set_level((gpio_num_t)PIN_DATA_COMMAND, 1);
GPIO::set(PIN_DATA_COMMAND);
}
};
#endif

255
ext/lcd/SSD1306.h Normal file
View File

@@ -0,0 +1,255 @@
#ifndef LCD_SSD1306
#define LCD_SSD1306
#include "../../io/SoftI2C.h"
//#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
class SSD1306 {
private:
static constexpr uint8_t ADDR7 = 0b0111100;
bool inited = false;
public:
bool isPresent() {
return i2c::query(ADDR7);
}
void initOnce() {
if (inited) {return;}
init();
inited = true;
}
void flush(const uint8_t* data) {
sendCommand(SSD1306_COLUMNADDR);
// special handling for 64x48 oled shield
#if SSD1306_LCDWIDTH == 64 && SSD1306_LCDHEIGHT == 48
sendCommand(32);
sendCommand(32 + SSD1306_LCDWIDTH - 1);
#else
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
// #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++) {
i2c::writeByteAndCheck(data[i]);
}
i2c::stop();
}
private:
void init() {
uint8_t vccstate = 0;
sendCommand(SSD1306_DISPLAYOFF); // 0xAE
sendCommand(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
sendCommand(0x80); // the suggested ratio 0x80
sendCommand(SSD1306_SETMULTIPLEX); // 0xA8
sendCommand(SSD1306_LCDHEIGHT - 1);
sendCommand(SSD1306_SETDISPLAYOFFSET); // 0xD3
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_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); // 0xDA
sendCommand(0x12);
if (vccstate == SSD1306_EXTERNALVCC) {
sendCommand(0x9F);
} else {
sendCommand(0xCF);
}
sendCommand(SSD1306_SETPRECHARGE); // 0xd9
if (vccstate == SSD1306_EXTERNALVCC) {
sendCommand(0x22);
} else {
sendCommand(0xF1);
}
sendCommand(SSD1306_SETVCOMDETECT); // 0xDB
sendCommand(0x40);
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();
}
};
#endif

249
ext/lcd/SSD1306_old.h Normal file
View File

@@ -0,0 +1,249 @@
#ifndef LCD_SSD1306
#define LCD_SSD1306
#include "../../io/SoftI2C.h"
//#define SSD1306_128_64 1
#define SSD1306_64_48 1
#if defined SSD1306_128_64
#define SSD1306_LCDWIDTH 128
#define SSD1306_LCDHEIGHT 64
#endif
#if defined SSD1306_128_32
#define SSD1306_LCDWIDTH 128
#define SSD1306_LCDHEIGHT 32
#endif
#if defined SSD1306_96_16
#define SSD1306_LCDWIDTH 96
#define SSD1306_LCDHEIGHT 16
#endif
#if defined SSD1306_64_48
#define SSD1306_LCDWIDTH 64
#define SSD1306_LCDHEIGHT 48
#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
class SSD1306 {
private:
static constexpr uint8_t ADDR7 = 0b0111100;
bool inited = false;
public:
bool isPresent() {
return i2c::query(ADDR7);
}
void initOnce() {
if (inited) {return;}
init();
inited = true;
}
void flush(const uint8_t* data) {
sendCommand(SSD1306_COLUMNADDR);
sendCommand(0); // Column start address (0 = reset)
sendCommand(SSD1306_LCDWIDTH-1); // Column end address (127 = reset)
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
// #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 < 256; ++i) {//i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) {
i2c::writeByteAndCheck(data[i]);
}
i2c::stop();
}
private:
void init() {
uint8_t vccstate = 0;
sendCommand(SSD1306_DISPLAYOFF); // 0xAE
sendCommand(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
sendCommand(0x80); // the suggested ratio 0x80
sendCommand(SSD1306_SETMULTIPLEX); // 0xA8
sendCommand(SSD1306_LCDHEIGHT - 1);
sendCommand(SSD1306_SETDISPLAYOFFSET); // 0xD3
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_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); // 0xDA
sendCommand(0x12);
if (vccstate == SSD1306_EXTERNALVCC) {
sendCommand(0x9F);
} else {
sendCommand(0xCF);
}
sendCommand(SSD1306_SETPRECHARGE); // 0xd9
if (vccstate == SSD1306_EXTERNALVCC) {
sendCommand(0x22);
} else {
sendCommand(0xF1);
}
sendCommand(SSD1306_SETVCOMDETECT); // 0xDB
sendCommand(0x40);
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();
}
};
#endif

295
ext/lcd/ST7735.h Normal file
View File

@@ -0,0 +1,295 @@
#ifndef LCD_SSD1306
#define LCD_SSD1306
#include "../../io/SoftSPI.h"
/**
* https://www.displayfuture.com/Display/datasheet/controller/ST7735.pdf
* https://www.aliexpress.com/item/1-8-inch-TFT-color-screen-module-ST7735-SPI-at-least-4IO-support-C51-STM32-with/32809505663.html?spm=2114.search0302.3.266.14d83b8cQXOxfz&ws_ab_test=searchweb0_0,searchweb201602_0_450_452_532_533_534_10618_535_317_318_319_10059_10696_10084_100031_10083_10547_10304_10546_10843_10887_320_10307_10548_204_448_10065_449_10068_10320_10103_10884_10820,searchweb201603_0,ppcSwitch_0&algo_pvid=7cf0bb24-ac60-4e97-9878-8716f61a79f3&algo_expid=7cf0bb24-ac60-4e97-9878-8716f61a79f3-33
* https://sites.google.com/site/arduinomega2560projects/microchip-pic/level-3/st7735-1-8-tft (!!!!)
*
* display is SPI
* CLK = clock
* SDA = mosi
* RS = data/command
* RST = reset
* CS = chip-select
*/
class ST7735 {
private:
static constexpr const char* NAME = "ST7735";
bool inited = false;
/** switch D/C line low */
inline void modeCommand() {
GPIO5_OUTPUT_SET;
GPIO5_L;
}
/** switch D/C line high */
inline void modeData() {
GPIO5_OUTPUT_SET;
GPIO5_H;
}
/** set CS = low */
inline void select() {
spi::chipSelect();
}
/** set CS = high */
inline void deselect() {
spi::chipDeselect();
}
public:
void initOnce() {
if (inited) {return;}
init();
inited = true;
}
#define ST7735_NOP 0x00
#define ST7735_SWRESET 0x01
#define ST7735_RDDID 0x04
#define ST7735_RDDST 0x09
#define ST7735_SLPIN 0x10
#define ST7735_SLPOUT 0x11
#define ST7735_PTLON 0x12
#define ST7735_NORON 0x13
#define ST7735_INVOFF 0x20
#define ST7735_INVON 0x21
#define ST7735_DISPOFF 0x28
#define ST7735_DISPON 0x29
#define ST7735_CASET 0x2A
#define ST7735_RASET 0x2B
#define ST7735_RAMWR 0x2C
#define ST7735_RAMRD 0x2E
#define ST7735_PTLAR 0x30
#define ST7735_COLMOD 0x3A
#define ST7735_MADCTL 0x36
#define ST7735_FRMCTR1 0xB1
#define ST7735_FRMCTR2 0xB2
#define ST7735_FRMCTR3 0xB3
#define ST7735_INVCTR 0xB4
#define ST7735_DISSET5 0xB6
#define ST7735_PWCTR1 0xC0
#define ST7735_PWCTR2 0xC1
#define ST7735_PWCTR3 0xC2
#define ST7735_PWCTR4 0xC3
#define ST7735_PWCTR5 0xC4
#define ST7735_VMCTR1 0xC5
#define ST7735_RDID1 0xDA
#define ST7735_RDID2 0xDB
#define ST7735_RDID3 0xDC
#define ST7735_RDID4 0xDD
#define ST7735_PWCTR6 0xFC
#define ST7735_GMCTRP1 0xE0
#define ST7735_GMCTRN1 0xE1
private:
#define V 128
#define H 160
void waitLong() {
for (int i = 0; i < 50; ++i) {
os_delay_us(10*1000);
}
}
void waitShort() {
os_delay_us(10*1000);
}
void init() {
spi::init();
select();
sendCommand(ST7735_SWRESET); // 1: Software reset, 0 args
waitLong();
sendCommand(ST7735_SLPOUT); // 2: Out of sleep mode, 0 args
waitLong();
sendCommand(ST7735_FRMCTR1); // 3: Frame rate ctrl - normal mode) 3 args: 0xb1
sendData(0x01); sendData(0x2C); sendData(0x2D); // Rate = fosc/(1x2+40) * (LINE+2C+2D)
sendCommand(ST7735_FRMCTR2); // 4: Frame rate control - idle mode) 3 args: 0xb2
sendData(0x01); sendData(0x2C); sendData(0x2D); // Rate = fosc/(1x2+40) * (LINE+2C+2D)
sendCommand(ST7735_FRMCTR3); // 5: Frame rate ctrl - partial mode) 6 args: 0xb3
sendData(0x01); sendData(0x2C); sendData(0x2D); // Dot inversion mode
sendData(0x01); sendData(0x2C); sendData(0x2D); // Line inversion mode
sendCommand(ST7735_INVCTR); // 6: Display inversion ctrl) 1 arg) no delay: 0xb4
sendData(0x07); // No inversion
sendCommand(ST7735_PWCTR1); // 7: Power control) 3 args) no delay: 0xc0
sendData(0xA2);
sendData(0x02); // -4.6V
sendData(0x84); // AUTO mode
sendCommand(ST7735_PWCTR2); // 8: Power control) 1 arg) no delay: 0xc1
sendData(0xC5); // VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD
sendCommand(ST7735_PWCTR3); // 9: Power control) 2 args) no delay: 0xc2
sendData(0x0A); // Opamp current small
sendData(0x00); // Boost frequency
sendCommand(ST7735_PWCTR4); // 10: Power control) 2 args) no delay:
sendData(0x8A); // BCLK/2) Opamp current small & Medium low
sendData(0x2A);
sendCommand(ST7735_PWCTR5); // 11: Power control) 2 args) no delay:
sendData(0x8A); sendData(0xEE);
sendCommand(ST7735_VMCTR1); // 12: Power control) 1 arg) no delay:
sendData(0x0E);
sendCommand(ST7735_INVOFF); // 13: Don't invert display) no args) no delay 0x20
sendCommand(ST7735_MADCTL); // 14: Memory access control (directions)) 1 arg:
sendData(0xC8); // row addr/col addr); bottom to top refresh
sendCommand(ST7735_COLMOD); // 15: set color mode); 1 arg); no delay:
sendData(0x05); // 16-bit color
// required???
if (1 == 1) {
sendCommand(ST7735_GMCTRP1); // 1: Magical unicorn dust, 16 args, no delay:
sendData(0x02); sendData(0x1c); sendData(0x07); sendData(0x12);
sendData(0x37); sendData(0x32); sendData(0x29); sendData(0x2d);
sendData(0x29); sendData(0x25); sendData(0x2B); sendData(0x39);
sendData(0x00); sendData(0x01); sendData(0x03); sendData(0x10);
sendCommand(ST7735_GMCTRN1); // 2: Sparkles and rainbows, 16 args, no delay:
sendData(0x03); sendData(0x1d); sendData(0x07); sendData(0x06);
sendData(0x2E); sendData(0x2C); sendData(0x29); sendData(0x2D);
sendData(0x2E); sendData(0x2E); sendData(0x37); sendData(0x3F);
sendData(0x00); sendData(0x00); sendData(0x02); sendData(0x10);
}
sendCommand(ST7735_NORON); // 3: Normal display on, no args
waitShort();
sendCommand(ST7735_DISPON); // 4: Main screen turn on, no args
waitLong();
deselect();
debugMod(NAME, "init() done");
}
void clean(uint16_t color){
select();
uint8_t lo = color & 0xFF;
uint8_t hi = color >> 8;
sendCommand(ST7735_CASET); // Column addr set
sendData(0x00);
sendData(0); // XSTART
sendData(0x00);
sendData(V-1); // XEND
sendCommand(ST7735_RASET); // Row addr set
sendData(0x00);
sendData(0); // YSTART
sendData(0x00);
sendData(H-1); // YEND
sendCommand(ST7735_RAMWR);
for(char x=0;x<V;x++){
for(char y=0;y<H;y++){
sendData(lo);
sendData(hi);
}
}
deselect();
}
public:
void flush(uint16_t* data) {
select();
sendCommand(ST7735_CASET); // Column addr set
sendData(0x00);
sendData(0); // XSTART
sendData(0x00);
sendData(V-1); // XEND
sendCommand(ST7735_RASET); // Row addr set
sendData(0x00);
sendData(0); // YSTART
sendData(0x00);
sendData(H-1); // YEND
sendCommand(ST7735_RAMWR);
modeData();
for (int i = 0; i < (V*H); ++i) {
const uint16_t color = data[i];
//const uint8_t lo = color & 0xFF;
//const uint8_t hi = color >> 8;
//sendData(lo);
//sendData(hi);
spi::writeWord(color);
}
deselect();
}
private:
void sendData(uint8_t data) {
modeData();
//select();
spi::writeByte(data);
//deselect();
}
void sendCommand(uint8_t cmd) {
modeCommand();
//select();
spi::writeByte(cmd);
//deselect();
}
};
#endif

413
ext/lcd/ST7735_old.h Normal file
View File

@@ -0,0 +1,413 @@
#ifndef LCD_SSD1306
#define LCD_SSD1306
#include "../../io/SoftSPI.h"
/**
* https://www.displayfuture.com/Display/datasheet/controller/ST7735.pdf
* https://www.aliexpress.com/item/1-8-inch-TFT-color-screen-module-ST7735-SPI-at-least-4IO-support-C51-STM32-with/32809505663.html?spm=2114.search0302.3.266.14d83b8cQXOxfz&ws_ab_test=searchweb0_0,searchweb201602_0_450_452_532_533_534_10618_535_317_318_319_10059_10696_10084_100031_10083_10547_10304_10546_10843_10887_320_10307_10548_204_448_10065_449_10068_10320_10103_10884_10820,searchweb201603_0,ppcSwitch_0&algo_pvid=7cf0bb24-ac60-4e97-9878-8716f61a79f3&algo_expid=7cf0bb24-ac60-4e97-9878-8716f61a79f3-33
* https://sites.google.com/site/arduinomega2560projects/microchip-pic/level-3/st7735-1-8-tft (!!!!)
*
* display is SPI
* CLK = clock
* SDA = mosi
* RS = data/command
* RST = reset
* CS = chip-select
*/
class ST7735 {
private:
static constexpr const char* NAME = "ST7735";
bool inited = false;
/** switch D/C line low */
inline void modeCommand() {
GPIO5_OUTPUT_SET;
GPIO5_L;
}
/** switch D/C line high */
inline void modeData() {
GPIO5_OUTPUT_SET;
GPIO5_H;
}
/** set CS = low */
inline void select() {
spi::chipSelect();
}
/** set CS = high */
inline void deselect() {
spi::chipDeselect();
}
public:
void initOnce() {
if (inited) {return;}
init();
inited = true;
}
//#define ST77XX_NOP 0x00
//#define ST77XX_SWRESET 0x01
//#define ST77XX_RDDID 0x04
//#define ST77XX_RDDST 0x09
//#define ST77XX_SLPIN 0x10
//#define ST77XX_SLPOUT 0x11
//#define ST77XX_PTLON 0x12
//#define ST77XX_NORON 0x13
//#define ST77XX_INVOFF 0x20
//#define ST77XX_INVON 0x21
//#define ST77XX_DISPOFF 0x28
//#define ST77XX_DISPON 0x29
//#define ST77XX_CASET 0x2A
//#define ST77XX_RASET 0x2B
//#define ST77XX_RAMWR 0x2C
//#define ST77XX_RAMRD 0x2E
//#define ST77XX_PTLAR 0x30
//#define ST77XX_COLMOD 0x3A
//#define ST77XX_MADCTL 0x36
//#define ST77XX_MADCTL_MY 0x80
//#define ST77XX_MADCTL_MX 0x40
//#define ST77XX_MADCTL_MV 0x20
//#define ST77XX_MADCTL_ML 0x10
//#define ST77XX_MADCTL_RGB 0x00
//#define ST77XX_RDID1 0xDA
//#define ST77XX_RDID2 0xDB
//#define ST77XX_RDID3 0xDC
//#define ST77XX_RDID4 0xDD
//#define ST7735_MADCTL_BGR 0x08
//#define ST7735_MADCTL_MH 0x04
//#define ST7735_FRMCTR1 0xB1
//#define ST7735_FRMCTR2 0xB2
//#define ST7735_FRMCTR3 0xB3
//#define ST7735_INVCTR 0xB4
//#define ST7735_DISSET5 0xB6
//#define ST7735_PWCTR1 0xC0
//#define ST7735_PWCTR2 0xC1
//#define ST7735_PWCTR3 0xC2
//#define ST7735_PWCTR4 0xC3
//#define ST7735_PWCTR5 0xC4
//#define ST7735_VMCTR1 0xC5
//#define ST7735_PWCTR6 0xFC
//#define ST7735_GMCTRP1 0xE0
//#define ST7735_GMCTRN1 0xE1
#define ST7735_NOP 0x00
#define ST7735_SWRESET 0x01
#define ST7735_RDDID 0x04
#define ST7735_RDDST 0x09
#define ST7735_SLPIN 0x10
#define ST7735_SLPOUT 0x11
#define ST7735_PTLON 0x12
#define ST7735_NORON 0x13
#define ST7735_INVOFF 0x20
#define ST7735_INVON 0x21
#define ST7735_DISPOFF 0x28
#define ST7735_DISPON 0x29
#define ST7735_CASET 0x2A
#define ST7735_RASET 0x2B
#define ST7735_RAMWR 0x2C
#define ST7735_RAMRD 0x2E
#define ST7735_PTLAR 0x30
#define ST7735_COLMOD 0x3A
#define ST7735_MADCTL 0x36
#define ST7735_FRMCTR1 0xB1
#define ST7735_FRMCTR2 0xB2
#define ST7735_FRMCTR3 0xB3
#define ST7735_INVCTR 0xB4
#define ST7735_DISSET5 0xB6
#define ST7735_PWCTR1 0xC0
#define ST7735_PWCTR2 0xC1
#define ST7735_PWCTR3 0xC2
#define ST7735_PWCTR4 0xC3
#define ST7735_PWCTR5 0xC4
#define ST7735_VMCTR1 0xC5
#define ST7735_RDID1 0xDA
#define ST7735_RDID2 0xDB
#define ST7735_RDID3 0xDC
#define ST7735_RDID4 0xDD
#define ST7735_PWCTR6 0xFC
#define ST7735_GMCTRP1 0xE0
#define ST7735_GMCTRN1 0xE1
private:
#define V 128
#define H 160
void waitLong() {
for (int i = 0; i < 50; ++i) {
os_delay_us(10*1000);
}
}
void waitShort() {
os_delay_us(10*1000);
}
void init() {
spi::init();
debugMod(NAME, "init()");
// sendCommand(ST77XX_SWRESET); waitLong();
// sendCommand(ST77XX_SLPOUT); waitLong();
// sendCommand(ST77XX_COLMOD, 0x05); waitShort();
// sendCommand(ST7735_FRMCTR1, 0x00, 0x06, 0x03); waitShort();
// sendCommand(ST77XX_MADCTL, 0x08);
// sendCommand(ST7735_DISSET5, 0x15, 0x02);
// sendCommand(ST7735_INVCTR, 0x0);
// sendCommand(ST7735_PWCTR1, 0x02, 0x70); waitShort();
// sendCommand(ST7735_PWCTR2, 0x05);
// sendCommand(ST7735_PWCTR3, 0x01, 0x02);
// sendCommand(ST7735_VMCTR1, 0x3C, 0x38); waitShort();
// sendCommand(ST7735_PWCTR6, 0x11, 0x15);
// sendCommand(ST7735_GMCTRP1,
// 0x09, 0x16, 0x09, 0x20,
// 0x21, 0x1B, 0x13, 0x19,
// 0x17, 0x15, 0x1E, 0x2B,
// 0x04, 0x05, 0x02, 0x0E);
// sendCommand(ST7735_GMCTRN1,
// 0x0B, 0x14, 0x08, 0x1E,
// 0x22, 0x1D, 0x18, 0x1E,
// 0x1B, 0x1A, 0x24, 0x2B,
// 0x06, 0x06, 0x02, 0x0F);
// waitShort();
// sendCommand(ST77XX_CASET, 0x00, 0x02, 0x00, 0x81);
// sendCommand(ST77XX_RASET, 0x00, 0x02, 0x00, 0x81);
// sendCommand(ST77XX_NORON); waitShort();
// sendCommand(ST77XX_DISPON); waitLong();
sendCommand(ST7735_SWRESET); // 1: Software reset, 0 args, w/delay 150ms 0x01
waitLong();
sendCommand(ST7735_SLPOUT); // 2: Out of sleep mode, 0 args, w/delay 500ms 0x11
waitLong();
sendCommand(ST7735_FRMCTR1); // 3: Frame rate ctrl - normal mode) 3 args: 0xb1
sendData(0x01); sendData(0x2C); sendData(0x2D); // Rate = fosc/(1x2+40) * (LINE+2C+2D)
sendCommand(ST7735_FRMCTR2); // 4: Frame rate control - idle mode) 3 args: 0xb2
sendData(0x01); sendData(0x2C); sendData(0x2D); // Rate = fosc/(1x2+40) * (LINE+2C+2D)
sendCommand(ST7735_FRMCTR3); // 5: Frame rate ctrl - partial mode) 6 args: 0xb3
sendData(0x01); sendData(0x2C); sendData(0x2D); // Dot inversion mode
sendData(0x01); sendData(0x2C); sendData(0x2D); // Line inversion mode
sendCommand(ST7735_INVCTR); // 6: Display inversion ctrl) 1 arg) no delay: 0xb4
sendData(0x07); // No inversion
sendCommand(ST7735_PWCTR1); // 7: Power control) 3 args) no delay: 0xc0
sendData(0xA2);
sendData(0x02); // -4.6V
sendData(0x84); // AUTO mode
sendCommand(ST7735_PWCTR2); // 8: Power control) 1 arg) no delay: 0xc1
sendData(0xC5); // VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD
sendCommand(ST7735_PWCTR3); // 9: Power control) 2 args) no delay: 0xc2
sendData(0x0A); // Opamp current small
sendData(0x00); // Boost frequency
sendCommand(ST7735_PWCTR4); // 10: Power control) 2 args) no delay:
sendData(0x8A); // BCLK/2) Opamp current small & Medium low
sendData(0x2A);
sendCommand(ST7735_PWCTR5); // 11: Power control) 2 args) no delay:
sendData(0x8A); sendData(0xEE);
sendCommand(ST7735_VMCTR1); // 12: Power control) 1 arg) no delay:
sendData(0x0E);
sendCommand(ST7735_INVOFF); // 13: Don't invert display) no args) no delay 0x20
sendCommand(ST7735_MADCTL); // 14: Memory access control (directions)) 1 arg:
sendData(0xC8); // row addr/col addr); bottom to top refresh
sendCommand(ST7735_COLMOD); // 15: set color mode); 1 arg); no delay:
sendData(0x05); // 16-bit color
sendCommand(ST7735_NORON); // 3: Normal display on, no args, w/delay 10ms 0x13
waitShort();
sendCommand(ST7735_DISPON); // 4: Main screen turn on, no args w/delay 100ms 0x29
waitLong();
debugMod(NAME, "init() done");
clean(0x1111110000001111);
}
void clean(uint16_t color){
uint8_t lo = color & 0xFF;
uint8_t hi = color >> 8;
sendCommand(ST7735_CASET); // Column addr set
sendData(0x00);
sendData(0); // XSTART
sendData(0x00);
sendData(V); // XEND
sendCommand(ST7735_RASET); // Row addr set
sendData(0x00);
sendData(0); // YSTART
sendData(0x00);
sendData(H); // YEND
sendCommand(ST7735_RAMWR);
for(char x=0;x<V;x++){
for(char y=0;y<H;y++){
sendData(lo);
sendData(hi);
}
}
}
public:
void flush(uint16_t* data) {
sendCommand(ST7735_CASET); // Column addr set
sendData(0x00);
sendData(0); // XSTART
sendData(0x00);
sendData(V); // XEND
sendCommand(ST7735_RASET); // Row addr set
sendData(0x00);
sendData(0); // YSTART
sendData(0x00);
sendData(H); // YEND
sendCommand(ST7735_RAMWR);
for (int i = 0; i < (V*H); ++i) {
uint16_t color = data[i];
uint8_t lo = color & 0xFF;
uint8_t hi = color >> 8;
sendData(lo);
sendData(hi);
}
}
private:
void sendData(uint8_t data) {
modeData();
select();
spi::writeByte(data);
deselect();
}
void sendCommand(uint8_t cmd) {
modeCommand();
select();
spi::writeByte(cmd);
deselect();
}
// void sendCommand(uint8_t cmd, uint8_t arg1) {
// modeCommand();
// select();
// spi::writeByte(cmd);
// deselect();
// sendData(arg1);
// }
// void sendCommand(uint8_t cmd, uint8_t arg1, uint8_t arg2) {
// modeCommand();
// select();
// spi::writeByte(cmd);
// deselect();
// sendData(arg1);
// sendData(arg2);
// }
// void sendCommand(uint8_t cmd, uint8_t arg1, uint8_t arg2, uint8_t arg3) {
// modeCommand();
// select();
// spi::writeByte(cmd);
// deselect();
// sendData(arg1);
// sendData(arg2);
// sendData(arg3);
// }
// void sendCommand(uint8_t cmd, uint8_t arg1, uint8_t arg2, uint8_t arg3, uint8_t arg4) {
// modeCommand();
// select();
// spi::writeByte(cmd);
// deselect();
// sendData(arg1);
// sendData(arg2);
// sendData(arg3);
// sendData(arg4);
// }
// void sendCommand(uint8_t cmd,
// uint8_t a1, uint8_t a2, uint8_t a3, uint8_t a4,
// uint8_t a5, uint8_t a6, uint8_t a7, uint8_t a8,
// uint8_t a9, uint8_t a10, uint8_t a11, uint8_t a12,
// uint8_t a13, uint8_t a14, uint8_t a15, uint8_t a16) {
// modeCommand();
// select();
// spi::writeByte(cmd);
// deselect();
// sendData(a1);
// sendData(a2);
// sendData(a3);
// sendData(a4);
// sendData(a5);
// sendData(a6);
// sendData(a7);
// sendData(a8);
// sendData(a9);
// sendData(a10);
// sendData(a11);
// sendData(a12);
// sendData(a13);
// sendData(a14);
// sendData(a15);
// sendData(a16);
// }
};
#endif

101
ext/lcd/ui/UI.h Normal file
View File

@@ -0,0 +1,101 @@
#ifndef UI_H
#define UI_H
#include <cstdint>
#include "../Draw.h"
#include "../../../Debug.h"
class Setter;
extern Setter setter;
//uint8_t f1_data[] = {84,18,71,192,137,130,0,0,32,135,28,7,250,156,207,113,0,0,112,124,156,199,121,190,207,137,130,162,32,40,114,30,231,113,190,40,10,138,162,239,226,8,16,64,0,64,0,7,4,65,65,0,0,0,0,0,0,0,0,0,0,0,172,1,84,146,170,32,74,164,2,0,160,200,162,8,11,34,40,138,0,0,136,130,162,40,138,130,32,138,130,162,32,40,138,162,40,138,136,40,10,138,34,40,130,20,32,64,0,64,128,0,4,0,65,0,0,0,0,0,32,0,0,0,0,0,34,74,84,191,162,36,40,200,33,0,160,168,32,136,10,2,40,138,10,129,128,178,162,40,136,130,32,136,130,146,96,44,138,162,40,10,136,40,74,138,34,40,130,34,0,206,227,120,142,224,61,65,81,55,143,243,120,153,243,68,81,80,20,125,34,74,4,146,66,34,32,168,34,0,144,140,16,72,122,2,36,138,128,60,65,170,162,40,136,130,32,136,130,138,160,106,138,162,40,10,136,40,74,82,20,36,132,0,0,81,20,69,209,19,69,65,73,73,81,20,69,69,36,68,81,80,20,65,34,74,4,18,7,193,33,136,248,240,144,138,8,38,130,30,194,241,64,0,34,170,162,39,136,142,35,251,130,134,32,169,138,158,232,113,136,40,74,34,8,34,132,0,0,80,20,68,145,16,69,65,69,73,81,20,69,67,32,68,81,146,18,33,33,76,4,18,138,36,34,8,32,0,144,137,4,232,131,34,33,130,128,60,33,170,190,40,136,130,32,138,130,138,32,40,139,130,168,128,136,40,74,82,8,33,132,0,0,94,20,68,159,16,69,65,67,73,81,20,69,129,35,68,81,18,17,17,34,74,4,63,74,42,34,8,32,0,136,136,2,8,130,162,32,130,0,129,32,114,162,40,136,130,32,138,130,146,32,40,138,130,42,129,136,40,74,138,136,32,136,0,0,81,20,68,129,16,69,65,69,73,81,20,69,1,36,68,81,146,18,9,34,74,0,146,10,42,66,4,0,0,136,136,130,8,138,162,32,138,0,0,0,2,162,40,138,130,32,138,138,162,32,40,138,130,36,138,136,72,73,138,136,32,136,0,0,81,20,69,145,224,69,65,73,65,81,20,69,65,36,68,74,82,228,5,34,74,4,18,7,196,131,2,0,2,10,135,62,7,114,156,192,113,10,0,32,124,162,199,121,190,192,139,114,162,47,40,114,2,43,114,8,135,176,137,136,239,232,0,0,222,227,120,142,0,69,65,81,65,145,243,120,129,195,57,132,77,4,125,172,73,};
//uint16_t f1_offsets[] = {0,1,3,7,14,20,28,34,36,40,44,50,56,59,64,66,70,76,80,86,92,98,104,110,116,122,128,130,133,137,142,146,152,160,166,172,178,184,190,196,202,208,210,216,222,228,236,242,248,254,260,266,272,278,284,290,298,304,310,316,320,324,328,334,340,343,349,355,361,367,373,379,385,391,393,399,405,407,415,421,427,433,439,445,451,457,463,469,477,483,489,495,500,502,507,};
//FontWrap fnt_f1(512,9,f1_data,f1_offsets);
//uint8_t f1_data[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,128,0,128,20,0,0,0,0,0,0,0,0,0,0,0,0,0,240,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,53,0,2,229,155,6,162,138,0,128,156,227,251,162,239,251,190,15,8,226,11,250,158,239,249,190,47,250,184,40,136,162,239,249,158,239,139,162,40,138,190,4,34,0,124,207,247,124,223,23,125,92,20,124,223,247,125,223,247,69,81,21,69,159,36,0,130,175,88,18,34,135,0,64,34,2,130,162,32,128,162,168,228,4,234,138,162,32,10,130,32,34,160,36,216,166,40,138,162,128,136,162,72,137,144,8,82,0,64,81,16,69,65,16,17,80,18,84,81,20,69,65,64,68,81,165,68,136,36,0,2,229,35,62,162,239,227,32,34,226,227,190,239,131,190,15,2,136,171,250,190,32,58,142,238,35,160,35,168,170,232,171,190,143,136,162,138,248,136,16,138,0,124,95,16,125,71,247,17,208,17,84,81,244,85,193,71,68,81,69,124,196,100,0,128,143,210,18,34,135,0,16,34,34,128,32,40,130,34,8,228,4,232,139,162,32,10,130,40,34,160,36,136,178,40,72,18,136,136,148,77,33,132,32,2,0,68,81,16,5,65,20,17,80,18,84,81,20,36,1,68,68,74,165,64,130,36,0,2,229,203,62,162,138,8,10,156,239,251,160,231,131,190,175,8,130,8,136,158,239,249,130,47,250,158,232,139,162,47,184,162,143,248,136,40,34,190,64,2,0,124,207,247,124,193,23,125,79,244,85,209,23,92,193,71,124,196,23,125,159,36,0,0,128,0,0,20,0,8,0,0,0,0,0,0,0,0,128,0,0,240,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,1,3,62,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,49,0,};
//uint16_t f1_offsets[] = {0,1,3,7,13,19,25,31,33,36,39,45,51,53,57,59,65,71,77,83,89,95,101,107,113,119,125,127,129,133,137,141,147,155,161,167,173,179,185,191,197,203,209,215,221,227,233,239,245,251,257,263,269,275,281,287,293,299,305,311,314,320,323,329,335,338,344,350,356,362,368,374,380,386,392,398,404,410,416,422,428,434,440,446,452,458,464,470,476,482,488,494,498,500,};
//FontWrap fnt_f1(512,9,f1_data,f1_offsets);
//static uint8_t f1_data[] = {40,0,4,0,0,130,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,10,158,16,132,130,42,0,0,64,140,56,142,228,49,15,195,0,16,32,48,0,140,195,57,239,113,210,129,36,33,52,113,56,140,195,249,164,72,80,36,242,137,0,2,4,4,0,1,12,16,36,4,1,0,0,0,0,16,0,0,0,0,48,26,0,2,10,69,9,138,130,8,0,0,32,210,64,144,36,8,136,36,1,8,64,72,0,146,36,72,33,8,146,128,36,97,54,137,72,146,36,32,164,72,144,34,2,9,1,2,12,4,0,1,2,16,0,36,1,0,0,0,0,16,0,0,0,0,16,18,0,130,63,133,4,132,130,0,2,0,16,146,64,144,36,8,136,36,1,196,135,64,60,146,36,72,33,8,146,128,20,161,85,137,72,146,36,32,164,72,146,66,129,8,2,2,192,28,199,25,135,113,36,20,253,112,204,193,53,183,148,130,34,233,17,18,0,2,10,14,194,10,130,0,2,30,8,146,48,12,231,56,4,195,73,2,0,33,66,158,35,72,231,105,158,128,12,33,84,137,56,146,195,32,36,133,10,65,65,8,4,2,0,165,32,37,66,146,36,12,37,145,82,34,141,144,148,146,20,9,9,34,0,130,63,20,9,17,130,128,15,0,4,146,8,16,4,73,132,4,1,196,135,16,89,146,36,72,33,72,146,144,20,33,84,137,8,146,4,33,36,133,138,130,32,8,8,2,192,165,32,29,66,146,36,20,37,145,82,34,5,147,148,146,8,201,16,18,0,2,10,148,20,17,130,0,66,0,2,146,8,16,4,73,132,4,65,8,64,0,85,146,36,72,33,72,146,144,36,33,148,137,8,146,4,33,36,133,138,130,16,8,16,2,32,165,32,5,66,146,36,36,37,145,82,34,5,148,164,146,20,41,16,18,0,2,10,79,136,14,130,0,66,64,1,140,120,14,228,48,4,195,72,16,32,16,57,146,195,57,47,48,210,97,36,47,148,113,8,140,228,32,24,130,77,132,240,9,32,226,193,29,199,25,130,147,36,36,37,145,204,193,133,35,71,108,34,238,49,26,0,0,0,4,0,0,130,0,32,0,0,0,0,0,0,0,0,0,32,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,8,0,2,0,0,0,0,0,2,32,0,0,0,64,0,1,0,0,0,0,8,0,0,0,2,0,0,0,0,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,2,0,0,0,0,128,1,16,0,0,0,64,0,1,0,0,0,0,6,0,0,0,};
//static uint16_t f1_offsets[] = {0,1,3,7,15,22,30,38,41,45,49,55,61,65,70,72,80,86,90,96,102,108,114,120,126,132,138,141,144,150,156,162,168,176,182,188,194,200,205,210,216,222,227,233,239,245,252,259,266,272,278,284,290,297,303,310,318,325,332,339,343,351,355,356,362,365,370,375,380,386,391,397,403,409,412,417,423,426,435,441,446,452,458,463,468,471,476,481,489,495,501,507,512,515,};
//static FontWrap fnt_f1(528,10,f1_data,f1_offsets);
//static uint8_t f1_data[] = {42,202,49,130,17,133,0,0,228,144,227,32,158,243,57,14,0,0,224,224,3,225,195,121,124,31,71,40,20,10,130,66,28,15,199,199,243,133,130,33,36,20,228,91,140,0,4,8,0,8,32,32,40,33,0,0,0,0,0,2,0,0,0,0,128,10,42,170,74,65,146,200,1,0,20,89,20,49,66,132,68,17,0,0,16,25,132,34,38,138,4,129,72,40,20,9,198,70,34,145,72,40,68,132,130,81,68,34,2,73,72,1,8,8,0,8,16,32,0,33,0,0,0,0,0,2,0,0,0,0,64,18,170,175,72,65,82,144,16,0,18,21,4,41,65,128,68,81,65,64,0,201,138,34,22,8,5,65,80,40,148,8,198,74,65,81,80,40,64,132,68,82,66,34,130,136,72,1,192,105,28,203,57,171,41,169,158,199,105,172,114,39,138,34,138,162,79,18,2,197,177,128,65,80,17,0,18,17,228,40,207,67,56,17,56,159,131,164,139,226,23,8,125,79,192,47,212,8,170,74,65,81,208,199,64,132,68,82,130,65,129,136,40,2,32,154,162,44,146,108,42,165,165,40,154,178,137,34,138,82,82,34,68,18,2,133,130,70,65,16,124,0,18,17,2,37,80,68,68,30,4,0,68,148,201,38,22,8,5,65,92,40,180,8,170,82,65,79,80,2,67,132,40,138,130,129,64,136,8,0,192,139,130,232,147,40,42,163,164,40,138,162,48,34,82,84,33,20,34,34,130,143,66,41,70,16,16,28,18,17,1,125,80,36,68,16,56,159,67,148,201,39,22,8,5,65,80,168,20,9,170,82,65,65,86,4,68,132,40,138,66,130,64,136,8,0,32,138,130,40,144,40,42,165,164,40,138,162,64,34,82,84,33,20,66,18,128,162,66,41,66,16,16,0,17,145,16,33,81,36,68,17,64,64,0,148,37,40,38,138,4,129,72,168,20,9,146,98,34,129,72,36,68,132,16,4,65,130,32,8,9,0,32,155,162,44,146,44,42,165,164,40,154,178,136,34,35,136,80,8,65,18,130,194,33,198,69,16,0,65,225,208,231,32,142,35,56,78,1,0,64,228,35,232,195,121,124,1,71,40,19,250,146,66,28,1,87,200,67,120,16,4,33,132,240,11,9,0,192,106,28,203,17,43,42,169,164,200,105,172,112,198,34,136,136,136,79,18,0,128,0,0,128,8,0,1,0,0,0,0,0,0,0,0,1,0,0,8,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,8,0,0,0,0,0,0,8,32,0,0,0,8,32,0,0,0,0,0,8,64,18,0,0,0,0,0,5,0,1,0,0,0,0,0,0,0,0,1,0,0,240,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,12,248,1,0,0,0,128,7,16,0,0,0,8,32,0,0,0,0,0,4,128,10,};
//static uint16_t f1_offsets[] = {0,1,3,7,13,19,29,36,38,42,46,50,56,58,62,64,68,74,78,84,90,96,102,108,114,120,126,128,130,136,142,148,154,165,173,180,187,194,200,206,214,221,223,228,235,241,249,256,264,270,278,285,292,298,305,313,325,332,340,347,350,354,357,363,370,373,379,385,391,397,403,407,413,419,421,424,429,431,439,445,451,457,463,467,473,477,483,489,499,505,511,517,521,523,};
//static FontWrap fnt_f1(528,10,f1_data,f1_offsets);
static uint8_t f1_data[] = {0,0,5,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42,137,159,16,35,155,10,0,0,144,179,231,65,62,231,115,28,0,1,193,241,113,30,231,249,62,39,58,40,10,66,145,243,56,30,231,139,162,160,40,250,46,224,4,16,32,0,32,128,1,65,10,1,0,0,0,0,64,0,0,0,0,0,204,102,0,170,95,69,137,164,32,7,0,0,72,36,8,98,130,0,138,34,128,0,34,10,138,162,40,10,130,40,18,40,9,102,81,20,69,162,136,136,162,160,40,130,66,128,10,32,32,0,32,64,0,1,8,1,0,0,0,0,64,0,0,0,0,0,34,137,0,2,73,133,132,164,160,138,0,0,68,38,8,82,130,0,137,162,77,0,4,234,138,162,32,10,130,32,18,168,8,90,83,20,69,162,128,136,162,36,37,66,130,128,0,0,231,113,60,231,120,79,74,253,60,206,227,53,239,69,81,82,20,125,34,136,0,2,137,15,130,131,32,130,0,0,66,37,199,73,158,7,113,188,45,124,8,169,250,158,32,122,158,238,19,104,8,66,85,20,69,34,135,136,162,36,66,33,2,129,0,0,40,138,162,72,68,81,42,37,69,81,20,141,64,68,81,146,18,33,33,8,1,130,31,21,73,138,32,224,195,3,193,164,0,250,160,136,136,32,64,0,132,232,139,162,32,10,130,40,18,168,8,66,89,244,68,30,136,136,20,21,133,16,2,130,0,0,47,10,162,79,68,81,26,37,69,81,20,5,71,68,74,18,17,17,66,132,0,0,9,149,84,132,32,128,24,152,64,164,0,66,160,136,136,160,141,124,2,8,136,162,40,10,130,40,146,40,9,66,81,20,100,146,136,136,20,149,136,8,2,132,0,128,40,138,162,64,68,81,42,37,69,81,20,5,72,68,74,146,18,9,130,130,0,2,192,79,136,11,27,128,24,88,128,163,239,65,30,71,112,156,13,1,129,240,137,30,231,249,2,39,58,39,250,66,145,19,120,34,135,112,8,138,136,248,14,232,224,7,239,113,60,79,120,81,74,37,69,206,227,133,135,57,132,77,228,125,12,97,0,0,0,5,0,0,0,0,16,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,2,0,0,64,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,0,1,0,0,64,0,1,0,0,0,0,224,0,0,0,0,};
static uint16_t f1_offsets[] = {0,1,3,7,14,22,30,37,39,43,47,53,59,62,67,70,78,84,87,93,99,105,111,117,123,129,135,138,141,146,152,157,163,171,177,183,189,195,201,207,213,219,223,229,235,241,248,254,260,266,273,279,285,291,297,303,311,317,323,329,333,341,345,349,356,359,365,371,377,383,389,394,400,406,408,411,416,418,426,432,438,444,450,455,461,466,472,478,486,492,498,504,509,517,};
static FontWrap fnt_f1(528,10,f1_data,f1_offsets);
#include "UIElement.h"
#include "UIStructs.h"
#include "UIPainter.h"
#undef min
#undef max
#include <vector>
class UI {
UIPainter p;
UIElement root;
UIElement* eFocused = nullptr;
UIElement* eDown = nullptr;
Color cBackground = Color::fromRGB(180,240,180);
public:
UI() {
root.setRect(0,0,240,320);
root.setVisible(true);
p.setFG(cBackground);
p.fillRect(root.getRect());
}
void add(UIElement* e) {
root.addChild(e);
}
void onTouch(const uint16_t x, const uint16_t y) {
if (eDown) {
const uint16_t x1 = x - eDown->getRect().x; // (x,y) relative to elements top-left
const uint16_t y1 = y - eDown->getRect().y;
eDown->onTouch(x1, y1);
} else {
ESP_LOGI("UI", "root_onTouch(%d, %d)", x,y );
eDown = root._onTouch(x,y);
}
}
void onTouchDone() {
if (eDown) {
eDown->onTouchUp();
eDown = nullptr;
}
}
void draw() {
//debugMod1("UI", "draw %zu elements", elements.size());
// for (UIElement* e : elements) {
// e->_draw(p);
// }
root._draw(p);
}
};
#endif // UI_H

97
ext/lcd/ui/UIButton.h Normal file
View File

@@ -0,0 +1,97 @@
#ifndef UI_BUTTON_H
#define UI_BUTTON_H
#include "UIElement.h"
class UIButton : public UIElement {
public:
class Listener {
public:
virtual void onClick(UIButton*) = 0;
};
private:
bool enabled = true;
const char* txt;
uint8_t txtH;
uint16_t txtW;
bool down = false;
const Color fillNormal = Color::fromRGB(180,180,180);
const Color fillDown = Color::fromRGB(120,120,120);
const Color frameBright = Color::fromRGB(230,230,230);
const Color frameDark = Color::fromRGB(50,50,50);
const Color cText = Color::fromRGB(0,0,0);
const Color cTextDisabled = Color::fromRGB(140,140,140);
Listener* listener = nullptr;
static constexpr const char* TAG = "UIButton";
public:
UIButton(const char* txt) : txt(txt) {
txtW = fnt_f1.getWidth(txt);
txtH = fnt_f1.getHeight();
}
void setText(const char* txt) {
this->txt = txt;
}
const char* getText() const {
return this->txt;
}
void setListener(Listener* l) {
this->listener = l;
}
void setEnabled(const bool en) {
this->enabled = en;
setNeedsRedraw();
}
void draw(UIPainter& p) override {
p.setFG( down ? fillDown : fillNormal );
p.fillRect(rect);
p.setFG( down ? frameDark : frameBright );
// p.drawLine(rect.x, rect.y, rect.x+rect.w, rect.y); // top
// p.drawLine(rect.x, rect.y, rect.x, rect.y+rect.h); // left
p.drawLineHor(rect.x, rect.x+rect.w, rect.y); // top
p.drawLineVer(rect.y, rect.y+rect.h, rect.x); // left;
p.setFG( down ? frameBright : frameDark );
// p.drawLine(rect.x, rect.y+rect.h, rect.x+rect.w, rect.y+rect.h); // bottom
// p.drawLine(rect.x+rect.w, rect.y, rect.x+rect.w, rect.y+rect.h); // right
p.drawLineHor(rect.x, rect.x+rect.w, rect.y+rect.h); // bottom
p.drawLineVer(rect.y, rect.y+rect.h, rect.x+rect.w); // right;
p.setFG( enabled ? cText : cTextDisabled );
uint16_t o = down ? 1 : 0;
p.drawText(rect.x+rect.w/2-txtW/2+o, rect.y+rect.h/2-txtH/2+o, txt);
}
void onTouchDown(const uint16_t, const uint16_t) override {
ESP_LOGI(TAG, "onTouchDown()");
if (!enabled) {return;}
down = true;
setNeedsRedraw();
}
void onTouchUp() override {
if (!enabled) {return;}
down = false;
setNeedsRedraw();
if (listener) {listener->onClick(this);}
}
};
#endif // UI_BUTTON_H

121
ext/lcd/ui/UIElement.h Normal file
View File

@@ -0,0 +1,121 @@
#ifndef UI_ELEMENT_H
#define UI_ELEMENT_H
#include "UIStructs.h"
#include "UIPainter.h"
#undef min
#undef max
#include <vector>
class UIElement {
protected:
UIRect rect;
bool _visible = true;
bool _needsRedraw = true;
std::vector<UIElement*> children;
static constexpr const char* TAG = "UIElement";
public:
void setRect(const UIRect r) {
this->rect = r;
setNeedsRedraw();
reLayout();
}
void setRect(const uint16_t x, const uint16_t y, const uint16_t w, const uint16_t h) {
this->rect = UIRect(x,y,w,h);
setNeedsRedraw();
reLayout();
}
const UIRect& getRect() const {
return rect;
}
void setVisible(bool visible) {
this->_visible = visible;
setNeedsRedraw();
}
bool isVisible() const {
return this->_visible;
}
void setNeedsRedraw() {
this->_needsRedraw = true;
}
bool needsRedraw() const {
return this->_needsRedraw;
}
void addChild(UIElement* e) {
children.push_back(e);
}
protected:
friend class UI;
virtual void draw(UIPainter& p) {;}
/** layout needs updating */
virtual void reLayout() {;}
virtual void onTouchDown(uint16_t, uint16_t) {;} // relative (x,y) coordinate
virtual void onTouch(uint16_t, uint16_t) {;} // relative (x,y) coordinate
virtual void onTouchUp() {;}
protected:
UIElement* _onTouch(const uint16_t x, const uint16_t y) {
// if i'm invisible, ignore for me and children
if (!isVisible()) {return nullptr;}
// touch outside of me, ignore for me and children
if (!getRect().contains(x,y)) {return nullptr;}
// find first child that takes the event
for (UIElement* e : children) {
UIElement* taken = e->_onTouch(x, y);
if (taken) {return taken;}
}
// take the event myself
const uint16_t x1 = x - getRect().x; // (x,y) relative to elements top-left
const uint16_t y1 = y - getRect().y;
debugMod2(TAG, "onTouchDown(%d,%d)", x1, y1);
onTouchDown(x1, y1);
return this;
}
void _draw(UIPainter& p) {
// if hidde, ignore for me and children
if (!_visible) {return;}
// draw myself (if needed)
if (_needsRedraw) {
draw(p);
_needsRedraw = false;
}
// call for children as well
for (UIElement* child : children) {
child->_draw(p);
}
}
};
#endif // UI_ELEMENT_H

45
ext/lcd/ui/UILabel.h Normal file
View File

@@ -0,0 +1,45 @@
#ifndef UI_LABEL_H
#define UI_LABEL_H
#include "UIElement.h"
#include "UIStructs.h"
#undef min
#undef max
#include <string>
class UILabel : public UIElement {
std::string txt;
Color cBackground = Color::fromRGB(255,255,255);
Color cText = Color::fromRGB(0,0,0);
public:
UILabel() {
;
}
void setText(const std::string& txt) {
this->txt = txt;
setNeedsRedraw();
}
void draw(UIPainter& p) {
p.setFG(cBackground);
p.fillRect(rect);
//const uint16_t txtW = fnt_f1.getWidth(txt);
//const uint16_t txtH = fnt_f1.getHeight();
p.setFG(cText);
p.drawText(rect.x, rect.y, txt.c_str());
}
};
#endif // UI_LABEL_H

208
ext/lcd/ui/UIList.h Normal file
View File

@@ -0,0 +1,208 @@
#ifndef UI_LIST_H
#define UI_LIST_H
#undef min
#undef max
#include <vector>
#include <string>
#include "UIElement.h"
#include "UIButton.h"
class UIListModel {
std::vector<std::string> entries;
public:
void add(const std::string& str) {
entries.push_back(str);
}
void remove(const size_t idx) {
entries.erase(entries.begin()+idx);
}
size_t size() const {
return entries.size();
}
const std::string& get(const size_t idx) const {
return entries[idx];
}
};
class UIList : public UIElement, public UIButton::Listener {
public:
class Listener {
public:
virtual void onSelected(UIList* lst, int idx) = 0;
};
private:
UIListModel model;
int offset = 0;
int selectedIndex = -1;
UIButton btnUp;
UIButton btnDown;
static constexpr const int btnW = 32;
Color cRect = Color::fromRGB(0,0,0);
Color cNormalBG = Color::fromRGB(230,230,230);
Color cSelectedBG = Color::fromRGB(190,190,255);
Color cText = Color::fromRGB(0,0,0);
Listener* listener = nullptr;
static constexpr const char* TAG = "UIList";
public:
/** ctor */
UIList() : btnUp("<"), btnDown(">") {
addChild(&btnUp);
addChild(&btnDown);
btnUp.setListener(this);
btnDown.setListener(this);
}
void setListener(Listener* l) {
this->listener = l;
}
// UIListModel& getModel() {
// setNeedsRedraw();
// return model;
// }
// const UIListModel& getModel() const {
// return model;
// }
void add(const std::string& str) {
model.add(str);
btnUp.setVisible(needsScroll());
btnDown.setVisible(needsScroll());
setNeedsRedraw();
}
void remove(const size_t idx) {
model.remove(idx);
if (idx == selectedIndex) {
selectedIndex = -1;
if (listener) {listener->onSelected(this, selectedIndex);}
} else if (idx < selectedIndex) {
--selectedIndex;
if (listener) {listener->onSelected(this, selectedIndex);}
}
if (offset > maxOffset()) {offset = maxOffset();}
btnUp.setVisible(needsScroll());
btnDown.setVisible(needsScroll());
setNeedsRedraw();
}
size_t size() const {
return model.size();
}
const std::string& get(const size_t idx) const {
return model.get(idx);
}
int getSelectedIndex() const {
return this->selectedIndex;
}
void reLayout() override {
int h = rect.h / 2 - 1;
btnUp.setRect(rect.x+rect.w-btnW-1, rect.y+1, btnW, h);
btnDown.setRect(rect.x+rect.w-btnW-1, rect.y+h+2, btnW, h);
}
virtual void draw(UIPainter& p) override {
debugMod(TAG, "draw()");
debugMod4(TAG, "rect: %d %d %d %d", rect.x, rect.y, rect.w, rect.h);
const uint8_t oy = (elementHeight() - fnt_f1.getHeight()) / 2;
const uint16_t entryW = rect.w - (needsScroll() ? btnW : 0);
// outline rectangle
p.setFG(cNormalBG);
p.fillRect(rect.x+1, rect.y+1, entryW, rect.h-2);
p.setFG(cRect);
p.drawRect(rect);
// display as many elements as fit within the list's height
for (unsigned int i = 0; i < elementsVisible(); ++i) {
// determine position (y-coordinate)
const uint16_t y = i * elementHeight();
// determine element from model
const int idx = i+offset;
const bool selected = idx == selectedIndex;
// draw background depending on selection
//p.setFG( selected ? cSelectedBG : cNormalBG );
//p.fillRect(UIRect(rect.x+1, rect.y+y+1, entryW-1, elementHeight()-1));
if (selected) {
p.setFG( cSelectedBG );
p.fillRect(UIRect(rect.x+1, rect.y+y+1, entryW-1, elementHeight()-1));
}
// draw text
p.setFG(cText);
p.drawText(rect.x+3, rect.y + y + oy, model.get(idx).c_str());
}
}
virtual void onTouchDown(uint16_t, uint16_t y) override {
unsigned int idx = y / elementHeight() + offset;
this->selectedIndex = (idx < numElements()) ? (idx) : (-1);
debugMod1(TAG, "selected: %d", selectedIndex);
setNeedsRedraw();
if (listener) {listener->onSelected(this, selectedIndex);}
}
virtual void onTouch(uint16_t, uint16_t) override {
}
virtual void onTouchUp() override {
}
virtual void onClick(UIButton* btn) override {
if (btn == &btnUp) {
if (offset > 0) {--offset; setNeedsRedraw();}
} else if (btn == &btnDown) {
if (offset < maxOffset()) {++offset; setNeedsRedraw();}
}
}
private:
unsigned int elementHeight() const {return 16;}
unsigned int maxElementsVisible() const {return rect.h / elementHeight();}
unsigned int elementsVisible() const {return std::min(maxElementsVisible(), numElements());}
unsigned int numElements() const {return model.size();}
unsigned int maxOffset() const {return numElements()-maxElementsVisible();}
bool needsScroll() const {return numElements() > maxElementsVisible();}
};
#endif // UI_LIST_H

52
ext/lcd/ui/UIPainter.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef UI_PAINTER_H
#define UI_PAINTER_H
#include "../../../Debug.h"
#include "../Draw.h"
#include "UIStructs.h"
class Setter;
class FontWrap;
extern FontWrap fnt_f1;
extern Setter setter;
class UIPainter {
public:
void drawLine(const uint16_t x1, const uint16_t y1, const uint16_t x2, const uint16_t y2) {
debugMod("UI", "draw line");
drawer.drawLine(x1,y1, x2,y2);
}
void drawLineHor(const uint16_t x1, const uint16_t x2, const uint16_t y) {
drawer.drawLineHor(x1,x2,y);
}
void drawLineVer(const uint16_t y1, const uint16_t y2, const uint16_t x) {
drawer.drawLineVer(y1,y2,x);
}
void drawRect(UIRect r) {
drawer.drawRect(r.x, r.y, r.w, r.h);
}
void drawText(const uint16_t x, const uint16_t y, const char* str) {
fnt_f1.draw(str, x, y, setter);
}
void setFG(const Color fg) {
drawer.setColor(fg);
}
void fillRect(const UIRect rect) {
drawer.fillRect(rect.x, rect.y, rect.w, rect.h);
}
void fillRect(const uint16_t x, const uint16_t y, const uint16_t w, const uint16_t h) {
drawer.fillRect(x,y,w,h);
}
};
#endif // UI_PAINTER_H

39
ext/lcd/ui/UIStructs.h Normal file
View File

@@ -0,0 +1,39 @@
#ifndef UI_STRUCTS_H
#define UI_STRUCTS_H
#include <cstdint>
struct UIPoint {
uint16_t x;
uint16_t y;
UIPoint() : x(0), y(0) {;}
UIPoint(uint16_t x, uint16_t y) : x(x), y(y) {;}
};
struct UIRect {
uint16_t x;
uint16_t y;
uint16_t w;
uint16_t h;
UIRect() : x(0), y(0), w(0), h(0) {;}
UIRect(const uint16_t x, const uint16_t y, const uint16_t w, const uint16_t h) : x(x), y(y), w(w), h(h) {;}
bool contains(const uint16_t x, const uint16_t y) const {
return
(this->x <= x) &&
(this->y <= y) &&
(x <= this->x+this->w) &&
(y <= this->y+this->h);
}
};
#endif // UI_STRUCTS_H

BIN
ext/lcd/ui/ui.tar.gz Normal file

Binary file not shown.

View File

@@ -4,6 +4,7 @@
#include "../../data/Color.h"
#include "../../Platforms.h"
#include "../../Debug.h"
@@ -14,9 +15,11 @@
template <int numLEDs> class WS2812B {
#define LED_SET_PIN_TO_OUTPUT GPIO5_OUTPUT_SET
#define LED_SET_PIN_H GPIO5_H
#define LED_SET_PIN_L GPIO5_L
static constexpr const char* NAME = "WS2812B";
// #define LED_SET_PIN_TO_OUTPUT GPIO5_OUTPUT_SET
// #define LED_SET_PIN_H GPIO5_H
// #define LED_SET_PIN_L GPIO5_L
//#define NS_PER_TICK ( (1000ul*1000ul*1000ul) / (80ul*1000ul*1000ul) )
@@ -35,6 +38,7 @@
void init() {
LED_SET_PIN_TO_OUTPUT;
debugMod1(NAME, "init with %d leds", numLEDs);
}
/** set the color for the given LED */
@@ -78,7 +82,7 @@
ets_intr_lock();
// process each LED
for (uint8_t i = 0; i < numLEDs; ++i) {
for (int i = 0; i < numLEDs; ++i) {
// send each LEDs 24-bit GRB data
if (enabled[i]) {
@@ -100,6 +104,36 @@
}
/** flush configured changes, including global brightness */
void flushBrightness(const uint8_t brightness) {
LED_SET_PIN_TO_OUTPUT;
ets_intr_lock();
// process each LED
for (int i = 0; i < numLEDs; ++i) {
// send each LEDs 24-bit GRB data
if (enabled[i]) {
const Color rgb = colors[i].brightness(brightness);
sendByte(rgb.g);
sendByte(rgb.r);
sendByte(rgb.b);
} else {
sendByte(0);
sendByte(0);
sendByte(0);
}
}
ets_intr_unlock();
reset();
}
private:
inline void sendByte(uint8_t b) {
@@ -212,7 +246,7 @@
};
#elif ESP32aaa
#elif false// ESP32aaa
//#include <driver/gpio.h>
#include <rom/ets_sys.h>
@@ -419,7 +453,7 @@
};
#elif ESP32
#elif false //ESP32
#include <driver/gpio.h>
#include <rom/ets_sys.h>
@@ -612,7 +646,7 @@
};
#elif othertest
#elif false //othertest
//#include <driver/gpio.h>
#include <rom/ets_sys.h>

277
ext/sens/BME280.h Normal file
View File

@@ -0,0 +1,277 @@
#ifndef SENS_BME280
#define SENS_BME280
#include "../../io/SoftI2C.h"
class BME280 {
static constexpr const char* NAME = "BME280";
static constexpr uint8_t ADDR7 = 0b1110110;
static constexpr uint8_t REG_CTRL1 = 0xF2; // humidity
static constexpr uint8_t REG_CTRL2 = 0xF4; // temp, pressure, mode
static constexpr uint8_t REG_STATUS = 0xF3;
static constexpr uint8_t REG_PRESSURE = 0xF7;
static constexpr uint8_t REG_TEMPERATURE= 0xFA;
static constexpr uint8_t REG_HUMIDITY = 0xFD;
static constexpr uint8_t REG_DIG_T1 = 0x88;
static constexpr uint8_t REG_DIG_T2 = 0x8A;
static constexpr uint8_t REG_DIG_T3 = 0x8C;
public:
bool started = false;
/** internal sensor calibration values */
struct Calibration {
uint16_t dig_T1 = 0;
int16_t dig_T2 = 0;
int16_t dig_T3 = 0;
uint16_t dig_P1 = 0;
int16_t dig_P2 = 0;
int16_t dig_P3 = 0;
int16_t dig_P4 = 0;
int16_t dig_P5 = 0;
int16_t dig_P6 = 0;
int16_t dig_P7 = 0;
int16_t dig_P8 = 0;
int16_t dig_P9 = 0;
uint8_t dig_H1 = 0;
int16_t dig_H2 = 0;
uint8_t dig_H3 = 0;
int16_t dig_H4 = 0;
int16_t dig_H5 = 0;
int8_t dig_H6 = 0;
} cal;
bool isPresent() {
return i2c::query(ADDR7);
}
private:
void readCalib() {
debugMod(NAME, "readCalib()");
// read all 24 calibration bytes for temperature and pressure
uint8_t b1[24];
readRegister(REG_DIG_T1, b1, 24);
cal.dig_T1 = (b1[1] << 8) | b1[0];
cal.dig_T2 = (b1[3] << 8) | b1[2];
cal.dig_T3 = (b1[5] << 8) | b1[4];
cal.dig_P1 = (b1[7] << 8) | b1[6];
cal.dig_P2 = (b1[9] << 8) | b1[8];
cal.dig_P3 = (b1[11] << 8) | b1[10];
cal.dig_P4 = (b1[13] << 8) | b1[12];
cal.dig_P5 = (b1[15] << 8) | b1[14];
cal.dig_P6 = (b1[17] << 8) | b1[16];
cal.dig_P7 = (b1[19] << 8) | b1[18];
cal.dig_P8 = (b1[21] << 8) | b1[20];
cal.dig_P9 = (b1[23] << 8) | b1[22];
// humidity
readRegister(0xA1, &cal.dig_H1, 1);
readRegister(0xE1, b1, 7);
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_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);
}
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);
writeRegister(REG_CTRL1, &cfg1, 1);
writeRegister(REG_CTRL2, &cfg2, 1);
}
public:
void startOnce() {
if (started) {return;}
debugMod(NAME, "startOnce()");
readCalib();
start();
started = true;
}
uint8_t getStatus() {
uint8_t res[1];
readRegister(REG_STATUS, res, 1);
//os_printf("Status: %d \n", res[0]);
return 0;
}
/** get current pressure in hPa */
float getPressure() {
uint8_t res[3];
readRegister(REG_PRESSURE, res, 3);
//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];
readRegister(REG_TEMPERATURE, res, 3);
//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];
readRegister(REG_HUMIDITY, res, 2);
//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) {os_printf("failed start write\n"); return false;}
ok = i2c::writeByteAndCheck(addr);
if (!ok) {os_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) {os_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) {os_printf("failed start write\n"); return false;}
ok = i2c::writeByteAndCheck(addr);
if (!ok) {os_printf("failed to select register %d\n", addr); return false;}
ok = i2c::writeBytesAndCheck(src, len);
if (!ok) {os_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;
using BME280_U32_t = uint32_t;
using BME280_S64_t = int64_t;
BME280_S32_t t_fine = 0;
// Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC.
// t_fine carries fine temperature as global value
BME280_S32_t BME280_compensate_T_int32(BME280_S32_t adc_T) {
BME280_S32_t var1, var2, T;
var1 = ((((adc_T>>3) - ((BME280_S32_t)cal.dig_T1<<1))) * ((BME280_S32_t)cal.dig_T2)) >> 11;
var2 = (((((adc_T>>4) - ((BME280_S32_t)cal.dig_T1)) * ((adc_T>>4) - ((BME280_S32_t)cal.dig_T1))) >> 12) * ((BME280_S32_t)cal.dig_T3)) >> 14;
t_fine = var1 + var2;
T = (t_fine * 5 + 128) >> 8;
return T;
}
// Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
// Output value of “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa
BME280_U32_t BME280_compensate_P_int64(BME280_S32_t adc_P) {
BME280_S64_t var1, var2, p;
var1 = ((BME280_S64_t)t_fine) - 128000;
var2 = var1 * var1 * (BME280_S64_t)cal.dig_P6;
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;
if (var1 == 0) {return 0;} // avoid exception caused by division by zero
p = 1048576-adc_P;
p = (((p<<31)-var2)*3125)/var1;
var1 = (((BME280_S64_t)cal.dig_P9) * (p>>13) * (p>>13)) >> 25;
var2 = (((BME280_S64_t)cal.dig_P8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((BME280_S64_t)cal.dig_P7)<<4);
return (BME280_U32_t)p;
}
// Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22 integer and 10 fractional bits).
// Output value of “47445” represents 47445/1024 = 46.333 %RH
BME280_U32_t bme280_compensate_H_int32(BME280_S32_t adc_H) {
BME280_S32_t v_x1_u32r;
v_x1_u32r = (t_fine - ((BME280_S32_t)76800));
v_x1_u32r = (((((adc_H << 14) - (((BME280_S32_t)cal.dig_H4) << 20) - (((BME280_S32_t)cal.dig_H5) * v_x1_u32r)) +
((BME280_S32_t)16384)) >> 15) * (((((((v_x1_u32r * ((BME280_S32_t)cal.dig_H6)) >> 10) * (((v_x1_u32r *
((BME280_S32_t)cal.dig_H3)) >> 11) + ((BME280_S32_t)32768))) >> 10) + ((BME280_S32_t)2097152)) *
((BME280_S32_t)cal.dig_H2) + 8192) >> 14));
v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((BME280_S32_t)cal.dig_H1)) >>
4));
v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
return (BME280_U32_t)(v_x1_u32r>>12);
}
};
#endif

154
ext/sens/MPU6050.h Normal file
View File

@@ -0,0 +1,154 @@
#ifndef SENS_MPU6050
#define SENS_MPU6050
#include "../../io/SoftI2C.h"
#include "../../Debug.h"
/**
* accelereomter/gyroscope
* https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Datasheet1.pdf
* https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf
* https://github.com/kriswiner/MPU6050/blob/master/MPU6050BasicExample.ino
*/
class MPU6050 {
private:
static constexpr const char* NAME = "MPU6050";
static constexpr uint8_t ADDR = 0b1101000 ;
static constexpr uint8_t REG_CFG_GYRO = 0x1B;
static constexpr uint8_t REG_CFG_ACC = 0x1C;
static constexpr uint8_t REG_ACCEL_XOUT_H = 0x3B;
static constexpr uint8_t REG_SMPLRT_DIV = 0x19;
static constexpr uint8_t REG_CONFIG = 0x1A;
static constexpr uint8_t REG_PWR_MGMT_1 = 0x6B;
bool inited = false;
private:
void init() {
debugMod(NAME, "init()");
// set clock source to be PLL with x-axis gyroscope reference, bits 2:0 = 001
writeRegister(REG_PWR_MGMT_1, 0b001); // table on page 40
// Configure Gyro and Accelerometer
// Disable FSYNC and set accelerometer and gyro bandwidth to 44 and 42 Hz, respectively;
// DLPF_CFG = bits 2:0 = 010; this sets the sample rate at 1 kHz for both
//writeRegister(REG_CONFIG, 0x03); // table on page 13
writeRegister(REG_CONFIG, 0x00); // table on page 13
// Set sample rate = gyroscope output rate/(1 + SMPLRT_DIV)
writeRegister(REG_SMPLRT_DIV, 0x04); // Use a 200 Hz sample rate
// configure gyro as +/- 4G -> +32767 = +4G, -32768 = -4G
writeRegister(REG_CFG_ACC, 0b01 << 3); // table on page 15
#define oneGto1000(x) ((int)x)*1000/(32768/4)
}
bool writeRegister(const uint8_t addr, const uint8_t val) {
bool ok;
// address the slave in write mode and select the first register to read
ok = i2c::startWrite(ADDR);
if (!ok) {os_printf("failed start write\n"); return false;}
ok = i2c::writeByteAndCheck(addr);
if (!ok) {os_printf("failed to select register %d\n", addr); return false;}
ok = i2c::writeBytesAndCheck(&val, 1);
if (!ok) {os_printf("failed to write register contents \n"); return false;}
// done
i2c::stop();
return true;
}
public:
struct Acc {
int16_t x;
int16_t y;
int16_t z;
};
struct Gyro {
int16_t x;
int16_t y;
int16_t z;
};
struct Res {
Acc acc;
int16_t temp;
Gyro gyro;
};
void initOnce() {
if (inited) {return;}
init();
inited = true;
}
bool isPresent() {
return i2c::query(ADDR);
}
bool query(Res& res) {
bool ok;
// select register(s) to read
//i2c::start();
ok = i2c::startWrite(ADDR);
if (!ok) {os_printf("failed start write1\n"); return false;}
ok = i2c::writeByteAndCheck(REG_ACCEL_XOUT_H);
if (!ok) {os_printf("failed select register\n"); return false;}
i2c::stop();
// read registers
uint8_t buf[14];
//i2c::start();
ok = i2c::startRead(ADDR);
if (!ok) {os_printf("failed start write2\n"); return false;}
i2c::readBytes(buf, 14);
i2c::stop();
res.acc.x = (buf[0] << 8) | buf[1];
res.acc.y = (buf[2] << 8) | buf[3];
res.acc.z = (buf[4] << 8) | buf[5];
res.temp = (buf[6] << 8) | buf[7];
res.gyro.x = (buf[8] << 8) | buf[9];
res.gyro.y = (buf[10] << 8) | buf[11];
res.gyro.z = (buf[12] << 8) | buf[13];
res.acc.x = oneGto1000(res.acc.x);
res.acc.y = oneGto1000(res.acc.y);
res.acc.z = oneGto1000(res.acc.z);
//os_printf("Acc (%d, %d, %d)\n", res.acc.x, res.acc.y, res.acc.z);
//os_printf("Gyro (%d, %d, %d)\n", res.gyro.x, res.gyro.y, res.gyro.z);
//os_printf("Temp (%d)\n", res.temp);
return true;
}
};
#endif

1127
ext/sens/VL53L0X.h Normal file

File diff suppressed because it is too large Load Diff

132
ext/sens/XPT2046.h Normal file
View File

@@ -0,0 +1,132 @@
#ifndef XPT2046_H
#define XPT2046_H
#include "../../Platforms.h"
#include "../../io/HardSPI.h"
#include "../../io/SoftSPI.h"
// https://www.buydisplay.com/download/ic/XPT2046.pdf
/** SPI-like touch controller */
//template <int PIN_CS, int PIN_MISO, int PIN_MOSI, int PIN_CLK> class XPT2046 {
template <int PIN_CS, typename SPI> class XPT2046 {
//SoftSPI<PIN_MISO, PIN_MOSI, PIN_CLK, true> spi;
//HardSPI<PIN_MISO, PIN_MOSI, PIN_CLK> spi;
static constexpr int PD0 = 0;
static constexpr int PD1 = 1;
static constexpr int SER_DFR = 2;
static constexpr int MODE = 3;
static constexpr int ADDR = 4;
static constexpr int START = 7;
SPI& spi;
public:
XPT2046(SPI& spi) : spi(spi) {
//spi.init();
GPIO::setOutput(PIN_CS);
}
struct Result {
bool valid;
uint16_t x;
uint16_t y;
};
Result read() {
GPIO::clear(PIN_CS);
//vTaskDelay(1 / portTICK_PERIOD_MS);
Result res;
if (!isTouched()) {
res.valid = false;
} else {
const uint16_t y = readAvg(1);
const uint16_t x = readAvg(5);
res.y = y;
res.x = x;
res.valid = (x != 0xFFFF) && (y != 0xFFFF);
}
GPIO::set(PIN_CS);
return res;
}
private:
/** read 12-bit result from the given input-address using either differential mode or not */
uint16_t read(const int inp, const bool differential) {
//uint8_t buf[2];
const uint8_t diff = differential ? 0 : 1;
const uint8_t cmd = (1 << START) | (inp << ADDR) | (0 << MODE) | (diff << SER_DFR) | (1 << PD1) | (1 << PD0);
//printf("touch cmd: %d\n", cmd);
// spi.writeByte(cmd);
// uint8_t v1 = spi.readByte();
// uint8_t v2 = spi.readByte();
// spi.read(buf, 2);
// mainly needed for hardware SPI, where send8+read8+read8 does not work as expected
// output: cccccccc 00000000 00000000 00000000
// input: -------- -rrrrrrr rrrrr--- --------
const uint32_t tmp = spi.readWriteQuad(cmd << 24);
const uint8_t v1 = (tmp >> 16) & 0xFF;
const uint8_t v2 = (tmp >> 8) & 0xFF;
const uint16_t res = (v1 << 8 | v2) >> 3;
//printf("res: %d\n", res);
return res;
}
bool isTouched() {
// read Y-axis in non-differential mode. if result is close to 4095, screen is not touched
for (int i = 0; i < 4; ++i) {
if (read(1,false) > 3900) {return false;}
}
// read X-axis in non-differential mode. if result is close to 4095, screen is not touched
for (int i = 0; i < 4; ++i) {
if (read(5,false) > 3900) {return false;}
}
return true;
}
uint16_t readAvg(const int inp) {
// dummy-reads to stabilize the result
for (int i = 0; i < 4; ++i) {read(inp, true);}
// perform several reads and estimate std-dev
static constexpr uint8_t cnt = 12;
uint32_t sum = 0;
uint32_t sum2 = 0;
for (int i = 0; i < cnt; ++i) {
const uint16_t cur = read(inp, true);
sum += cur;
sum2 += cur*cur;
}
const uint32_t stdDev = (sum2/cnt) - (sum/cnt)*(sum/cnt);
//printf("%d\n", stdDev);
return (stdDev < 4096) ? ((sum/cnt)&0xFFFF) : (0xFFFF);
}
};
#endif // XPT2046_H

124
ext/time/DS3231.h Normal file
View File

@@ -0,0 +1,124 @@
#ifndef TIME_DS3231
#define TIME_DS3231
#include "../../io/SoftI2C.h"
class DS3231 {
static constexpr uint8_t ADDR7 = 0x68;
static constexpr uint8_t REG_SECONDS = 0x00;
static constexpr uint8_t REG_MINUTES = 0x01;
static constexpr uint8_t REG_HOURS = 0x02;
public:
bool isPresent() {
return i2c::query(ADDR7);
}
struct Time {
uint8_t h;
uint8_t m;
uint8_t s;
};
struct Date {
uint8_t d;
uint8_t m;
uint8_t y;
};
struct Res {
Time time;
Date date;
};
Res get() {
uint8_t buf[8];
readRegister(0x00, buf, 8);
Res res;
res.time.h = (((buf[2] & 0b00110000)>>4)*10) + (buf[2] & 0b1111);
res.time.m = (((buf[1] & 0b01110000)>>4)*10) + (buf[1] & 0b1111);
res.time.s = (((buf[0] & 0b01110000)>>4)*10) + (buf[0] & 0b1111);
res.date.d = (((buf[4] & 0b00110000)>>4)*10) + (buf[4] & 0b1111);
res.date.m = (((buf[5] & 0b00010000)>>4)*10) + (buf[5] & 0b1111);
res.date.y = (((buf[6] & 0b11110000)>>4)*10) + (buf[6] & 0b1111);
os_printf("%d %d %d \n", res.time.h, res.time.m, res.time.s);
os_printf("%d %d %d \n", res.date.d, res.date.m, res.date.y);
return res;
}
void setTime(uint8_t h, uint8_t m, uint8_t s) {
uint8_t buf[3];
buf[0] = ((s/10)<<4) + (s % 10);
buf[1] = ((m/10)<<4) + (m % 10);
buf[2] = ((h/10)<<4) + (h % 10);
writeRegister(0x00, buf, 3);
}
void setDate(uint8_t d, uint8_t m, uint8_t y) {
uint8_t buf[3];
buf[0] = ((d/10)<<4) + (d % 10);
buf[1] = ((m/10)<<4) + (m % 10);
buf[2] = ((y/10)<<4) + (y % 10);
writeRegister(0x04, buf, 3);
}
private:
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) {os_printf("failed start write\n"); return false;}
ok = i2c::writeByteAndCheck(addr);
if (!ok) {os_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) {os_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) {os_printf("failed start write\n"); return false;}
ok = i2c::writeByteAndCheck(addr);
if (!ok) {os_printf("failed to select register %d\n", addr); return false;}
ok = i2c::writeBytesAndCheck(src, len);
if (!ok) {os_printf("failed to write register contents \n"); return false;}
// done
i2c::stop();
return true;
}
};
#endif

122
io/GPIO.h Normal file
View File

@@ -0,0 +1,122 @@
#ifndef ESP_LIB_GPIO_H
#define ESP_LIB_GPIO_H
#include "../Platforms.h"
#if ESP8266
#include "fastGPIO.h"
struct GPIO {
static inline bool get(const uint8_t num) {
return GPIO_INPUT_GET(num);
}
static inline void set(const uint8_t num) {
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << num);
}
static inline void clear(const uint8_t num) {
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << num);
}
static inline void setOutput(const uint8_t num) {
switch(num) {
case 0: GPIO0_OUTPUT_SET; break;
case 1: GPIO1_OUTPUT_SET; break;
case 2: GPIO2_OUTPUT_SET; break;
case 3: GPIO3_OUTPUT_SET; break;
case 4: GPIO4_OUTPUT_SET; break;
case 5: GPIO5_OUTPUT_SET; break;
//case 6: GPIO6_OUTPUT_SET; break;
//case 7: GPIO7_OUTPUT_SET; break;
//case 8: GPIO8_OUTPUT_SET; break;
case 9: GPIO9_OUTPUT_SET; break;
case 10: GPIO10_OUTPUT_SET; break;
//case 11: GPIO11_OUTPUT_SET; break;
case 12: GPIO12_OUTPUT_SET; break;
case 13: GPIO13_OUTPUT_SET; break;
case 14: GPIO14_OUTPUT_SET; break;
case 15: GPIO15_OUTPUT_SET; break;
}
}
static inline void setInput(const uint8_t num) {
switch(num) {
case 0: GPIO0_INPUT_SET; break;
case 1: GPIO1_INPUT_SET; break;
case 2: GPIO2_INPUT_SET; break;
case 3: GPIO3_INPUT_SET; break;
case 4: GPIO4_INPUT_SET; break;
case 5: GPIO5_INPUT_SET; break;
//case 6: GPIO6_INPUT_SET; break;
//case 7: GPIO7_INPUT_SET; break;
//case 8: GPIO8_INPUT_SET; break;
case 9: GPIO9_INPUT_SET; break;
case 10: GPIO10_INPUT_SET; break;
//case 11: GPIO11_INPUT_SET; break;
case 12: GPIO12_INPUT_SET; break;
case 13: GPIO13_INPUT_SET; break;
case 14: GPIO14_INPUT_SET; break;
case 15: GPIO15_INPUT_SET; break;
}
}
};
#elif ESP32
#include "driver/gpio.h"
struct MyGPIO {
static inline bool get(const uint8_t num) {
return get((gpio_num_t)num);
}
static inline bool get(const gpio_num_t num) {
return gpio_get_level(num); // TODO faster access like READ_PERI_REG??
}
template <typename T> static inline void setOrClear(const uint8_t num, const T val) {
if (val) {set(num);} else {clear(num);}
//WRITE_PERI_REG(GPIO_OUT_W1TS_REG, (val != 0) << num); // branchless but usually slower
//WRITE_PERI_REG(GPIO_OUT_W1TC_REG, (val == 0) << num);
}
static inline void set(const uint8_t num) {
WRITE_PERI_REG(GPIO_OUT_W1TS_REG, 1 << num);
}
static inline void clear(const uint8_t num) {
WRITE_PERI_REG(GPIO_OUT_W1TC_REG, 1 << num);
}
static inline void setOutput(const uint8_t num) {
setOutput((gpio_num_t)num);
}
static inline void setOutput(const gpio_num_t num) {
gpio_set_direction(num, GPIO_MODE_OUTPUT);
}
static inline void setInput(const uint8_t num) {
setInput((gpio_num_t)num);
}
static inline void setInput(const gpio_num_t num) {
gpio_set_direction(num, GPIO_MODE_INPUT);
}
static void toggleBuiltInLED() {
static bool level = false;
setOutput(GPIO_NUM_2);
level = !level;
if (level) {set(GPIO_NUM_2);} else {clear(GPIO_NUM_2);}
}
};
#endif
#endif // ESP_LIB_GPIO_H

228
io/HardSPI.h Normal file
View File

@@ -0,0 +1,228 @@
#ifndef HARDSPI_H
#define HARDSPI_H
#include "../Debug.h"
#include "driver/spi_master.h"
#include <cmath>
#include <string.h>
//static spi_transaction_t trans[2];
#define PIN_NUM_MISO GPIO_NUM_19
#define PIN_NUM_MOSI GPIO_NUM_23
#define PIN_NUM_CLK GPIO_NUM_18
#define PIN_NUM_CS GPIO_NUM_2
template <int PIN_NUM_MISO, int PIN_NUM_MOSI, int PIN_NUM_CLK> class HardSPI {
//class HardSPI {
static constexpr int MAX_LEN = 4000;
spi_device_handle_t spi;
spi_bus_config_t buscfg;
spi_device_interface_config_t devcfg;
static constexpr const char* TAG = "hwSPI";
public:
// can be called before every transmit
// static void IRAM_ATTR pre_transfer_callback(spi_transaction_t *t) {
// }
/** ctor */
HardSPI() {
init();
}
private:
void init() {
int ret;
// BUS specific options
memset(&buscfg, 0, sizeof(buscfg));
buscfg.miso_io_num = PIN_NUM_MISO;
buscfg.mosi_io_num = PIN_NUM_MOSI;
buscfg.sclk_io_num = PIN_NUM_CLK;
buscfg.quadwp_io_num = -1;
buscfg.quadhd_io_num = -1;
buscfg.max_transfer_sz = MAX_LEN;//320*240*2;
buscfg.flags = 0;
buscfg.intr_flags = 0;
// DEVICE specific options
memset(&devcfg, 0, sizeof(devcfg));
devcfg.clock_speed_hz = 10 * 1000 * 1000;
devcfg.mode = 0;
devcfg.spics_io_num = -1;//PIN_NUM_CS; // currently not used
devcfg.queue_size = 2;
devcfg.pre_cb = nullptr;
//devcfg.pre_cb = pre_transfer_callback; // can be called before every transmit
// Initialize the SPI bus
ret = spi_bus_initialize(HSPI_HOST, &buscfg, 1);
ESP_ERROR_CHECK(ret);
// Attach the device to the SPI bus
ret = spi_bus_add_device(HSPI_HOST, &devcfg, &spi);
ESP_ERROR_CHECK(ret);
}
public:
/** blocking transmit the given bytes */
void write(const uint8_t* data, size_t len) {
spi_transaction_t t;
memset(&t, 0, sizeof(spi_transaction_t));
while(len > 0) {
const size_t chunkLen = min(MAX_LEN, (len));
t.length = 8 * chunkLen; // in bits
t.tx_buffer = data; // MOSI only
t.flags = 0;
// blocking transfer
esp_err_t ret = spi_device_polling_transmit(spi, &t);
ESP_ERROR_CHECK(ret);
// update remaining length and data pointer
len -= chunkLen;
data += chunkLen;
}
}
void read(uint8_t* dst, size_t len) {
// sanity check
{
const size_t addr = reinterpret_cast<size_t>(dst);
if ((addr % 4) != 0) {
ESP_LOGE(TAG, "read-buffer must be 32-bit aligned");
}
}
spi_transaction_t t;
memset(&t, 0, sizeof(spi_transaction_t));
//debugMod1(TAG, "read %d bytes", len);
while(len > 0) {
const size_t chunkLen = min(MAX_LEN, (len));
//ESP_LOGI(TAG, "- read %d byte chunk", chunkLen);
t.length = 8 * chunkLen; // in bits
t.rx_buffer = dst; // MISO only
t.flags = 0;
// blocking transfer
esp_err_t ret = spi_device_polling_transmit(spi, &t);
ESP_ERROR_CHECK(ret);
// update remaining length and destination-data pointer
len -= chunkLen;
dst += chunkLen;
}
}
/** send 4 bytes onto the bus while reading 4 bytes response */
uint32_t readWriteQuad(uint32_t write) {
spi_transaction_t t;
memset(&t, 0, sizeof(spi_transaction_t));
t.length = 8*4;
t.rxlength = 8*4;
t.tx_data[0] = (write >> 24) & 0xFF;
t.tx_data[1] = (write >> 16) & 0xFF;
t.tx_data[2] = (write >> 8) & 0xFF;
t.tx_data[3] = (write >> 0) & 0xFF;
t.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
esp_err_t ret = spi_device_polling_transmit(spi, &t);
ESP_ERROR_CHECK(ret);
return
(static_cast<uint32_t>(t.rx_data[0]) << 24) |
(static_cast<uint32_t>(t.rx_data[1]) << 16) |
(static_cast<uint32_t>(t.rx_data[2]) << 8) |
(static_cast<uint32_t>(t.rx_data[3]) << 0);
}
/** read one byte from the bus */
uint8_t readByte() {
spi_transaction_t t;
memset(&t, 0, sizeof(spi_transaction_t));
t.length = 8*1;
t.flags = SPI_TRANS_USE_RXDATA;
esp_err_t ret = spi_device_polling_transmit(spi, &t);
ESP_ERROR_CHECK(ret);
return t.rx_data[0];
}
void writeByte(const uint8_t byte) {
spi_transaction_t t;
memset(&t, 0, sizeof(spi_transaction_t));
t.length = 8*1;
t.tx_data[0] = byte;
t.flags = SPI_TRANS_USE_TXDATA;
esp_err_t ret = spi_device_polling_transmit(spi, &t);
ESP_ERROR_CHECK(ret);
}
void writeWord(const uint16_t word) {
spi_transaction_t t;
memset(&t, 0, sizeof(spi_transaction_t));
t.length = 8*2;
t.tx_data[0] = static_cast<uint8_t>(word>>8);
t.tx_data[1] = static_cast<uint8_t>(word>>0);
t.flags = SPI_TRANS_USE_TXDATA;
esp_err_t ret = spi_device_polling_transmit(spi, &t);
ESP_ERROR_CHECK(ret);
}
void writeQuad(const uint32_t quad) {
spi_transaction_t t;
memset(&t, 0, sizeof(spi_transaction_t));
t.length = 8*4;
t.tx_data[0] = static_cast<uint8_t>(quad>>24);
t.tx_data[1] = static_cast<uint8_t>(quad>>16);
t.tx_data[2] = static_cast<uint8_t>(quad>>8);
t.tx_data[3] = static_cast<uint8_t>(quad>>0);
t.flags = SPI_TRANS_USE_TXDATA;
esp_err_t ret = spi_device_polling_transmit(spi, &t);
ESP_ERROR_CHECK(ret);
}
};
#endif // HARDSPI_H

1
io/PWM.h Normal file
View File

@@ -0,0 +1 @@

240
io/SoftI2C.h Normal file
View File

@@ -0,0 +1,240 @@
#ifndef SOFTI2C_H
#define SOFTI2C_H
#include "../Platforms.h"
#include "../Debug.h"
#include "GPIO.h"
#if ESP8266
#include "fastGPIO.h"
#elif ESP32
# error "Not yet supported"
#endif
// https://www.best-microcontroller-projects.com/i2c-tutorial.html
namespace i2c {
static constexpr const char* NAME = "SoftI2C";
#if ESP8266
// static inline void init() {
// //debugMod(NAME, "init()");
// GPIO5_OUTPUT_SET; // clock is always output
// //GPIO5_INPUT_PULLUP_SET; // pullup for i2c
// //GPIO4_INPUT_PULLUP_SET; // pullup for i2c
// }
// static inline void sclLo() {GPIO5_L;}
// static inline void sclHi() {GPIO5_H;}
// static inline void sclDirOut() {GPIO5_OUTPUT_SET;}
// static inline void sdaDirIn() {GPIO4_INPUT_SET;}// GPIO4_INPUT_PULLUP_SET;}
// static inline void sdaDirOut() {GPIO4_OUTPUT_SET;}
// static inline uint8_t sdaRead() {return GPIO4_IN;}
// static inline void sdaLo() {GPIO4_L;}
// static inline void sdaHi() {GPIO4_H;}
static constexpr const uint8_t PIN_SCL = 5;
static constexpr const uint8_t PIN_SDA = 4;
#elif ESP32
//# error "Not yet supported"
#endif
#if (SOFTI2C_SPEED == 1)
// safe
static inline void waitShort() {os_delay_us(1);}
static inline void waitLong() {os_delay_us(10);}
#elif (SOFTI2C_SPEED == 2)
// fast
static inline void waitShort() {asm("nop");asm("nop");}
static inline void waitLong() {os_delay_us(1);}
#elif (SOFTI2C_SPEED == 3)
// ultra fast
static inline void waitShort() {}
static inline void waitLong() {asm("nop");asm("nop");asm("nop");asm("nop");}
#else
#error "SOFTI2C Speed not set"
#endif
static inline void init() {
GPIO::setOutput(PIN_SCL); // always output
}
static inline void sclLo() {GPIO::clear(PIN_SCL);}
static inline void sclHi() {GPIO::set(PIN_SCL);}
static inline void sclDirOut() {GPIO::setOutput(PIN_SCL);}
static inline void sdaDirIn() {GPIO::setInput(PIN_SDA);}// GPIO4_INPUT_PULLUP_SET;}
static inline void sdaDirOut() {GPIO::setOutput(PIN_SDA);}
static inline uint8_t sdaRead() {return GPIO::get(PIN_SDA);}
static inline void sdaLo() {GPIO::clear(PIN_SDA);}
static inline void sdaHi() {GPIO::set(PIN_SDA);}
static inline void start() {
init();
sdaDirOut();
sclDirOut();
sdaHi();
sclHi();
waitLong();
sdaLo();
waitLong();
sclLo();
waitLong();
}
static inline void stop() {
sdaDirOut();
sclDirOut();
sdaLo();
sclLo();
waitLong();
sclHi();
waitLong();
sdaHi();
sdaDirIn(); // free the bus
waitLong();
}
/** write one bit to the bus */
static inline void writeBit(const bool out) {
sdaDirOut(); // switch to output mode
if(out) {sdaHi();} else {sdaLo();} // apply data
sclHi(); // clock pulse
waitShort();
sclLo();
waitShort();
sdaDirIn(); // free the bus
}
/** read one bit from the bus */
static inline uint8_t readBit() {
sdaDirIn(); // switch to input mode
sclHi(); // clock pulse and read
waitShort();
const uint8_t val = sdaRead();
sclLo();
waitShort();
return val;
}
static inline bool readAck() {
const uint8_t res = readBit();
//os_printf("readAck() - Bus: %d\n", res);
return res == 0; // ACK when input pulled low
}
static inline void writeAck() {
writeBit(0);
}
static inline void writeNAck() {
writeBit(1);
}
/** read 8 bits from the bus, WITHOUT sending ACK/NACK */
static uint8_t IN_FLASH readByte() {
return
(readBit() << 7) |
(readBit() << 6) |
(readBit() << 5) |
(readBit() << 4) |
(readBit() << 3) |
(readBit() << 2) |
(readBit() << 1) |
(readBit() << 0);
}
/** read the given number of bytes from the slave and generate ACK/NACK as needed */
static void readBytes(uint8_t* dst, uint8_t len) {
while(len) {
*dst = readByte();
--len;
++dst;
if (len) {writeAck();} else {writeNAck();} // done? or want more?
}
}
/** write one byte to the bus */
static void IN_FLASH writeByte(const uint8_t byte) {
writeBit(byte & BIT( 7));
writeBit(byte & BIT( 6));
writeBit(byte & BIT( 5));
writeBit(byte & BIT( 4));
writeBit(byte & BIT( 3));
writeBit(byte & BIT( 2));
writeBit(byte & BIT( 1));
writeBit(byte & BIT( 0));
}
/** write one byte to the bus and check slave's ACK/NACK */
static bool IN_FLASH writeByteAndCheck(const uint8_t byte) {
writeByte(byte);
return readAck();
}
/** write several bytes to the bus and check slave's ACK/NACK */
static bool IN_FLASH writeBytesAndCheck(const uint8_t* src, uint8_t len) {
while(len) {
const bool ok = writeByteAndCheck(*src);
if (!ok) {return false;}
--len; ++src;
}
return true;
}
static inline bool startWrite(const uint8_t addr7) {
start();
writeByte( (addr7<<1) | 0 );
const bool ok = readAck();
return ok;
}
static inline bool startRead(const uint8_t addr7) {
start();
writeByte( (addr7<<1) | 1 );
const bool ok = readAck();
return ok;
}
static inline bool query(const uint8_t addr7) {
bool ok = startWrite(addr7);
stop();
return ok;
}
}
#endif // SOFTSPI_H

View File

@@ -1,11 +1,19 @@
#ifndef SOFTSPI_H
#define SOFTSPI_H
//#include "IO.h"
#include "GPIO.h"
#include "../Platforms.h"
#include "../Debug.h"
#pragma GCC push_options
#pragma GCC optimize ("O3")
/*
#if (PLATFORM == NODE_MCU) || (PLATFORM == WEMOS_D1_MINI)
#include "fastGPIO.h"
@@ -34,29 +42,35 @@
#include "driver/gpio.h"
#include <stdint.h>
#define SPI_PIN_MISO GPIO_NUM_35
#define SPI_PIN_MOSI GPIO_NUM_32
#define SPI_PIN_CLK GPIO_NUM_27
#define SPI_PIN_CS GPIO_NUM_25
// #define SPI_PIN_MISO GPIO_NUM_35
// #define SPI_PIN_MOSI GPIO_NUM_32
// #define SPI_PIN_CLK GPIO_NUM_27
// #define SPI_PIN_CS GPIO_NUM_25
#define SPI_CS_OUTPUT gpio_set_direction(SPI_PIN_CS, GPIO_MODE_OUTPUT)
#define SPI_MOSI_OUTPUT gpio_set_direction(SPI_PIN_MOSI, GPIO_MODE_OUTPUT)
#define SPI_MISO_INPUT gpio_set_direction(SPI_PIN_MISO, GPIO_MODE_INPUT)
#define SPI_PIN_MISO GPIO_NUM_19
#define SPI_PIN_MOSI GPIO_NUM_23
#define SPI_PIN_CLK GPIO_NUM_18
#define SPI_PIN_CS GPIO_NUM_2
#define SPI_CS_OUTPUT GPIO::setOutput(SPI_PIN_CS)
#define SPI_MOSI_OUTPUT GPIO::setOutput(SPI_PIN_MOSI)
#define SPI_MISO_INPUT GPIO::setInput(SPI_PIN_MISO)
#define SPI_MISO_NO_PULLUP //gpio_set_pull_mode(SPI_PIN_MISO, GPIO_FLOATING) /// ??????
#define SPI_CLK_OUTPUT gpio_set_direction(SPI_PIN_CLK, GPIO_MODE_OUTPUT)
#define SPI_CLK_OUTPUT GPIO::setOutput(SPI_PIN_CLK)
#define SPI_CS_LO gpio_set_level(SPI_PIN_CS, 0)
#define SPI_CS_HI gpio_set_level(SPI_PIN_CS, 1)
#define SPI_CS_LO GPIO::clear(SPI_PIN_CS)
#define SPI_CS_HI GPIO::set(SPI_PIN_CS)
#define SPI_CLK_LO gpio_set_level(SPI_PIN_CLK, 0)
#define SPI_CLK_HI gpio_set_level(SPI_PIN_CLK, 1)
#define SPI_CLK_LO GPIO::clear(SPI_PIN_CLK)
#define SPI_CLK_HI GPIO::set(SPI_PIN_CLK)
#define SPI_MOSI_LO gpio_set_level(SPI_PIN_MOSI, 0)
#define SPI_MOSI_HI gpio_set_level(SPI_PIN_MOSI, 1)
#define SPI_MOSI_LO GPIO::clear(SPI_PIN_MOSI)
#define SPI_MOSI_HI GPIO::set(SPI_PIN_MOSI)
#define SPI_MOSI_SC(v) GPIO::setOrClear(SPI_PIN_MOSI, v)
#define SPI_MISO_READ gpio_get_level(SPI_PIN_MISO)
#define SPI_MISO_READ GPIO::get(SPI_PIN_MISO);
#define SPI_FAST
#define SPI_FAST
#else
#error "not supported"
@@ -66,18 +80,6 @@ namespace spi {
static constexpr const char* NAME = "SoftSPI";
// MTDI GPIO12 MISO (DIN) D6
// MTCK GPIO13 MOSI (DOUT) D7
// MTMS GPIO14 CLOCK D5
// MTDO GPIO15 CS / SS D8
// #define PIN_CLK 14
// #define PIN_MISO 12
// #define PIN_MOSI 13
// #define BIT(nr) (1 << 0)
//public:
// SoftSPI() {
// // NOT CALLED!
@@ -94,12 +96,14 @@ namespace spi {
static inline bool getMISO() {return SPI_MISO_READ;} // D6
#ifdef SPI_FAST
static inline void wait() {
__asm__ __volatile__("nop");
//__asm__ __volatile__("nop");
}
static inline void waitLong() {
DELAY_US(1);
//DELAY_US(1);
__asm__ __volatile__("nop"); __asm__ __volatile__("nop");
}
#else
static inline void wait() {
@@ -136,7 +140,7 @@ namespace spi {
return (inp) ? 1 : 0;
}
/** write one bit to the bus */
// write one bit to the bus
static inline void writeBit(const bool out) {
if(out) {SPI_MOSI_HI;} else {SPI_MOSI_LO;}
wait();
@@ -146,7 +150,7 @@ namespace spi {
wait();
}
/** read one bit from the bus */
// read one bit from the bus
static inline uint8_t readBit() {
clkHi();
wait();
@@ -172,7 +176,7 @@ namespace spi {
}
/** read 16 bits */
// read 16 bits
static uint16_t IN_FLASH readWord() {
return
(readBit() << 15) |
@@ -193,54 +197,87 @@ namespace spi {
(readBit() << 0);
}
/** read 8 bits */
static uint8_t IN_FLASH readByte() {
// read 8 bits
static uint8_t IRAM_ATTR readByte() {
return
(readBit() << 7) |
(readBit() << 6) |
(readBit() << 5) |
(readBit() << 4) |
(readBit() << 3) |
(readBit() << 2) |
(readBit() << 1) |
(readBit() << 0);
(readBit() << 7) |
(readBit() << 6) |
(readBit() << 5) |
(readBit() << 4) |
(readBit() << 3) |
(readBit() << 2) |
(readBit() << 1) |
(readBit() << 0);
}
static void IN_FLASH writeWord(const uint16_t word) {
writeBit(word & BIT(15));
writeBit(word & BIT(14));
writeBit(word & BIT(13));
writeBit(word & BIT(12));
writeBit(word & BIT(11));
writeBit(word & BIT(10));
writeBit(word & BIT( 9));
writeBit(word & BIT( 8));
writeBit(word & BIT( 7));
writeBit(word & BIT( 6));
writeBit(word & BIT( 5));
writeBit(word & BIT( 4));
writeBit(word & BIT( 3));
writeBit(word & BIT( 2));
writeBit(word & BIT( 1));
writeBit(word & BIT( 0));
static void IRAM_ATTR writeQuad(const uint32_t quad) {
writeBit(quad & BIT(31));
writeBit(quad & BIT(30));
writeBit(quad & BIT(29));
writeBit(quad & BIT(28));
writeBit(quad & BIT(27));
writeBit(quad & BIT(26));
writeBit(quad & BIT(25));
writeBit(quad & BIT(24));
writeBit(quad & BIT(23));
writeBit(quad & BIT(22));
writeBit(quad & BIT(21));
writeBit(quad & BIT(20));
writeBit(quad & BIT(19));
writeBit(quad & BIT(18));
writeBit(quad & BIT(17));
writeBit(quad & BIT(16));
writeBit(quad & BIT(15));
writeBit(quad & BIT(14));
writeBit(quad & BIT(13));
writeBit(quad & BIT(12));
writeBit(quad & BIT(11));
writeBit(quad & BIT(10));
writeBit(quad & BIT( 9));
writeBit(quad & BIT( 8));
writeBit(quad & BIT( 7));
writeBit(quad & BIT( 6));
writeBit(quad & BIT( 5));
writeBit(quad & BIT( 4));
writeBit(quad & BIT( 3));
writeBit(quad & BIT( 2));
writeBit(quad & BIT( 1));
writeBit(quad & BIT( 0));
}
static void IN_FLASH writeByte(const uint8_t byte) {
writeBit(byte & BIT( 7));
writeBit(byte & BIT( 6));
writeBit(byte & BIT( 5));
writeBit(byte & BIT( 4));
writeBit(byte & BIT( 3));
writeBit(byte & BIT( 2));
writeBit(byte & BIT( 1));
writeBit(byte & BIT( 0));
static void IRAM_ATTR writeWord(const uint16_t word) {
writeBit(word & BIT(15));
writeBit(word & BIT(14));
writeBit(word & BIT(13));
writeBit(word & BIT(12));
writeBit(word & BIT(11));
writeBit(word & BIT(10));
writeBit(word & BIT( 9));
writeBit(word & BIT( 8));
writeBit(word & BIT( 7));
writeBit(word & BIT( 6));
writeBit(word & BIT( 5));
writeBit(word & BIT( 4));
writeBit(word & BIT( 3));
writeBit(word & BIT( 2));
writeBit(word & BIT( 1));
writeBit(word & BIT( 0));
}
static void IRAM_ATTR writeByte(uint8_t byte) {
writeBit(byte & BIT( 7));
writeBit(byte & BIT( 6));
writeBit(byte & BIT( 5));
writeBit(byte & BIT( 4));
writeBit(byte & BIT( 3));
writeBit(byte & BIT( 2));
writeBit(byte & BIT( 1));
writeBit(byte & BIT( 0));
}
static uint16_t IN_FLASH readWriteWord(const uint16_t word) {
return
(readWriteBit(word & BIT(15)) << 15) |
(readWriteBit(word & BIT(15)) << 15) |
(readWriteBit(word & BIT(14)) << 14) |
(readWriteBit(word & BIT(13)) << 13) |
(readWriteBit(word & BIT(12)) << 12) |
@@ -273,6 +310,225 @@ namespace spi {
}
*/
template <int PIN_MISO, int PIN_MOSI, int PIN_CLK, bool fast> class SoftSPI {
static constexpr const char* NAME = "softSPI";
public:
/** ctor */
SoftSPI() {
init();
}
private:
void init() {
debugMod(NAME, "init()");
GPIO::setInput(PIN_MISO);
GPIO::setOutput(PIN_MOSI);
GPIO::setOutput(PIN_CLK);
}
private:
static inline void wait() {
if (!fast) {
for (int i = 0; i < 8; ++i) {
__asm__ __volatile__("nop");
}
}
}
inline void clkLo() { GPIO::clear(PIN_CLK); }
inline void clkHi() { GPIO::set(PIN_CLK); }
/** write one bit to the bus */
inline void writeBit(const bool out) {
if(out) {GPIO::set(PIN_MOSI);} else {GPIO::clear(PIN_MOSI);}
wait();
clkHi();
wait();
clkLo();
wait();
}
/** read one bit from the bus */
inline uint8_t readBit() {
clkHi();
wait();
const bool val = GPIO::get(PIN_MISO);
wait();
clkLo();
wait();
return (val) ? 1 : 0;
}
inline uint8_t readWriteBit(const bool out) {
if(out) {GPIO::set(PIN_MOSI);} else {GPIO::clear(PIN_MOSI);}
wait();
clkHi();
wait();
const bool inp = GPIO::get(PIN_MISO);
wait();
clkLo();
wait();
return (inp) ? 1 : 0;
}
public:
void IRAM_ATTR writeQuad(const uint32_t quad) {
// writeBit(quad & BIT(31));
// writeBit(quad & BIT(30));
// writeBit(quad & BIT(29));
// writeBit(quad & BIT(28));
// writeBit(quad & BIT(27));
// writeBit(quad & BIT(26));
// writeBit(quad & BIT(25));
// writeBit(quad & BIT(24));
// writeBit(quad & BIT(23));
// writeBit(quad & BIT(22));
// writeBit(quad & BIT(21));
// writeBit(quad & BIT(20));
// writeBit(quad & BIT(19));
// writeBit(quad & BIT(18));
// writeBit(quad & BIT(17));
// writeBit(quad & BIT(16));
// writeBit(quad & BIT(15));
// writeBit(quad & BIT(14));
// writeBit(quad & BIT(13));
// writeBit(quad & BIT(12));
// writeBit(quad & BIT(11));
// writeBit(quad & BIT(10));
// writeBit(quad & BIT( 9));
// writeBit(quad & BIT( 8));
// writeBit(quad & BIT( 7));
// writeBit(quad & BIT( 6));
// writeBit(quad & BIT( 5));
// writeBit(quad & BIT( 4));
// writeBit(quad & BIT( 3));
// writeBit(quad & BIT( 2));
// writeBit(quad & BIT( 1));
// writeBit(quad & BIT( 0));
writeByte((quad>>24)&0xFF);
writeByte((quad>>16)&0xFF);
writeByte((quad>> 8)&0xFF);
writeByte((quad>> 0)&0xFF);
}
void IRAM_ATTR writeWord(const uint16_t word) {
// writeBit(word & BIT(15));
// writeBit(word & BIT(14));
// writeBit(word & BIT(13));
// writeBit(word & BIT(12));
// writeBit(word & BIT(11));
// writeBit(word & BIT(10));
// writeBit(word & BIT( 9));
// writeBit(word & BIT( 8));
// writeBit(word & BIT( 7));
// writeBit(word & BIT( 6));
// writeBit(word & BIT( 5));
// writeBit(word & BIT( 4));
// writeBit(word & BIT( 3));
// writeBit(word & BIT( 2));
// writeBit(word & BIT( 1));
// writeBit(word & BIT( 0));
writeByte((word>>8)&0xFF);
writeByte((word>>0)&0xFF);
}
void IRAM_ATTR writeByte(uint8_t byte) {
writeBit(byte & BIT( 7));
writeBit(byte & BIT( 6));
writeBit(byte & BIT( 5));
writeBit(byte & BIT( 4));
writeBit(byte & BIT( 3));
writeBit(byte & BIT( 2));
writeBit(byte & BIT( 1));
writeBit(byte & BIT( 0));
}
/** read 8 bits */
uint8_t readByte() {
GPIO::clear(PIN_MOSI);
return
(readBit() << 7) |
(readBit() << 6) |
(readBit() << 5) |
(readBit() << 4) |
(readBit() << 3) |
(readBit() << 2) |
(readBit() << 1) |
(readBit() << 0);
}
uint8_t readWriteByte(const uint8_t byte) {
return
(readWriteBit(byte & BIT( 7)) << 7) |
(readWriteBit(byte & BIT( 6)) << 6) |
(readWriteBit(byte & BIT( 5)) << 5) |
(readWriteBit(byte & BIT( 4)) << 4) |
(readWriteBit(byte & BIT( 3)) << 3) |
(readWriteBit(byte & BIT( 2)) << 2) |
(readWriteBit(byte & BIT( 1)) << 1) |
(readWriteBit(byte & BIT( 0)) << 0);
}
uint32_t readWriteQuad(const uint32_t quad) {
return
readWriteByte((quad>>24)&0xFF) << 24 |
readWriteByte((quad>>16)&0xFF) << 16 |
readWriteByte((quad>> 8)&0xFF) << 8 |
readWriteByte((quad>> 0)&0xFF) << 0;
}
void write(const uint8_t* data, size_t len) {
while(len) {
writeByte(*data);
++data;
--len;
}
}
void read(uint8_t* dst, size_t len) {
while(len) {
*dst = readByte();
++dst;
--len;
}
}
};
#pragma GCC pop_options
// create an instance ONCE
//SoftSPI spi;
//using spi = SoftSPI;

View File

@@ -13,17 +13,17 @@
ip_addr_t addr;
/** empty ctor */
explicit IP() {
explicit IP4() {
addr.addr = 0;
}
/** ctor with IP-string */
explicit IP(const char* ipStr) {
explicit IP4(const char* ipStr) {
set(ipStr);
}
/** ctor with ip_addr_t */
explicit IP(ip_addr addr) : addr(addr) {
explicit IP4(ip_addr addr) : addr(addr) {
;
}

View File

@@ -46,7 +46,7 @@ public:
}
bool send(const IP ip, const Port port, const void* data, const uint16_t dataLen) {
bool send(const IP4 ip, const Port port, const void* data, const uint16_t dataLen) {
debugMod1(NAME, "sending packet to remote port %d", port);
@@ -65,9 +65,21 @@ public:
/** set the callback to call whenever a packet is received */
void setRecvCallback(UDPCallback callback) {
debugMod(NAME, "setRecvCallback()");
espconn_regist_recvcb(con, callback);
}
/** get the IP address of the most recent packet's sender */
IP4 getSenderIP() {
remot_info* rem;
espconn_get_connection_info(con, &rem, 0);
ip_addr_t* _ip = (ip_addr_t*) rem->remote_ip;
return IP4(*_ip);
//const uint16_t port = rem->remote_port;
}
private:
/** initialize the UDP "connection" */