t0 — Xiao Esp32 S3 simulation

tx

An interactive Xiao Esp32 S3 circuit simulation you can run free in your browser on Velxio, by liuse.

Components

Sketch code

#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>

#define I2C_SDA 4
#define I2C_SCL 5

#define JOY_X      1
#define JOY_Y      2
#define JOY_SW     3

#define KEY_BACK   8
#define KEY_SPACE  9
#define KEY_SEND   7

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

enum PageMode {
  PAGE_STANDBY,
  PAGE_CHAT,
  PAGE_EDIT
};
PageMode pageMode = PAGE_STANDBY;

const char charTable[3][16] = {
  {'Q','W','E','R','T','Y','U','I','O','P','1','2','3','4','\0','\0'},
  {'A','S','D','F','G','H','J','K','L','\0','5','6','7','8','\0','\0'},
  {'Z','X','C','V','B','N','M','\0','\0','\0','!','?','.','9','0','\0'}
};
const int tableRows = 3;
const int tableCols = 16;

int curRow = 0;
int curCol = 0;
String inputBuf = "";
const int maxInputLen = 32;

#define CHAT_BUF_SIZE 16
String chatBuf[CHAT_BUF_SIZE];
uint8_t oldestIdx = 0;
uint8_t msgCount = 0;
int viewScroll = 0;

const unsigned long joyHoldThreshold = 400;
bool joyHoldFired = false;
unsigned long joyHoldTs = 0;

const int joyThreshold = 1200;
bool isSleep = false;
bool hasUnread = false;
unsigned long sleepTimer = 0;
const unsigned long sleepDelay = 5000;

unsigned long secBase = 0;
String serialLineBuf;
const size_t SERIAL_LINE_MAX = 128;

typedef struct {
  uint8_t pin;
  uint8_t state;
  unsigned long tsPress;
} KeyState;

KeyState keyJoySw     = {JOY_SW,0,0};
KeyState keyBack      = {KEY_BACK,0,0};
KeyState keySpace     = {KEY_SPACE,0,0};
KeyState keySend      = {KEY_SEND,0,0};
const unsigned long keyDebounce = 20;

bool showSendTip = false;
unsigned long sendTipTs = 0;
const unsigned long sendTipDur = 800;

bool blinkCursor = false;
unsigned long blinkTs = 0;
const unsigned long blinkInterval = 500;

int getMessageLines(const String &msg) {
  int lines = 1;
  int width = 0;
  const char *str = msg.c_str();
  int len = msg.length();
  int pos = 0;
  
  while (pos < len) {
    int nextPos = pos;
    unsigned char c = (unsigned char)str[pos];
    if ((c & 0x80) == 0) nextPos = pos + 1;
    else if ((c & 0xE0) == 0xC0) nextPos = pos + 2;
    else if ((c & 0xF0) == 0xE0) nextPos = pos + 3;
    else if ((c & 0xF8) == 0xF0) nextPos = pos + 4;
    else nextPos = pos + 1;
    
    String piece = msg.substring(pos, nextPos);
    width += u8g2.getUTF8Width(piece.c_str());
    if (width >= 120) {
      lines++;
      width = 0;
    }
    pos = nextPos;
  }
  return lines;
}

int getTotalLines() {
  int total = 0;
  for (int i = 0; i < msgCount; i++) {
    int idx = chatGetIndex(i);
    if (idx >= 0) {
      total += getMessageLines(chatBuf[idx]);
    }
  }
  return total;
}

void drawSendTipOverlay()
{
  u8g2.drawBox(30,22,68,20);
  u8g2.setDrawColor(0);
  u8g2.setFont(u8g2_font_wqy12_t_gb2312);
  u8g2.setCursor(34,36);
  u8g2.print("发送成功");
  u8g2.setDrawColor(1);
  u8g2.sendBuffer();
}

void resetActivity(){
  sleepTimer = millis();
  if(isSleep){
    u8g2.setPowerSave(0);
    isSleep = false;
  }
}

void chatAppend(const String &text)
{
  uint8_t writePos = (oldestIdx + msgCount) %