Subversion Repositories HomeAutomation

Rev

Rev 645 | Rev 653 | Go to most recent revision | 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_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.  
  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);
  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
  94. int16_t sensor_Boost_Max = 200;  //highest boost so far
  95.  
  96. uint16_t sensor_RPM = 2573;
  97. uint8_t sensor_Lambda = 127;
  98. uint8_t sensor_Voltage = 143;
  99.  
  100. #define scale_Boost 200 //see "Representation av storheter"
  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){
  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.                 }
  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){
  241.     char buffer[20];   
  242.    
  243.     if (transition){
  244.         lcd_clrscr();
  245.         lcd_setanimation(0);
  246.     } else {
  247.         lcd_setanimation(0);
  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);
  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);
  273.        
  274.         //lcd_gotoxy(13,0);
  275.         lcd_puts(" bar");
  276.        
  277.         lcd_gotoxy(0,1);
  278.         lcdProgressBar(max(0,sensor_Boost), scale_BoostMAX, 16);
  279.     break;
  280.     case SCR_MAXBOOST: //currently just a testscreen ffs omg
  281.         lcd_gotoxy(0,0);
  282.         lcd_puts("Max Boost: ");
  283.         lcd_gotoxy(11,0);
  284.         lcd_gotoxy(0,1);
  285.         rattoascii(0x0001,6,buffer);
  286.         lcd_puts(buffer);
  287.     break;
  288.     case SCR_VOLTAGE:
  289.  
  290.         lcd_gotoxy(0,0);
  291.         lcd_puts("Voltage:");
  292.        
  293.         lcd_gotoxy(9,0);
  294.         //lcd_puts(io_u16toStr(((uint32_t)sensor_Voltage*scale_Voltage)>>10,buffer,1,0));
  295.        
  296.         lcd_gotoxy(14,0);
  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.  
  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.  
  418. //Supersnodd:
  419.  
  420.  
  421.  
  422. uint8_t _io_buf[10];
  423.  
  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Œ.
  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. }
  515.