Subversion Repositories HomeAutomation

Rev

Go to most recent revision | Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
645 noddan 1
/**
2
 * CanCarDisplay. HID for simple carsensor network
3
 * For HD44780- and KS0073-based LCD displays
4
 *
5
 * Contains no intelligence. It just prints what it is told to.
6
 *
7
 * @date    2007-10-01
8
 * @author  Martin Norden
9
 *
647 noddan 10
 * TODO: put rotary encoder in external library, same with s16/u16tostr, cleanup, read external sensors... a lot basically.
11
 * Assume all sensor conversion done on the sensorcard, use canstandard here
645 noddan 12
 */
13
 
14
/*-----------------------------------------------------------------------------
15
 * Includes
16
 *---------------------------------------------------------------------------*/
17
/* system files */
18
#include <avr/io.h>
19
#include <inttypes.h>
20
#include <avr/interrupt.h>
21
#include <stdio.h>
22
/* lib files */
23
#include <bios.h>
24
#include <config.h>
25
#include <drivers/lcd/clcd/lcd_HD44780.h>
26
#include <stdlib.h> //for itoa
27
 
28
#include <string.h> //for memcpy
29
 
30
 
31
/* <SIZE> 8 bits 0xFFL */
32
#define LCD_SIZE_ALL    0x00L
33
#define LCD_SIZE_16x2   0x02L
34
#define LCD_SIZE_20x4   0x10L
35
 
36
 
37
//Borde ha en bŠttre plats.
38
#define max(a,b) ((a>b)?a:b)
39
#define min(a,b) ((a<b)?a:b)
40
 
41
 
42
/*-----------------------------------------------------------------------------
43
 * Defines
44
 *---------------------------------------------------------------------------*/
45
#define SIZE_X  20
46
#define SIZE_Y  4
47
#define SIZE_LCD LCD_SIZE_20x4
48
 
49
#define BUFFER_SIZE SIZE_X
50
#define TRUE 1
51
#define FALSE 0
52
 
53
#define LEFT    0x01
54
#define RIGHT   0x02
55
#define BUTTON_PUSH 0x03
56
#define BUTTON_RELEASE 0x04
57
 
58
volatile Can_Message_t rxMsg;
59
 
60
char incoming_text[ BUFFER_SIZE ];
61
uint8_t rxMsgFull;
62
 
63
 
64
char buffer[ BUFFER_SIZE ];
65
 
66
void send_dimensions(void);
67
void rotenc(void);
68
void rotenc_action(uint8_t type);
69
 
70
 
71
void updateDisplay(uint8_t screen, uint8_t transition);
72
 
73
#define SCR_LAMBDA      0x00
74
#define SCR_BOOST       0x01
75
#define SCR_MAXBOOST    0x02
76
#define SCR_RPM         0x03
77
#define SCR_VOLTAGE     0x04
78
#define LAST_SCREEN     0x04
79
void standardScreen(char* text, uint16_t value, uint16_t maxvalue);
80
 
647 noddan 81
void numtoascii( int16_t num, char **str );
82
void rattoascii( int16_t num, uint8_t decimalplace, char *string); //decimalplace is number ofjah
83
 
84
uint8_t *parsetemperature(int16_t value, uint8_t *str,uint8_t decimal,uint8_t options);
645 noddan 85
uint8_t *io_s16toStr(int16_t value, uint8_t *str,uint8_t decimal,uint8_t options);
86
uint8_t *io_u16toStr(uint16_t value, uint8_t *str,uint8_t decimal,uint8_t options);
87
 
88
 
89
 
90
/*******************************************************************************
91
 * Sensor Values, Scale factors etc.                                           *
92
 *******************************************************************************/
93
int16_t sensor_Boost = 120; //Should be set automagically by incoming CAN
647 noddan 94
int16_t sensor_Boost_Max = 200;  //highest boost so far
645 noddan 95
 
96
uint16_t sensor_RPM = 2573;
97
uint8_t sensor_Lambda = 127;
98
uint8_t sensor_Voltage = 143;
99
 
647 noddan 100
#define scale_Boost 200 //see "Representation av storheter"
645 noddan 101
#define scale_BoostMAX 200
102
#define scale_RPMMAX 8000 //Can be set as in eeprom later perhaps?
103
#define scale_Voltage 1024
104
#define scale_VoltageMAX 150
105
 
106
 
107
uint8_t currentScreen;
108
 
109
// CAN message reception callback
110
// This function runs with interrupts disabled, keep it as short as possible
111
void can_receive(Can_Message_t *msg){
112
    if(!rxMsgFull){
113
        memcpy((void*)&rxMsg, msg, sizeof(rxMsg));
114
        rxMsgFull = 1;
115
    }
116
}
117
 
118
ISR( PCINT2_vect ){
119
// For ROTENC_A and ROTENC_B FIXME Šr inte riktigt rŠtt. Verkar vara bra tycker jag?
120
    rotenc();
121
}
122
 
123
ISR( PCINT0_vect ){
124
// For ROTENC_BTN
125
    rotenc();
126
}
127
 
128
/*-----------------------------------------------------------------------------
129
 * Main Program
130
 *---------------------------------------------------------------------------*/
131
int main(void) {
132
    currentScreen = 0; //init display position
133
 
134
//  uint32_t act; not used anymoer
135
//  uint8_t act_type, lcd_size; not used anymore
136
    //uint8_t m, lcd_action;
137
 
138
    sei();
139
 
140
    /*
141
     * Initialize rotaryencoders and buttons
142
     */
143
    // Set as input
144
    DDRD &= ~(1<<DDD2);
145
    DDRB &= ~((1<<DDB7)|(1<<DDB0));
146
    // Enable pull-up
147
    PORTD |= (1<<PD2);
148
    PORTB |= (1<<PB7)|(1<<PB0);
149
    // Enable IO-pin interrupt
150
    PCICR |= (1<<PCIE2)|(1<<PCIE0);
151
    // Unmask PB7, PB0 and PD2
152
    PCMSK2 |= (1<<PCINT18);
153
    PCMSK0 |= (1<<PCINT7)|(1<<PCINT0);
154
 
155
    // Contrast
156
    TCCR0A |= (1<<COM0B1)|(1<<WGM01)|(1<<WGM00);
157
    TCCR0B |= (1<<CS00);
158
    OCR0B = 0x10;
159
    DDRD |= (1<<DDD5);
160
 
161
    // Backlight
162
    TCCR1A |= (1<<COM1A1)|(1<<WGM11);
163
    TCCR1B |= (1<<WGM13)|(1<<WGM12)|(1<<CS10);
164
    ICR1 = 0xFF; // Make it 8 bits
165
    OCR1A = 0xFF;
166
    DDRB |= (1<<DDB1);
167
 
168
 
169
    Can_Message_t txMsg;
170
    txMsg.ExtendedFlag=1;
171
    txMsg.RemoteFlag=0;
172
// FIXME skicka app startad
173
    BIOS_CanCallback = &can_receive;
174
 
175
    lcd_init( LCD_DISP_ON );
176
    lcd_clrscr();
177
    lcd_puts("CarDisplay");
178
 
179
    send_dimensions();
180
    lcd_gotoxy(0,1);
181
    lcd_puts("CAN Connected!");
182
 
183
    /* main loop */
184
    while(1){
185
        /* check if any messages have been received */
186
        if(rxMsgFull){
647 noddan 187
            uint16_t sns_type;
188
            uint8_t snsid;
189
            if ( ((rxMsg.Id & CAN_MASK_CLASS)>>CAN_SHIFT_CLASS) == CAN_SNS){// FIXME ett jŠkla herk, stŠda upp
190
 
191
                sns_type = (uint16_t)((rxMsg.Id & CAN_MASK_SNS_TYPE) >> CAN_SHIFT_SNS_TYPE);
192
                snsid = (uint8_t)((rxMsg.Id & CAN_MASK_SNS_ID) >> CAN_SHIFT_SNS_ID);
193
 
194
 
195
                if (sns_type == SNS_TYPE_PRESSURE) {
196
                    sensor_Boost = rxMsg.Data.bytes[0]*256 + rxMsg.Data.bytes[1];
197
                    if (currentScreen == SCR_BOOST) updateDisplay(SCR_BOOST,0);
198
                }
645 noddan 199
 
200
            }
201
            rxMsgFull = 0;
202
        }
203
    }
204
}
205
 
206
void send_dimensions(){
207
    Can_Message_t txMsg;
208
 
209
    txMsg.ExtendedFlag=1;
210
    txMsg.RemoteFlag=0;
211
    txMsg.Id=0xA000001;
212
    txMsg.Data.bytes[0] = SIZE_X;
213
    txMsg.Data.bytes[1] = SIZE_Y;
214
    txMsg.DataLength = 2;
215
 
216
    BIOS_CanSend(&txMsg);
217
}
218
 
219
void rotenc_action(uint8_t type){
220
    //Let's do something with something!
221
    lcd_clrscr();
222
    if (type == LEFT){ 
223
        if (currentScreen == 0) currentScreen = LAST_SCREEN+1;
224
        currentScreen--;
225
        updateDisplay(currentScreen,1);
226
    }
227
    if (type == RIGHT){
228
        currentScreen++;
229
        if (currentScreen > LAST_SCREEN) currentScreen = 0;
230
        updateDisplay(currentScreen,1);
231
    }
232
    if (type == BUTTON_PUSH){
233
 
234
    }
235
    if (type == BUTTON_RELEASE){
236
 
237
    }
238
}
239
 
240
void updateDisplay(uint8_t screen, uint8_t transition){
647 noddan 241
    char buffer[20];   
645 noddan 242
 
243
    if (transition){
244
        lcd_clrscr();
647 noddan 245
        lcd_setanimation(0);
246
    } else {
247
        lcd_setanimation(0);
645 noddan 248
    }
249
    switch (screen){
250
    case SCR_LAMBDA:
251
        lcd_gotoxy(0,0);
252
        lcd_puts("LEAN Lambda RICH");
253
        lcd_gotoxy(0,1);
254
        lcdProgressBar(sensor_Lambda, 255, 16); //TODO: vacker bargraph med bara en plupp i mitten
255
    break;
256
    case SCR_RPM:      
257
        lcd_gotoxy(0,0);
258
        itoa(sensor_RPM,buffer,10);
259
        lcd_puts("RPM: ");
260
        lcd_puts(buffer);
261
        lcd_gotoxy(0,1);
262
        lcdProgressBar(sensor_RPM, scale_RPMMAX, 16);
263
    break;
264
    case SCR_BOOST:
265
 
266
        lcd_gotoxy(0,0);
267
        lcd_puts("Boost:");
268
 
269
        lcd_gotoxy(7,0);
647 noddan 270
        //lcd_puts(io_s16toStr(((int32_t)sensor_Boost*scale_Boost)>>10,buffer,2,1));
271
        rattoascii(sensor_Boost,6,buffer);
272
        lcd_puts(buffer);
645 noddan 273
 
647 noddan 274
        //lcd_gotoxy(13,0);
275
        lcd_puts(" bar");
276
 
645 noddan 277
        lcd_gotoxy(0,1);
647 noddan 278
        lcdProgressBar(max(0,sensor_Boost), scale_BoostMAX, 16);
645 noddan 279
    break;
647 noddan 280
    case SCR_MAXBOOST: //currently just a testscreen ffs omg
645 noddan 281
        lcd_gotoxy(0,0);
282
        lcd_puts("Max Boost: ");
283
        lcd_gotoxy(11,0);
647 noddan 284
        lcd_gotoxy(0,1);
285
        rattoascii(0x0001,6,buffer);
286
        lcd_puts(buffer);
645 noddan 287
    break;
288
    case SCR_VOLTAGE:
289
 
290
        lcd_gotoxy(0,0);
291
        lcd_puts("Voltage:");
292
 
293
        lcd_gotoxy(9,0);
647 noddan 294
        //lcd_puts(io_u16toStr(((uint32_t)sensor_Voltage*scale_Voltage)>>10,buffer,1,0));
645 noddan 295
 
647 noddan 296
        lcd_gotoxy(14,0);
645 noddan 297
        lcd_puts("V");     
298
        lcd_puts("spanning!");
299
 
300
        lcd_gotoxy(0,1);
301
        lcdProgressBar(sensor_Voltage, scale_VoltageMAX, 16);
302
    break;
303
    }
304
}
305
 
306
void standardScreen(char* text, uint16_t value, uint16_t maxvalue){
307
    lcd_gotoxy(0,0);
308
    char buffer[5];
309
    itoa(value,buffer,10);
310
    lcd_puts(text);
311
    lcd_puts(" ");
312
    lcd_puts(buffer);
313
    lcd_gotoxy(0,1);
314
    lcdProgressBar(value, maxvalue, 16);
315
}
316
 
317
 
318
 
319
 
320
 
321
 
322
 
323
 
324
 
325
 
326
 
327
 
328
 
329
 
330
 
331
 
332
void rotenc(){
333
    uint8_t rot_data = 0;
334
    static uint8_t rot_lastdir = 0, rot_laststate = 0, btn_laststate = 0;
335
 
336
    Can_Message_t txMsg;
337
    txMsg.ExtendedFlag=1;
338
    txMsg.RemoteFlag=0;
339
    //txMsg.Id = ( CLASS_SNS<<CLASS_MASK_BITS )|( SNS_ACT_BUTTON<<SNS_TYPE_BITS )|( 0x01<<SNS_ID_BITS )| NODE_ID;//FIXME: borttaget
340
    txMsg.DataLength=2;
341
 
342
    //Take care of button push
343
    if ((PINB&(1<<PB7)) != btn_laststate){ //The buttonstate has changed! Let's send a message!
344
        btn_laststate = (PINB&(1<<PB7));
345
        txMsg.Data.bytes[0] = 5;
346
        txMsg.Data.bytes[1] = (btn_laststate)?0:1;
347
        txMsg.DataLength=2;
348
        BIOS_CanSend(&txMsg);
349
        rotenc_action((btn_laststate)?BUTTON_RELEASE:BUTTON_PUSH);
350
    }
351
 
352
    //Take care of rotary encoder movement
353
    if(PINB&(1<<PB0)){
354
        rot_data |= 0x01;
355
    }
356
    if(PIND&(1<<PD2)){
357
        rot_data |= 0x02;
358
    }
359
 
360
    if( rot_data==0 || rot_data==3 ){ // Are both signals high or low?
361
        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. 
362
            if( rot_lastdir&0x01 ){
363
                // Moving right
364
                txMsg.Data.bytes[0]=RIGHT;
365
                txMsg.Data.bytes[1] = (PINB&(1<<PB7))?0:1;
366
                txMsg.DataLength=2;
367
                BIOS_CanSend(&txMsg);
368
                rotenc_action(RIGHT);
369
            }else{
370
                // Moving left
371
                txMsg.Data.bytes[0]=LEFT;
372
                txMsg.Data.bytes[1] = (PINB&(1<<PB7))?0:1;
373
                txMsg.DataLength=2;
374
                BIOS_CanSend(&txMsg);
375
                rotenc_action(LEFT);
376
            }
377
        }
378
        rot_laststate = rot_data;
379
    } else { // No, only one of the signals are high. We can use this to find out what direction we are moving.
380
        rot_lastdir = rot_data;
381
    }
382
}
383
 
384
 
385
 
386
 
387
 
388
 
389
 
390
 
647 noddan 391
 
392
//‡ la pengi
393
void numtoascii( int16_t num, char **str ) {
394
    if( num==0 ) return;
395
    numtoascii( num/10, str );
396
    **str = '0' + (num%10);
397
    (*str)++;
398
}
399
 
400
void rattoascii( int16_t num, uint8_t decimalplace, char *string){ //decimalplace is number of decimals
401
    uint8_t i;
402
#define ANTAL_NUFFROR 3
403
    if( num<0 ) {
404
        *(string++) = '-';
405
        num = -num;
406
    }
407
    numtoascii(num>>decimalplace, &string );
408
    *(string++) = '.';
409
    for(i=0;i<ANTAL_NUFFROR;i++) {
410
        num %= 1<<decimalplace;
411
        num *= 10;
412
        *(string++) = '0' + (num>>decimalplace);
413
    }
414
    *(string++) = 0;
415
}
416
 
417
 
645 noddan 418
//Supersnodd:
419
 
420
 
421
 
422
uint8_t _io_buf[10];
423
 
647 noddan 424
 
425
/*
426
uint8_t *parsetemperature(int16_t value,uint8_t *str,uint8_t decimal,uint8_t options){
427
    uint16_t tmp;
428
    uint8_t i=0;
429
 
430
    //value = 0xfcf4;
431
    //decimal = 6;
432
 
433
    if(value<0) {
434
        str[i++]='-'; //add negative sign
435
        tmp=-value>>decimal;
436
    } else {
437
        if(options&0x01) str[i++]=' '; //Can the number be negative? Leave space for minussign
438
        tmp=value>>decimal;
439
    }  
440
 
441
    //Let's start axing up the value to print it beautifully. We have tmp, the integer part of the value
442
    while(tmp>0) {
443
        str[i++]='0' + (tmp%10);
444
        tmp=tmp/10;
445
    }  
446
 
447
    //now we hafve printed all of zat
448
    str[i++] = '.';
449
 
450
    //let's go on to the fractional part... (cwap!)
451
 
452
 
453
    str[i++]=0;
454
    return(str);
455
}
456
*/
457
 
458
// nŒn annans rutin som jag inte riktigt fšrstŒr mig pŒ.
645 noddan 459
uint8_t *io_s16toStr(int16_t value,uint8_t *str,uint8_t decimal,uint8_t options) {
460
    uint8_t i=0,j=0,w=0;
461
    uint16_t tmp;
462
 
463
    if(value<0) {
464
        str[i++]='-';
465
        tmp=-value;
466
    } else {
467
        if(options&0x01) str[i++]=' ';
468
        tmp=value;
469
    }
470
    while(tmp>0) {
471
        _io_buf[j++]='0'+(tmp%10);
472
        tmp=tmp/10;
473
    }
474
    if(j<=decimal) {
475
        str[i++]='0';
476
        if(decimal>0) str[i++]='.';
477
        w=i;
478
        while((i-w)<(decimal-j)) str[i++]='0';
479
        while(j!=0) str[i++]=_io_buf[--j];
480
    } else {
481
        while(j!=0) {
482
            str[i++]=_io_buf[--j];
483
            if(j==decimal) str[i++]='.';
484
        }
485
    }
486
    str[i++]=0;
487
    return(str);
488
}
489
 
490
uint8_t *io_u16toStr(uint16_t value,uint8_t *str,uint8_t decimal,uint8_t options) {
491
    uint8_t i=0;
492
    uint8_t j=0;
493
    uint8_t w=0;
494
 
495
    while(value>0) {
496
        _io_buf[j++]='0'+(value%10);
497
        value=value/10;
498
    }
499
 
500
    if(j<=decimal) {
501
        str[i++]='0';
502
        if(decimal>0) str[i++]='.';
503
        w=i;
504
        while((i-w)<(decimal-j)) str[i++]='0';
505
        while(j!=0) str[i++]=_io_buf[--j];
506
    } else {
507
        while(j>0) {
508
            str[i++]=_io_buf[--j];
509
            if((decimal>0)&&(j==decimal)) str[i++]='.';
510
        }
511
    }
512
    str[i++]=0;
513
    return(str);
514
}