Subversion Repositories HomeAutomation

Rev

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

  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.  *
  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
  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_BOOST       0x00
  74. #define SCR_MAXBOOST    0x01
  75. #define SCR_LAMBDA      0x02
  76. #define SCR_RPM         0x03
  77. #define SCR_VOLTAGE     0x04
  78. #define SCR_VELOCITY    0x05
  79. #define SCR_FUELCONS    0x06
  80. //#define SCR_OILPRESS  0x07
  81. //#define SCR_OILTEMP   0x08
  82. #define LAST_SCREEN     0x06
  83.  
  84. void numtoascii( int16_t num, char **str );
  85. void signedtoascii(int16_t num, uint8_t decimalplace, char *string, uint8_t numberofdecimals);
  86. void unsignedtoascii(uint16_t num, uint8_t decimalplace, char *string, uint8_t numberofdecimals);
  87.  
  88.  
  89.  
  90. /*******************************************************************************
  91.  * Sensor Values, Scale factors etc.                                           *
  92.  *******************************************************************************/
  93. int16_t     sensor_Boost        = 0.001*64;
  94. int16_t     sensor_Boost_Max    = 0.92*64;  //highest boost so far
  95. uint16_t    sensor_Lambda       = 32000;
  96. uint16_t    sensor_RPM          = 3973*(2<<(SNS_DECPOINT_ROTSPEED-1));
  97. uint16_t    sensor_Voltage      = 12.7*(2<<(SNS_DECPOINT_VOLTAGE-1));
  98. uint16_t    sensor_Velocity     = 120*(2<<(SNS_DECPOINT_VELOCITY-1));
  99. uint16_t    sensor_Fuelcons     = 0.78*(2<<(SNS_DECPOINT_FUELCONS-1));
  100.  
  101. #define SCALE_BOOSTMAX 1.2*64 //depending on memory usage later, maybe put these in eeprom?
  102. #define SCALE_LAMBDAMAX 65535
  103. #define SCALE_RPMMAX 8000*(2<<(SNS_DECPOINT_ROTSPEED-1))
  104. #define SCALE_VOLTAGEMAX 15*(2<<(SNS_DECPOINT_VOLTAGE-1))
  105. #define SCALE_VELOCITYMAX 150*(2<<(SNS_DECPOINT_VELOCITY-1))
  106. #define SCALE_FUELCONSMAX 2*(2<<(SNS_DECPOINT_FUELCONS-1))
  107.  
  108.  
  109.  
  110. /*******************************************************************************
  111.  * Something else..                                                            *
  112.  *******************************************************************************/
  113.  
  114. uint8_t currentScreen; //current screen
  115.  
  116. // CAN message reception callback
  117. // This function runs with interrupts disabled, keep it as short as possible
  118. void can_receive(Can_Message_t *msg){
  119.     if(!rxMsgFull){
  120.         memcpy((void*)&rxMsg, msg, sizeof(rxMsg));
  121.         rxMsgFull = 1;
  122.     }
  123. }
  124.  
  125. ISR( PCINT2_vect ){
  126. // For ROTENC_A and ROTENC_B FIXME Šr inte riktigt rŠtt. Verkar vara bra tycker jag?
  127.     rotenc();
  128. }
  129.  
  130. ISR( PCINT0_vect ){
  131. // For ROTENC_BTN
  132.     rotenc();
  133. }
  134.  
  135. /*-----------------------------------------------------------------------------
  136.  * Main Program
  137.  *---------------------------------------------------------------------------*/
  138. int main(void) {
  139.     currentScreen = 0; //init display position
  140.    
  141. //  uint32_t act; not used anymoer
  142. //  uint8_t act_type, lcd_size; not used anymore
  143.     //uint8_t m, lcd_action;
  144.  
  145.     sei();
  146.  
  147.     /*
  148.      * Initialize rotaryencoders and buttons
  149.      */
  150.     // Set as input
  151.     DDRD &= ~(1<<DDD2);
  152.     DDRB &= ~((1<<DDB7)|(1<<DDB0));
  153.     // Enable pull-up
  154.     PORTD |= (1<<PD2);
  155.     PORTB |= (1<<PB7)|(1<<PB0);
  156.     // Enable IO-pin interrupt
  157.     PCICR |= (1<<PCIE2)|(1<<PCIE0);
  158.     // Unmask PB7, PB0 and PD2
  159.     PCMSK2 |= (1<<PCINT18);
  160.     PCMSK0 |= (1<<PCINT7)|(1<<PCINT0);
  161.  
  162.     // Contrast
  163.     TCCR0A |= (1<<COM0B1)|(1<<WGM01)|(1<<WGM00);
  164.     TCCR0B |= (1<<CS00);
  165.     OCR0B = 0x10;
  166.     DDRD |= (1<<DDD5);
  167.  
  168.     // Backlight
  169.     TCCR1A |= (1<<COM1A1)|(1<<WGM11);
  170.     TCCR1B |= (1<<WGM13)|(1<<WGM12)|(1<<CS10);
  171.     ICR1 = 0xFF; // Make it 8 bits
  172.     OCR1A = 0xFF;
  173.     DDRB |= (1<<DDB1);
  174.  
  175.  
  176.     Can_Message_t txMsg;
  177.     txMsg.ExtendedFlag=1;
  178.     txMsg.RemoteFlag=0;
  179. // FIXME skicka app startad
  180.     BIOS_CanCallback = &can_receive;
  181.  
  182.     lcd_init( LCD_DISP_ON );
  183.     lcd_clrscr();
  184.     lcd_puts("CarDisplay");
  185.  
  186.     send_dimensions();
  187.     lcd_gotoxy(0,1);
  188.     lcd_puts("CAN Connected!");
  189.  
  190.     /* main loop */
  191.     while(1){
  192.         /* check if any messages have been received */
  193.         if(rxMsgFull){
  194.             uint16_t sns_type;
  195.             uint8_t snsid;
  196.             if ( ((rxMsg.Id & CAN_MASK_CLASS)>>CAN_SHIFT_CLASS) == CAN_SNS){// FIXME ett jŠkla herk, stŠda upp
  197.            
  198.                 sns_type = (uint16_t)((rxMsg.Id & CAN_MASK_SNS_TYPE) >> CAN_SHIFT_SNS_TYPE);
  199.                 snsid = (uint8_t)((rxMsg.Id & CAN_MASK_SNS_ID) >> CAN_SHIFT_SNS_ID);
  200.                
  201.                 switch(sns_type){
  202.                 case SNS_TYPE_PRESSURE:
  203.                     sensor_Boost = rxMsg.Data.bytes[0]*256 + rxMsg.Data.bytes[1];
  204.                     sensor_Boost_Max = max(sensor_Boost,sensor_Boost_Max);
  205.                     if (currentScreen == SCR_BOOST) updateDisplay(SCR_BOOST,0);        
  206.                 break;
  207.                 case SNS_TYPE_ROTSPEED:
  208.                     sensor_RPM = rxMsg.Data.bytes[0]*256 + rxMsg.Data.bytes[1];
  209.                     if (currentScreen == SCR_RPM) updateDisplay(SCR_RPM,0);
  210.                 break;
  211.                 case SNS_TYPE_VOLTAGE:
  212.                     sensor_Voltage = rxMsg.Data.bytes[0]*256 + rxMsg.Data.bytes[1];
  213.                     if (currentScreen == SCR_VOLTAGE) updateDisplay(SCR_VOLTAGE,0);
  214.                 }
  215.  
  216.             }
  217.             rxMsgFull = 0;
  218.         }
  219.     }
  220. }
  221.  
  222. void send_dimensions(){
  223.     Can_Message_t txMsg;
  224.  
  225.     txMsg.ExtendedFlag=1;
  226.     txMsg.RemoteFlag=0;
  227.     txMsg.Id=0xA000001;
  228.     txMsg.Data.bytes[0] = SIZE_X;
  229.     txMsg.Data.bytes[1] = SIZE_Y;
  230.     txMsg.DataLength = 2;
  231.  
  232.     BIOS_CanSend(&txMsg);
  233. }
  234.  
  235. void rotenc_action(uint8_t type){
  236.     //Let's do something with something!
  237.    
  238.     if (type == LEFT){ 
  239.         if (currentScreen == 0) currentScreen = LAST_SCREEN+1;
  240.         currentScreen--;
  241.         updateDisplay(currentScreen,1);
  242.     }
  243.     if (type == RIGHT){
  244.         currentScreen++;
  245.         if (currentScreen > LAST_SCREEN) currentScreen = 0;
  246.         updateDisplay(currentScreen,1);
  247.     }
  248.     if (type == BUTTON_PUSH){
  249.  
  250.     }
  251.     if (type == BUTTON_RELEASE){
  252.  
  253.     }
  254. }
  255.  
  256. void updateDisplay(uint8_t screen, uint8_t transition){
  257.     char buffer[20];   
  258.    
  259.     if (transition){
  260.         lcd_clrscr();
  261.         lcd_setanimation(1);
  262.     } else {
  263.         lcd_setanimation(0);
  264.     }
  265.     switch (screen){
  266.     case SCR_LAMBDA:
  267.         lcd_gotoxy(0,0);
  268.         lcd_puts("LEAN   Lambda   RICH");
  269.         lcd_gotoxy(0,1);
  270.         lcdProgressBar(sensor_Lambda, SCALE_LAMBDAMAX, SIZE_X); //TODO: vacker bargraph med bara en plupp i mitten
  271.     break;
  272.     case SCR_RPM:      
  273.         lcd_gotoxy(0,0);
  274.         lcd_puts("RPM: ");
  275.         unsignedtoascii(sensor_RPM,SNS_DECPOINT_ROTSPEED,buffer,0);
  276.         lcd_puts(buffer);
  277.         lcd_gotoxy(0,1);
  278.         lcdProgressBar(sensor_RPM, SCALE_RPMMAX, SIZE_X);
  279.     break;
  280.     case SCR_BOOST:        
  281.         lcd_gotoxy(0,0);
  282.         lcd_puts("Boost: ");   
  283.         signedtoascii(sensor_Boost,SNS_DECPOINT_PRESSURE,buffer,2);
  284.         lcd_puts(buffer);
  285.         lcd_puts(" bar    ");
  286.        
  287.         lcd_gotoxy(0,1);
  288.         lcdProgressBar(max(0,sensor_Boost), SCALE_BOOSTMAX, SIZE_X);
  289.     break;
  290.     case SCR_MAXBOOST: //currently just a testscreen ffs omg
  291.         lcd_gotoxy(0,0);
  292.         lcd_puts("Max Boost: ");
  293.         signedtoascii(sensor_Boost_Max ,SNS_DECPOINT_PRESSURE,buffer,2);
  294.         lcd_puts(buffer);
  295.         lcd_puts(" bar");
  296.     break;
  297.     case SCR_VOLTAGE:
  298.         lcd_gotoxy(0,0);
  299.         lcd_puts("Voltage: "); 
  300.         unsignedtoascii(sensor_Voltage,SNS_DECPOINT_VOLTAGE,buffer,2);
  301.         lcd_puts(buffer);
  302.         lcd_puts(" V");    
  303.         lcd_gotoxy(0,1);
  304.         lcdProgressBar(max(0,sensor_Voltage), SCALE_VOLTAGEMAX, SIZE_X);
  305.     break;
  306.     case SCR_FUELCONS:
  307.         lcd_gotoxy(0,0);
  308.         lcd_puts("Fuel: ");
  309.         unsignedtoascii(sensor_Fuelcons,SNS_DECPOINT_FUELCONS,buffer,2);
  310.         lcd_puts(buffer);
  311.         lcd_puts(" L/10km");       
  312.         lcd_gotoxy(0,1);
  313.         lcdProgressBar(max(0,sensor_Fuelcons), SCALE_FUELCONSMAX, SIZE_X);
  314.     break;
  315.     case SCR_VELOCITY:
  316.         lcd_gotoxy(0,0);
  317.         lcd_puts("Speed: ");   
  318.         unsignedtoascii(sensor_Velocity,SNS_DECPOINT_VELOCITY,buffer,0);
  319.         lcd_puts(buffer);
  320.         lcd_puts(" km/h");     
  321.         lcd_gotoxy(0,1);
  322.         lcdProgressBar(max(0,sensor_Velocity), SCALE_VELOCITYMAX, SIZE_X);
  323.     break;
  324.     }
  325. }
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.  
  339.  
  340. void rotenc(){
  341.     uint8_t rot_data = 0;
  342.     static uint8_t rot_lastdir = 0, rot_laststate = 0, btn_laststate = 0;
  343.  
  344.     Can_Message_t txMsg;
  345.     txMsg.ExtendedFlag=1;
  346.     txMsg.RemoteFlag=0;
  347.     //txMsg.Id = ( CLASS_SNS<<CLASS_MASK_BITS )|( SNS_ACT_BUTTON<<SNS_TYPE_BITS )|( 0x01<<SNS_ID_BITS )| NODE_ID;//FIXME: borttaget
  348.     txMsg.DataLength=2;
  349.  
  350.     //Take care of button push
  351.     if ((PINB&(1<<PB7)) != btn_laststate){ //The buttonstate has changed! Let's send a message!
  352.         btn_laststate = (PINB&(1<<PB7));
  353.         txMsg.Data.bytes[0] = 5;
  354.         txMsg.Data.bytes[1] = (btn_laststate)?0:1;
  355.         txMsg.DataLength=2;
  356.         BIOS_CanSend(&txMsg);
  357.         rotenc_action((btn_laststate)?BUTTON_RELEASE:BUTTON_PUSH);
  358.     }
  359.    
  360.     //Take care of rotary encoder movement
  361.     if(PINB&(1<<PB0)){
  362.         rot_data |= 0x01;
  363.     }
  364.     if(PIND&(1<<PD2)){
  365.         rot_data |= 0x02;
  366.     }
  367.  
  368.     if( rot_data==0 || rot_data==3 ){ // Are both signals high or low?
  369.         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.
  370.             if( rot_lastdir&0x01 ){
  371.                 // Moving right
  372.                 txMsg.Data.bytes[0]=RIGHT;
  373.                 txMsg.Data.bytes[1] = (PINB&(1<<PB7))?0:1;
  374.                 txMsg.DataLength=2;
  375.                 BIOS_CanSend(&txMsg);
  376.                 rotenc_action(RIGHT);
  377.             }else{
  378.                 // Moving left
  379.                 txMsg.Data.bytes[0]=LEFT;
  380.                 txMsg.Data.bytes[1] = (PINB&(1<<PB7))?0:1;
  381.                 txMsg.DataLength=2;
  382.                 BIOS_CanSend(&txMsg);
  383.                 rotenc_action(LEFT);
  384.             }
  385.         }
  386.         rot_laststate = rot_data;
  387.     } else { // No, only one of the signals are high. We can use this to find out what direction we are moving.
  388.         rot_lastdir = rot_data;
  389.     }
  390. }
  391.  
  392.  
  393.  
  394. //‡ la pengi. Skall libbifieras.
  395. void numtoascii( int16_t num, char **str ) {
  396.     if( num==0 ) return;
  397.     numtoascii( num/10, str );
  398.     **str = '0' + (num%10);
  399.     (*str)++;
  400. }
  401.  
  402. void signedtoascii(int16_t num, uint8_t decimalplace, char *string, uint8_t numberofdecimals){ //decimalplace is number of decimals
  403.     uint8_t i;
  404.  
  405.     if( num<0 ) {
  406.         *(string++) = '-';
  407.         num = -num;
  408.     }
  409.     numtoascii(num>>decimalplace, &string );
  410.     if(numberofdecimals!=0) *(string++) = '.';
  411.     for(i=0;i<numberofdecimals;i++) {
  412.         num %= 1<<decimalplace;
  413.         num *= 10;
  414.         *(string++) = '0' + (num>>decimalplace);
  415.     }
  416.     *(string++) = 0;
  417. }
  418.  
  419. void unsignedtoascii(uint16_t num, uint8_t decimalplace, char *string, uint8_t numberofdecimals){ //decimalplace is number of decimals
  420.     uint8_t i;
  421.     numtoascii(num>>decimalplace, &string );
  422.     if(numberofdecimals!=0) *(string++) = '.';
  423.     for(i=0;i<numberofdecimals;i++) {
  424.         num %= 1<<decimalplace;
  425.         num *= 10;
  426.         *(string++) = '0' + (num>>decimalplace);
  427.     }
  428.     *(string++) = 0;
  429. }
  430.  
  431.  
  432.