/** * \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 #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(); } }