Subversion Repositories HomeAutomation

Rev

Rev 653 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /**
  2.  * CanEggWatch. Currenty only supports nodeCLCD, this will probably change since I want 7-segments in the long run.
  3.  * Hardware: http://projekt.auml.se/homeautomation:hardware:avr:clcd
  4.  * TODO: Sending messages to report status, cleanup, graphical bar, nicer GUI, multiple timers
  5.  *
  6.  *
  7.  * @date    2007-09-09
  8.  * @author  Martin Norden
  9.  *
  10.  */
  11.  
  12. /*-----------------------------------------------------------------------------
  13.  * Includes
  14.  *---------------------------------------------------------------------------*/
  15. /* system files */
  16. #include <avr/io.h>
  17. #include <inttypes.h>
  18. #include <avr/interrupt.h>
  19. #include <stdio.h>
  20. /* lib files */
  21. #include <bios.h>
  22. #include <config.h>
  23. #include <drivers/lcd/clcd/lcd_HD44780.h>
  24. #include <drivers/timer/timebase.h>
  25.  
  26.  
  27. #include <string.h> //for memcpy
  28. #include <stdlib.h> //for itoa
  29.  
  30.  
  31. /*-----------------------------------------------------------------------------
  32.  * Defines
  33.  *---------------------------------------------------------------------------*/
  34. #define SIZE_X  20
  35. #define SIZE_Y  4
  36. #define SIZE_LCD LCD_SIZE_20x4
  37.  
  38. #define BUFFER_SIZE SIZE_X
  39. #define TRUE 1
  40. #define FALSE 0
  41.  
  42. #define LEFT    0x01
  43. #define RIGHT   0x02
  44. #define BUTTON_PUSH 0x03
  45. #define BUTTON_RELEASE 0x04
  46.  
  47. volatile Can_Message_t rxMsg;
  48.  
  49. char incoming_text[ BUFFER_SIZE ];
  50. uint8_t rxMsgFull;
  51.  
  52.  
  53. char buffer[ BUFFER_SIZE ];
  54.  
  55. void send_dimensions(void);
  56. void rotenc(void);
  57. void action(uint8_t type);
  58. void alarm(void);
  59. void refreshDisplay(void);
  60.  
  61. uint32_t timeBase = 0;
  62.  
  63. uint32_t timeBase_turnspeed = 0;
  64.  
  65. char lcdBuffer[5];
  66.  
  67. //Struct for countdown
  68. typedef struct
  69. {
  70.     uint16_t timerCnt;
  71.     uint8_t alarmTimer;
  72.     uint16_t timerMax;
  73. } countDown;
  74.  
  75. countDown countTimer1;
  76.  
  77.  
  78. // CAN message reception callback
  79. // This function runs with interrupts disabled, keep it as short as possible
  80. void can_receive(Can_Message_t *msg){
  81.     if(!rxMsgFull){
  82.         memcpy((void*)&rxMsg, msg, sizeof(rxMsg));
  83.         rxMsgFull = 1;
  84.     }
  85. }
  86.  
  87. ISR( PCINT2_vect ){
  88. // For ROTENC_A and ROTENC_B FIXME Šr inte riktigt rŠtt. Verkar vara bra tycker jag?
  89.     rotenc();
  90. }
  91.  
  92. ISR( PCINT0_vect ){
  93. // For ROTENC_BTN
  94.     rotenc();
  95. }
  96.  
  97. /*-----------------------------------------------------------------------------
  98.  * Main Program
  99.  *---------------------------------------------------------------------------*/
  100. int main(void) {
  101. //  uint32_t act; not used anymoer
  102. //  uint8_t act_type, lcd_size; not used anymore
  103. //  uint8_t m, lcd_action; These are probably not needed now
  104.  
  105.     sei();
  106.    
  107.     Timebase_Init();
  108.  
  109.     /*
  110.      * Initialize rotaryencoders and buttons
  111.      */
  112.     // Set as input
  113.     DDRD &= ~(1<<DDD2);
  114.     DDRB &= ~((1<<DDB7)|(1<<DDB0));
  115.     // Enable pull-up
  116.     PORTD |= (1<<PD2);
  117.     PORTB |= (1<<PB7)|(1<<PB0);
  118.     // Enable IO-pin interrupt
  119.     PCICR |= (1<<PCIE2)|(1<<PCIE0);
  120.     // Unmask PB7, PB0 and PD2
  121.     PCMSK2 |= (1<<PCINT18);
  122.     PCMSK0 |= (1<<PCINT7)|(1<<PCINT0);
  123.  
  124.     // Contrast
  125.     TCCR0A |= (1<<COM0B1)|(1<<WGM01)|(1<<WGM00);
  126.     TCCR0B |= (1<<CS00);
  127.     OCR0B = 0x10;
  128.     DDRD |= (1<<DDD5);
  129.  
  130.     // Backlight
  131.     TCCR1A |= (1<<COM1A1)|(1<<WGM11);
  132.     TCCR1B |= (1<<WGM13)|(1<<WGM12)|(1<<CS10);
  133.     ICR1 = 0xFF; // Make it 8 bits
  134.     OCR1A = 0xFF;
  135.     DDRB |= (1<<DDB1);
  136.  
  137.  
  138.     Can_Message_t txMsg;
  139.     txMsg.ExtendedFlag=1;
  140.     txMsg.RemoteFlag=0;
  141. // FIXME skicka app startad
  142.     BIOS_CanCallback = &can_receive;
  143.  
  144.     lcd_init( LCD_DISP_ON );
  145.     lcd_clrscr();
  146.     lcd_puts("CanEggWatch\n");
  147.  
  148.     send_dimensions();
  149.     lcd_puts("CAN Connected!\n");
  150.    
  151.     lcd_clrscr();
  152.    
  153.  
  154.     /* main loop */
  155.     while(1){
  156.        
  157.        
  158.         if( Timebase_PassedTimeMillis(timeBase) >= 1000 ){
  159.             if (countTimer1.timerCnt != 0){
  160.                 countTimer1.timerCnt--;
  161.                 refreshDisplay();
  162.             } else {
  163.                 if (countTimer1.alarmTimer != 0){
  164.                     alarm();
  165.                     countTimer1.alarmTimer--;
  166.                 }
  167.             }
  168.             timeBase =  Timebase_CurrentTime();
  169.         }
  170.        
  171.        
  172.         /* check if any messages have been received */
  173.         if(rxMsgFull){
  174.             //Throw it away. We don't use them yet. TODO: Support for time and remote setting.
  175.             rxMsgFull = 0;
  176.         }
  177.     }
  178. }
  179.  
  180. void send_dimensions(){
  181.     Can_Message_t txMsg;
  182.  
  183.     txMsg.ExtendedFlag=1;
  184.     txMsg.RemoteFlag=0;
  185.     txMsg.Id=0xA000001;
  186.     txMsg.Data.bytes[0] = SIZE_X;
  187.     txMsg.Data.bytes[1] = SIZE_Y;
  188.     txMsg.DataLength = 2;
  189.  
  190.     BIOS_CanSend(&txMsg);
  191. }
  192.  
  193. void rotenc(){
  194.     uint8_t rot_data = 0;
  195.     static uint8_t rot_lastdir = 0, rot_laststate = 0, btn_laststate = 0;
  196.  
  197.     Can_Message_t txMsg;
  198.     txMsg.ExtendedFlag=1;
  199.     txMsg.RemoteFlag=0;
  200.     //txMsg.Id = ( CLASS_SNS<<CLASS_MASK_BITS )|( SNS_ACT_BUTTON<<SNS_TYPE_BITS )|( 0x01<<SNS_ID_BITS )| NODE_ID;//FIXME: borttaget
  201.     txMsg.DataLength=2;
  202.  
  203.     //Take care of button push
  204.     if ((PINB&(1<<PB7)) != btn_laststate){ //The buttonstate has changed! Let's send a message!
  205.         btn_laststate = (PINB&(1<<PB7));
  206.         txMsg.Data.bytes[0] = 5;
  207.         txMsg.Data.bytes[1] = (btn_laststate)?0:1;
  208.         txMsg.DataLength=2;
  209.         BIOS_CanSend(&txMsg);
  210.         action((btn_laststate)?BUTTON_RELEASE:BUTTON_PUSH);
  211.     }
  212.    
  213.     //Take care of rotary encoder movement
  214.     if(PINB&(1<<PB0)){
  215.         rot_data |= 0x01;
  216.     }
  217.     if(PIND&(1<<PD2)){
  218.         rot_data |= 0x02;
  219.     }
  220.  
  221.     if( rot_data==0 || rot_data==3 ){ // Are both signals high or low?
  222.         if( rot_data==0 && rot_laststate!=rot_data ){ // Are both signals low? In that case we are finished with one turn and should print out the direction it went.
  223.             if( rot_lastdir&0x01 ){
  224.                 // Moving right
  225.                 txMsg.Data.bytes[0]=RIGHT;
  226.                 txMsg.Data.bytes[1] = (PINB&(1<<PB7))?0:1;
  227.                 txMsg.DataLength=2;
  228.                 BIOS_CanSend(&txMsg);
  229.                 action(RIGHT);
  230.             }else{
  231.                 // Moving left
  232.                 txMsg.Data.bytes[0]=LEFT;
  233.                 txMsg.Data.bytes[1] = (PINB&(1<<PB7))?0:1;
  234.                 txMsg.DataLength=2;
  235.                 BIOS_CanSend(&txMsg);
  236.                 action(LEFT);
  237.             }
  238.         }
  239.         rot_laststate = rot_data;
  240.     } else { // No, only one of the signals are high. We can use this to find out what direction we are moving.
  241.         rot_lastdir = rot_data;
  242.     }
  243. }
  244.  
  245. void action(uint8_t type){
  246.     //Let's do something with something!
  247.     lcd_clrscr();
  248.     if (type == LEFT){
  249.         countTimer1.timerCnt = countTimer1.timerCnt - 10;
  250.         refreshDisplay();
  251.     }
  252.     if (type == RIGHT){
  253.         countTimer1.timerCnt = countTimer1.timerCnt + 10;
  254.         if  (countTimer1.timerCnt > countTimer1.timerMax){
  255.             countTimer1.timerMax = countTimer1.timerCnt;
  256.         }
  257.         refreshDisplay();
  258.     }
  259.     if (type == BUTTON_PUSH){
  260.         lcd_puts("Init!");
  261.     }
  262.     if (type == BUTTON_RELEASE){
  263.         timeBase = Timebase_CurrentTime();
  264.         countTimer1.timerCnt = 10;
  265.         countTimer1.timerMax = 10;
  266.         countTimer1.alarmTimer = 1;
  267.         refreshDisplay();
  268.     }
  269. }
  270.  
  271. void alarm(void){
  272.     lcd_puts("Riing!");
  273. }
  274.  
  275. void refreshDisplay(void){
  276.     lcd_clrscr();
  277.     itoa(countTimer1.timerCnt/60,lcdBuffer,10);
  278.     lcd_puts(lcdBuffer);
  279.     lcd_puts(":");
  280.     itoa(countTimer1.timerCnt%60,lcdBuffer,10);
  281.     lcd_puts(lcdBuffer);
  282.    
  283.     lcd_gotoxy(0,1);
  284.     lcdProgressBar(countTimer1.timerCnt,countTimer1.timerMax,16);  
  285. }
  286.