source: roaraudio/roard/light.c @ 6052:d48765b2475e

Last change on this file since 6052:d48765b2475e was 6052:d48765b2475e, checked in by phi, 9 years ago

updated copyright headers

File size: 9.6 KB
Line 
1//light.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2015
5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 */
25
26#include "roard.h"
27
28#ifndef ROAR_WITHOUT_DCOMP_LIGHT
29
30static uint8_t nextcycle_events[MAX_EVENTS_PER_CYCLE];
31static size_t nextcycle_eventsqueuelen;
32static int __cb_event_add(struct roar_slfi_inst * inst, void * userdata, uint8_t event);
33
34// declared 'extern'
35struct light_state g_light_state;
36struct light_mixer g_light_mixer;
37// //
38
39static inline void __set_channel(size_t index, uint8_t val) {
40 g_light_state.changes[index] |= g_light_state.state[index] ^ val;
41 g_light_state.state[index]    =                              val;
42}
43
44int light_init  (uint32_t channels) {
45 struct roar_stream_server * ss;
46 int i;
47
48 g_light_state.channels = 0;
49
50 if ( channels == 0 || channels > ((uint32_t)512UL*(uint32_t)512UL) ) /* unrealstic values */
51  return -1;
52
53 if ( (g_light_state.state = roar_mm_malloc(channels)) == NULL ) {
54  return -1;
55 }
56
57 if ( (g_light_state.changes = roar_mm_malloc(channels)) == NULL ) {
58  roar_mm_free(g_light_state.state);
59  return -1;
60 }
61
62 if ( (g_light_state.output = roar_mm_malloc(channels)) == NULL ) {
63  roar_mm_free(g_light_state.state);
64  roar_mm_free(g_light_state.changes);
65  return -1;
66 }
67
68 if ( (g_light_state.outputchanges = roar_mm_malloc(channels)) == NULL ) {
69  roar_mm_free(g_light_state.state);
70  roar_mm_free(g_light_state.changes);
71  roar_mm_free(g_light_state.output);
72  return -1;
73 }
74
75 g_light_state.channels = channels;
76 g_light_state.filter   = NULL;
77
78 if ( (g_light_mixer.stream = add_mixer(ROAR_SUBSYS_LIGHT, _MIXER_NAME("Light Control"), &ss)) == -1 ) {
79  roar_mm_free(g_light_state.state);
80  return -1;
81 }
82
83 ROAR_STREAM(ss)->info.codec = ROAR_CODEC_DMX512;
84 ROAR_STREAM(ss)->info.bits  = ROAR_LIGHT_BITS;
85 ROAR_STREAM(ss)->info.rate  = ROAR_OUTPUT_CFREQ;
86
87 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
88  if ( g_streams[i] != NULL ) {
89   if ( streams_get_subsys(i) == ROAR_SUBSYS_LIGHT ) {
90    streams_set_mixer_stream(i, g_light_mixer.stream);
91   }
92  }
93 }
94
95 return light_reset();
96}
97
98int light_free  (void) {
99 if ( g_light_state.filter != NULL ) {
100  roar_slfi_unref(g_light_state.filter);
101 }
102
103 if ( g_light_state.state != NULL ) {
104  roar_mm_free(g_light_state.state);
105 }
106
107 if ( g_light_state.changes != NULL ) {
108  roar_mm_free(g_light_state.changes);
109 }
110
111 if ( g_light_state.output != NULL ) {
112  roar_mm_free(g_light_state.output);
113 }
114
115 if ( g_light_state.outputchanges != NULL ) {
116  roar_mm_free(g_light_state.outputchanges);
117 }
118
119 g_light_state.channels = 0;
120
121 return 0;
122}
123
124int light_reset (void) {
125 if ( g_light_state.channels == 0 )
126  return 0;
127
128 if ( g_light_state.state == NULL )
129  return -1;
130
131 if ( g_light_state.changes == NULL )
132  return -1;
133
134 memset(g_light_state.state,         0, g_light_state.channels);
135 memset(g_light_state.changes,       0, g_light_state.channels);
136 memset(g_light_state.output,        0, g_light_state.channels);
137 memset(g_light_state.outputchanges, 0, g_light_state.channels);
138 memset(g_light_state.events,        0, sizeof(g_light_state.events));
139
140 g_light_state.eventsqueuelen = 0;
141
142 return 0;
143}
144
145// called at end of mainloop.
146int light_reinit(void) {
147 if ( g_light_state.changes == NULL )
148  return -1;
149
150 memset(g_light_state.changes, 0, g_light_state.channels);
151 memset(g_light_state.events,  0, sizeof(g_light_state.events));
152
153 g_light_state.eventsqueuelen = 0;
154
155 if ( nextcycle_eventsqueuelen ) {
156  light_dmxevent_add(nextcycle_events, nextcycle_eventsqueuelen);
157  nextcycle_eventsqueuelen = 0;
158 }
159
160 return 0;
161}
162
163// called at mid of mainloop.
164int light_update(void) {
165 uint8_t * tmp;
166 unsigned int c;
167
168 // swap buffers:
169 // after that step we have the old values in outputchanges and output is a fresh buffer.
170 tmp = g_light_state.outputchanges;
171 g_light_state.outputchanges = g_light_state.output;
172 g_light_state.output = tmp;
173
174 // copy data for filters:
175 memcpy(g_light_state.output, g_light_state.state, g_light_state.channels);
176
177 // TODO: next run filters
178 if ( g_light_state.filter != NULL ) {
179  if ( roar_slfi_update(g_light_state.filter,
180                        g_light_state.output, g_light_state.channels,
181                        ((int32_t)1000000LU)/(int32_t)ROAR_OUTPUT_CFREQ,
182                        g_light_state.events, g_light_state.eventsqueuelen) == -1 ) {
183   ROAR_WARN("light_update(void): Can not run SLFI filter: %s", roar_errorstring);
184  }
185 }
186
187 // calculate diffrence:
188 // after this step we have only teh changes in the outputchanges array.
189 for (c = 0; c < g_light_state.channels; c++)
190  g_light_state.outputchanges[c] ^= g_light_state.output[c];
191
192 return 0;
193}
194
195int light_check_stream  (int id) {
196 struct roar_stream        *   s;
197 struct roar_stream_server *  ss;
198 char buf[512];
199 int i;
200
201 if ( g_streams[id] == NULL )
202  return -1;
203
204 ROAR_DBG("light_check_stream(id=%i) = ?", id);
205
206 s = ROAR_STREAM(ss = g_streams[id]);
207
208 switch (s->info.codec) {
209  case ROAR_CODEC_DMX512:
210    if ( stream_vio_s_read(ss, buf, 512) != 512 ) {
211     streams_delete(id);
212     return -1;
213    }
214
215    for (i = 0; i < (g_light_state.channels < 512 ? g_light_state.channels : 512); i++) {
216     __set_channel(i, buf[i]);
217    }
218//    memcpy(g_light_state.state, buf, g_light_state.channels < 512 ? g_light_state.channels : 512);
219
220    s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, 1);
221
222    return 0;
223   break;
224  case ROAR_CODEC_ROARDMX:
225    ROAR_DBG("light_check_stream(id=%i): Codec: RoarDMX", id);
226    if ( cf_light_roardmx_read(id, ss) == -1 ) {
227     streams_delete(id); // simply drop the client on error.
228     return -1;
229    }
230   break;
231  default:
232    streams_delete(id);
233    return -1;
234 }
235
236 return 0;
237}
238
239static inline int light_send_stream_dmx512  (int id, struct roar_stream * s, struct roar_stream_server * ss) {
240 size_t chans = g_light_state.channels;
241 uint8_t buf[512];
242 register uint8_t * bufptr;
243
244 if ( chans > 512 )
245  chans = 512;
246
247 if ( chans == 512 ) {
248  bufptr = g_light_state.output;
249 } else {
250  memset(buf, 0, 512);
251  memcpy(buf, g_light_state.output, chans);
252  bufptr = buf;
253 }
254
255 if ( stream_vio_s_write(ss, bufptr, 512) != 512 ) {
256  streams_delete(id);
257  return -1;
258 }
259
260 s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, 1);
261
262 return 0;
263}
264
265int light_send_stream   (int id) {
266 struct roar_stream        *   s;
267 struct roar_stream_server *  ss;
268
269 if ( g_streams[id] == NULL )
270  return -1;
271
272 ROAR_DBG("light_send_stream(id=%i) = ?", id);
273
274 s = ROAR_STREAM(ss = g_streams[id]);
275
276 switch (s->info.codec) {
277  case ROAR_CODEC_DMX512:
278    return light_send_stream_dmx512(id, s, ss);
279   break;
280  case ROAR_CODEC_ROARDMX:
281    return cf_light_roardmx_write(id, ss);
282   break;
283  default:
284    streams_delete(id);
285    return -1;
286 }
287
288 return 0;
289}
290
291int light_filter_load(int primary, const char * name, int autoload, const struct roar_keyval * para, ssize_t paralen) {
292 struct roar_slfi_inst * filter;
293 int ret;
294 int err;
295
296 if ( primary && g_light_state.filter != NULL ) {
297  roar_err_set(ROAR_ERROR_ALREADY);
298  return -1;
299 } else if ( !primary && g_light_state.filter == NULL ) {
300  roar_err_set(ROAR_ERROR_BADSTATE);
301  return -1;
302 }
303
304 filter = roar_slfi_new(name, autoload, para, paralen);
305 if ( filter == NULL )
306  return -1;
307
308 if ( primary ) {
309  roar_slfi_cb_set_event_add(filter, __cb_event_add, NULL);
310  g_light_state.filter = filter;
311  return 0;
312 }
313
314 ret = roar_slfi_ctl(g_light_state.filter, ROAR_SLFI_CMD_PUSH, filter);
315 err = roar_error;
316
317 roar_slfi_unref(filter);
318
319 roar_err_set(err);
320 return ret;
321}
322
323int light_dmxchannel_get(size_t index) {
324 if ( (size_t)g_light_state.channels <= index ) {
325  roar_err_set(ROAR_ERROR_NOENT);
326  return -1;
327 }
328
329 return (int)(unsigned int)(uint8_t)g_light_state.output[index];
330}
331
332int light_dmxchannel_set(size_t index, uint8_t val) {
333 if ( (size_t)g_light_state.channels <= index ) {
334  roar_err_set(ROAR_ERROR_NOENT);
335  return -1;
336 }
337
338 __set_channel(index, val);
339 return 0;
340}
341
342ssize_t light_dmxchannel_num(void) {
343 if ( g_light_state.state == NULL ) {
344  roar_err_set(ROAR_ERROR_BADSTATE);
345  return -1;
346 }
347
348 return g_light_state.channels;
349}
350
351int light_dmxevent_add(const uint8_t * events, size_t len) {
352 size_t i;
353
354 if ( events == NULL ) {
355  roar_err_set(ROAR_ERROR_FAULT);
356  return -1;
357 }
358
359 if ( len > (sizeof(g_light_state.events) - g_light_state.eventsqueuelen) ) {
360  roar_err_set(ROAR_ERROR_NOSPC);
361  return -1;
362 }
363
364 for (i = 0; i < len; i++) {
365  g_light_state.events[g_light_state.eventsqueuelen++] = events[i];
366  roar_notify_core_emit_simple(ROAR_DATA_DMX512_EVENT, -1, g_light_mixer.stream, ROAR_OT_STREAM, events[i], -1, NULL, -1);
367 }
368
369 return 0;
370}
371
372int light_dmxevent_read(const uint8_t ** events, size_t * len) {
373 if ( events == NULL || len == NULL ) {
374  roar_err_set(ROAR_ERROR_FAULT);
375  return -1;
376 }
377
378 *events = g_light_state.events;
379 *len    = g_light_state.eventsqueuelen;
380
381 return 0;
382}
383
384static int __cb_event_add(struct roar_slfi_inst * inst, void * userdata, uint8_t event) {
385 if ( nextcycle_eventsqueuelen == MAX_EVENTS_PER_CYCLE ) {
386  roar_err_set(ROAR_ERROR_NOSPC);
387  return -1;
388 }
389
390 nextcycle_events[nextcycle_eventsqueuelen++] = event;
391
392 return 0;
393}
394
395#endif
396
397//ll
Note: See TracBrowser for help on using the repository browser.