Subversion Repositories HomeAutomation

Rev

Rev 330 | Blame | Last modification | View Log | SVN | RSS feed

  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.  *
  8.  * TODO: Better CAN Integration, Failsafe mode, Tempsensors etc.
  9.  * Also, check current/destination intensity better when in a program?
  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 */
  24. #include <bios.h>
  25. #include <noddan_funcdefs.h>
  26.  
  27. /*----------------------------------------------------------------------------
  28.  * Defines
  29.  * -------------------------------------------------------------------------*/
  30.  
  31. //Working on implementing all of these...
  32.  
  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 */
  40.  
  41. #define APP_TYPE    0xf001
  42. #define APP_VERSION 0x0001
  43.  
  44. #define GROUP_ID    0x01L // FIXME
  45. #define TRUE 1
  46. #define FALSE !TRUE
  47.  
  48.  
  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. /*-----------------------------------------------------------------------------
  103.  * Global variables
  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.  
  117. uint8_t msg_received = FALSE;
  118.  
  119. Can_Message_t txMsg;
  120. Can_Message_t rxMsg;
  121.  
  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.  
  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.     }
  151. }
  152.  
  153.  
  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.  
  181.     reformatRGB(0x00,0x00,0x00,1);
  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.  
  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);
  196.     txMsg.DataLength = 4;
  197.     txMsg.RemoteFlag = 0;
  198.     txMsg.ExtendedFlag = 1;
  199.     txMsg.Data.words[0] = APP_TYPE;
  200.     txMsg.Data.words[1] = APP_VERSION;
  201.     bios->can_send(&txMsg);
  202.  
  203.  
  204.     /* main loop */
  205.     while (1) {
  206.        
  207.         /* Time to fade color? */
  208.         if ((bios->timebase_get() - timeStamp) >= fadeSpeed) {
  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? */
  219.         if (bios->timebase_get() - dimStamp >= dimSpeed) {
  220.             fade(&currColor.Intens, &destColor.Intens);
  221.             dimStamp = bios->timebase_get();
  222.             updateLED();
  223.         }
  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.  
  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.  
  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.  
  313. /*     
  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);
  326. */
  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.                    *
  335.  *     TODO: Smarter 16-bit arithmetics would be nice.                          *
  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. }
  384.  
  385.