From: Advaith Menon Date: Wed, 4 Feb 2026 18:22:12 +0000 (-0500) Subject: Modify code to work with Arduino X-Git-Url: https://git.devinivas.org/?a=commitdiff_plain;h=a53ca88a3f62819c0ddf28ab1c295b9d8f3f21f7;p=4dulcd-nolibrary.git Modify code to work with Arduino --- diff --git a/Arduino_Starter.ino b/Arduino_Starter.ino new file mode 100644 index 0000000..15fd861 --- /dev/null +++ b/Arduino_Starter.ino @@ -0,0 +1,407 @@ +#include +#include +#include + +#include +#include +#include + +#define PIN_ULCD_RESET 4 +#define PIN_UART_RXD 5 +#define PIN_UART_TXD 6 + +#define ULCD_DEFAULT_BAUD_RATE 9600 +#define ULCD_DEFAULT_DATA_BITS UART_DATA_8_BITS +#define ULCD_DEFAULT_PARITY UART_PARITY_DISABLE +#define ULCD_DEFAULT_STOP_BITS UART_STOP_BITS_1 +#define TIME_LIMIT 2000 + +/* screen width and height */ +#define SCR_W 128 +#define SCR_H 128 + + +HardwareSerial LCDSer(1); + + +/* Helper functions to make things easier for Arduino users */ +/* DO NOT CALL UNTIL UART IS INITIALIZED */ +int write_tx(const void *data, size_t bufsz); +int read_rx(void *data, size_t bufsz, uint32_t timeout); +int flush_rx(); +int flush_tx(uint32_t timeout); +void update_baud(int baud); + + +void ulcd_init(void); +void ulcd_cls(void); +void ulcd_txt_demo(void); +void ulcd_moving_circle(void); +void ulcd_faster_baud(void); +void ulcd_default_baud(void); +void ulcd_baud(int, int); +void ulcd_lab2(void); + + +void setup(void) +{ + Serial.begin(9600); + Serial.println("Starting program"); + Serial.println("Initializing GPIO..."); + pinMode(PIN_ULCD_RESET, OUTPUT); + Serial.println("Initializing UART..."); + + /* Install Drivers */ + LCDSer.begin(9600, SERIAL_8N1, PIN_UART_RXD, PIN_UART_TXD); + + /* Reset the ULCD manually */ + Serial.println("Reset the ULCD..."); + digitalWrite(PIN_ULCD_RESET, 0); + delay(1000); + digitalWrite(PIN_ULCD_RESET, 1); + delay(1000); + + /* UART is initialized. We can now work on initializing the uLCD. */ + Serial.println("Wait 3 Seconds for ULCD to be Initialized"); + delay(3000); + + + Serial.println("Initializing ULCD..."); + /* This is not mentioned in the code. */ + ulcd_init(); + + ulcd_cls(); + ulcd_txt_demo(); + delay(3000); /* wait for a bit */ + +} + + +void loop() { + ulcd_cls(); + ulcd_moving_circle(); +} + + +void ulcd_init(void) { + /* TODO port ported library without helpers */ +} + + +void ulcd_cls(void) { + unsigned char instr[2]; + unsigned char ack; + int written; + + /* 1: move cursor to 0, 0 */ + Serial.println("Clearing screen (gfx_Cls)"); + + /* opcode (big-endian) */ + instr[0] = 0xFF; + instr[1] = 0xD7; + + written = write_tx(instr, 2); + flush_tx(TIME_LIMIT); + + if (written != 2) Serial.println("Failed to write gfx_Cls!"); + + written = read_rx(&ack, 1, TIME_LIMIT); + if (written != 1 || ack != 6) + Serial.println("Failed to get acknowledge"); +} + + +void ulcd_txt_demo(void) { + unsigned char instr[16]; + unsigned char ack; + int written; /* or read */ + + /* 1: move cursor to 0, 0 */ + Serial.println("Moving cursor to 0, 0"); + + /* opcode (big-endian) */ + instr[0] = 0xFF; + instr[1] = 0xE4; + + /* Line value is 2 bytes */ + instr[2] = 0; + instr[3] = 0; + + /* Column is again 2 bytes */ + instr[4] = 0; + instr[5] = 0; + + /* Since this is a demo, we do not use helpers. */ + /* START the below code can be made into a helper */ + written = write_tx(instr, 6); + flush_tx(TIME_LIMIT); + + if (written != 6) Serial.println("Failed to write txt_MoveCursor!"); + + written = read_rx(&ack, 1, TIME_LIMIT); + if (written != 1 || ack != 6) + Serial.println("Failed to get acknowledge"); + /* END the below code can be made into a helper */ + + /* write Hello, World (12) to the display */ + /* see putstr on Goldelox */ + + instr[0] = 0x00; + instr[1] = 0x06; + + instr[2] = 'H'; + instr[3] = 'e'; + instr[4] = 'l'; + instr[5] = 'l'; + instr[6] = 'o'; + instr[7] = ','; + instr[8] = ' '; + instr[9] = 'W'; + instr[10] = 'o'; + instr[11] = 'r'; + instr[12] = 'l'; + instr[13] = 'd'; + + instr[14] = '\0'; + + written = write_tx(instr, 15); + flush_tx(TIME_LIMIT); + + if (written != 15) Serial.println("Failed to write putstr!"); + + written = read_rx(&ack, 1, TIME_LIMIT); + if (written != 1 || ack != 6) + Serial.println("Failed to get acknowledge"); +} + + +void ulcd_lab2(void) { + uint16_t current_x = 64; + uint16_t current_y = 64; + uint16_t prev_x = 64; + uint16_t prev_y = 64; + uint16_t step_x = 2; + uint16_t step_y = 2; + const uint16_t rad = 15; + int written; + unsigned char ack; + unsigned char instr[10]; + /* using gfx_CircleFilled */ + instr[0] = 0xFF; + instr[1] = 0xCC; + + while (1) { + /* we draw a circle as long as it is in bounds */ + + /* draw a black circle to cover our tracks */ + + /* x coord */ + instr[2] = (prev_x >> 8); + instr[3] = prev_x & 0xFF; + /* y coord */ + instr[4] = (prev_y >> 8); + instr[5] = prev_y & 0xFF; + + /* rad */ + instr[6] = (rad >> 8); + instr[7] = rad; + + /* color (British spelling used in docs) */ + instr[8] = 0x00; + instr[9] = 0x00; + + written = write_tx(instr, 10); + flush_tx(TIME_LIMIT); + + if (written != 10) Serial.println("Failed to write gfx_CircleFilled!"); + + written = read_rx(&ack, 1, TIME_LIMIT); + if (written != 1 || ack != 6) + Serial.println("Failed to get acknowledge"); + + + /* draw blue circle */ + instr[2] = (current_x >> 8); + instr[3] = current_x & 0xFF; + /* y coord */ + instr[4] = (current_y >> 8); + instr[5] = current_y & 0xFF; + + /* rad */ + instr[6] = (rad >> 8); + instr[7] = rad; + + /* 5 bits for red, 6 for green and 5 for blue */ + instr[8] = 0x00; + instr[9] = 0x1F; + + written = write_tx(instr, 10); + flush_tx(TIME_LIMIT); + + if (written != 10) Serial.println("Failed to write gfx_CircleFilled!"); + + written = read_rx(&ack, 1, TIME_LIMIT); + if (written != 1 || ack != 6) + Serial.println("Failed to get acknowledge"); + + + /* increment motion counters */ + prev_x = current_x; + prev_y = current_y; + current_x += step_x; + current_y += step_y; + } +} +void ulcd_moving_circle(void) { + /* This demo generates a circle that moves from left to right of the screen. + * It is supposed to show that having a higher baud rate makes a difference. + */ + uint16_t current_x = 0; + uint16_t current_y = 0; + uint16_t step_x = 2; + uint16_t step_y = 2; + const uint16_t rad = 15; + int written; + unsigned char ack; + unsigned char instr[10]; + /* using gfx_CircleFilled */ + instr[0] = 0xFF; + instr[1] = 0xCC; + + while (current_x < SCR_W && current_y < SCR_H) { + /* we draw a moving circle as long as it is in bounds */ + uint16_t prev_x = (current_x - step_x) % SCR_W; + uint16_t prev_y = (current_y - step_y) % SCR_H; + + /* draw a black circle to cover our tracks */ + + /* x coord */ + instr[2] = (prev_x >> 8); + instr[3] = prev_x & 0xFF; + /* y coord */ + instr[4] = (prev_y >> 8); + instr[5] = prev_y & 0xFF; + + /* rad */ + instr[6] = (rad >> 8); + instr[7] = rad; + + /* color (British spelling used in docs) */ + instr[8] = 0x00; + instr[9] = 0x00; + + written = write_tx(instr, 10); + flush_tx(TIME_LIMIT); + + if (written != 10) Serial.println("Failed to write gfx_CircleFilled!"); + + written = read_rx(&ack, 1, TIME_LIMIT); + if (written != 1 || ack != 6) + Serial.println("Failed to get acknowledge"); + + + /* draw blue circle */ + instr[2] = (current_x >> 8); + instr[3] = current_x & 0xFF; + /* y coord */ + instr[4] = (current_y >> 8); + instr[5] = current_y & 0xFF; + + /* rad */ + instr[6] = (rad >> 8); + instr[7] = rad; + + /* 5 bits for red, 6 for green and 5 for blue */ + instr[8] = 0x00; + instr[9] = 0x1F; + + written = write_tx(instr, 10); + flush_tx(TIME_LIMIT); + + if (written != 10) Serial.println("Failed to write gfx_CircleFilled!"); + + written = read_rx(&ack, 1, TIME_LIMIT); + if (written != 1 || ack != 6) + Serial.println("Failed to get acknowledge"); + + + /* increment motion counters */ + current_x += step_x; + current_y += step_y; + } +} + + +void ulcd_faster_baud(void) { + /* this makes the baud rate the max possible */ + ulcd_baud(4, 600000); +} + + +void ulcd_default_baud(void) { + /* this makes the baud rate the max possible */ + ulcd_baud(312, 9600); +} + + +void ulcd_baud(int baud_table_idx, int actual_baud) { + unsigned char instr[4], ack; + int written; + + /* see the setbaudWait function */ + instr[0] = 0x00; + instr[1] = 0x0B; + instr[2] = (baud_table_idx >> 8); + instr[3] = baud_table_idx; + + written = write_tx(instr, 4); + flush_tx(TIME_LIMIT); + + if (written != 4) Serial.println("Failed to write setbaudWait!"); + + update_baud(actual_baud); + + /* wait 100 ms for the acknowledge in the new baud rate */ + delay(100); + + written = read_rx(&ack, 1, TIME_LIMIT); + if (written != 1 || ack != 6) + Serial.println("Failed to get acknowledge"); +} + +/* ================================================================= */ +/* for arduino */ + +int write_tx(const void *data, size_t sz) { + return LCDSer.write((char *) data, sz); +} + + +int read_rx(void *data, size_t sz, uint32_t wait_ms) { + if (sizeof(size_t) > sizeof(uint32_t) && sz > UINT32_MAX) + return -1; + time_t tm = time(NULL); + while (time(NULL) - tm < wait_ms / 1000) { + if (LCDSer.available() >= sz) + return LCDSer.readBytes((char *) data, sz); + } + return 0; +} + + +int flush_rx() { + LCDSer.flush(); + return 1; +} + + +int flush_tx(uint32_t wait_ms) { + return 1; +} + +void update_baud(int baud) { + LCDSer.end(); + LCDSer.begin(baud, SERIAL_8N1, PIN_UART_RXD, PIN_UART_TXD); +} + +/* ================================================================= */ diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 75a2178..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# The following lines of boilerplate have to be in your project's -# CMakeLists in this exact order for cmake to work correctly -cmake_minimum_required(VERSION 3.16) - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) -# "Trim" the build. Include the minimal set of components, main, and anything it depends on. -idf_build_set_property(MINIMAL_BUILD ON) -project(ulcd_nolib) diff --git a/GUIDE.adoc b/GUIDE.adoc deleted file mode 100644 index 8cf918f..0000000 --- a/GUIDE.adoc +++ /dev/null @@ -1,180 +0,0 @@ -= Writing to the uLCD without a library: Student Guide -Advaith Menon ; Diego Fratta -v0.1.0, 2026-01-20 -:toc: -:link-goldelox: https://github.com/4dsystems/Goldelox-Serial-Linux-Library -:link-spe: https://resources.4dsystems.com.au/manuals/workshop4/serial/goldelox/#text-and-string-commands -:link-repository: https://git.devinivas.org/?p=4dulcd-nolibrary.git;a=summary - -== Abstract -This document details the necessary steps to write to the uLCD without using the -libraries provided by 4D Systems. - -NOTE: Some of this code was written by -reverse-engineering the {link-goldelox}[Linux library] provided by 4D Systems. -This is not necessary - 4D provides {link-spe}[comprehensive -documentation] on the opcodes and how to use them. - -== Copyright -The code is licensed under the MIT License. Students should legally be able to -copy code from this demo into their assignments, as long as the copyright notice -is retained. - -The authors of this document discourage copying code. Instead, they encourage -understanding what the code does and then attempting to rewrite it on their own. - -== Approach -The code uses ESP-IDF as its platform. Since all other platforms, such as -Arduino, run on top of ESP-IDF, this code should be portable. The wiring for the -reset is also done directly to the ESP's reset line, hence there is no code to -reset the uLCD. - -NOTE: To get the code to work with Arduino, rename the `app_main` function to -`setup` and add a new line: `void loop(void) {}`. - -== Code -Code can be found at Advaith's personal Git server. The link is as follows: -{link-repository}. To clone the repository, run `git clone -git://git.devinivas.org/4dulcd-nolibrary.git`. - -== Basic Steps -The steps to initialize UART are not covered here since these depend on the -platform that the user chooses to use. The UART interface has been abstracted to -four functions: - -* `write_tx(const void *data, size_t bufsz)`: Send `bufsz` data from the `data` - buffer via the TX line. Returns number of bytes sent. -* `read_rx(void *data, size_t bufsz, uint32_t tout)`: Read `bufsz` data into the - `data` buffer, and limit to `tout` seconds. If it takes longer, this function - fails. Returns number of bytes read. -* `flush_rx()`: Flush the receiving buffer. -* `flush_tx(uint32_t timeout)`: Flush the transmit buffers. The operation times - out if it exceeds `timeout` seconds. - -By abstracting the UART interface into these four functions, it should be -possible to use this code with any microcontroller that supports UART - these -functions will simply have to be implemented for that specific architecture. - -=== Initialization -The EVE (Extensible Virtual Engine) takes 3 seconds to boot up. This is the -most reliable way to perform the -boot wait - alternate methods will not work. - -NOTE: The official uLCD libraries work by sending a bunch of 'X's until a `0x15` -is received. At least, that is how it's supposed to work in theory, but actually -the read just times out, basically having the same effect as above. - -=== uLCD Default Parameters -By default, the ULCD uses `8N1` UART at a baud rate of 9600. This baud rate can -be changed via a special opcode. - -The uLCD can be treated as a "big-endian" device. This means most significant -bits are sent first. For instance, if you wish to send the data `0xDEADBEEF`, -you would send it as `0xDE`, `0xAD`, `0xBE`, `0xEF`. - -=== uLCD opcodes -uLCD opcodes are 16 bits in length. These opcodes can be found at {link-spe}[the -4D Systems documentation]. For example, the opcode for clearing the screen is -`0xFFD7`, which means you send `0xFF`, then `0xD7`. - -Some opcodes take arguments. Argument values are sent in a big-endian -fashion. - -=== uLCD Acknowledge -After every instruction is set, an acknowledge can be obtained from the uLCD by -reading 1 byte from it. This byte should be `0x06`. Any other value indicates an -error code. - -TIP: The reader is encouraged to create a helper function to perform this -acknowledge since it is a -very commonly used operation. The demo code does not do so to promote learning. - -== Demos - -TIP: The reader is encouraged to attempt writing the code without looking at the -aforementioed repository. Doing so will train one on how to read documentation. - -IMPORTANT: The code must be pulled from the actual repository, and is not -provided here. - -=== Clearing the screen -Per the uLCD documentation, if there is no serial activity after 5 seconds from -EVE initialization, the "flash" screen will be written. To prevent writing on -top of this screen in the event the uLCD has not been reset, the screen must be -cleared. To perform this action, there is the `gfx_Cls` command in GOLDELOX. -This has an opcode of `0xFFD7` and takes no arguments. - -=== Hello, World! -The function `ulcd_txt_demo` demonstrates this process by writing a Hello World -string to the first line and column. This code is in the function -`ulcd_txt_demo`. - -The text cursor first has to be placed at the desired location. -This is done with the `txt_MoveCursor` -function with an opcode of `0xFFE4`. It takes two arguments, the line number and -the column number, both which are 16-bit unsigned integers. Since the uLCD's -number of pixels don't even exceed one byte, it can easily be fit within the -lower byte. The code goes to (0,0). - -Now, the `putstr` command can be used to print a string to the current location -on the LCD. In standard C convention, the string must end with a `0x00` byte to -denote its end. The string "Hello, World" is sent here. - -**Exercise to the reader:** (Not for credit) - -. Make the text bold and change its color to white. - The `txt_Bold` and `txt_FGcolour` commands might help. -. Center the text horizontally and vertically to the screen. - Avoid using trial-and-error, and use the - `charwidth`, `charheight` and `gfx_MoveTo` functions instead. -. Display the text inside a sufficiently big semicircle. - - -=== Changing the baud rate -Unlike other instructions which basically follow the same process, the baud rate -instruction is a bit tricky to implement. It works in three steps: - -. Call the `setBaudWait` command -. Change the baud rate -. With the new baud rate, perform the acknowledge procedure. - -To ease understanding of the code, we have abstracted the process of changing -the baud rate to a function called `update_baud`. - -Note that `setBaudWait` doesn't take a baud rate as its argument! It instead -takes a mapping to a number indicating a baud rate. The mapping table can be -found at 4D's website. - -The function `ulcd_baud` performs the baud rate change. It takes two arguments, -the first being the index from the table, and the second the actual baud rate. -The below table lists a few of the possible values. - -[cols="1,1"] -|=== -|Index |Baud Rate - -|312 -|9600 (default) - -|207 -|14400 - -|155 -|19200 - -|77 -|38400 - -|25 -|115200 - -|4 -|600000 (fastest) -|=== - -The baud rate change happens in 100ms. We wait while the hardware gets the -acknowledge and stores it, and then we check for the acknowledge afterwards. - -To demonstrate the difference in using a faster baud rate, a demo program -showing a moving circle has been made. Note that the circle moves faster and is -more clear with a higher baud rate. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 9e6b0e6..0000000 --- a/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2026 Advaith Menon - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the “Software”), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/README.adoc b/README.adoc deleted file mode 100644 index 109f2cd..0000000 --- a/README.adoc +++ /dev/null @@ -1,62 +0,0 @@ -= Writing to the uLCD without a library -Advaith Menon ; Diego Fratta -v0.1.0, 2026-01-20 -:toc: -:link-goldelox: https://github.com/4dsystems/Goldelox-Serial-Linux-Library -:link-spe: https://resources.4dsystems.com.au/manuals/workshop4/serial/goldelox/#text-and-string-commands -:link-repository: https://git.devinivas.org/?p=4dulcd-nolibrary.git;a=summary - -== Abstract -This document details the necessary steps to write to the uLCD without using the -libraries provided by 4D Systems. Most of this code was written by -reverse-engineering the {link-goldelox}[Linux library] provided by 4D Systems. -This is not necessary - 4D provides {link-spe}[comprehensive -documentation] on the opcodes and how to use them. It is left as an exercise to -the reader to replicate the same without referring to library code. - -== Approach -The code uses ESP-IDF as its platform. Since all other platforms, such as -Arduino, run on top of ESP-IDF, this code should be portable. The wiring for the -reset is also done directly to the ESP's reset line, hence there is no code to -reset the uLCD. - -== Code -Code can be found at Advaith's personal Git server. The link is as follows: -{link-repository}. To clone the repository, run `git clone -git://git.devinivas.org/4dulcd-nolibrary.git`. - -== Basic Steps -We do not cover the steps to initialize UART here, since these depend on the -platform that the user chooses to use. We have abstracted the UART interface to -four functions: - -* `write_tx(const void *data, size_t bufsz)`: Send `bufsz` data from the `data` - buffer via the TX line. Returns number of bytes sent. -* `read_rx(void *data, size_t bufsz, uint32_t tout)`: Read `bufsz` data into the - `data` buffer, and limit to `tout` seconds. If it takes longer, this function - fails. Returns number of bytes read. -* `flush_rx()`: Flush the receiving buffer. -* `flush_tx(uint32_t timeout)`: Flush the transmit buffers. The operation times - out if it exceeds `timeout` seconds. - -The uLCD is a "big-endian" device. This means we send the most significant bit -over UART. - -=== Initialization -The EVE takes 3 seconds to boot up. This is the most reliable way to perform the -boot wait - alternate methods, like sending a bunch of 'K's until we get an -acknowledge are not reliable and can even cause irrepairable harm to the uLCDs -in some cases. - -=== uLCD opcodes -uLCD opcodes are 8 bits in length. These opcodes can be found at {link-spe}[the -4D Systems documentation]. For example, the opcode for clearing the screen is -`0xFFD7`, which means you send `0xFF`, then `0xD7`. - -Most opcodes (except the baud rate switch) return an acknowledge. This -acknowledge can be obtained by reading one byte of data from the UART device, -and this byte should be `0x06`. - -=== Demos -The function `ulcd_txt_demo` demonstrates this process by writing a Hello World -string to the first line and column. More demo functions will come soon. diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt deleted file mode 100644 index 6ee2157..0000000 --- a/main/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -idf_component_register(SRCS "main.c" - PRIV_REQUIRES spi_flash - esp_driver_uart - esp_driver_gpio - INCLUDE_DIRS "") diff --git a/main/main.c b/main/main.c deleted file mode 100644 index 19285b2..0000000 --- a/main/main.c +++ /dev/null @@ -1,351 +0,0 @@ -#include -#include -#include "freertos/FreeRTOS.h" -#include "esp_log.h" -#include "esp_system.h" -#include -#include "driver/uart.h" - -#define PIN_UART_RXD 4 -#define PIN_UART_TXD 5 - -#define ULCD_DEFAULT_BAUD_RATE 9600 -#define ULCD_DEFAULT_DATA_BITS UART_DATA_8_BITS -#define ULCD_DEFAULT_PARITY UART_PARITY_DISABLE -#define ULCD_DEFAULT_STOP_BITS UART_STOP_BITS_1 -#define TIME_LIMIT 2000 - -/* screen width and height */ -#define SCR_W 128 -#define SCR_H 128 - - -static const char *TAG = "main"; -static const uart_port_t uart_port = UART_NUM_1; - -/* UART config. This is handy as some sort of default. */ -static const uart_config_t uart_cfg = { - .baud_rate = ULCD_DEFAULT_BAUD_RATE, - .data_bits = ULCD_DEFAULT_DATA_BITS, - .parity = ULCD_DEFAULT_PARITY, - .stop_bits = ULCD_DEFAULT_STOP_BITS, - .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS, - .rx_flow_ctrl_thresh = 10 -}; - - -/* Helper functions to make things easier for Arduino users */ -/* DO NOT CALL UNTIL UART IS INITIALIZED */ -int write_tx(const void *data, size_t bufsz); -int read_rx(void *data, size_t bufsz, uint32_t timeout); -int flush_rx(); -int flush_tx(uint32_t timeout); -void update_baud(int baud); - - -void ulcd_init(void); -void ulcd_cls(void); -void ulcd_txt_demo(void); -void ulcd_moving_circle(void); -void ulcd_faster_baud(void); -void ulcd_default_baud(void); -void ulcd_baud(int, int); - - -void app_main(void) -{ - ESP_LOGI(TAG, "Starting program"); - ESP_LOGI(TAG, "Initializing UART..."); - - /* Install Drivers */ - const int uart_bufsz = UART_HW_FIFO_LEN(uart_port) + 4; - QueueHandle_t uart_q; - ESP_ERROR_CHECK(uart_driver_install(uart_port, - uart_bufsz, - uart_bufsz, - 10, - &uart_q, - 0)); - - /* Set comms parameters */ - ESP_ERROR_CHECK(uart_param_config(uart_port, &uart_cfg)); - - /* Set pins */ - ESP_ERROR_CHECK(uart_set_pin(uart_port, PIN_UART_TXD, PIN_UART_RXD, - UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); - - /* UART is initialized. We can now work on initializing the uLCD. */ - ESP_LOGI(TAG, "Wait 3 Seconds for ULCD to be Initialized"); - vTaskDelay(pdMS_TO_TICKS(3000)); /* see "Power-Up and Reset" in 4D docs */ - - - ESP_LOGI(TAG, "Initializing ULCD..."); - /* This is not mentioned in the code. */ - ulcd_init(); - - ulcd_cls(); - ulcd_txt_demo(); - vTaskDelay(pdMS_TO_TICKS(3000)); /* wait for a bit */ - - ulcd_cls(); - ulcd_moving_circle(); - vTaskDelay(pdMS_TO_TICKS(1000)); /* let the user digest how bad that was */ - - ulcd_faster_baud(); - ulcd_cls(); - ulcd_moving_circle(); - /* Hey, it's Andy from LTT here and look at my crazy-fast 60fps gaming - * monitor! */ - vTaskDelay(pdMS_TO_TICKS(1000)); - - /* Allows the program to loop w/o resetting uLCD */ - ulcd_default_baud(); - - - ESP_LOGI(TAG, "Work is done"); - vTaskDelay(pdMS_TO_TICKS(1000)); - esp_restart(); -} - - -void ulcd_init(void) { - /* TODO port ported library without helpers */ -} - - -void ulcd_cls(void) { - unsigned char instr[2]; - unsigned char ack; - int written; - - /* 1: move cursor to 0, 0 */ - ESP_LOGI(TAG, "Clearing screen (gfx_Cls)"); - - /* opcode (big-endian) */ - instr[0] = 0xFF; - instr[1] = 0xD7; - - written = write_tx(instr, 2); - flush_tx(TIME_LIMIT); - - if (written != 2) ESP_LOGE(TAG, "Failed to write gfx_Cls!"); - - written = read_rx(&ack, 1, TIME_LIMIT); - if (written != 1 || ack != 6) - ESP_LOGE(TAG, "Failed to get acknowledge"); -} - - -void ulcd_txt_demo(void) { - unsigned char instr[16]; - unsigned char ack; - int written; /* or read */ - - /* 1: move cursor to 0, 0 */ - ESP_LOGI(TAG, "Moving cursor to 0, 0"); - - /* opcode (big-endian) */ - instr[0] = 0xFF; - instr[1] = 0xE4; - - /* Line value is 2 bytes */ - instr[2] = 0; - instr[3] = 0; - - /* Column is again 2 bytes */ - instr[4] = 0; - instr[5] = 0; - - /* Since this is a demo, we do not use helpers. */ - /* START the below code can be made into a helper */ - written = write_tx(instr, 6); - flush_tx(TIME_LIMIT); - - if (written != 6) ESP_LOGE(TAG, "Failed to write txt_MoveCursor!"); - - written = read_rx(&ack, 1, TIME_LIMIT); - if (written != 1 || ack != 6) - ESP_LOGE(TAG, "Failed to get acknowledge"); - /* END the below code can be made into a helper */ - - /* write Hello, World (12) to the display */ - /* see putstr on Goldelox */ - - instr[0] = 0x00; - instr[1] = 0x06; - - instr[2] = 'H'; - instr[3] = 'e'; - instr[4] = 'l'; - instr[5] = 'l'; - instr[6] = 'o'; - instr[7] = ','; - instr[8] = ' '; - instr[9] = 'W'; - instr[10] = 'o'; - instr[11] = 'r'; - instr[12] = 'l'; - instr[13] = 'd'; - - instr[14] = '\0'; - - written = write_tx(instr, 15); - flush_tx(TIME_LIMIT); - - if (written != 15) ESP_LOGE(TAG, "Failed to write putstr!"); - - written = read_rx(&ack, 1, TIME_LIMIT); - if (written != 1 || ack != 6) - ESP_LOGE(TAG, "Failed to get acknowledge"); -} - - -void ulcd_moving_circle(void) { - /* This demo generates a circle that moves from left to right of the screen. - * It is supposed to show that having a higher baud rate makes a difference. - */ - uint16_t current_x = 0; - uint16_t current_y = 0; - uint16_t step_x = 2; - uint16_t step_y = 2; - const uint16_t rad = 15; - int written; - unsigned char ack; - unsigned char instr[10]; - /* using gfx_CircleFilled */ - instr[0] = 0xFF; - instr[1] = 0xCC; - - while (current_x < SCR_W && current_y < SCR_H) { - /* we draw a moving circle as long as it is in bounds */ - uint16_t prev_x = (current_x - step_x) % SCR_W; - uint16_t prev_y = (current_y - step_y) % SCR_H; - - /* draw a black circle to cover our tracks */ - - /* x coord */ - instr[2] = (prev_x >> 8); - instr[3] = prev_x & 0xFF; - /* y coord */ - instr[4] = (prev_y >> 8); - instr[5] = prev_y & 0xFF; - - /* rad */ - instr[6] = (rad >> 8); - instr[7] = rad; - - /* color (British spelling used in docs) */ - instr[8] = 0x00; - instr[9] = 0x00; - - written = write_tx(instr, 10); - flush_tx(TIME_LIMIT); - - if (written != 10) ESP_LOGE(TAG, "Failed to write gfx_CircleFilled!"); - - written = read_rx(&ack, 1, TIME_LIMIT); - if (written != 1 || ack != 6) - ESP_LOGE(TAG, "Failed to get acknowledge"); - - - /* draw blue circle */ - instr[2] = (current_x >> 8); - instr[3] = current_x & 0xFF; - /* y coord */ - instr[4] = (current_y >> 8); - instr[5] = current_y & 0xFF; - - /* rad */ - instr[6] = (rad >> 8); - instr[7] = rad; - - /* 5 bits for red, 6 for green and 5 for blue */ - instr[8] = 0x00; - instr[9] = 0x1F; - - written = write_tx(instr, 10); - flush_tx(TIME_LIMIT); - - if (written != 10) ESP_LOGE(TAG, "Failed to write gfx_CircleFilled!"); - - written = read_rx(&ack, 1, TIME_LIMIT); - if (written != 1 || ack != 6) - ESP_LOGE(TAG, "Failed to get acknowledge"); - - - /* increment motion counters */ - current_x += step_x; - current_y += step_y; - } -} - - -void ulcd_faster_baud(void) { - /* this makes the baud rate the max possible */ - ulcd_baud(4, 600000); -} - - -void ulcd_default_baud(void) { - /* this makes the baud rate the max possible */ - ulcd_baud(312, 9600); -} - - -void ulcd_baud(int baud_table_idx, int actual_baud) { - unsigned char instr[4], ack; - int written; - - /* see the setbaudWait function */ - instr[0] = 0x00; - instr[1] = 0x0B; - instr[2] = (baud_table_idx >> 8); - instr[3] = baud_table_idx; - - written = write_tx(instr, 4); - flush_tx(TIME_LIMIT); - - if (written != 4) ESP_LOGE(TAG, "Failed to write setbaudWait!"); - - update_baud(actual_baud); - - /* wait 100 ms for the acknowledge in the new baud rate */ - vTaskDelay(pdMS_TO_TICKS(100)); - - written = read_rx(&ack, 1, TIME_LIMIT); - if (written != 1 || ack != 6) - ESP_LOGE(TAG, "Failed to get acknowledge"); -} - -/* ================================================================= */ - -int write_tx(const void *data, size_t sz) { - return uart_write_bytes(uart_port, data, sz); -} - - -int read_rx(void *data, size_t sz, uint32_t wait_ms) { - if (sizeof(size_t) > sizeof(uint32_t) && sz > UINT32_MAX) - return -1; - return uart_read_bytes(uart_port, data, (uint32_t) sz, - (TickType_t) wait_ms / portTICK_PERIOD_MS); -} - - -int flush_rx() { - return (int) uart_flush(uart_port); -} - - -int flush_tx(uint32_t wait_ms) { - return (int) uart_wait_tx_done(uart_port, - (TickType_t) wait_ms / portTICK_PERIOD_MS); -} - -void update_baud(int baud) { - uart_config_t ucfg2 = uart_cfg; - ucfg2.baud_rate = baud; - ESP_ERROR_CHECK(uart_param_config(uart_port, &ucfg2)); -} - -/* ================================================================= */ diff --git a/pytest_hello_world.py b/pytest_hello_world.py deleted file mode 100644 index eb02bd7..0000000 --- a/pytest_hello_world.py +++ /dev/null @@ -1,55 +0,0 @@ -# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD -# SPDX-License-Identifier: CC0-1.0 -import hashlib -import logging -from typing import Callable - -import pytest -from pytest_embedded_idf.dut import IdfDut -from pytest_embedded_idf.utils import idf_parametrize -from pytest_embedded_qemu.app import QemuApp -from pytest_embedded_qemu.dut import QemuDut - - -@pytest.mark.generic -@idf_parametrize('target', ['supported_targets', 'preview_targets'], indirect=['target']) -def test_hello_world(dut: IdfDut, log_minimum_free_heap_size: Callable[..., None]) -> None: - dut.expect('Hello world!') - log_minimum_free_heap_size() - - -@pytest.mark.host_test -@idf_parametrize('target', ['linux'], indirect=['target']) -def test_hello_world_linux(dut: IdfDut) -> None: - dut.expect('Hello world!') - - -@pytest.mark.host_test -@pytest.mark.macos_shell -@idf_parametrize('target', ['linux'], indirect=['target']) -def test_hello_world_macos(dut: IdfDut) -> None: - dut.expect('Hello world!') - - -def verify_elf_sha256_embedding(app: QemuApp, sha256_reported: str) -> None: - sha256 = hashlib.sha256() - with open(app.elf_file, 'rb') as f: - sha256.update(f.read()) - sha256_expected = sha256.hexdigest() - - logging.info(f'ELF file SHA256: {sha256_expected}') - logging.info(f'ELF file SHA256 (reported by the app): {sha256_reported}') - - # the app reports only the first several hex characters of the SHA256, check that they match - if not sha256_expected.startswith(sha256_reported): - raise ValueError('ELF file SHA256 mismatch') - - -@pytest.mark.host_test -@pytest.mark.qemu -@idf_parametrize('target', ['esp32', 'esp32c3'], indirect=['target']) -def test_hello_world_host(app: QemuApp, dut: QemuDut) -> None: - sha256_reported = dut.expect(r'ELF file SHA256:\s+([a-f0-9]+)').group(1).decode('utf-8') - verify_elf_sha256_embedding(app, sha256_reported) - - dut.expect('Hello world!') diff --git a/sdkconfig.ci b/sdkconfig.ci deleted file mode 100644 index e69de29..0000000