Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
330 noddan 1
/**
2
 * CAN RGB LED. This application is used to control a RGB LED.
3
 * Still under heavy development
4
 *
5
 * @date    2007-02-10
6
 * @author  Martin Nordén
7
 *
331 noddan 8
 * TODO: Better CAN Integration, Failsafe mode, Tempsensors etc.
9
 * Also, check current/destination intensity better when in a program?
330 noddan 10
 *
11
 */
12
 
13
 
14
/*-----------------------------------------------------------------------------
15
 * Includes
16
 *---------------------------------------------------------------------------*/
17
/* system files */
18
#include <avr/interrupt.h>
19
#include <inttypes.h>
20
#include <stdio.h>
21
#include <avr/pgmspace.h> //To allow read/write from flash
22
 
23
/* lib files */
331 noddan 24
#include <bios.h>
25
#include <noddan_funcdefs.h>
330 noddan 26
 
27
/*----------------------------------------------------------------------------
28
 * Defines
29
 * -------------------------------------------------------------------------*/
30
 
331 noddan 31
//Working on implementing all of these...
330 noddan 32
 
331 noddan 33
#define RGBLED_CMD_STATUS           0x00    /* Get status */
34
#define RGBLED_CMD_SETRGB           0x01    /* Set RGB Triplet */
35
#define RGBLED_CMD_CHANGERGB        0x02    /* Change RGB +/- */
36
#define RGBLED_CMD_SETPROGRAM       0x03  /* Set program */
37
#define RGBLED_CMD_SETFADESPEED     0x04  /* Set fadespeed */
38
#define RGBLED_CMD_SETDIMSPEED      0x05  /* Set dimspeed */
39
#define RGBLED_CMD_SETINTENS        0x10  /* Set intensity */
330 noddan 40
 
331 noddan 41
#define APP_TYPE    0xf001
42
#define APP_VERSION 0x0001
330 noddan 43
 
331 noddan 44
#define GROUP_ID    0x01L // FIXME
45
#define TRUE 1
46
#define FALSE !TRUE
47
 
48
 
330 noddan 49
/*----------------------------------------------------------------------------
50
 * Ehm, struct?
51
 * -------------------------------------------------------------------------*/
52
typedef struct
53
{
54
    uint8_t R;
55
    uint8_t G;
56
    uint8_t B;
57
    uint8_t Intens;
58
} Color;
59
 
60
/*-----------------------------------------------------------------------------
61
 * Programs! There will be a better way to add programs here.. some day.
62
 *---------------------------------------------------------------------------*/
63
 
64
//Special combinations that means something special
65
//The combinations are useless for lighting anyway
66
//So we might as well use them!
67
//0x00, 0x00, 0x00, 0x00 means end of program, keep looping it
68
//0x00, 0x00, 0x00, 0x01 means end of program, halt 
69
 
70
Color pgm1[] PROGMEM = {
71
{0xff,0x00,0x00,0x64},
72
{0xff,0xff,0x00,0x10},
73
{0x00,0xff,0x00,0xa0},
74
{0x00,0xff,0xff,0x7f},
75
{0x00,0x00,0xff,0x7f},
76
{0xff,0x00,0xff,0x40},
77
{0x00,0x00,0x00,0x00}
78
};
79
 
80
Color pgm2[] PROGMEM = {
81
{0xff,0x00,0x00,0x00},
82
{0xff,0xff,0x00,0x00},
83
{0xff,0xff,0xff,0x00},
84
{0xa0,0x00,0xa0,0x00},
85
{0x00,0x00,0xff,0x00},
86
{0x00,0x00,0x00,0x00}
87
};
88
 
89
Color pgm3[] PROGMEM = {
90
{0xff,0xff,0xff,0x00},
91
{0x00,0x00,0x00,0x01}
92
};
93
 
94
Color* programs[] PROGMEM = {
95
(Color*)pgm1,
96
(Color*)pgm2,
97
(Color*)pgm3
98
};
99
 
100
 
101
 
102
/*-----------------------------------------------------------------------------
331 noddan 103
 * Global variables
330 noddan 104
 *---------------------------------------------------------------------------*/
105
uint32_t timeStamp; //TimeStamp to keep track of time
106
uint32_t dimStamp;  //Timestamp to keep track of dimmer changes
107
 
108
Color currColor;    //Current color
109
Color destColor;    //Destination color
110
 
111
uint16_t fadeSpeed; //Fadingspeed. 16bit for reaaaally slow fading. Sets the speed of colorchange.
112
uint8_t dimSpeed;       //Dimmer speed. Sets the speed of intensitychange.
113
 
114
uint8_t currProgram;    //This variable keeps track of what program is currently running. 
115
uint8_t programMode;    //This keeps track of what mode we are currently using. 0: the program obeyes the current brightness, 1: the program is allowed to set it's own brightness
116
 
331 noddan 117
uint8_t msg_received = FALSE;
118
 
119
Can_Message_t txMsg;
120
Can_Message_t rxMsg;
121
 
330 noddan 122
/*----------------------------------------------------------------------------
123
 * Functions
124
 * -------------------------------------------------------------------------*/
125
void updateLED();
126
void reformatRGB(uint8_t R, uint8_t G, uint8_t B, uint8_t setBright);
127
void changeColor(int8_t amount, uint8_t* color);
128
void fade(uint8_t* current, uint8_t* destination);
129
 
130
 
331 noddan 131
/* Takes care about incoming messages and parses them if this node is adressed */
132
void can_receive(Can_Message_t *msg){
133
    uint32_t act;
134
    uint8_t m, act_type, group, node;
135
    if( ((msg->Id & CLASS_MASK) >> CLASS_MASK_BITS) == CLASS_ACT ){
136
        act = (msg->Id & TYPE_MASK) >> TYPE_MASK_BITS;
137
        act_type = (act & ACT_TYPE_MASK) >> ACT_TYPE_BITS;
138
        group = (act & ACT_GROUP_MASK) >> ACT_GROUP_BITS;
139
        node = (act & ACT_NODE_MASK) >> ACT_NODE_BITS;
140
 
141
        /* Check if it is command to control this servo */
142
        if(act_type == ACT_TYPE_RGB){
143
            if(group == GROUP_ID || node == NODE_ID){
144
                for(m=0;m<msg->DataLength;m++){
145
                    rxMsg.Data.bytes[m] = msg->Data.bytes[m];
146
                }
147
                msg_received = TRUE;
148
            }
149
        }
150
    }
330 noddan 151
}
152
 
331 noddan 153
 
330 noddan 154
/*-----------------------------------------------------------------------------
155
 * Main Program
156
 *---------------------------------------------------------------------------*/
157
int main(void) {
158
 
159
//Setting up OC1A, 16 bit counter used as 8 bit.
160
    TCCR1A |= (1<<COM1A1) | (1<<WGM11); /* Set OC1A at TOP, mode 14 */
161
    TCCR1B |= (1<<WGM13) | (1<<WGM12) | (1<<CS12); /* Timer uses main system clock with ? prescale */
162
    ICR1 = 256; //8 bit precision to match the other two counters.
163
    OCR1A = 0;  //0% as standard
164
    DDRB |= (1<<PB1); /* Enable pin as output */
165
//Setting up OC0A
166
    TCCR0A |= (1<<COM0A1)|(1<<WGM01)|(1<<WGM00); /* Set OC0A at TOP, Mode 7 */
167
    TCCR0B |= (1<<CS02); /* Prescaler updating now */
168
    OCR0A = 0;  //0% standard
169
    DDRD |= (1<<PD6);
170
//Setting up OC0B
171
    TCCR0A |= (1<<COM0B1);
172
    OCR0B = 0;
173
    DDRD |= (1<<PD5);
174
 
175
//Initialize variables
176
    fadeSpeed = 10;
177
    dimSpeed = 10;
178
    timeStamp = 0;
179
    dimStamp = 0;
180
 
331 noddan 181
    reformatRGB(0x00,0x00,0x00,1);
330 noddan 182
    destColor.Intens = 100;
183
    currColor = destColor;
184
 
185
//Just temporary for now, they keep track of some kind of demo-program.
186
    currProgram = 1;
187
    programMode = 0;
188
    uint16_t temp_adress = pgm_read_word(&programs[currProgram-1]); //Get adress for program 0
189
 
190
    sei();
191
 
192
    bios->can_callback = &can_receive;
193
 
331 noddan 194
//Send a message that we are alive!
195
    txMsg.Id = (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE) | (NODE_ID << CAN_SHIFT_NMT_SID);
330 noddan 196
    txMsg.DataLength = 4;
197
    txMsg.RemoteFlag = 0;
198
    txMsg.ExtendedFlag = 1;
331 noddan 199
    txMsg.Data.words[0] = APP_TYPE;
200
    txMsg.Data.words[1] = APP_VERSION;
330 noddan 201
    bios->can_send(&txMsg);
202
 
203
 
204
    /* main loop */
205
    while (1) {
206
 
207
        /* Time to fade color? */
331 noddan 208
        if ((bios->timebase_get() - timeStamp) >= fadeSpeed) {
330 noddan 209
            fade(&currColor.R, &destColor.R);          
210
            fade(&currColor.G, &destColor.G);
211
            fade(&currColor.B, &destColor.B);
212
 
213
            timeStamp = bios->timebase_get();
214
            updateLED();
215
        }
216
 
217
 
218
        /* Time to fade intensity? */
331 noddan 219
        if (bios->timebase_get() - dimStamp >= dimSpeed) {
220
            fade(&currColor.Intens, &destColor.Intens);
221
            dimStamp = bios->timebase_get();
222
            updateLED();
223
        }
330 noddan 224
 
225
 
226
        /* Program management */
227
        if (currProgram != 0) { //Check if a program is currently running
228
            if ((currColor.R == destColor.R)&(currColor.G == destColor.G)&(currColor.B == destColor.B)&(currColor.Intens == destColor.Intens)){//Is the current sequence finished?
229
                //Now we have to check if the program is finished and if we should loop
230
                if ((pgm_read_byte(temp_adress)==0)&(pgm_read_byte(temp_adress+1)==0)&(pgm_read_byte(temp_adress+2)==0)){
231
                    //The program has ended! Shall we loop it?
232
                    if (pgm_read_byte(temp_adress+3)==0){
233
                        //Yes, let's loop it
234
                        temp_adress = pgm_read_word(&programs[currProgram-1]);
235
                    } else {
236
                        //No, halt!
237
                        currProgram = 0;
238
                    }
239
                } else {
240
                    //The program has not ended, let's get the next RGB-triplet!
241
                    destColor.R = pgm_read_byte(temp_adress);
242
                    destColor.G = pgm_read_byte(temp_adress + 1);
243
                    destColor.B = pgm_read_byte(temp_adress + 2);
244
                    if (programMode == 1){
245
                        destColor.Intens = pgm_read_byte(temp_adress + 3);
246
                    }
247
 
248
                    temp_adress = temp_adress + 4;             
249
                }
250
 
251
            }
252
 
253
        }
254
 
331 noddan 255
        /* check if any messages have been received */
256
        if(msg_received){
257
            /* This node that controls a RGB LED is adressed */
258
            if( rxMsg.Data.bytes[0] == RGBLED_CMD_SETPROGRAM ){
259
                /* Set a program! */
260
                currProgram = rxMsg.Data.bytes[1];
261
                temp_adress = pgm_read_word(&programs[currProgram-1]);             
262
            }else if( rxMsg.Data.bytes[0] == RGBLED_CMD_SETINTENS ){
263
                /* Set intensity! */
264
                if (rxMsg.Data.bytes[1] == TRUE){
265
                    currColor.Intens = rxMsg.Data.bytes[2];                
266
                }
267
                destColor.Intens = rxMsg.Data.bytes[2];
268
                if (rxMsg.Data.bytes[3] != 0){
269
                    dimSpeed = rxMsg.Data.bytes[3];
270
                }
271
                currProgram = rxMsg.Data.bytes[1];
272
                temp_adress = pgm_read_word(&programs[currProgram-1]);
273
            } else if( rxMsg.Data.bytes[0] == RGBLED_CMD_SETRGB) {
274
                /* Set RGB-triplet! */
275
                reformatRGB(rxMsg.Data.bytes[2],rxMsg.Data.bytes[3],rxMsg.Data.bytes[4],0);
276
                if (rxMsg.Data.bytes[5] != 0){
277
                    destColor.Intens = rxMsg.Data.bytes[5];
278
                }
279
                if (rxMsg.Data.bytes[1] == TRUE){
280
                    currColor = destColor;
281
                }
282
 
283
                if (rxMsg.Data.bytes[7] != 0){
284
                    fadeSpeed = rxMsg.Data.bytes[6] * 255 + rxMsg.Data.bytes[7];
285
                }
286
                currProgram = 0;
287
 
288
            }
289
            msg_received = FALSE; //Let's clear the flag yes.
290
        }
291
 
330 noddan 292
    }
293
 
294
    return 0;
295
}
296
 
297
 
298
 
299
 
300
/************************************************************************************************
301
 *     updateLED updates the PWM counter values and thus changes the color of the RGBLED.       *
302
 *     It doesn't reculculate anything, except the values to write to the PWM registers.        *
303
 *     TODO: Get rid of the tempcontainer!                                  *
304
 ************************************************************************************************/
305
void updateLED(){
306
    uint8_t tempcontainer;
307
 
308
    tempcontainer = currColor.R * currColor.Intens / 255;   //I really want to skip this, don't know how yet though.
309
    OCR1A = tempcontainer; 
310
      OCR0A = currColor.G * currColor.Intens / 255;
311
    OCR0B = currColor.B * currColor.Intens / 255;      
312
 
331 noddan 313
/*     
330 noddan 314
    //Bara för debugcrap
315
    Can_Message_t txMsg;
316
    txMsg.Id = 0x55;
317
    txMsg.RemoteFlag = 0;
318
    txMsg.ExtendedFlag = 1;
319
    txMsg.DataLength = 4;
320
    txMsg.Data.bytes[0] = currColor.R;
321
    txMsg.Data.bytes[1] = currColor.G;
322
    txMsg.Data.bytes[2] = currColor.B;
323
    txMsg.Data.bytes[3] = currColor.Intens;
324
 
325
    bios->can_send(&txMsg);
331 noddan 326
*/
330 noddan 327
}
328
 
329
 
330
 
331
/************************************************************************************************
332
 *     reformatRGB sets a new target RGB triplet to fade to. It reformats it so that            *
333
 *     the highest color always gets 0xff. Brightness is recalculated.                          *
334
 *     if setBright is set to 0, the brightness will not be updated.                    *
331 noddan 335
 *     TODO: Smarter 16-bit arithmetics would be nice.                          *
330 noddan 336
 ************************************************************************************************/
337
void reformatRGB(uint8_t R, uint8_t G, uint8_t B, uint8_t setBright){
338
    uint8_t maxvalue;
339
    uint16_t tempcontainer;
340
 
341
    if ((R>=G)&(R>=B)){
342
        maxvalue = R;
343
    } else if ((G>=R)&(G>=B)){
344
        maxvalue = G;
345
    } else {
346
        maxvalue = B;
347
    }
348
 
349
    tempcontainer = R * 255;
350
    destColor.R = tempcontainer/maxvalue;
351
    tempcontainer = G * 255;
352
    destColor.G = tempcontainer/maxvalue;
353
    tempcontainer = B * 255;
354
    destColor.B = tempcontainer/maxvalue;
355
 
356
    if (setBright){
357
        destColor.Intens = maxvalue;
358
    }
359
}
360
 
361
 
362
/************************************************************************************************
363
 *     fade takes two pointers, current and destination and fades current               *
364
 *     one tick closer to destination.                                                        *
365
 ************************************************************************************************/
366
void fade(uint8_t* current, uint8_t* destination){
367
    if (*current > *destination){
368
        *current = *current - 1;
369
    } else if (*current < *destination){
370
        *current = *current + 1;
371
    }
372
}
373
 
374
 
375
/************************************************************************************************
376
 *     changeColor changes a color accord to amount. -127>127.                                  *
377
 *     color is either dest och curr R,G,B.                                                     *
378
 *     Maybe TODO: If red is already 255 and we want to increase it, decrease the other ones.   *
379
 ************************************************************************************************/
380
void changeColor(int8_t amount, uint8_t* color){
381
    if ( ((amount > 0)&(*color < 255)) || ((amount < 0)&(*color > 0)) ) //Se till att vi inte slĺr över *color
382
    *color = *color + amount;
383
}
331 noddan 384