]> Devi Nivas Git - 4dulcd-nolibrary.git/commitdiff
Initial commit
authorAdvaith Menon <noreply-git@bp4k.net>
Tue, 20 Jan 2026 20:02:00 +0000 (15:02 -0500)
committerAdvaith Menon <noreply-git@bp4k.net>
Tue, 20 Jan 2026 20:02:00 +0000 (15:02 -0500)
* Reorganize Espressif hello_world example
* Add a .gitignore file
* Write a basic README

.gitignore [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
LICENSE [new file with mode: 0644]
README.adoc [new file with mode: 0644]
main/CMakeLists.txt [new file with mode: 0644]
main/main.c [new file with mode: 0644]
pytest_hello_world.py [new file with mode: 0644]
sdkconfig.ci [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..d2067b7
--- /dev/null
@@ -0,0 +1,24 @@
+.pytest_cache/
+__pycache__/
+
+# esp-idf built binaries
+build/
+build_*_*/
+sdkconfig
+sdkconfig.old
+
+# idf-ci build run output
+build_summary_*.xml
+app_info_*.txt
+size_info_*.txt
+
+# pytest-embedded log folder
+pytest_embedded_log/
+
+# idf-component-manager output
+dependencies.lock
+
+.vscode/
+managed_components/
+
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..75a2178
--- /dev/null
@@ -0,0 +1,8 @@
+# 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/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..9e6b0e6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+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
new file mode 100644 (file)
index 0000000..44b2071
--- /dev/null
@@ -0,0 +1,20 @@
+= 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.
+
+== 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`.
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6692d62
--- /dev/null
@@ -0,0 +1,3 @@
+idf_component_register(SRCS "main.c"
+                       PRIV_REQUIRES spi_flash
+                       INCLUDE_DIRS "")
diff --git a/main/main.c b/main/main.c
new file mode 100644 (file)
index 0000000..7010f3e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include "sdkconfig.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_chip_info.h"
+#include "esp_flash.h"
+#include "esp_system.h"
+
+void app_main(void)
+{
+    printf("Hello world!\n");
+
+    /* Print chip information */
+    esp_chip_info_t chip_info;
+    uint32_t flash_size;
+    esp_chip_info(&chip_info);
+    printf("This is %s chip with %d CPU core(s), %s%s%s%s, ",
+           CONFIG_IDF_TARGET,
+           chip_info.cores,
+           (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "",
+           (chip_info.features & CHIP_FEATURE_BT) ? "BT" : "",
+           (chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "",
+           (chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : "");
+
+    unsigned major_rev = chip_info.revision / 100;
+    unsigned minor_rev = chip_info.revision % 100;
+    printf("silicon revision v%d.%d, ", major_rev, minor_rev);
+    if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) {
+        printf("Get flash size failed");
+        return;
+    }
+
+    printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024),
+           (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
+
+    printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size());
+
+    for (int i = 10; i >= 0; i--) {
+        printf("Restarting in %d seconds...\n", i);
+        vTaskDelay(1000 / portTICK_PERIOD_MS);
+    }
+    printf("Restarting now.\n");
+    fflush(stdout);
+    esp_restart();
+}
diff --git a/pytest_hello_world.py b/pytest_hello_world.py
new file mode 100644 (file)
index 0000000..eb02bd7
--- /dev/null
@@ -0,0 +1,55 @@
+# 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
new file mode 100644 (file)
index 0000000..e69de29