USB-LED-Fader/firmware/pwm_channels.c

118 lines
3.8 KiB
C

/**
* \file pwm_channels.c
* \brief Manages the values of the displayed channels.
* \author Thomas Stegemann
* \version $Id: pwm_channels.c,v 1.2 2006/09/29 22:30:03 rschaten Exp $
*
* License: See documentation.
*/
#include <stdlib.h>
#include "pwm_channels.h"
#include "pwm_timer.h"
#include "config_pwm_timer_impl.h"
#include "message_queue.h"
/** Structure to contain the state of one channel */
typedef struct S_pwm_Channels_ChannelBrightness {
pwm_Channels_Bitfield field; /**< Bitfield resembling one channel */
pwm_Timer_Cycles cycle; /**< Number of on-cycles */
} pwm_Channels_ChannelBrightness;
/**
* Initialize channels. Basically, only the PWM-timer is started.
*/
void pwm_Channels_init(void) {
pwm_Timer_init();
}
/**
* Clean up channels. Basically, the PWM-timer gets cleaned.
*/
void pwm_Channels_cleanup(void) {
pwm_Timer_cleanup();
}
/**
* Calculate the Channels_Message. Requires the channel-list to be sorted by
* cycles.
* \param channels Array of the channels.
* \return Current message.
*/
static pwm_Channels_Message pwm_Channels_Message_get(pwm_Channels_ChannelBrightness channels[CHANNELS]) {
int j; /* index of the current channel */
pwm_Channels_StepCounter i= 0; /* index of the current step */
pwm_Channels_Message message;
/* first step: switch on all channels at cycle 0 */
message.step[i].field = 0;
for (j = 0; j < CHANNELS; j++) {
message.step[i].field |= channels[j].field;
}
message.step[i].cycle= 0;
for (j = 0; j < CHANNELS; j++) {
if(channels[j].cycle == message.step[i].cycle) {
/* if cycle for this channel is reached
switch off channel in current step */
message.step[i].field&= ~channels[j].field;
} else {
/* need another step for this channel:
set end of the current step
use copy of current step for next step
and switch off this channel
*/
message.step[i].cycle= channels[j].cycle;
i++;
message.step[i]= message.step[i-1];
message.step[i].field&= ~channels[j].field;
}
}
/* last step ends at pwm_Timer_Cycles_Max */
message.step[i].cycle= pwm_Timer_Cycles_Max;
return message;
}
/**
* Calculate number of cycles from a brightness.
* \param brightness The brightness.
* \return The number of cycles.
*/
pwm_Timer_Cycles pwm_Channels_BrightnessToCycles(pwm_Channels_Brightness brightness) {
return brightness * brightness;
}
/**
* Compare the number of cycles in two channels. This is needed for the
* qsort-call in pwm_Channels_show().
* \param cmp1 First channel.
* \param cmp2 Second channel.
* \return A value <0 if cmp1 is smaller than cmp2, 0 if they are of the same
* length and a value >0 if cmp1 is larger than cmp2.
*/
int pwm_Channels_CompareChannels(const void * cmp1, const void * cmp2) {
return ((const pwm_Channels_ChannelBrightness*)cmp1)->cycle - ((const pwm_Channels_ChannelBrightness*)cmp2)->cycle;
}
/**
* Writes the current pattern to the message-queue. The pattern is built from
* the state of all channels.
* \param channels Array with the channel-states.
*/
void pwm_Channels_show(pwm_Channels channels) {
int i;
pwm_Channels_Message message;
pwm_Channels_ChannelBrightness channel_brightness[CHANNELS];
for (i = 0; i < CHANNELS; i++) {
channel_brightness[i].field = 1 << i; // 1 << i equals 2^i: the channel i, uses the bit i
channel_brightness[i].cycle = pwm_Channels_BrightnessToCycles(channels.channel[i]);
}
qsort(channel_brightness, CHANNELS, sizeof(pwm_Channels_ChannelBrightness), pwm_Channels_CompareChannels);
message= pwm_Channels_Message_get(channel_brightness);
while(!messageQueue_write(message)) {
pwm_Timer_idle();
}
}