Subversion Repositories HomeAutomation

Rev

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

Rev Author Line No. Line
631 noddan 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);
636 noddan 59
void refreshDisplay(void);
631 noddan 60
 
61
uint32_t timeBase = 0;
62
 
653 noddan 63
uint32_t timeBase_turnspeed = 0;
64
 
631 noddan 65
char lcdBuffer[5];
66
 
636 noddan 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
 
631 noddan 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();
636 noddan 146
    lcd_puts("CanEggWatch\n");
631 noddan 147
 
148
    send_dimensions();
149
    lcd_puts("CAN Connected!\n");
636 noddan 150
 
151
    lcd_clrscr();
152
 
631 noddan 153
 
154
    /* main loop */
155
    while(1){
156
 
157
 
158
        if( Timebase_PassedTimeMillis(timeBase) >= 1000 ){
636 noddan 159
            if (countTimer1.timerCnt != 0){
160
                countTimer1.timerCnt--;
161
                refreshDisplay();
631 noddan 162
            } else {
636 noddan 163
                if (countTimer1.alarmTimer != 0){
631 noddan 164
                    alarm();
636 noddan 165
                    countTimer1.alarmTimer--;
631 noddan 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){
653 noddan 249
        countTimer1.timerCnt = countTimer1.timerCnt - 10;
636 noddan 250
        refreshDisplay();
631 noddan 251
    }
252
    if (type == RIGHT){
653 noddan 253
        countTimer1.timerCnt = countTimer1.timerCnt + 10;
636 noddan 254
        if  (countTimer1.timerCnt > countTimer1.timerMax){
255
            countTimer1.timerMax = countTimer1.timerCnt;
256
        }
257
        refreshDisplay();
631 noddan 258
    }
259
    if (type == BUTTON_PUSH){
260
        lcd_puts("Init!");
261
    }
262
    if (type == BUTTON_RELEASE){
263
        timeBase = Timebase_CurrentTime();
636 noddan 264
        countTimer1.timerCnt = 10;
265
        countTimer1.timerMax = 10;
266
        countTimer1.alarmTimer = 1;
267
        refreshDisplay();
631 noddan 268
    }
269
}
270
 
271
void alarm(void){
272
    lcd_puts("Riing!");
273
}
636 noddan 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
}