Subversion Repositories HomeAutomation

Rev

Rev 389 | Rev 671 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /**
  2.  * CAN test program.
  3.  *
  4.  * @target  AVR
  5.  * @date    2006-10-29
  6.  * @author  Jimmy Myhrman, Andreas Fritiofsson
  7.  *  
  8.  */
  9.  
  10. /*-----------------------------------------------------------------------------
  11.  * Includes
  12.  *---------------------------------------------------------------------------*/
  13. /* system files */
  14. #include <avr/io.h>
  15. #include <avr/interrupt.h>
  16. #include <avr/wdt.h>
  17. #include <avr/eeprom.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. /* lib files */
  21. #include <mcp2515.h>
  22. #include <serial.h>
  23. #include <uart.h>
  24. #include <timebase.h>
  25.  
  26.  
  27. /*-----------------------------------------------------------------------------
  28.  * Defines
  29.  *---------------------------------------------------------------------------*/
  30. #define UART_START_BYTE 253
  31. #define UART_END_BYTE 250
  32.  
  33. volatile Can_Message_t rxMsg; // Message storage
  34. volatile uint8_t rxMsgFull;   // Synchronization flag
  35.  
  36. const uint8_t days[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
  37.  
  38. union {
  39.     uint32_t packed;
  40.     struct date_t {
  41.         unsigned ss:6;
  42.         unsigned mm:6;
  43.         unsigned hh:5;
  44.         unsigned DD:5;
  45.         unsigned MM:4;
  46.         unsigned YY:6;
  47.     } unpacked;
  48. } date;
  49.  
  50. #if SENDTIMESTAMP == 1
  51. void IncTime(void) {
  52.     static uint8_t YY=07, MM=03, DD=02, hh=23, mm=58, ss=00;
  53.    
  54.     if (ss++ > 59) {
  55.         ss=0;
  56.         if (mm++ > 59) {
  57.             mm=0;
  58.             if (hh++ > 23) {
  59.                 hh=0;
  60.                 if (DD++ > days[MM-1] + ((YY%4) & (MM==2)) ? 1 : 0) {
  61.                     DD=1;
  62.                     if (MM++ > 12) {
  63.                         MM=1; YY++;
  64.                     }
  65.                 }
  66.             }
  67.         }
  68.     }
  69.     date.unpacked.YY = YY;
  70.     date.unpacked.MM = MM;
  71.     date.unpacked.DD = DD;
  72.     date.unpacked.hh = hh;
  73.     date.unpacked.mm = mm;
  74.     date.unpacked.ss = ss;
  75. }
  76. #endif
  77. /*-----------------------------------------------------------------------------
  78.  * Functions
  79.  *---------------------------------------------------------------------------*/
  80. /**
  81.  * Parses an incoming UART byte by maintaining a state machine. The UART
  82.  * bytes will build up a CAN message according to the protocol described here:
  83.  *
  84.  * http://www.arune.se/projekt/doku.php?id=homeautomation:pc-mjukvara
  85.  *
  86.  * @param c
  87.  *      The received UART byte.
  88.  */
  89. void UartParseByte(uint8_t c) {
  90.     static Can_Message_t cm;
  91.     static uint8_t waitingMessage = 0;
  92.     static uint32_t startTime = 0;
  93.     static int8_t count = 0;
  94.    
  95.     /* 50ms timeout */
  96.     if (waitingMessage && Timebase_PassedTimeMillis(startTime) > 50) {
  97.         waitingMessage = 0;
  98.     }
  99.    
  100.     if (waitingMessage) {
  101.         /* save start time */
  102.         startTime = Timebase_CurrentTime();
  103.         /* UART END */
  104.         if (count >= 15) {
  105.             if (c == UART_END_BYTE) {
  106.                 PORTC ^= (1<<PC0);
  107.                 Can_Send(&cm);
  108.             }
  109.             waitingMessage = 0;
  110.             return;
  111.         }
  112.         /* data */
  113.         else if (count >= 7) {
  114.             cm.Data.bytes[count-7] = c;
  115.             count++;
  116.             return;
  117.         }
  118.         /* data length */
  119.         else if (count >= 6) {
  120.             cm.DataLength = c;
  121.             count++;
  122.             return;
  123.         }
  124.         /* remote request flag */
  125.         else if (count >= 5) {
  126.             cm.RemoteFlag = c;
  127.             count++;
  128.             return;
  129.         }
  130.         /* extended */
  131.         else if (count >= 4) {
  132.             cm.ExtendedFlag = c;
  133.             count++;
  134.             return;
  135.         }
  136.         /* ident */
  137.         else if (count >= 0) {
  138.             cm.Id += ((uint32_t)c << (count*8));
  139.             count++;
  140.             return;
  141.         }
  142.     }
  143.    
  144.     if (c == UART_START_BYTE && !waitingMessage) {
  145.         waitingMessage = 1;
  146.         startTime = Timebase_CurrentTime();
  147.         count = 0;
  148.         cm.Id = 0;
  149.         return;
  150.     }
  151. }
  152.  
  153. void Can_Process(Can_Message_t* msg) {
  154.     if (!(msg->ExtendedFlag)) return; // We don't care about standard CAN frames.
  155.  
  156.     if (!rxMsgFull) {
  157.         memcpy((void*)&rxMsg, msg, sizeof(rxMsg));
  158.         rxMsgFull = 1;
  159.     }
  160. }
  161.  
  162. ISR(MCP_INT_VECTOR) {
  163.     // Get first available message from controller and pass it to
  164.     // application handler. If both RX buffers contain messages
  165.     // we will get another interrupt as soon as this one returns.
  166.     if (Can_Receive(&rxMsg) == CAN_OK) {
  167.         // Callbacks are run with global interrupts disabled but
  168.         // with controller flag cleared so another msg can be
  169.         // received while this one is processed.
  170.         Can_Process(&rxMsg);
  171.     }
  172. }
  173.  
  174.  
  175. /*-----------------------------------------------------------------------------
  176.  * Main Program
  177.  *---------------------------------------------------------------------------*/
  178. int main(void) {
  179. //  For calibrating internal oscillator
  180. //  OSCCAL = eeprom_read_byte(0);
  181.     Timebase_Init();
  182.     Serial_Init();
  183.     Can_Init();
  184.    
  185.     DDRC = 1<<PC1 | 1<<PC0;
  186.     PORTC = (1<<PC1) | (1<<PC0);
  187.    
  188.     sei();
  189.    
  190.     Can_Message_t timeMsg;
  191. #if SENDTIMESTAMP == 1
  192.     uint32_t time = Timebase_CurrentTime();
  193.     uint32_t time1 = time;
  194.     uint32_t unixtime = 0;
  195. #endif
  196.     uint16_t rxByte;
  197.     uint8_t i = 0;
  198.    
  199. #if SENDTIMESTAMP == 1
  200.     timeMsg.ExtendedFlag = 1;
  201.     timeMsg.RemoteFlag = 0;
  202.     timeMsg.Id = (CAN_NMT << CAN_SHIFT_CLASS) | (CAN_NMT_TIME << CAN_SHIFT_NMT_TYPE);
  203.     //timeMsg.Id = 0; //Same thing, and lib's can.h is not updated.
  204.     timeMsg.DataLength = 8;
  205. #endif
  206.    
  207.     /* main loop */
  208.     while (1) {
  209.         /* any new CAN messages received? */
  210.         if (rxMsgFull) {
  211.             // Toggle activity LED
  212.             PORTC ^= (1<<PC1);
  213.             /* send message to CanWatcher */
  214.             uart_putc(UART_START_BYTE);
  215.             uart_putc((uint8_t)rxMsg.Id);
  216.             uart_putc((uint8_t)(rxMsg.Id>>8));
  217.             uart_putc((uint8_t)(rxMsg.Id>>16));
  218.             uart_putc((uint8_t)(rxMsg.Id>>24));
  219.             uart_putc(rxMsg.ExtendedFlag);
  220.             uart_putc(rxMsg.RemoteFlag);
  221.             uart_putc(rxMsg.DataLength);
  222.             for (i=0; i<8; i++) {
  223.                 uart_putc(rxMsg.Data.bytes[i]);
  224.             }
  225.             uart_putc(UART_END_BYTE);
  226.            
  227.             rxMsgFull = 0;
  228.         }
  229.        
  230.         /* any UART bytes received? */
  231.         rxByte = uart_getc();
  232.         while (rxByte != UART_NO_DATA) {
  233.             /* parse byte! */
  234.             UartParseByte((uint8_t)(rxByte & 0x00FF));
  235.             /* receive next */
  236.             rxByte = uart_getc();
  237.         }
  238.        
  239. #if SENDTIMESTAMP == 1
  240.         time1 = Timebase_CurrentTime();
  241.         if ((time1 - time) > 1000) {
  242.             time = time1;
  243.             timeMsg.Data.dwords[0] = ++unixtime;
  244.             IncTime();
  245.             timeMsg.Data.dwords[1] = date.packed;
  246.             Can_Send(&timeMsg);
  247.         }
  248. #endif
  249.     }
  250.    
  251.     return 0;
  252. }
  253.