Initial commit
This commit is contained in:
commit
2437c7b18d
79
Makefile
Normal file
79
Makefile
Normal file
|
@ -0,0 +1,79 @@
|
|||
# --- START OF CONFIG ---------------------------------------------------
|
||||
# Edit the following variables for your own needs
|
||||
|
||||
# toolchain configuration
|
||||
CXX=gcc
|
||||
LD=gcc
|
||||
|
||||
# default build configuration
|
||||
# "make BUILD=release" does a release build
|
||||
BUILD:=release
|
||||
|
||||
# basic build flags configuration
|
||||
CFLAGS+=-std=c99 -Wall -pedantic -Wno-long-long -D_POSIX_C_SOURCE=20120607L -D_FILE_OFFSET_BITS=64
|
||||
LIBS+=-lm
|
||||
|
||||
# library specific flags
|
||||
# wiringPi
|
||||
CFLAGS+=
|
||||
LIBS+=-lwiringPi
|
||||
|
||||
# build type specific flags
|
||||
CFLAGS_debug=-O0 -ggdb -DDEBUG
|
||||
LIBS_debug=
|
||||
|
||||
CFLAGS_release=-Os -pipe -march=armv6zk -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard
|
||||
LIBS_release=
|
||||
|
||||
# target configuration
|
||||
TARGET := ws2801d
|
||||
VERSION := 0.0.0
|
||||
VCSVERSION := $(shell git rev-parse --short HEAD)
|
||||
|
||||
# source files for the project
|
||||
SOURCE := $(shell find src/ -name '*.c')
|
||||
INCLUDES := $(shell find include/ -name '*.h')
|
||||
|
||||
# --- END OF CONFIG -----------------------------------------------------
|
||||
|
||||
OBJ1=$(patsubst %.c, %.o, $(SOURCE))
|
||||
OBJ=$(patsubst src/%, obj/$(BUILD)/%, $(OBJ1))
|
||||
|
||||
VERSIONSTR="\"$(VERSION)-$(VCSVERSION)\""
|
||||
|
||||
CFLAGS+=-Iinclude -DVERSION=$(VERSIONSTR)
|
||||
|
||||
TARGETFILE := bin/$(BUILD)/$(TARGET)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
CFLAGS+=$(CFLAGS_$(BUILD))
|
||||
LIBS+=$(LIBS_$(BUILD))
|
||||
|
||||
.PHONY show_cflags:
|
||||
@echo --- Build parameters: ------------------------------------------
|
||||
@echo CFLAGS\=$(CFLAGS)
|
||||
@echo LIBS\=$(LIBS)
|
||||
@echo SOURCE\=$(SOURCE)
|
||||
@echo -----------------------------------------------------------------
|
||||
|
||||
$(TARGET): show_cflags $(TARGETFILE)
|
||||
@echo ">>> $(BUILD) build complete."
|
||||
|
||||
$(TARGETFILE): $(OBJ) $(INCLUDES) Makefile
|
||||
@echo Linking $@ ...
|
||||
@mkdir -p $(shell dirname $@)
|
||||
@$(LD) -o $(TARGETFILE) $(OBJ) $(LIBS)
|
||||
|
||||
obj/$(BUILD)/%.o: src/%.c $(INCLUDES) Makefile
|
||||
@echo Compiling $< ...
|
||||
@mkdir -p $(shell dirname $@)
|
||||
@$(CXX) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
doc:
|
||||
doxygen doxygen.conf
|
||||
|
||||
clean:
|
||||
rm -f $(TARGETFILE)
|
||||
rm -f $(OBJ)
|
||||
|
37
include/logger.h
Normal file
37
include/logger.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* vim: sw=2 ts=2 expandtab
|
||||
*
|
||||
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
|
||||
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
|
||||
* notice you can do whatever you want with this stuff. If we meet some day,
|
||||
* and you think this stuff is worth it, you can buy me a pizza in return.
|
||||
* - Thomas Kolb
|
||||
*/
|
||||
|
||||
#ifndef LOGGER_H
|
||||
#define LOGGER_H
|
||||
|
||||
#include <semaphore.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
static const int LVL_FATAL = 0; /*!< Fatal message level */
|
||||
static const int LVL_ERR = 5; /*!< Error message level */
|
||||
static const int LVL_WARN = 50; /*!< Warning message level */
|
||||
static const int LVL_INFO = 100; /*!< Information message level */
|
||||
static const int LVL_DEBUG = 200; /*!< Debug message level */
|
||||
static const int LVL_DUMP = 500; /*!< Dump message level */
|
||||
|
||||
extern sem_t logger_semaphore;
|
||||
extern int logger_verbosity;
|
||||
extern int logger_use_colors;
|
||||
|
||||
void logger_init(void);
|
||||
void logger_shutdown(void);
|
||||
void logger_enable_colors(int enable);
|
||||
void logger_set_verbosity(int verbosity);
|
||||
|
||||
void logger_log(int level, const char *format, ...);
|
||||
|
||||
#define LOG(level, ...) logger_log(level, __VA_ARGS__)
|
||||
|
||||
#endif // LOGGER_H
|
11
include/ws2801.h
Normal file
11
include/ws2801.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef WS2801_H
|
||||
#define WS2801_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int ws2801_init(uint8_t num_modules);
|
||||
void ws2801_shutdown(void);
|
||||
void ws2801_set_colour(uint8_t module, uint8_t red, uint8_t green, uint8_t blue);
|
||||
void ws2801_send_update(void);
|
||||
|
||||
#endif // WS2801_H
|
161
src/logger.c
Normal file
161
src/logger.c
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* vim: sw=2 ts=2 expandtab
|
||||
*
|
||||
* "THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
|
||||
* Thomas Kolb <cfr34k@tkolb.de> wrote this file. As long as you retain this
|
||||
* notice you can do whatever you want with this stuff. If we meet some day,
|
||||
* and you think this stuff is worth it, you can buy me a pizza in return.
|
||||
* - Thomas Kolb
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
// define constants
|
||||
const char *LOGGER_STR_FATAL = "FATAL";
|
||||
const char *LOGGER_STR_ERR = "ERROR";
|
||||
const char *LOGGER_STR_WARN = "WARN ";
|
||||
const char *LOGGER_STR_INFO = "INFO ";
|
||||
const char *LOGGER_STR_DEBUG = "DEBUG";
|
||||
const char *LOGGER_STR_DUMP = "DUMP ";
|
||||
|
||||
const char *LOGGER_COLOR_FATAL = "\033[1;31m";
|
||||
const char *LOGGER_COLOR_ERR = "\033[1;31m";
|
||||
const char *LOGGER_COLOR_WARN = "\033[1;33m";
|
||||
const char *LOGGER_COLOR_INFO = "\033[1;32m";
|
||||
const char *LOGGER_COLOR_DEBUG = "\033[1m";
|
||||
const char *LOGGER_COLOR_DUMP = "\033[1;30m";
|
||||
const char *LOGGER_COLOR_NONE = "\033[0m";
|
||||
|
||||
// global variables
|
||||
sem_t logger_semaphore;
|
||||
int logger_verbosity;
|
||||
int logger_use_colors;
|
||||
|
||||
void logger_init(void) {
|
||||
// Initialize the semaphore
|
||||
sem_init(&logger_semaphore, 0, 1);
|
||||
|
||||
logger_verbosity = 2147483647;
|
||||
logger_use_colors = 1;
|
||||
}
|
||||
|
||||
void logger_shutdown(void) {
|
||||
sem_destroy(&logger_semaphore);
|
||||
}
|
||||
|
||||
void logger_enable_colors(int enable) {
|
||||
logger_use_colors = enable;
|
||||
}
|
||||
|
||||
void logger_set_verbosity(int verbosity) {
|
||||
logger_verbosity = verbosity;
|
||||
}
|
||||
|
||||
void logger_debug_message(const char *prefix, const char *fmt, va_list ap) {
|
||||
/* Guess we need no more than 100 bytes. */
|
||||
int n, size = 100;
|
||||
char *p, *np;
|
||||
va_list internal_ap;
|
||||
|
||||
if ((p = (char*)malloc(size)) == NULL) {
|
||||
fprintf(stderr, "[%s] FATAL: Cannot allocate string buffer while processing arguments.\n", LOGGER_STR_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
/* Try to print in the allocated space. */
|
||||
va_copy(internal_ap, ap);
|
||||
n = vsnprintf(p, size, fmt, internal_ap);
|
||||
va_end(internal_ap);
|
||||
|
||||
/* If that worked, return the string. */
|
||||
if (n > -1 && n < size)
|
||||
break;
|
||||
|
||||
/* Else try again with more space. */
|
||||
if (n > -1) /* glibc 2.1 */
|
||||
size = n+1; /* precisely what is needed */
|
||||
else /* glibc 2.0 */
|
||||
size *= 2; /* twice the old size */
|
||||
|
||||
if ((np = (char*)realloc (p, size)) == NULL) {
|
||||
free(p);
|
||||
fprintf(stderr, "[%s] FATAL: Cannot reallocate string buffer while processing arguments.\n", LOGGER_STR_ERR);
|
||||
return;
|
||||
} else {
|
||||
p = np;
|
||||
}
|
||||
}
|
||||
|
||||
sem_wait(&logger_semaphore);
|
||||
fprintf(stderr, "%s %s\n", prefix, p);
|
||||
sem_post(&logger_semaphore);
|
||||
|
||||
free(p);
|
||||
}
|
||||
|
||||
void logger_log(int level, const char *format, ...) {
|
||||
va_list argptr;
|
||||
|
||||
char timebuf[32];
|
||||
char timebuf2[32];
|
||||
|
||||
char prefixbuf[64];
|
||||
const char *prefixcolor = "", *prefixtext = "";
|
||||
|
||||
if(level > logger_verbosity)
|
||||
return;
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
strftime(timebuf, 32, "%Y-%M-%d %H:%M:%S.%%03d", localtime(&(tv.tv_sec)));
|
||||
snprintf(timebuf2, 32, timebuf, tv.tv_usec/1000);
|
||||
|
||||
if(level >= LVL_DUMP) {
|
||||
if(logger_use_colors)
|
||||
prefixcolor = LOGGER_COLOR_DUMP;
|
||||
|
||||
prefixtext = LOGGER_STR_DUMP;
|
||||
} else if(level >= LVL_DEBUG) {
|
||||
if(logger_use_colors)
|
||||
prefixcolor = LOGGER_COLOR_DEBUG;
|
||||
|
||||
prefixtext = LOGGER_STR_DEBUG;
|
||||
} else if(level >= LVL_INFO) {
|
||||
if(logger_use_colors)
|
||||
prefixcolor = LOGGER_COLOR_INFO;
|
||||
|
||||
prefixtext = LOGGER_STR_INFO;
|
||||
} else if(level >= LVL_WARN) {
|
||||
if(logger_use_colors)
|
||||
prefixcolor = LOGGER_COLOR_WARN;
|
||||
|
||||
prefixtext = LOGGER_STR_WARN;
|
||||
} else if(level >= LVL_ERR) {
|
||||
if(logger_use_colors)
|
||||
prefixcolor = LOGGER_COLOR_ERR;
|
||||
|
||||
prefixtext = LOGGER_STR_ERR;
|
||||
} else {
|
||||
if(logger_use_colors)
|
||||
prefixcolor = LOGGER_COLOR_FATAL;
|
||||
|
||||
prefixtext = LOGGER_STR_FATAL;
|
||||
}
|
||||
|
||||
if(logger_use_colors) {
|
||||
sprintf(prefixbuf, "%s [%s%s%s]", timebuf2, prefixcolor, prefixtext, LOGGER_COLOR_NONE);
|
||||
} else {
|
||||
sprintf(prefixbuf, "%s [%s]", timebuf2, prefixtext);
|
||||
}
|
||||
|
||||
va_start(argptr, format);
|
||||
logger_debug_message(prefixbuf, format, argptr);
|
||||
va_end(argptr);
|
||||
}
|
54
src/main.c
Normal file
54
src/main.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../include/ws2801.h"
|
||||
#include "../include/logger.h"
|
||||
|
||||
#define PI 3.141592654f
|
||||
|
||||
void set_all(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
for(uint8_t i = 0; i < 20; i++) {
|
||||
ws2801_set_colour(i, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
float sin_off(float phase)
|
||||
{
|
||||
return 255 * (0.5f + 0.5f * sin(phase));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
float phase = 0;
|
||||
|
||||
logger_init();
|
||||
|
||||
if(ws2801_init(20) == -1) {
|
||||
LOG(LVL_FATAL, "Could not initialize WS2801 library.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
while(1) {
|
||||
//phase += PI/1000;
|
||||
|
||||
for(uint8_t i = 0; i < 20; i++) {
|
||||
ws2801_set_colour(i, sin_off(i * PI / 10 + phase), sin_off(i * PI / 10 + 1.241*phase), sin_off(i * PI / 10 + 1.537*phase));
|
||||
}
|
||||
|
||||
ws2801_send_update();
|
||||
|
||||
static const struct timespec sleepval = {0, 40000000};
|
||||
nanosleep(&sleepval, NULL);
|
||||
}
|
||||
|
||||
ws2801_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
107
src/ws2801.c
Normal file
107
src/ws2801.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <wiringPi.h>
|
||||
|
||||
#include "../include/logger.h"
|
||||
#include "../include/ws2801.h"
|
||||
|
||||
#define WS2801_CLK_GPIO 17
|
||||
#define WS2801_DAT_GPIO 18
|
||||
|
||||
// the interface rpi->ws2801 is active low
|
||||
#define BUS_HIGH LOW
|
||||
#define BUS_LOW HIGH
|
||||
|
||||
uint8_t *modRed = NULL;
|
||||
uint8_t *modGreen = NULL;
|
||||
uint8_t *modBlue = NULL;
|
||||
uint8_t numModules;
|
||||
|
||||
void busy_wait(void)
|
||||
{
|
||||
static const struct timespec bitsleep = {0, 1000};
|
||||
nanosleep(&bitsleep, NULL);
|
||||
}
|
||||
|
||||
void send_bit(uint8_t value)
|
||||
{
|
||||
digitalWrite(WS2801_DAT_GPIO, (value ? BUS_HIGH : BUS_LOW));
|
||||
|
||||
digitalWrite(WS2801_CLK_GPIO, BUS_LOW);
|
||||
busy_wait();
|
||||
|
||||
// rising edge at clock
|
||||
digitalWrite(WS2801_CLK_GPIO, BUS_HIGH);
|
||||
busy_wait();
|
||||
}
|
||||
|
||||
void send_commit_condition(void)
|
||||
{
|
||||
digitalWrite(WS2801_DAT_GPIO, BUS_LOW);
|
||||
digitalWrite(WS2801_CLK_GPIO, BUS_LOW);
|
||||
}
|
||||
|
||||
void send_byte(uint8_t byte)
|
||||
{
|
||||
for(int i = 0; i <= 7; i++) {
|
||||
send_bit(byte & 0x1);
|
||||
byte >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void send_colour(uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
send_byte(red);
|
||||
send_byte(green);
|
||||
send_byte(blue);
|
||||
}
|
||||
|
||||
int ws2801_init(uint8_t nMod)
|
||||
{
|
||||
if(wiringPiSetupGpio() == -1) {
|
||||
LOG(LVL_FATAL, "ws2801: wiringPi setup failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
numModules = nMod;
|
||||
modRed = malloc(nMod * sizeof(uint8_t));
|
||||
modGreen = malloc(nMod * sizeof(uint8_t));
|
||||
modBlue = malloc(nMod * sizeof(uint8_t));
|
||||
|
||||
if(!modRed || !modGreen || !modBlue) {
|
||||
LOG(LVL_ERR, "ws2801: could not allocate all colour arrays!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ws2801_shutdown(void)
|
||||
{
|
||||
if(modRed != NULL) { free(modRed); modRed = NULL; }
|
||||
if(modGreen != NULL) { free(modGreen); modGreen = NULL; }
|
||||
if(modBlue != NULL) { free(modBlue); modBlue = NULL; }
|
||||
}
|
||||
|
||||
void ws2801_set_colour(uint8_t module, uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
modRed[module] = red;
|
||||
modGreen[module] = green;
|
||||
modBlue[module] = blue;
|
||||
}
|
||||
|
||||
void ws2801_send_update(void)
|
||||
{
|
||||
for(uint8_t i = 0; i < numModules; i++) {
|
||||
send_colour(modRed[i], modGreen[i], modBlue[i]);
|
||||
}
|
||||
|
||||
send_commit_condition();
|
||||
|
||||
static const struct timespec sleepval = {0, 550000};
|
||||
nanosleep(&sleepval, NULL);
|
||||
}
|
||||
|
Loading…
Reference in a new issue