The only examples I have found rely on esp32-Cam library functions that I don't know how to replicate for my environment. Namely these:
Code: Select all
typedef struct {
uint8_t * buf; /*!< Pointer to the pixel data */
size_t len; /*!< Length of the buffer in bytes */
size_t width; /*!< Width of the buffer in pixels */
size_t height; /*!< Height of the buffer in pixels */
pixformat_t format; /*!< Format of the pixel data */
} camera_fb_t;
Code: Select all
void saveCapturedImage(String filename) {
Serial.println("Connect to " + String(host));
client.setInsecure();
if (client.connect(host, port)) {
Serial.println("Client connection successful");
bmpFile = SD.open(filename, FILE_READ);
//char *input = (char *)fb->buf;
char *input = (char *)bmpFile.read();
//int fbLen = fb->len;
int fbLen = sizeof(bmpFile);
char output[base64_enc_len(3)];
String imageFile = "";
for (int i=0; i<fbLen; i++) {
base64_encode(output, (input++), 3);
if (i%3==0) imageFile += urlencode(String(output));
}
String Data = filename+mimeType+myImage;
Serial.println("Send a captured image to Google Drive.");
client.println("POST " + url + " HTTP/1.1");
client.println("Host: " + String(host));
client.println("Content-Length: " + String(Data.length()+imageFile.length()));
client.println("Content-Type: application/x-www-form-urlencoded");
client.println();
client.print(Data);
int Index;
for (Index = 0; Index < imageFile.length(); Index = Index+1000) {
client.print(imageFile.substring(Index, Index+1000));
}
Serial.println("Waiting for response.");
long int StartTime=millis();
while (!client.available()) {
Serial.print(".");
delay(100);
if ((StartTime+waitingTime) < millis()) {
Serial.println();
Serial.println("No response.");
//If you have no response, maybe need a greater value of waitingTime
break;
}
}
Serial.println();
while (client.available()) {
Serial.print(char(client.read()));
}
} else {
Serial.println("Connected to " + String(host) + " failed.");
}
client.stop();
}
Code: Select all
Connect to script.google.com
Client connection successful
Fatal exception 28(LoadProhibitedCause):
epc1=0x4020180b, epc2=0x00000000, epc3=0x00000000, excvaddr=0x00000042, depc=0x00000000
Code: Select all
//char *input = (char *)fb->buf;
char *input = (char *)bmpFile.read();
//int fbLen = fb->len;
int fbLen = sizeof(bmpFile);
full code here:
Code: Select all
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_HX8357.h>
#include <Adafruit_STMPE610.h>
//#include <Adafruit_ImageReader.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
//#include "SdFat.h"
#include "SD.h"
#include <Bounce2.h>
#include "time.h"
#include <Arduino_JSON.h>
#include "Base64.h"
#define STMPE_CS 16
#define TFT_CS 0
#define TFT_DC 15
#define SD_CS 2
#define TFT_RST -1
Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC, TFT_RST);
Adafruit_STMPE610 touch = Adafruit_STMPE610(STMPE_CS);
File bmpFile;
const char* ssid = "mySSID";
const char* password = "myPass";
const char* NTP_SERVER = "pool.ntp.org";
const char* TZ_INFO = "EST5EDT,M3.2.0,M11.1.00";
// const long gmtOffset = -18000; //should be 5 * 3600 or 18000 (seconds)
// const int daylightOffset = 3600; //Replace with your daylight offset (seconds)
tm timeinfo;
time_t now;
long unsigned lastNTPtime;
unsigned long lastEntryTime;
char theDate[20];
char fileDate[20];
//google drive stuff
WiFiClientSecure client;
const char* host = "script.google.com";
const uint16_t port = 443;
String myDeploymentID = "string_of_nonsense";
String url = "/macros/s/string_of_nonsense/exec";
String myMainFolderName = "myFolder";
String mimeType = "&mimetype=image/jpeg";
String myImage = "&data=";
int waitingTime = 30000; //Wait 30 seconds to google response.
// This is calibration data for touchscreen at no rotation
#define TS_MINX 120
#define TS_MAXX 3950
#define TS_MINY 120
#define TS_MAXY 3950
#define PENRADIUS 1
unsigned long lastTouch = millis();
int prevPt[] = {0,0,0};
const int debounceDelay = 50;
#define capPin 17
Bounce captureButton = Bounce();
#define clearPin 5
Bounce clearButton = Bounce();
#define menuPin 4
Bounce menuButton = Bounce();
const unsigned int penColor = 0x0000; //Black
const unsigned int bgColor = 0xF72F; //#F3E779
void setup() {
Serial.begin(115200);
//pinMode(capPin, INPUT);
captureButton.attach(capPin, INPUT);
captureButton.interval(debounceDelay);
//pinMode(clearPin, INPUT);
clearButton.attach(clearPin, INPUT);
clearButton.interval(debounceDelay);
//pinMode(menuPin, INPUT);
menuButton.attach(menuPin, INPUT);
menuButton.interval(debounceDelay);
tft.begin();
//tft.setRotation(1);
tft.fillScreen(bgColor);
if (! touch.begin()) {
Serial.println("STMPE not found!");
while(1);
}
Serial.println("Waiting for touch sense");
Serial.print("Initializing SD card...");
if(!SD.begin(SD_CS)) {
//if(!SD.begin(SD_CS, SD_SCK_MHZ(25))) { // ESP32 requires 25 MHz limit
Serial.println(F("SD begin() failed"));
for(;;); // Fatal error, do not continue
}
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(300);
Serial.print(".");
}
Serial.println("CONNECTED to WIFI");
configTime(0, 0, NTP_SERVER);
setenv("TZ", TZ_INFO, 1);
if(getNTPtime(5)) { // wait up to 10sec to sync
} else {
Serial.println("Time not set");
//ESP.restart();
}
lastNTPtime = time(&now);
lastEntryTime = millis();
}
void loop() {
captureButton.update();
if(captureButton.fell()){
bmpSave();
}
clearButton.update();
if(clearButton.fell()){
clearScreen();
}
menuButton.update();
if(menuButton.fell()){
menuCall();
}
uint16_t x, y, ptX, ptY;
uint8_t z, ptZ;
if (touch.touched()) {
// read x & y & z;
while (! touch.bufferEmpty()) {
touch.readData(&x, &y, &z);
// normal alignment with no setRotation
ptX = map(x, TS_MINX, TS_MAXX, 0, tft.width());
ptY = map(y, TS_MINY, TS_MAXY, 0, tft.height());
if(millis() - lastTouch < 40){
tft.drawLine(prevPt[0], prevPt[1], ptX, ptY, penColor);
prevPt[0] = ptX; prevPt[1] = ptY; prevPt[2] = ptZ;
lastTouch = millis();
} else{
prevPt[0] = ptX; prevPt[1] = ptY; prevPt[2] = ptZ;
lastTouch = millis();
}
}
}
//delay(10);
}
void drawAngledLine(int x, int y, int x1, int y1) {
float dx = (PENRADIUS+1/2.0) * (x-x1) / sqrt(sq(x-x1) + sq(y-y1));
float dy = (PENRADIUS+1/2.0) * (y-y1) / sqrt(sq(x-x1) + sq(y-y1));
tft.fillTriangle(x+dx, y-dy, x-dx, y+dy, x1+dx, y1-dy, HX8357_WHITE);
tft.fillTriangle(x-dx, y+dy, x1-dx, y1+dy, x1+dx, y1-dy, HX8357_WHITE);
}
void clearScreen() {
tft.fillScreen(bgColor);
}
void bmpSave() {
uint32_t filesize, offset;
uint16_t width = tft.width(), height = tft.height();
unsigned long startTime;
unsigned long elapsedTime;
if(!SD.begin(SD_CS)){
Serial.println(F("SD begin() failed"));
for(;;); // Fatal error, do not continue
}
//String filename = getDate();
//filename = filename + ".bmp";
char filename[20] ;
strcpy(filename, fileDate);
strcat(filename, "_note001.bmp");
while (SD.exists(filename)) {
String num = String(filename).substring(13, 16);
int val = num.toInt();
char stuff[20];
sprintf(stuff, "num in string: %s | value: %d", num, val);
val++;
sprintf(filename, "%s_note%03d.bmp", fileDate, val);
}
Serial.println(filename);
bmpFile = SD.open(filename, FILE_WRITE);
// On error hang up
if (!bmpFile) for (;;);
Serial.print("image: "); Serial.print(filename); Serial.println(" started processing");
//
// File header: 14 bytes
bmpFile.write('B'); bmpFile.write('M');
writeFour(14+40+12+width*height*2); // File size in bytes
writeFour(0);
writeFour(14+40+12); // Offset to image data from start
//
// Image header: 40 bytes
writeFour(40); // Header size
writeFour(width); // Image width
writeFour(height); // Image height
writeTwo(1); // Planes
writeTwo(16); // Bits per pixel
writeFour(0); // Compression (none)
writeFour(0); // Image size (0 for uncompressed)
writeFour(0); // Preferred X resolution (ignore)
writeFour(0); // Preferred Y resolution (ignore)
writeFour(0); // Colour map entries (ignore)
writeFour(0); // Important colours (ignore)
Serial.println("header written");
// Colour masks: 12 bytes
writeFour(0b0000011111100000); // Green
writeFour(0b1111100000000000); // Red
writeFour(0b0000000000011111); // Blue
Serial.println("color mask applied");
// Image data: width * height * 2 bytes
for (int y=height-1; y>=0; y--) {
for (int x=0; x<width; x++) {
writeTwo(getPixel(x,y)); // Each row must be a multiple of four bytes
}
}
Serial.println("finished encoding");
// Close the file
bmpFile.close();
elapsedTime = millis() - startTime;
Serial.println("file finished saving");
Serial.print("the file took "); Serial.print(elapsedTime/1000); Serial.println(" secs to complete");
//uploadFile(filename);
saveCapturedImage(filename);
// http://www.technoblogy.com/show?398X
}
void writeTwo (uint16_t word) {
bmpFile.write(word & 0xFF); bmpFile.write((word >> 8) & 0xFF);
}
void writeFour (uint32_t word) {
bmpFile.write(word & 0xFF); bmpFile.write((word >> 8) & 0xFF);
bmpFile.write((word >> 16) & 0xFF); bmpFile.write((word >> 24) & 0xFF);
}
uint16_t getPixel(int x, int y) { // get pixel color code in rgb565 format
tft.startWrite(); //needed for low-level methods. CS active
tft.setAddrWindow(x, y, 1, 1);
tft.writeCommand(0x2E); // memory read command. sets DC
uint8_t r, g, b;
r = tft.spiRead(); // discard dummy read
r = tft.spiRead();
g = tft.spiRead();
b = tft.spiRead();
tft.endWrite(); //needed for low-level methods. CS idle
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
//https://forum.arduino.cc/t/create-snapshot-of-3-5-tft-and-save-to-file-in-bitmap-format/391367/7
}
bool getNTPtime(int sec) {
{
uint32_t start = millis();
do {
time(&now);
localtime_r(&now, &timeinfo);
Serial.print(".");
delay(10);
} while (((millis() - start) <= (1000 * sec)) && (timeinfo.tm_year < (2016 - 1900)));
if (timeinfo.tm_year <= (2016 - 1900)) return false; // the NTP call was not successful
Serial.print("now "); Serial.println(now);
char time_output[30];
strftime(time_output, 30, "%a %d-%m-%y %T", localtime(&now));
strftime(theDate, 30, "%d-%m-%y", localtime(&now));
strftime(fileDate, 30, "%b%d-%y", localtime(&now));
Serial.println(time_output);
Serial.println();
}
return true;
//https://github.com/SensorsIot/NTP-time-for-ESP8266-and-ESP32/blob/master/NTP_Example/NTP_Example.ino
//https://microcontrollerslab.com/current-date-time-esp8266-nodemcu-ntp-server/
//https://arduino.stackexchange.com/questions/42922/get-hour-with-ctime-time-library-with-esp8266
}
void saveCapturedImage(String filename) {
Serial.println("Connect to " + String(host));
client.setInsecure();
if (client.connect(host, port)) {
Serial.println("Client connection successful");
bmpFile = SD.open(filename, FILE_READ);
//char *input = (char *)fb->buf;
char *input = (char *)bmpFile.read();
//int fbLen = fb->len;
int fbLen = sizeof(bmpFile);
char output[base64_enc_len(3)];
String imageFile = "";
for (int i=0; i<fbLen; i++) {
base64_encode(output, (input++), 3);
if (i%3==0) imageFile += urlencode(String(output));
}
String Data = filename+mimeType+myImage;
Serial.println("Send a captured image to Google Drive.");
client.println("POST " + url + " HTTP/1.1");
client.println("Host: " + String(host));
client.println("Content-Length: " + String(Data.length()+imageFile.length()));
client.println("Content-Type: application/x-www-form-urlencoded");
client.println();
client.print(Data);
int Index;
for (Index = 0; Index < imageFile.length(); Index = Index+1000) {
client.print(imageFile.substring(Index, Index+1000));
}
Serial.println("Waiting for response.");
long int StartTime=millis();
while (!client.available()) {
Serial.print(".");
delay(100);
if ((StartTime+waitingTime) < millis()) {
Serial.println();
Serial.println("No response.");
//If you have no response, maybe need a greater value of waitingTime
break;
}
}
Serial.println();
while (client.available()) {
Serial.print(char(client.read()));
}
} else {
Serial.println("Connected to " + String(host) + " failed.");
}
client.stop();
}
String urlencode(String str) {
String encodedString="";
char c;
char code0;
char code1;
char code2;
for (int i =0; i < str.length(); i++){
c=str.charAt(i);
if (c == ' '){
encodedString+= '+';
} else if (isalnum(c)){
encodedString+=c;
} else{
code1=(c & 0xf)+'0';
if ((c & 0xf) >9){
code1=(c & 0xf) - 10 + 'A';
}
c=(c>>4)&0xf;
code0=c+'0';
if (c > 9){
code0=c - 10 + 'A';
}
code2='\0';
encodedString+='%';
encodedString+=code0;
encodedString+=code1;
//encodedString+=code2;
}
yield();
}
return encodedString;
}