file: channel.c
/*
* This file contains the "channel" software module. It contains the
* data structures and C functions that maintain and modify the DMX-512
* channel values. This module uses a repetitive timer to update the
* DMX-512 channels every 50ms. This module also performs dimming
* operations.
*/
# define __KERNEL__
#endif
# define MODULE
#endif
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <asm/param.h>
#include <asm/system.h>
/* local definitions */
#include "slh.h"
/* prevent symbols from this file from
* being accessed by any part of the
* kernel outside of this driver.
*/
EXPORT_NO_SYMBOLS;
/* interval timer in milliseconds */
#define TMR_INTERVAL 50
/* interval timer in clock ticks */
#define TMR_TICKS (HZ*TMR_INTERVAL/1000)
/* DMX-512 channel status */
typedef struct {
/* total amount channel is to change with dim */
long delta;
/* current number of timer expirations into dim */
unsigned long tick;
/* total number of timer expirations in dim */
unsigned long total_ticks;
/* channel value at start of dim */
unsigned long start_value;
/* current channel value */
unsigned long current_value;
} CHAN_STATUS;
CHAN_STATUS chan_status[NUM_DMX_CHANS];
/* "is the timer running?" flag */
static unsigned long timer_running;
/* kernel timer structure */
static struct timer_list slh_timer;
int
slh_channel_mod_init()
{
/* initialize the "channel" software module
* (called when the slh driver is loaded).
*/
/* zero the channel status structure */
memset( (void *)chan_status, 0, sizeof(chan_status) );
/* zero the kernel timer structure */
memset( (void *)&slh_timer, 0, sizeof(slh_timer) );
timer_running = 0;
return ( 0 );
}
void
slh_channel_mod_cleanup()
{
/* cleanup the "channel" software module
* (called when the slh driver is unloaded).
*/
/* stop the channel timer (if running) */
slh_channel_timer_stop();
}
void
slh_channel_dim( unsigned long chan,
unsigned long new_value,
unsigned long transition )
{
/* dim a DMX-512 channel */
register CHAN_STATUS *stat;
unsigned long flags;
/* validate the DMX-512 channel number (it must be 1 -> 512) */
if ( (chan == 0) || (chan > NUM_DMX_CHANS) ) {
return;
}
/* block interrupts */
save_flags( flags );
cli();
/* update channel data */
stat = &chan_status[ chan - 1 ];
stat->delta = new_value - stat->current_value;
stat->tick = 0;
stat->total_ticks = transition / TMR_INTERVAL;
stat->start_value = stat->current_value;
#if 0
new_value, stat->delta, stat->current_value, stat->start_value);
#endif
/* allow interrupts */
restore_flags( flags );
}
void
slh_channel_timeout( unsigned long data )
{
/* When the kernel timer expires, this function is called.
* It will perform dimmer calculations, update channel data,
* start the SoundLight board to send the DMX-512 channel data,
* and restart the kernel channel timer.
*/
register unsigned long i;
register CHAN_STATUS *stat;
timer_running = 0;
/* set the channel status pointer */
stat = &chan_status[0];
/* The 1512b board requires at least one channel be
* set before it will transmit the DMX channel data...
* so we will always set channel 0.
*/
slh_board_chan_set( 0, stat->current_value );
/* loop through the channel status structure looking for
* channels currently being dimmed.
*/
for ( i = 0; i < NUM_DMX_CHANS; i++, stat++ ) {
/* check if channel is being dimmed */
if ( stat->delta == 0L ) {
continue;
}
/* increment the count of timer expirations
* for this channel being dimmed.
*/
stat->tick += 1;
/* check if this is an immediate or gradual
* change to the new channel value
*/
if ( stat->total_ticks ) {
/* gradual change */
stat->current_value = stat->start_value + (long)
(stat->tick * stat->delta) / (long)stat->total_ticks;
} else {
/* immediate change */
stat->current_value = stat->start_value + stat->delta;
}
/* set channel value */
slh_board_chan_set( i, stat->current_value );
/* check if the dim is complete */
if ( stat->tick >= stat->total_ticks ) {
stat->delta = 0;
}
} /* end for ( ... ) */
/* start board DMX-512 transmitter */
slh_board_start();
/* start timer */
slh_channel_timer_start();
}
void
slh_channel_timer_start()
{
/* start kernel channel timer */
if ( timer_running ) {
return;
}
timer_running = 1;
/* initialize timer */
init_timer( &slh_timer );
slh_timer.function = slh_channel_timeout;
slh_timer.data = 0;
slh_timer.expires = jiffies + TMR_TICKS;
/* start timer */
add_timer( &slh_timer );
}
void
slh_channel_timer_stop()
{
/* stop kernel channel timer */
if ( !timer_running ) {
return;
}
del_timer( &slh_timer );
timer_running = 0;
}
int
slh_channel_load()
{
/* load all channel values to SoundLight board */
register unsigned long i;
register CHAN_STATUS *stat;
unsigned long flags;
/* block interrupts */
save_flags( flags );
cli();
for ( i = 0, stat = chan_status; i < NUM_DMX_CHANS; i++, stat++ ) {
/* set channel value */
slh_board_chan_set( i, stat->current_value );
} /* end for ( ... ) */
/* allow interrupts */
restore_flags( flags );
return ( 0 );
}
void
slh_channel_read( unsigned char *buffer )
{
/* read into a buffer all current channel values */
register unsigned long i;
register CHAN_STATUS *stat;
unsigned long flags;
/* block interrupts */
save_flags( flags );
cli();
for ( i = 0, stat = chan_status; i < NUM_DMX_CHANS; i++, stat++ ) {
/* save channel value */
*buffer++ = stat->current_value;
} /* end for ( ... ) */
/* allow interrupts */
restore_flags( flags );
}
C++ to HTML Conversion by ctoohtml