Files
eink-dairy/hello_usb.c
2025-11-17 23:34:35 -05:00

135 lines
4.8 KiB
C

/**
* Simple USB Serial Echo Program with Timeout, Reconnect, and Backspace Logic.
* This program now correctly handles the backspace character by deleting it
* from the buffer and sending the necessary control codes to the terminal
* for visual deletion.
*/
#include "pico/stdlib.h"
#include "pico/time.h" // Needed for time_us_64()
#include <stdio.h>
#include <ctype.h>
// Define the maximum size for the input string buffer
#define MAX_INPUT_LEN 64
// Define the timeout period: 1 second in microseconds
#define TIMEOUT_US 5000000
// ASCII code for Backspace (often sent as 0x08)
#define ASCII_BACKSPACE 8
// Helper function to handle the echoing and resetting of the buffer
void echo_and_reset(char* buffer, int* index_ptr) {
if (*index_ptr > 0) {
// Null-terminate the string
buffer[*index_ptr] = '\0';
// Echo the string back, converting to uppercase
printf("\nEchoed (ALL CAPS): ");
for (int i = 0; buffer[i] != '\0'; i++) {
printf("%c", toupper(buffer[i]));
}
printf("\n");
}
// Reset buffer for next line and print a new prompt
*index_ptr = 0;
printf("> ");
}
// Function to handle the initial waiting and reconnect waiting
void wait_for_usb_connection() {
printf("Waiting for USB host to connect...\n");
// Wait until the USB host (e.g., terminal program) opens the serial port
while (!stdio_usb_connected()) {
sleep_ms(100);
}
// Connection established!
printf("\nConnection Established! Starting Echo Session...\n");
}
void run_echo_session() {
char input_buffer[MAX_INPUT_LEN];
int buffer_index = 0;
// Track the time (in microseconds) when the last character was received
uint64_t last_char_time = time_us_64();
printf("--- Pico USB String Echo Program Started ---\n");
printf("Type a sentence (up to %d chars). It will echo on Enter/Timeout.\n", MAX_INPUT_LEN - 2);
printf("--------------------------------------------\n");
printf("> "); // Prompt for input
// Inner loop runs ONLY while the USB connection is active
while (stdio_usb_connected()) {
// Check for incoming character without blocking
int c = getchar_timeout_us(0);
if (c != PICO_ERROR_TIMEOUT) {
// Character received, update the timer
last_char_time = time_us_64();
char input_char = (char)c;
// 1. --- BACKSPACE HANDLING ---
if (input_char == ASCII_BACKSPACE || input_char == 127) { // 127 is sometimes sent by terminals (DEL key)
if (buffer_index > 0) {
// Decrease buffer index (remove the character)
buffer_index--;
// Send backspace, space, and backspace to erase the character on the terminal:
// \b: move cursor back
// ' ': overwrite with a space
// \b: move cursor back again, ready for the next character
printf("\b \b");
}
// 2. --- End of Input (Newline/CR) ---
} else if (input_char == '\r' || input_char == '\n') {
echo_and_reset(input_buffer, &buffer_index);
// 3. --- Collect regular characters ---
} else if (buffer_index < (MAX_INPUT_LEN - 1) && isprint(input_char)) {
// Echo character locally so the user sees what they type
printf("%c", input_char);
// Store character in the buffer
input_buffer[buffer_index] = input_char;
buffer_index++;
}
// Ignore non-printable characters and overflowed buffer input
}
// 4. Timeout Check
if (buffer_index > 0 && (time_us_64() - last_char_time) > TIMEOUT_US) {
printf("\n--- Timeout Reached (5.0s silence) ---\n");
echo_and_reset(input_buffer, &buffer_index);
last_char_time = time_us_64(); // Reset time to prevent immediate re-trigger
}
// Add a small delay to prevent the loop from consuming too much CPU time
sleep_us(100);
}
// Connection lost or closed by host
printf("\nHost disconnected. Ending Echo Session.\n");
}
int main() {
// Initialize Standard I/O (stdio) to use the USB backend
stdio_init_all();
// Outer loop: Allows the program to run continuously and restart the
// session after a disconnection.
while (true) {
// 1. Wait for a connection
wait_for_usb_connection();
// 2. Run the program logic while connected
run_echo_session();
// Loop repeats, going back to wait_for_usb_connection()
}
// Note: main should not return
}