Files
barnum/barnum.c

163 lines
4.8 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "hardware/clocks.h"
#include "ws2812.pio.h"
#include "ch9120.h"
#define WS2812_PIN 25
#define LED_FREQ 800000
void put_pixel(uint32_t pixel_grb) {
pio_sm_put_blocking(pio0, 0, pixel_grb << 8u);
}
void put_rgb(uint8_t red, uint8_t green, uint8_t blue) {
uint32_t mask = (green << 16) | (red << 8) | (blue << 0);
put_pixel(mask);
}
void parse_color_command(const char *cmd, uint8_t *r, uint8_t *g, uint8_t *b) {
if (strncmp(cmd, "RGB:", 4) == 0) {
sscanf(cmd + 4, "%hhu,%hhu,%hhu", r, g, b);
} else if (strcmp(cmd, "RED") == 0) {
*r = 255; *g = 0; *b = 0;
} else if (strcmp(cmd, "GREEN") == 0) {
*r = 0; *g = 255; *b = 0;
} else if (strcmp(cmd, "BLUE") == 0) {
*r = 0; *g = 0; *b = 255;
} else if (strcmp(cmd, "WHITE") == 0) {
*r = 255; *g = 255; *b = 255;
} else if (strcmp(cmd, "OFF") == 0) {
*r = 0; *g = 0; *b = 0;
}
}
int main() {
stdio_init_all();
printf("RP2040-ETH WS2812 Network Control\n");
// Initialize WS2812 LED
PIO pio = pio0;
int sm = 0;
uint offset = pio_add_program(pio, &ws2812_program);
ws2812_program_init(pio, sm, offset, WS2812_PIN, LED_FREQ, true);
// Initialize CH9120 Ethernet
CH9120_init();
printf("Ethernet initialized\n");
printf("IP: 192.168.1.201\n");
printf("Port: 1000\n");
printf("Mode: TCP Server\n");
printf("Send color commands: RED, GREEN, BLUE, WHITE, OFF, or RGB:r,g,b\n");
// Flash LED to indicate startup
for (int i = 0; i < 3; i++) {
put_rgb(0, 0, 255); // Blue flash
sleep_ms(200);
put_rgb(0, 0, 0); // Off
sleep_ms(200);
}
// Current LED state
uint8_t current_r = 0, current_g = 0, current_b = 0;
uint8_t target_r = 0, target_g = 0, target_b = 0;
bool color_changing = false;
char rx_buffer[256];
uint32_t last_heartbeat = 0;
uint32_t last_blink = 0;
bool show_blink = false;
while (1) {
// Check for network data
int received = CH9120_receive_data(rx_buffer, sizeof(rx_buffer) - 1);
if (received > 0) {
rx_buffer[received] = '\0';
// Flash amber to indicate traffic
put_rgb(255, 191, 0); // Amber
sleep_ms(50);
// Parse color command
uint8_t new_r, new_g, new_b;
parse_color_command(rx_buffer, &new_r, &new_g, &new_b);
// Set new target color
target_r = new_r;
target_g = new_g;
target_b = new_b;
color_changing = true;
// Send acknowledgment
char ack[64];
snprintf(ack, sizeof(ack), "Setting color to R:%d G:%d B:%d\n", new_r, new_g, new_b);
CH9120_send_data(ack, strlen(ack));
// Flash amber again for outgoing traffic
put_rgb(255, 191, 0); // Amber
sleep_ms(50);
printf("Received command: %s\n", rx_buffer);
}
// Smooth color transition
if (color_changing) {
bool done = true;
if (current_r != target_r) {
current_r += (current_r < target_r) ? 1 : -1;
done = false;
}
if (current_g != target_g) {
current_g += (current_g < target_g) ? 1 : -1;
done = false;
}
if (current_b != target_b) {
current_b += (current_b < target_b) ? 1 : -1;
done = false;
}
put_rgb(current_r, current_g, current_b);
if (done) {
color_changing = false;
}
sleep_ms(3);
} else {
// Keep current color
put_rgb(current_r, current_g, current_b);
sleep_ms(10);
}
// Periodic green flash to show firmware is running (regardless of state)
uint32_t now = to_ms_since_boot(get_absolute_time());
// Check if it's time to blink (every 1 second)
if (now - last_blink >= 1000) {
show_blink = true;
last_blink = now;
}
// Show green flash for 100ms
if (show_blink && (now - last_blink < 100)) {
put_rgb(0, 128, 0); // 50% green
}
// Clear blink flag after 100ms
if (now - last_blink >= 100) {
show_blink = false;
}
// Heartbeat log every 5 seconds
if (now - last_heartbeat > 5000) {
printf("Ethernet heartbeat - waiting for commands...\n");
last_heartbeat = now;
}
}
}