This commit is contained in:
Passthem
2025-04-11 15:40:18 +08:00
commit 7e455c591a
10 changed files with 296 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/dist/
*.o
*.out
*.swp
*.swo

13
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,13 @@
{
"files.associations": {
"*.py": "python",
"types.h": "c",
"spidev.h": "c",
"fcntl.h": "c",
"stdlib.h": "c",
"math.h": "c",
"spi_utils.h": "c",
"cstdint": "c",
"color_utils.h": "c"
}
}

24
Makefile Normal file
View File

@ -0,0 +1,24 @@
CC = gcc
CFLAGS = -Wall -Wextra -O2
LDFLAGS = -lm
SRCS = main.c spi_utils.c color_utils.c shader.c
OBJS = $(SRCS:%.c=dist/%.o)
TARGET = dist/main
MKDIR_P = mkdir -p
all: $(TARGET)
$(TARGET): $(OBJS)
$(MKDIR_P) dist
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
dist/%.o: %.c
$(MKDIR_P) dist
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -rf dist
.PHONY: all clean

84
color_utils.c Normal file
View File

@ -0,0 +1,84 @@
#include "color_utils.h"
#include <string.h>
Color hex_to_color(int hex) {
Color color;
color.r = (hex >> 16) % 256;
color.g = (hex >> 8) % 256;
color.b = hex % 256;
return color;
}
Color hsv_to_color(double h, double s, double v) {
h = fmod(h, 360);
if (s > 1)
s = fmod(s, 1);
if (v > 1)
v = fmod(v, 1);
double c = v * s;
double x = c * (1 - fabs(fmod(h / 60, 2) - 1));
double m = v - c;
double r0, g0, b0;
if (h >= 0 && h < 60) {
r0 = c;
g0 = x;
b0 = 0;
} else if (h >= 60 && h < 120) {
r0 = x;
g0 = c;
b0 = 0;
} else if (h >= 120 && h < 180) {
r0 = 0;
g0 = c;
b0 = x;
} else if (h >= 180 && h < 240) {
r0 = 0;
g0 = x;
b0 = c;
} else if (h >= 240 && h < 300) {
r0 = x;
g0 = 0;
b0 = c;
} else {
r0 = c;
g0 = 0;
b0 = x;
}
Color color;
color.r = (r0 + m) * 255;
color.g = (g0 + m) * 255;
color.b = (b0 + m) * 255;
return color;
}
void set_color(uint8_t* buffer, const Color color) {
for (int i = 7; i >= 0; i--)
*buffer++ = (color.g & (1 << i)) ? 0b11111000 : 0b10000000;
for (int i = 7; i >= 0; i--)
*buffer++ = (color.r & (1 << i)) ? 0b11111000 : 0b10000000;
for (int i = 7; i >= 0; i--)
*buffer++ = (color.b & (1 << i)) ? 0b11111000 : 0b10000000;
}
int construct_buffer(uint8_t* buffer,
const Color* colors,
const int num_leds,
const int color_bytes,
const int res_bytes) {
const int data_size = num_leds * color_bytes + res_bytes;
memset(buffer, 0, data_size);
for (int i = 0; i < num_leds; i++) {
set_color(buffer + i * color_bytes, colors[i]);
}
return data_size;
}

22
color_utils.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef COLOR_UTILS_H
#define COLOR_UTILS_H
#include <math.h>
#include <stdint.h>
typedef struct Color {
uint8_t g;
uint8_t r;
uint8_t b;
} Color;
Color hex_to_color(int hex);
Color hsv_to_color(double h, double s, double v);
void set_color(uint8_t* buffer, const Color color);
int construct_buffer(uint8_t* buffer,
const Color* colors,
const int num_leds,
const int color_bytes,
const int res_bytes);
#endif

68
main.c Normal file
View File

@ -0,0 +1,68 @@
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include "spi_utils.h"
#include "color_utils.h"
#include "shader.h"
#define RES_BYTES 40
#define COLOR_BYTES 24
volatile sig_atomic_t stop = 0;
void handle_sigint(int sig) {
stop = 1;
}
int main() {
signal(SIGINT, handle_sigint);
const char* device = "/dev/spidev1.0";
const uint8_t spi_mode = SPI_MODE_0;
const uint8_t spi_bits = 8;
const uint32_t spi_speed = 6400000;
int fd = init_device(device, spi_mode, spi_bits, spi_speed);
if (fd < 0)
return -1;
const int num_leds = 60;
const int data_size = COLOR_BYTES * num_leds + RES_BYTES;
uint8_t* buffer = malloc(data_size);
Color* colors = malloc(sizeof(Color) * num_leds);
struct timeval start_time;
gettimeofday(&start_time, NULL);
while (!stop) {
struct timeval current_time;
gettimeofday(&current_time, NULL);
double time_elapsed =
(current_time.tv_sec - start_time.tv_sec) +
(current_time.tv_usec - start_time.tv_usec) / 1000000.0;
for (int i = 0; i < num_leds; i++) {
colors[i] = shader(i, time_elapsed);
}
construct_buffer(buffer, colors, num_leds, COLOR_BYTES, RES_BYTES);
send_buffer(fd, buffer, data_size, spi_speed, spi_bits);
}
for (int i = 0; i < num_leds; i++) {
colors[i] = hex_to_color(0x000000);
}
construct_buffer(buffer, colors, num_leds, COLOR_BYTES, RES_BYTES);
send_buffer(fd, buffer, data_size, spi_speed, spi_bits);
free(buffer);
free(colors);
close(fd);
return 0;
}

5
shader.c Normal file
View File

@ -0,0 +1,5 @@
#include "shader.h"
Color shader(int index, double time) {
return hsv_to_color(time * 120 + index * 6, 1, 1);
}

8
shader.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef SHADER_H
#define SHADER_H
#include "color_utils.h"
Color shader(int index, double time);
#endif

43
spi_utils.c Normal file
View File

@ -0,0 +1,43 @@
#include "spi_utils.h"
int init_device(const char* device,
uint8_t spi_mode,
uint8_t spi_bits,
uint32_t spi_speed) {
int fd;
if ((fd = open(device, O_RDWR)) < 0) {
perror("SPI 设备打开失败");
close(fd);
return -1;
}
ioctl(fd, SPI_IOC_WR_MODE, &spi_mode);
ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits);
ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed);
return fd;
}
int send_buffer(int fd,
uint8_t* buffer,
const int data_size,
uint32_t spi_speed,
uint8_t spi_bits) {
int ret;
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)buffer,
.len = data_size,
.speed_hz = spi_speed,
.bits_per_word = spi_bits,
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 0) {
perror("SPI 信息发送失败");
}
return ret;
}

23
spi_utils.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef SPI_UTILS_H
#define SPI_UTILS_H
#include <fcntl.h>
#include <linux/spi/spidev.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
int init_device(const char* device,
uint8_t spi_mode,
uint8_t spi_bits,
uint32_t spi_speed);
int send_buffer(int fd,
uint8_t* buffer,
const int data_size,
uint32_t spi_speed,
uint8_t spi_bits);
#endif