Subversion Repositories HomeAutomation

Rev

Rev 631 | Rev 653 | Go to most recent revision | 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. char lcdBuffer[5];
  64.  
  65. //Struct for countdown
  66. typedef struct
  67. {
  68.     uint16_t timerCnt;
  69.     uint8_t alarmTimer;
  70.     uint16_t timerMax;
  71. } countDown;
  72.  
  73. countDown countTimer1;
  74.  
  75.  
  76. // CAN message reception callback
  77. // This function runs with interrupts disabled, keep it as short as possible
  78. void can_receive(Can_Message_t *msg){
  79.     if(!rxMsgFull){
  80.         memcpy((void*)&rxMsg, msg, sizeof(rxMsg));
  81.         rxMsgFull = 1;
  82.     }
  83. }
  84.  
  85. ISR( PCINT2_vect ){
  86. // For ROTENC_A and ROTENC_B FIXME Šr inte riktigt rŠtt. Verkar vara bra tycker jag?
  87.     rotenc();
  88. }
  89.  
  90. ISR( PCINT0_vect ){
  91. // For ROTENC_BTN
  92.     rotenc();
  93. }
  94.  
  95. /*-----------------------------------------------------------------------------
  96.  * Main Program
  97.  *---------------------------------------------------------------------------*/
  98. int main(void) {
  99. //  uint32_t act; not used anymoer
  100. //  uint8_t act_type, lcd_size; not used anymore
  101. //  uint8_t m, lcd_action; These are probably not needed now
  102.  
  103.     sei();
  104.    
  105.     Timebase_Init();
  106.  
  107.     /*
  108.      * Initialize rotaryencoders and buttons
  109.      */
  110.     // Set as input
  111.     DDRD &= ~(1<<DDD2);
  112.     DDRB &= ~((1<<DDB7)|(1<<DDB0));
  113.     // Enable pull-up
  114.     PORTD |= (1<<PD2);
  115.     PORTB |= (1<<PB7)|(1<<PB0);
  116.     // Enable IO-pin interrupt
  117.     PCICR |= (1<<PCIE2)|(1<<PCIE0);
  118.     // Unmask PB7, PB0 and PD2
  119.     PCMSK2 |= (1<<PCINT18);
  120.     PCMSK0 |= (1<<PCINT7)|(1<<PCINT0);
  121.  
  122.     // Contrast
  123.     TCCR0A |= (1<<COM0B1)|(1<<WGM01)|(1<<WGM00);
  124.     TCCR0B |= (1<<CS00);
  125.     OCR0B = 0x10;
  126.     DDRD |= (1<<DDD5);
  127.  
  128.     // Backlight
  129.     TCCR1A |= (1<<COM1A1)|(1<<WGM11);
  130.     TCCR1B |= (1<<WGM13)|(1<<WGM12)|(1<<CS10);
  131.     ICR1 = 0xFF; // Make it 8 bits
  132.     OCR1A = 0xFF;
  133.     DDRB |= (1<<DDB1);
  134.  
  135.  
  136.     Can_Message_t txMsg;
  137.     txMsg.ExtendedFlag=1;
  138.     txMsg.RemoteFlag=0;
  139. // FIXME skicka app startad
  140.     BIOS_CanCallback = &can_receive;
  141.  
  142.     lcd_init( LCD_DISP_ON );
  143.     lcd_clrscr();
  144.     lcd_puts("CanEggWatch\n");
  145.  
  146.     send_dimensions();
  147.     lcd_puts("CAN Connected!\n");
  148.    
  149.     lcd_clrscr();
  150.    
  151.  
  152.     /* main loop */
  153.     while(1){
  154.        
  155.        
  156.         if( Timebase_PassedTimeMillis(timeBase) >= 1000 ){
  157.             if (countTimer1.timerCnt != 0){
  158.                 countTimer1.timerCnt--;
  159.                 refreshDisplay();
  160.             } else {
  161.                 if (countTimer1.alarmTimer != 0){
  162.                     alarm();
  163.                     countTimer1.alarmTimer--;
  164.                 }
  165.             }
  166.             timeBase =  Timebase_CurrentTime();
  167.         }
  168.        
  169.        
  170.         /* check if any messages have been received */
  171.         if(rxMsgFull){
  172.             //Throw it away. We don't use them yet. TODO: Support for time and remote setting.
  173.             rxMsgFull = 0;
  174.         }
  175.     }
  176. }
  177.  
  178. void send_dimensions(){
  179.     Can_Message_t txMsg;
  180.  
  181.     txMsg.ExtendedFlag=1;
  182.     txMsg.RemoteFlag=0;
  183.     txMsg.Id=0xA000001;
  184.     txMsg.Data.bytes[0] = SIZE_X;
  185.     txMsg.Data.bytes[1] = SIZE_Y;
  186.     txMsg.DataLength = 2;
  187.  
  188.     BIOS_CanSend(&txMsg);
  189. }
  190.  
  191. void rotenc(){
  192.     uint8_t rot_data = 0;
  193.     static uint8_t rot_lastdir = 0, rot_laststate = 0, btn_laststate = 0;
  194.  
  195.     Can_Message_t txMsg;
  196.     txMsg.ExtendedFlag=1;
  197.     txMsg.RemoteFlag=0;
  198.     //txMsg.Id = ( CLASS_SNS<<CLASS_MASK_BITS )|( SNS_ACT_BUTTON<<SNS_TYPE_BITS )|( 0x01<<SNS_ID_BITS )| NODE_ID;//FIXME: borttaget
  199.     txMsg.DataLength=2;
  200.  
  201.     //Take care of button push
  202.     if ((PINB&(1<<PB7)) != btn_laststate){ //The buttonstate has changed! Let's send a message!
  203.         btn_laststate = (PINB&(1<<PB7));
  204.         txMsg.Data.bytes[0] = 5;
  205.         txMsg.Data.bytes[1] = (btn_laststate)?0:1;
  206.         txMsg.DataLength=2;
  207.         BIOS_CanSend(&txMsg);
  208.         action((btn_laststate)?BUTTON_RELEASE:BUTTON_PUSH);
  209.     }
  210.    
  211.     //Take care of rotary encoder movement
  212.     if(PINB&(1<<PB0)){
  213.         rot_data |= 0x01;
  214.     }
  215.     if(PIND&(1<<PD2)){
  216.         rot_data |= 0x02;
  217.     }
  218.  
  219.     if( rot_data==0 || rot_data==3 ){ // Are both signals high or low?
  220.         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.
  221.             if( rot_lastdir&0x01 ){
  222.                 // Moving right
  223.                 txMsg.Data.bytes[0]=RIGHT;
  224.                 txMsg.Data.bytes[1] = (PINB&(1<<PB7))?0:1;
  225.                 txMsg.DataLength=2;
  226.                 BIOS_CanSend(&txMsg);
  227.                 action(RIGHT);
  228.             }else{
  229.                 // Moving left
  230.                 txMsg.Data.bytes[0]=LEFT;
  231.                 txMsg.Data.bytes[1] = (PINB&(1<<PB7))?0:1;
  232.                 txMsg.DataLength=2;
  233.                 BIOS_CanSend(&txMsg);
  234.                 action(LEFT);
  235.             }
  236.         }
  237.         rot_laststate = rot_data;
  238.     } else { // No, only one of the signals are high. We can use this to find out what direction we are moving.
  239.         rot_lastdir = rot_data;
  240.     }
  241. }
  242.  
  243. void action(uint8_t type){
  244.     //Let's do something with something!
  245.     lcd_clrscr();
  246.     if (type == LEFT){
  247.         countTimer1.timerCnt--;
  248.         refreshDisplay();
  249.     }
  250.     if (type == RIGHT){
  251.         countTimer1.timerCnt++;
  252.         if  (countTimer1.timerCnt > countTimer1.timerMax){
  253.             countTimer1.timerMax = countTimer1.timerCnt;
  254.         }
  255.         refreshDisplay();
  256.     }
  257.     if (type == BUTTON_PUSH){
  258.         lcd_puts("Init!");
  259.     }
  260.     if (type == BUTTON_RELEASE){
  261.         timeBase = Timebase_CurrentTime();
  262.         countTimer1.timerCnt = 10;
  263.         countTimer1.timerMax = 10;
  264.         countTimer1.alarmTimer = 1;
  265.         refreshDisplay();
  266.     }
  267. }
  268.  
  269. void alarm(void){
  270.     lcd_puts("Riing!");
  271. }
  272.  
  273. void refreshDisplay(void){
  274.     lcd_clrscr();
  275.     itoa(countTimer1.timerCnt/60,lcdBuffer,10);
  276.     lcd_puts(lcdBuffer);
  277.     lcd_puts(":");
  278.     itoa(countTimer1.timerCnt%60,lcdBuffer,10);
  279.     lcd_puts(lcdBuffer);
  280.    
  281.     lcd_gotoxy(0,1);
  282.     lcdProgressBar(countTimer1.timerCnt,countTimer1.timerMax,16);  
  283. }
  284.