--- /dev/null
+#include <Arduino.h>
+#include <HardwareSerial.h>
+#include <time.h>
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#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);
+}
+
+/* ================================================================= */
+++ /dev/null
-# 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)
+++ /dev/null
-= Writing to the uLCD without a library: Student Guide
-Advaith Menon <advaith@gatech.edu>; Diego Fratta <dfratta3@gatech.edu>
-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.
+++ /dev/null
-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.
-
+++ /dev/null
-= Writing to the uLCD without a library
-Advaith Menon <advaith@gatech.edu>; Diego Fratta <dfratta3@gatech.edu>
-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.
+++ /dev/null
-idf_component_register(SRCS "main.c"
- PRIV_REQUIRES spi_flash
- esp_driver_uart
- esp_driver_gpio
- INCLUDE_DIRS "")
+++ /dev/null
-#include <stdio.h>
-#include <inttypes.h>
-#include "freertos/FreeRTOS.h"
-#include "esp_log.h"
-#include "esp_system.h"
-#include <stdint.h>
-#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));
-}
-
-/* ================================================================= */
+++ /dev/null
-# 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!')