Browse Source

Initial commit von Musiclight 2

lua
Thomas Kolb 7 years ago
commit
cf8193e421
13 changed files with 732 additions and 0 deletions
  1. 5
    0
      .gitignore
  2. 22
    0
      Makefile
  3. 54
    0
      config.h
  4. 151
    0
      fft.c
  5. 22
    0
      fft.h
  6. 263
    0
      main.c
  7. 3
    0
      run_alsa.sh
  8. 4
    0
      run_mpd.sh
  9. 16
    0
      run_pa.sh
  10. 42
    0
      utils.c
  11. 17
    0
      utils.h
  12. 112
    0
      ws2801.c
  13. 21
    0
      ws2801.h

+ 5
- 0
.gitignore View File

@@ -0,0 +1,5 @@
1
+*.o
2
+*.swp
3
+musiclight2
4
+core
5
+tags

+ 22
- 0
Makefile View File

@@ -0,0 +1,22 @@
1
+CC=gcc
2
+CFLAGS+=-O3 -Wall -march=native -pedantic -std=c99 -D_POSIX_C_SOURCE=20120607L -D_XOPEN_SOURCE
3
+LIBS=-lm -lpthread -lrt
4
+
5
+TARGET=musiclight2
6
+SOURCE=main.c fft.c utils.c ws2801.c
7
+DEPS=config.h fft.h utils.h ws2801.h
8
+
9
+OBJ=$(patsubst %.c, %.o, $(SOURCE))
10
+
11
+$(TARGET): $(OBJ) $(DEPS)
12
+	$(CC) -o $(TARGET) $(OBJ) $(LIBS)
13
+
14
+%.o: %.c $(DEPS)
15
+	$(CC) -c $(CFLAGS) -o $@ $< $(INCLUDES)
16
+
17
+doc:
18
+	doxygen doxygen.conf
19
+
20
+clean:
21
+	rm -f $(TARGET)
22
+	rm -f $(OBJ)

+ 54
- 0
config.h View File

@@ -0,0 +1,54 @@
1
+/*
2
+ * vim: sw=2 ts=2 expandtab
3
+ *
4
+ * THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
5
+ * <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
6
+ * do whatever you want with this stuff. If we meet some day, and you think
7
+ * this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
8
+ */
9
+
10
+#ifndef CONFIG_H
11
+#define CONFIG_H
12
+
13
+#include <stdint.h>
14
+
15
+// configuration variables for musiclight2
16
+
17
+// networking
18
+#define HOST "192.168.23.222"
19
+#define PORT 2703
20
+
21
+// FFT transformation parameters
22
+#define FFT_EXPONENT 10
23
+#define BLOCK_LEN (1 << FFT_EXPONENT) // 2^FFT_EXPONENT
24
+#define SAMPLE_RATE 44100
25
+#define DATALEN (BLOCK_LEN / 2)
26
+
27
+// Number of parts in the sample buffer
28
+#define BUFFER_PARTS 2
29
+
30
+// update rate for the led strip (in seconds)
31
+#define LED_INTERVAL 0.03
32
+
33
+// number of modules in LED strip
34
+#define NUM_MODULES 20
35
+
36
+// frequency ranges for the base colors
37
+#define RED_MIN_FREQ 0
38
+#define RED_MAX_FREQ 400
39
+#define GREEN_MIN_FREQ 400
40
+#define GREEN_MAX_FREQ 4000
41
+#define BLUE_MIN_FREQ 4000
42
+#define BLUE_MAX_FREQ SAMPLE_RATE/2
43
+
44
+#define COLOR_MAX_REDUCTION_FACTOR 0.9998
45
+
46
+#define CENTER_MODULE 10
47
+
48
+#define GAMMA 2.0
49
+
50
+// sample data types
51
+typedef int16_t sample;
52
+typedef int64_t sample_sum;
53
+
54
+#endif // CONFIG_H

+ 151
- 0
fft.c View File

@@ -0,0 +1,151 @@
1
+/*
2
+ * vim: sw=2 ts=2 expandtab
3
+ *
4
+ * THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
5
+ * <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
6
+ * do whatever you want with this stuff. If we meet some day, and you think
7
+ * this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
8
+ */
9
+
10
+#include <stdio.h>
11
+#include <math.h>
12
+#include <time.h>
13
+#include <stdint.h>
14
+
15
+#include "config.h"
16
+
17
+#include "fft.h"
18
+
19
+double hanning_buffer[BLOCK_LEN];
20
+int lookup_table[BLOCK_LEN];
21
+
22
+
23
+void init_fft(void) {
24
+  int i = 0;
25
+  int ri, b;
26
+
27
+  for(i = 0; i < BLOCK_LEN; i++) {
28
+    hanning_buffer[i] = 0.5 * (1 - cos(2 * M_PI * i / BLOCK_LEN));
29
+  }
30
+
31
+  for(i = 0; i < BLOCK_LEN; i++) {
32
+    ri = 0;
33
+
34
+    for(b = 0; b < FFT_EXPONENT; b++)
35
+      ri |= ((i >> b) & 1) << (FFT_EXPONENT - b - 1);
36
+
37
+    lookup_table[i] = ri;
38
+  }
39
+}
40
+
41
+
42
+
43
+void complex_to_absolute(double *re, double *im, double *result) {
44
+  int i;
45
+
46
+  for(i = 0; i < DATALEN; i++)
47
+  {
48
+    result[i] = sqrt( re[i]*re[i] + im[i]*im[i] );
49
+  }
50
+}
51
+
52
+
53
+
54
+void apply_hanning(sample *dftinput) {
55
+  int i;
56
+
57
+  for(i = 0; i < BLOCK_LEN; i++)
58
+    dftinput[i] *= hanning_buffer[i];
59
+}
60
+
61
+
62
+
63
+void fft_transform(sample *samples, double *resultRe, double *resultIm) {
64
+  int i;
65
+  int layer, part, element;
66
+  int num_parts, num_elements;
67
+
68
+  int left, right;
69
+
70
+  double x_left_re, x_left_im, x_right_re, x_right_im;
71
+  double param;
72
+  double sinval, cosval;
73
+
74
+  // re-arrange the input array according to the lookup table
75
+  // and store it into the real output array (as the input is obviously real).
76
+  // zero the imaginary output
77
+  for(i = 0; i < BLOCK_LEN; i++)
78
+  {
79
+    resultRe[lookup_table[i]] = samples[i];
80
+    resultIm[i] = 0;
81
+  }
82
+
83
+  // walk layers
84
+  for(layer = 0; layer < FFT_EXPONENT; layer++)
85
+  {
86
+    // number of parts in current layer
87
+    num_parts = 1 << (FFT_EXPONENT - layer - 1);
88
+
89
+    // walk parts of layer
90
+    for(part = 0; part < num_parts; part++)
91
+    {
92
+      // number of elements in current part
93
+      num_elements = (1 << layer);
94
+
95
+      // walk elements in part
96
+      for(element = 0; element < num_elements; element++)
97
+      {
98
+        // calculate index of element in left and right half of part
99
+        left = (1 << (layer + 1)) * part + element;
100
+        right = left + (1 << layer);
101
+
102
+        // buffer the elements for the calculation
103
+        x_left_re = resultRe[left];
104
+        x_left_im = resultIm[left];
105
+        x_right_re = resultRe[right];
106
+        x_right_im = resultIm[right];
107
+
108
+        // precalculate the parameter for sin and cos
109
+        param = -M_PI * element / (1 << layer);
110
+
111
+        // precalculate sinus and cosinus values for param
112
+        sinval = sin(param);
113
+        cosval = cos(param);
114
+
115
+        // combine the values according to a butterfly diagram
116
+        resultRe[left]  = x_right_re + x_left_re * cosval - x_left_im * sinval;
117
+        resultIm[left]  = x_right_im + x_left_im * cosval + x_left_re * sinval;
118
+        resultRe[right] = x_right_re - x_left_re * cosval + x_left_im * sinval;
119
+        resultIm[right] = x_right_im - x_left_im * cosval - x_left_re * sinval;
120
+      }
121
+    }
122
+  }
123
+}
124
+
125
+uint32_t find_loudest_frequency(double *absFFT) {
126
+  int maxPos = 0;
127
+  double maxVal = 0;
128
+  int i;
129
+
130
+  for(i = 0; i < BLOCK_LEN; i++) {
131
+    if(absFFT[i] > maxVal) {
132
+      maxPos = i;
133
+      maxVal = absFFT[i];
134
+    }
135
+  }
136
+
137
+  return (double)maxPos * SAMPLE_RATE / BLOCK_LEN;
138
+}
139
+
140
+double get_energy_in_band(double *fft, uint32_t minFreq, uint32_t maxFreq) {
141
+  int firstBlock = minFreq * BLOCK_LEN / SAMPLE_RATE;
142
+  int lastBlock = maxFreq * BLOCK_LEN / SAMPLE_RATE;
143
+  int i;
144
+
145
+  double energy = 0;
146
+  for(i = firstBlock; i < lastBlock; i++) {
147
+    energy += fft[i];
148
+  }
149
+
150
+  return energy;
151
+}

+ 22
- 0
fft.h View File

@@ -0,0 +1,22 @@
1
+/*
2
+ * vim: sw=2 ts=2 expandtab
3
+ *
4
+ * THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
5
+ * <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
6
+ * do whatever you want with this stuff. If we meet some day, and you think
7
+ * this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
8
+ */
9
+
10
+#ifndef FFT_H
11
+#define FFT_H
12
+
13
+#include "config.h"
14
+
15
+void init_fft(void);
16
+void complex_to_absolute(double *re, double *im, double *result);
17
+void apply_hanning(sample *dftinput);
18
+void fft_transform(sample *samples, double *resultRe, double *resultIm);
19
+uint32_t find_loudest_frequency(double *absFFT);
20
+double get_energy_in_band(double *fft, uint32_t minFreq, uint32_t maxFreq);
21
+
22
+#endif // FFT_H

+ 263
- 0
main.c View File

@@ -0,0 +1,263 @@
1
+/*
2
+ * vim: sw=2 ts=2 expandtab
3
+ *
4
+ * THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
5
+ * <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
6
+ * do whatever you want with this stuff. If we meet some day, and you think
7
+ * this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
8
+ */
9
+
10
+#include <pthread.h>
11
+#include <semaphore.h>
12
+
13
+#include <stdio.h>
14
+#include <math.h>
15
+#include <string.h>
16
+#include <stdint.h>
17
+
18
+#include "fft.h"
19
+#include "utils.h"
20
+#include "ws2801.h"
21
+
22
+#include "config.h"
23
+
24
+// Frames per second
25
+#define FPS ((double)BUFFER_PARTS * SAMPLE_RATE / BLOCK_LEN)
26
+
27
+// Number of new samples put into the buffer each frame
28
+#define READ_SAMPLES (BLOCK_LEN / BUFFER_PARTS)
29
+
30
+#define COLORBUF_SIZE (2*(NUM_MODULES+1))
31
+#define CENTER_POS (2*CENTER_MODULE)
32
+
33
+double fft[BLOCK_LEN];
34
+double rms;
35
+double redEnergy, greenEnergy, blueEnergy;
36
+double lastUpdateTime = 0;
37
+
38
+sem_t  fftSemaphore;
39
+
40
+int running = 1;
41
+
42
+void* fft_thread(void *param) {
43
+	sample       buffer[BLOCK_LEN];
44
+	sample       block[BLOCK_LEN];
45
+	double       fftOutReal[BLOCK_LEN], fftOutImag[BLOCK_LEN];
46
+	double       tmpFFT[BLOCK_LEN];
47
+  double       tmpRMS;
48
+
49
+	double       nextFrame = get_hires_time() + 0.05;
50
+	double       curTime;
51
+
52
+	int i;
53
+
54
+	init_fft();
55
+
56
+	while(running) {
57
+		// shift the buffer left
58
+		memmove(buffer, buffer + READ_SAMPLES,
59
+		        (BLOCK_LEN - READ_SAMPLES) * sizeof(sample));
60
+
61
+		size_t ret = fread(buffer + (BLOCK_LEN - READ_SAMPLES),
62
+		                   sizeof(sample), READ_SAMPLES, stdin);
63
+		if(ret != READ_SAMPLES) {
64
+			break;
65
+		}
66
+
67
+		memcpy(block, buffer, BLOCK_LEN * sizeof(sample));
68
+
69
+		apply_hanning(block);
70
+		fft_transform(block, fftOutReal, fftOutImag);
71
+		complex_to_absolute(fftOutReal, fftOutImag, tmpFFT);
72
+
73
+    tmpRMS = 0;
74
+    for(i = 0; i < BLOCK_LEN; i++) {
75
+      tmpRMS += block[i]*block[i];
76
+    }
77
+    tmpRMS = sqrt(tmpRMS/BLOCK_LEN);
78
+
79
+    // --- SAFE SECTION ---
80
+    sem_wait(&fftSemaphore);
81
+
82
+    memcpy(fft, tmpFFT, sizeof(fft));
83
+    rms = tmpRMS;
84
+    redEnergy = get_energy_in_band(fft, RED_MIN_FREQ, RED_MAX_FREQ);
85
+    greenEnergy = get_energy_in_band(fft, GREEN_MIN_FREQ, GREEN_MAX_FREQ);
86
+    blueEnergy = get_energy_in_band(fft, BLUE_MIN_FREQ, BLUE_MAX_FREQ);
87
+
88
+		curTime = get_hires_time();
89
+    lastUpdateTime = curTime;
90
+
91
+		sem_post(&fftSemaphore);
92
+    // --- END SAFE SECTION ---
93
+
94
+		if(curTime > nextFrame + 0.05) {
95
+			printf("Frame too late! Skipping.\n");
96
+			nextFrame = -1;
97
+		}
98
+
99
+		if(curTime < nextFrame - 0.05) {
100
+			printf("Frame too early.\n");
101
+			nextFrame = -1;
102
+		}
103
+
104
+		if(nextFrame < 0) {
105
+			printf("Frame time reset.\n");
106
+			nextFrame = curTime;
107
+		}
108
+
109
+		nextFrame += 1.000/FPS;
110
+		sleep_until(nextFrame);
111
+	}
112
+
113
+	return NULL;
114
+}
115
+
116
+double gamma_correct(double d) {
117
+  return pow(d, GAMMA);
118
+}
119
+
120
+void text_bar(double fill) {
121
+  int fillCnt = 10 * fill;
122
+  int i;
123
+
124
+  for(i = 0; i < fillCnt; i++) {
125
+    printf("|");
126
+  }
127
+
128
+  for(; i < 10; i++) {
129
+    printf("-");
130
+  }
131
+}
132
+
133
+double weighted_avg(uint8_t colorBuf[COLORBUF_SIZE][3], int channel, int centerPos) {
134
+  return 0.20 * colorBuf[centerPos - 1][channel] +
135
+         0.60 * colorBuf[centerPos][channel] +
136
+         0.20 * colorBuf[centerPos + 1][channel];
137
+}
138
+
139
+void show_status(double curRed, double maxRed, double curGreen, double maxGreen, double curBlue, double maxBlue) {
140
+  printf("\r");
141
+
142
+  printf("[\033[31m");
143
+  text_bar(curRed / maxRed);
144
+  printf("\033[0m] ");
145
+  printf("\033[1;31m%7.2e\033[0m ", maxRed / (RED_MAX_FREQ - RED_MIN_FREQ));
146
+
147
+  printf("[\033[32m");
148
+  text_bar(curGreen / maxGreen);
149
+  printf("\033[0m] ");
150
+  printf("\033[1;32m%7.2e\033[0m ", maxGreen / (GREEN_MAX_FREQ - GREEN_MIN_FREQ));
151
+
152
+  printf("[\033[34m");
153
+  text_bar(curBlue / maxBlue);
154
+  printf("\033[0m] ");
155
+  printf("\033[1;34m%7.2e\033[0m ", maxBlue / (BLUE_MAX_FREQ - BLUE_MIN_FREQ));
156
+
157
+  fflush(stdout);
158
+}
159
+
160
+int main(int argc, char **argv) {
161
+  double nextFrame = get_hires_time() + LED_INTERVAL;
162
+
163
+	int i, j;
164
+	pthread_t fftThread;
165
+
166
+  int active = 1;
167
+
168
+  uint8_t colorBuf[COLORBUF_SIZE][3];
169
+
170
+  double curRedEnergy, curGreenEnergy, curBlueEnergy;
171
+  double maxRedEnergy = 1, maxGreenEnergy = 1, maxBlueEnergy = 1;
172
+
173
+  memset(colorBuf, 0, sizeof(colorBuf));
174
+
175
+	// create semaphores
176
+	sem_init(&fftSemaphore, 0, 1);
177
+
178
+	// run the fft thread
179
+	pthread_create(&fftThread, NULL, fft_thread, NULL);
180
+
181
+  ws2801_init(HOST, PORT);
182
+
183
+	while(running) {
184
+    for(i = COLORBUF_SIZE-1; i >= 0; i--) {
185
+      int pos = CENTER_POS + i;
186
+      if(pos < COLORBUF_SIZE-1) {
187
+        for(j = 0; j < 3; j++) {
188
+          colorBuf[pos][j] = colorBuf[pos - 1][j];
189
+        }
190
+      }
191
+
192
+      pos = CENTER_POS - i;
193
+      if(pos >= 0) {
194
+        for(j = 0; j < 3; j++) {
195
+          colorBuf[pos][j] = colorBuf[pos + 1][j];
196
+        }
197
+      }
198
+    }
199
+
200
+    if(active) {
201
+      sem_wait(&fftSemaphore);
202
+      curRedEnergy = redEnergy;
203
+      curGreenEnergy = greenEnergy;
204
+      curBlueEnergy = blueEnergy;
205
+      sem_post(&fftSemaphore);
206
+
207
+      maxRedEnergy *= COLOR_MAX_REDUCTION_FACTOR;
208
+      if(curRedEnergy > maxRedEnergy) {
209
+        maxRedEnergy = curRedEnergy;
210
+      }
211
+
212
+      maxGreenEnergy *= COLOR_MAX_REDUCTION_FACTOR;
213
+      if(curGreenEnergy > maxGreenEnergy) {
214
+        maxGreenEnergy = curGreenEnergy;
215
+      }
216
+
217
+      maxBlueEnergy *= COLOR_MAX_REDUCTION_FACTOR;
218
+      if(curBlueEnergy > maxBlueEnergy) {
219
+        maxBlueEnergy = curBlueEnergy;
220
+      }
221
+
222
+      colorBuf[CENTER_POS][0] = 255 * gamma_correct(curRedEnergy / maxRedEnergy);
223
+      colorBuf[CENTER_POS][1] = 255 * gamma_correct(curGreenEnergy / maxGreenEnergy);
224
+      colorBuf[CENTER_POS][2] = 255 * gamma_correct(curBlueEnergy / maxBlueEnergy);
225
+
226
+      /*
227
+      show_status(curRedEnergy, maxRedEnergy, curGreenEnergy, maxGreenEnergy,
228
+          curBlueEnergy, maxBlueEnergy);
229
+      */
230
+
231
+      for(i = 0; i < NUM_MODULES; i++) {
232
+        ws2801_set_color(i,
233
+            weighted_avg(colorBuf, 0, 2 * i + 1),
234
+            weighted_avg(colorBuf, 1, 2 * i + 1),
235
+            weighted_avg(colorBuf, 2, 2 * i + 1));
236
+      }
237
+      ws2801_commit();
238
+
239
+      if(lastUpdateTime < nextFrame - 1) {
240
+        printf("Idle for 1 second -> stopping updates.\n");
241
+
242
+        for(i = 0; i < NUM_MODULES; i++) {
243
+          ws2801_fade_color(i, 20, 20, 20);
244
+        }
245
+        ws2801_commit();
246
+
247
+        active = 0;
248
+      }
249
+    } else if(lastUpdateTime > nextFrame - 1) {
250
+      printf("Resuming updates.\n");
251
+      active = 1;
252
+    }
253
+
254
+    nextFrame += LED_INTERVAL;
255
+    sleep_until(nextFrame);
256
+	}
257
+
258
+  ws2801_shutdown();
259
+
260
+	pthread_join(fftThread, NULL);
261
+
262
+	return 0;
263
+}

+ 3
- 0
run_alsa.sh View File

@@ -0,0 +1,3 @@
1
+#!/bin/sh
2
+
3
+arecord -c 1 -f s16 -r 22050 | ./rtfft

+ 4
- 0
run_mpd.sh View File

@@ -0,0 +1,4 @@
1
+#!/bin/sh
2
+
3
+#dd if=/tmp/mpd.fifo bs=1024 | ./musiclight2
4
+./musiclight2 < /tmp/mpd.fifo

+ 16
- 0
run_pa.sh View File

@@ -0,0 +1,16 @@
1
+#!/bin/sh
2
+
3
+#parec -d "alsa_output.pci-0000_00_1b.0.analog-stereo.monitor" --channels=1 --format=s16 | mbuffer -R 88200 | ./musiclight2
4
+
5
+case $1 in
6
+  mic)
7
+    #mikro
8
+    parec -d "alsa_input.pci-0000_00_1b.0.analog-stereo" --raw --rate=44100 --channels=1 --format=s16 | ./musiclight2
9
+    ;;
10
+
11
+  *)
12
+    # soundkarte
13
+    parec -d "alsa_output.pci-0000_00_1b.0.analog-stereo.monitor" --raw --rate=44100 --channels=1 --format=s16 | ./musiclight2
14
+    ;;
15
+esac
16
+

+ 42
- 0
utils.c View File

@@ -0,0 +1,42 @@
1
+/*
2
+ * vim: sw=2 ts=2 expandtab
3
+ *
4
+ * THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
5
+ * <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
6
+ * do whatever you want with this stuff. If we meet some day, and you think
7
+ * this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
8
+ */
9
+
10
+#include <errno.h>
11
+
12
+#include <time.h>
13
+#include <stdint.h>
14
+
15
+#include "utils.h"
16
+
17
+double get_hires_time(void) {
18
+  struct timespec clk;
19
+  clock_gettime(CLOCK_REALTIME, &clk);
20
+  return clk.tv_sec + 1e-9 * clk.tv_nsec;
21
+}
22
+
23
+void fsleep(double d) {
24
+  struct timespec ts;
25
+
26
+  ts.tv_sec = (time_t)d;
27
+  ts.tv_nsec = (long)(1e9 * (d - (long)d));
28
+
29
+  nanosleep(&ts, NULL);
30
+}
31
+
32
+void sleep_until(double hires_time) {
33
+  struct timespec tv;
34
+  int ret;
35
+
36
+  tv.tv_sec = hires_time;
37
+  tv.tv_nsec = (uint64_t)(1e9 * hires_time) % 1000000000;
38
+	do {
39
+		ret = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &tv, NULL);
40
+	} while(ret == EINTR);
41
+}
42
+

+ 17
- 0
utils.h View File

@@ -0,0 +1,17 @@
1
+/*
2
+ * vim: sw=2 ts=2 expandtab
3
+ *
4
+ * THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
5
+ * <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
6
+ * do whatever you want with this stuff. If we meet some day, and you think
7
+ * this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
8
+ */
9
+
10
+#ifndef UTILS_H
11
+#define UTILS_H
12
+
13
+double get_hires_time(void);
14
+void fsleep(double d);
15
+void sleep_until(double hires_time);
16
+
17
+#endif // UTILS_H

+ 112
- 0
ws2801.c View File

@@ -0,0 +1,112 @@
1
+/*
2
+ * vim: sw=2 ts=2 expandtab
3
+ *
4
+ * THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
5
+ * <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
6
+ * do whatever you want with this stuff. If we meet some day, and you think
7
+ * this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
8
+ */
9
+
10
+#include <sys/types.h>
11
+#include <sys/socket.h>
12
+#include <netdb.h>
13
+#include <unistd.h>
14
+
15
+#include <string.h>
16
+#include <stdio.h>
17
+
18
+#include "ws2801.h"
19
+
20
+#define SET_COLOR    0
21
+#define FADE_COLOR   1
22
+#define ADD_COLOR    2
23
+#define SET_FADESTEP 3
24
+
25
+struct WS2801Packet {
26
+  uint8_t metadata;
27
+  uint8_t data[3];
28
+};
29
+
30
+int ws2801_socket = -1;
31
+struct WS2801Packet packetQueue[50];
32
+int queueIndex = 0;
33
+
34
+// creates the socket needed for steering the LED strip
35
+int ws2801_init(char *host, unsigned short port) {
36
+  struct addrinfo  hints;
37
+  struct addrinfo *result;
38
+  char portstr[6];
39
+
40
+  memset(&hints, 0, sizeof(struct addrinfo));
41
+  hints.ai_family = AF_UNSPEC;
42
+  hints.ai_socktype = SOCK_DGRAM;
43
+  hints.ai_flags = 0;
44
+  hints.ai_protocol = 0;
45
+
46
+  sprintf(portstr, "%u", port);
47
+
48
+  if(getaddrinfo(host, portstr, &hints, &result) != 0) {
49
+    perror("getaddrinfo() failed");
50
+    return 1;
51
+  }
52
+
53
+  ws2801_socket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
54
+  if (ws2801_socket == -1) {
55
+    perror("socket() failed");
56
+    freeaddrinfo(result);
57
+    return 2;
58
+  }
59
+
60
+  if (connect(ws2801_socket, result->ai_addr, result->ai_addrlen) == -1) {
61
+    perror("connect() failed");
62
+    freeaddrinfo(result);
63
+    return 3;
64
+  }
65
+
66
+  freeaddrinfo(result);
67
+
68
+  return 0;
69
+}
70
+
71
+void ws2801_set_color(uint8_t module, uint8_t r, uint8_t g, uint8_t b) {
72
+  packetQueue[queueIndex].metadata = (SET_COLOR << 6) | (module & 0x3F);
73
+  packetQueue[queueIndex].data[0] = r;
74
+  packetQueue[queueIndex].data[1] = g;
75
+  packetQueue[queueIndex].data[2] = b;
76
+  queueIndex++;
77
+}
78
+
79
+void ws2801_fade_color(uint8_t module, uint8_t r, uint8_t g, uint8_t b) {
80
+  packetQueue[queueIndex].metadata = (FADE_COLOR << 6) | (module & 0x3F);
81
+  packetQueue[queueIndex].data[0] = r;
82
+  packetQueue[queueIndex].data[1] = g;
83
+  packetQueue[queueIndex].data[2] = b;
84
+  queueIndex++;
85
+}
86
+
87
+void ws2801_add_color(uint8_t module, uint8_t r, uint8_t g, uint8_t b) {
88
+  packetQueue[queueIndex].metadata = (ADD_COLOR << 6) | (module & 0x3F);
89
+  packetQueue[queueIndex].data[0] = r;
90
+  packetQueue[queueIndex].data[1] = g;
91
+  packetQueue[queueIndex].data[2] = b;
92
+  queueIndex++;
93
+}
94
+
95
+void ws2801_set_fadestep(uint8_t fadestep) {
96
+  packetQueue[queueIndex].metadata = (SET_FADESTEP << 6);
97
+  packetQueue[queueIndex].data[0] = fadestep;
98
+  queueIndex++;
99
+}
100
+
101
+int ws2801_commit(void) {
102
+  if(send(ws2801_socket, packetQueue, queueIndex * sizeof(struct WS2801Packet), 0) == -1) {
103
+    return 1;
104
+  }
105
+
106
+  queueIndex = 0;
107
+  return 0;
108
+}
109
+
110
+void ws2801_shutdown() {
111
+  close(ws2801_socket);
112
+}

+ 21
- 0
ws2801.h View File

@@ -0,0 +1,21 @@
1
+/*
2
+ * vim: sw=2 ts=2 expandtab
3
+ *
4
+ * THE PIZZA-WARE LICENSE" (derived from "THE BEER-WARE LICENCE"):
5
+ * <cfr34k@tkolb.de> wrote this file. As long as you retain this notice you can
6
+ * do whatever you want with this stuff. If we meet some day, and you think
7
+ * this stuff is worth it, you can buy me a pizza in return. - Thomas Kolb
8
+ */
9
+
10
+#ifndef WS2801_H
11
+#define WS2801_H
12
+
13
+int ws2801_init(char *host, unsigned short port);
14
+void ws2801_set_color(uint8_t module, uint8_t r, uint8_t g, uint8_t b);
15
+void ws2801_fade_color(uint8_t module, uint8_t r, uint8_t g, uint8_t b);
16
+void ws2801_add_color(uint8_t module, uint8_t r, uint8_t g, uint8_t b);
17
+void ws2801_set_fadestep(uint8_t fadestep);
18
+int ws2801_commit(void);
19
+void ws2801_shutdown(void);
20
+
21
+#endif // WS2801_H

Loading…
Cancel
Save