init
This commit is contained in:
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/dist/
|
||||
|
||||
*.o
|
||||
*.out
|
||||
*.swp
|
||||
*.swo
|
||||
13
.vscode/settings.json
vendored
Normal file
13
.vscode/settings.json
vendored
Normal 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
24
Makefile
Normal 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
84
color_utils.c
Normal 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
22
color_utils.h
Normal 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
68
main.c
Normal 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(¤t_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
5
shader.c
Normal 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
8
shader.h
Normal 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
43
spi_utils.c
Normal 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
23
spi_utils.h
Normal 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
|
||||
Reference in New Issue
Block a user