Skip to content

Commit

Permalink
initial
Browse files Browse the repository at this point in the history
  • Loading branch information
Tevz-Beskovnik committed Feb 17, 2024
1 parent de926e8 commit e547a4d
Show file tree
Hide file tree
Showing 27 changed files with 2,400 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.pio
data
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,38 @@
# bored_programing
# ESP32 basic web server

I was realy REALY bored recently and I decided to make a web server
using the ESP32. This specific example opens a Wi-Fi AP, that when connected to
will have a `home.local` domain. The website on the domain has two buttons, that when
pressed will change the displayed image on the screen. Very simple.

## The web server
The web server supports the following features:
- Serving static files (that are uploaded to SPIFFS)
- Endpoints with actions (like turning on and off a LED)
- Logging via serial when in debug mode
- The default action as written in `server.cpp` server the `index.html` file

Currently supported file types for static files are (but not limited to (it's very easy to expand upon)):
- HTML
- CSS
- JS
- PNG
- JPG

## The hardware
To run this you will need a:
- ESP32
- A display (I used a Sharp Memory low power LCD)

## Before running
Make sure to upload the file system image. All the files should be located in the
`data` folder.

## Included tools:
There is a script that will be run when the project is **BUILT**.
It's the included binary image converter. Converts .jpg images to suitable
monochrome binary file formats, that are used with the provided graphics library.

If you wish to add any custom images of yours they can be easily added into the
`pre_upload.py` script, take a look it's just an array. I recommend reading the docs
on [this](https://github.com/Tevz-Beskovnik/Binary-image-converter) repository beforehand though.
Binary file added images/desk.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/plant.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 39 additions & 0 deletions include/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

This directory is intended for project header files.

A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.

```src/main.c

#include "header.h"

int main (void)
{
...
}
```

Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.

In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.

Read more about using header files in official GCC documentation:

* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes

https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
16 changes: 16 additions & 0 deletions include/core/image_loader.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// Created by Tevz on 9. 02. 24.
//

#ifndef BORED_PROGRAMING_IMAGE_LOADER_HPP
#define BORED_PROGRAMING_IMAGE_LOADER_HPP

#include <GL.hpp>

void init_loader(GL* gl);

bool load_image(const char *file_path);

void refresh_top_to_bottom(uint16_t height);

#endif //BORED_PROGRAMING_IMAGE_LOADER_HPP
19 changes: 19 additions & 0 deletions include/core/server.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// Created by Tevz on 9. 02. 24.
//

#ifndef BORED_PROGRAMING_SERVER_HPP
#define BORED_PROGRAMING_SERVER_HPP

#include <WebServer.h>

// TODO: spawn thread for action and just call the handler
#define GET_PATH_WITH_ACTION(_path, _action) LOG(_path) server.on(_path, HTTP_GET, []() { _action; });
#define POST_PATH_WITH_ACTION(_path, _action) LOG(_path) server.on(_path, HTTP_POST, []() { _action; });
#define PUBLIC_FILE(_path_to_file) LOG(_path_to_file) server.on(_path_to_file, HTTP_GET, file_handler);

extern WebServer server;

void init_server();

#endif //BORED_PROGRAMING_SERVER_HPP
26 changes: 26 additions & 0 deletions include/core/util.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// Created by Tevz on 9. 02. 24.
//

#ifndef BORED_PROGRAMING_UTIL_HPP
#define BORED_PROGRAMING_UTIL_HPP

#include <freertos/task.h>

#ifdef DEBUG
#define LOG(x) Serial.println(x);
#else
#define LOG(x)
#endif

#define X_SCHEDULE_TASK(task) schadule_task([](void* args) { task; })

TaskHandle_t schadule_task(void (*task)(void *args)) {
TaskHandle_t handle = NULL;

xTaskCreate(task, "Task", 10000, NULL, 1, &handle);

return handle;
}

#endif //BORED_PROGRAMING_UTIL_HPP
140 changes: 140 additions & 0 deletions lib/Display_driver/Display_driver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#include <Display_driver.hpp>

// sharp memory display commands
#define SHARPMEM_CMD_WRITE_LINE 0b00000001
#define SHARPMEM_CMD_VCOM 0b00000010
#define SHARPMEM_CMD_CLEAR_SCREEN 0b00000100

#define TOGGLE_VCOM \
do { \
sharpmem_vcom = sharpmem_vcom ? 0x00 : SHARPMEM_CMD_VCOM; \
} while (0);

// 1<<n is a costly operation on AVR -- table usu. smaller & faster
static const uint8_t PROGMEM set[] = {1, 2, 4, 8, 16, 32, 64, 128},
clr[] = {(uint8_t)~1, (uint8_t)~2, (uint8_t)~4,
(uint8_t)~8, (uint8_t)~16, (uint8_t)~32,
(uint8_t)~64, (uint8_t)~128};

/**
* @brief constructor of the display driver
*
* @param cs cs pin
*
* @param clk clk pin
*
* @param mosi mosi pin
*
* @param freq spi frequency
*
* @param screen_width display width
*
* @param screen_height display height
*/
Display::Display(uint8_t cs, int32_t freq, uint16_t screen_width, uint16_t screen_height)
: device(new SPIDevice(SPI_DEVICE_BIT_LSBFIRST, freq)), sharpmem_vcom(SHARPMEM_CMD_VCOM), height(screen_height), width(screen_width), csPin(cs), bytes_per_line(screen_width/8)
{
gpio_pad_select_gpio(cs);
gpio_set_direction((gpio_num_t)cs, GPIO_MODE_OUTPUT);
}

Display::~Display() { free(display_buffer); }

/**
* @brief initializes the library
*/
void Display::begin()
{
display_buffer = (uint8_t*)malloc(sizeof(uint8_t)*height*width/8);
memset((void*)display_buffer, 0xFF, sizeof(uint8_t)*height*width/8);

gpio_set_level((gpio_num_t)csPin, 0);
}

/**
* @brief clear display
*/
void Display::clearDisplay()
{
gpio_set_level((gpio_num_t)csPin, 1);
uint8_t data[2] = {(uint8_t)(sharpmem_vcom | SHARPMEM_CMD_CLEAR_SCREEN), 0};
device->spiCommand(data, 2);
TOGGLE_VCOM
gpio_set_level((gpio_num_t)csPin, 0);
}

/**
* @brief clear display buffer
*/
void Display::clearDisplayBuffer()
{
memset((void*)display_buffer, 0xFFFFFFFF, sizeof(uint8_t)*height*width/8);
}

/**
* @brief draw pixel to display buffer at x y cooridnates
*
* @param x coordinate to draw to
*
* @param y cooridnate to draw to
*
* @param color to draw
*/
void Display::drawPixel(uint16_t x, uint16_t y, uint8_t color)
{
if (color) {
context_buffer[(y * width + x) / 8] |= pgm_read_byte(&set[x & 7]);
} else {
context_buffer[(y * width + x) / 8] &= pgm_read_byte(&clr[x & 7]);
}
}

/**
* @brief draw the display buffer to display
*/
void Display::refresh()
{
uint8_t cmd = sharpmem_vcom | SHARPMEM_CMD_WRITE_LINE;
uint8_t line[bytes_per_line+2];
uint16_t totalBytes = (width*height/8);

gpio_set_level((gpio_num_t)csPin, 1);
device->spiCommand(&cmd, 1);

for(uint16_t i = 0; i < totalBytes; i+=bytes_per_line){
line[0] = (i/bytes_per_line)+1;
line[bytes_per_line+1] = 0x00;

memcpy((uint8_t*)(line+1), (uint8_t*)(display_buffer+i), bytes_per_line);

device->spiCommand(line, bytes_per_line+2);
}

cmd = 0x00;
device->spiCommand(&cmd, 1);
TOGGLE_VCOM
gpio_set_level((gpio_num_t)csPin, 0);
}

/**
* @brief refresh display with display buffer at line number
*
* @param lineNum number of line to draw to
*/
void Display::refresh(uint8_t lineNum)
{
uint16_t lineAddress = lineNum*bytes_per_line;
uint8_t line[bytes_per_line+4];

line[0] = sharpmem_vcom | SHARPMEM_CMD_WRITE_LINE;
line[1] = lineNum;
line[bytes_per_line+2] = 0x00;
line[bytes_per_line+3] = 0x00;

memcpy((uint8_t*)((uint8_t*)(line)+2), (uint8_t*)(display_buffer+lineAddress), bytes_per_line);

gpio_set_level((gpio_num_t)csPin, 1); // <---- Data transmition
device->spiCommand(line, bytes_per_line+4);
TOGGLE_VCOM
gpio_set_level((gpio_num_t)csPin, 0);
}
53 changes: 53 additions & 0 deletions lib/Display_driver/Display_driver.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#ifndef _DISPLAY_DRIVER_
#define _DISPLAY_DRIVER_

#ifndef BLACK
#define BLACK 0
#endif

#ifndef WHITE
#define WHITE 1
#endif

#include <Print.h>
#include <SPI_driver.hpp>

class Display : public Print {
public:
virtual size_t write(uint8_t c) { return 0; };

Display(uint8_t cs, int32_t freq, uint16_t width, uint16_t height);

~Display();

void begin();

void clearDisplay();

void clearDisplayBuffer();

void drawPixel(uint16_t x, uint16_t y, uint8_t color);

void refresh();

void refresh(uint8_t line);

protected:
uint8_t* display_buffer;
uint8_t* context_buffer; // context buffer; It's basicly the frame buffer of the screen

private:
SPIDevice* device;

uint8_t sharpmem_vcom;

uint8_t bytes_per_line;

uint8_t csPin;

uint16_t width;
uint16_t height;

};

#endif
Loading

0 comments on commit e547a4d

Please sign in to comment.