I’ve had this working on a D1 and TFT screen…
I’ll try and dig out the code - it’s on a virtual machine somewhere.
Ah, found the .Net Visual Studio files here (the sketch is in the root of the Zip):
http://untamed.co.uk/miscFolder/ESP8266.zip
The most interesting bit isn’t the D1 sketch - it just reads in bytes from the website (along with the length of time to display the frame) - it’s the drawing buffers on the server.
I wrote two - one for the TFT LCD ST7735 - which is straight forward, and then one for the OLED panel badly named as ESP8266Canvas.vb
It creates a .Net drawing canvas the same size as the OLED display’s pixels.
Imagine! MULTIPLE PLATFORM displays using the same drawing code, just formatted for the relevant system. Arduboy, Arduboy Color, Arduboy HDMI… and so on. =D
You just draw on it using all the nice graphics commands .Net has - and then when it’s due to be sent to the Arduboy - a command called translates the display data by rotating the bits 90 degrees and adding a little header that contains the frame display time.
It can send a response back from the server as an OLED memory stream, or as a PNG graphic magnified twice. This is great for debugging - you can call the ASPX page from the browser, and see the image the Arduboy would be getting.
Obviously the Arduboy will be using the Serial connection - but the concept stays the same - create a .Net canvas, draw the graphics using standard graphics commands, and then use something like the encoding code here to Serial.write the result back to the Arduboy, avoiding all the nasty byte handling normally needed. =)
Sadly I can’t find the OLED clock display code anywhere! Damn.
So this page… getFrame.aspx or whatever… returns data for the OLED via sendToClient:
Dim c As New ESP8266Canvas()
Dim g As Graphics = c.g
Dim asOLEDFormat = (Request("debug") Is Nothing)
'All the drawing code goes here, using 'g' as the graphics context.
c.sendToClient(frameDelay:=frameDelay,
response:=Response,
asOLEDFormat:=asOLEDFormat)
Any none-0 value in RGB is a set pixel. This can be fine tuned by using the following subroutine, which forces the entire pixel to be black/white - that way, when using the “debugger - return as PNG” in a webpage, you can clamp the pixels to display exactly what will then be shown by the OLED panel.
blackWhiteFrame(ByVal limitRed As Integer, ByVal limitGreen As Integer, ByVal limitBlue As Integer)
And this is the D1 sketch - it was fairly reliable, though there was a pesky issue somewhere… (on inspection I think it’s if a byte is dropped, the code doesn’t request a new page, nor time out this one. Hm… it might time out and request a new page? I can’t remember the behaviour of get, streaming bytes, and dropped bits!)
#include <ESP8266WiFi.h>
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#define TFT_CS 5
#define TFT_RST 15
#define TFT_DC 2
String ssid="";
String password="";
const char* url="ESP8266.asp";
const char* host="untamed.co.uk";
uint16_t lineData[20480];
int lineDataPtr = 0;
byte b1 = 0, b2 = 0;
uint16_t color = 0;
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
WiFiClient client;
const int httpPort = 80;
inline void setCS(bool level) {
digitalWrite(5, level);
}
inline void setRS(bool level) {
digitalWrite(2, level);
}
inline void setDataBits(uint16_t bits) {
const uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
bits--;
SPI1U1 = ((SPI1U1 & mask) | ((bits << SPILMOSI) | (bits << SPILMISO)));
}
void setup(void){
Serial.begin(74880);
//SPI.setFrequency(500000);
tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab
tft.setRotation(2);
tft.fillScreen(ST7735_BLACK);
Serial.print("\n");
Serial.setDebugOutput(true);
tft.setCursor(0, 0);
tft.setTextColor(65534);
tft.setTextWrap(true);
tft.println("Scanning networks...");
tft.println("");
int n = WiFi.scanNetworks();
tft.fillScreen(ST7735_BLACK);
tft.setCursor(0,0);
for (int i = 0; i < n; ++i){
tft.print(i+1);
tft.print(" : ");
tft.println(WiFi.SSID(i));
if(WiFi.SSID(i)=="OfficeNetwork"){
ssid="OfficeNetwork";
password="PASSWORDHERE";
break;
}
if(WiFi.SSID(i)=="Assombalonga"){
ssid="Assombalonga";
password="PASSWORDHERE";
break;
}
}
delay(2000);
if(ssid==""){
tft.println("No known network!");
}else{
tft.println("");
tft.println("Identified: ");
tft.println(ssid);
tft.println("Logging in.");
}
tft.println("");
Serial.print("Connecting to " );
Serial.println(ssid.c_str());
tft.println("Connecting to " );
tft.println(ssid.c_str());
tft.println("");
if (String(WiFi.SSID()) != String(ssid)) {
tft.println("Connecting.");
WiFi.begin(ssid.c_str(), password.c_str());
}
while (WiFi.status() != WL_CONNECTED) {
delay(50);
Serial.print(".");
tft.print(".");
}
Serial.println("Connected! IP address: ");
Serial.println(WiFi.localIP());
tft.println("");
tft.println("Connected!");
tft.println("IP: " + WiFi.localIP().toString());
tft.println("");
tft.println("Requesting data...");
delay(2000);
SPI.setFrequency(30000000);
WiFi.mode(WIFI_OFF);
}
void loop(void){
int frameDelay = 5;
if (!client.connect(host, 80)) {
Serial.println("connection failed");
return;
}
client.print(String("GET ") + "/ESP8266/ST7735.aspx HTTP/1.1\r\n" +
"Host: untamed.co.uk\r\n" +
"Connection: close\r\n\r\n\r\n");
delay(50);
String line ="";
bool started = false;
tft.setAddrWindow(0,0,127,160);
while(client.available() || client.connected()){
if(!started){// The top two linse are a "flag" to show were the data stream starts, and then the length of the delay in text.
String temp = client.readStringUntil('\r');
if(temp.indexOf("DataFollows:") >= 0) {
Serial.print("HERE!");
started = true;
frameDelay = atoi(client.readStringUntil('\r').c_str());
Serial.print("Delay: ");
Serial.println(frameDelay);
client.read();
setRS(true);
setCS(false);
setDataBits(16);}
}else{
if(client.available()>1){//If the client has bytes available - read a couple in.
lineData[lineDataPtr++] = client.read() | (uint16_t) client.read() << 8;
if(lineDataPtr==20480){
for(int loc=0;loc<20480;loc++){
lineDataPtr = 0;
while(SPI1CMD & SPIBUSY) {}
SPI1W0 = lineData[loc];
SPI1CMD |= SPIBUSY;
}
}
} else {
delay(1);// Wait for more data in the buffer
}
}//End of post "started" pixel collect
}// No longer connected, and no longer any data pending.
if(!started) {delay(100); Serial.print("Connection not available... trying again ");}
setCS(true);
delay(frameDelay);
}