Subversion Repositories HomeAutomation

Rev

Rev 259 | Blame | Last modification | View Log | SVN | RSS feed

  1. #include "bios_funs.h"
  2. #include "avr_cfg.h"
  3. #include <inttypes.h>
  4. #include <avr/io.h>
  5. #include <avr/interrupt.h>
  6. #include <avr/wdt.h>
  7. #include <avr/pgmspace.h>
  8. #ifdef BIOS_UART
  9. #include <stdio.h>
  10. #endif
  11. #include <string.h>
  12. #include "flash.h"
  13. #include "vectors.h" // Must be included after sfr_defs.h but before any ISR()
  14. #include "mcp2515/mcp2515.h"
  15.  
  16. //---------------------------------------------------------------------------
  17. // Globals
  18.  
  19. volatile uint32_t gMilliSecTick;
  20. volatile uint8_t bios_msg_full;
  21. Can_Message_t* bios_msg_ptr; // only a pointer to main-local structure to save .bss space
  22.  
  23. //---------------------------------------------------------------------------
  24. // Function definitions for the exported interface
  25.  
  26. void reset(void) {
  27.     //Just loop and let the watchdog reset
  28.     cli();
  29.     while(1);
  30. }
  31.  
  32. #ifdef BIOS_UART
  33. void bios_putchar(char c) {
  34.     UART_PUTCHAR(c);
  35. }
  36.  
  37. char bios_getchar(void) {
  38.     char c;
  39.     UART_GETCHAR(c)
  40.     return c;
  41. }
  42. #endif
  43.  
  44. unsigned long timebase_get(void) {
  45.     uint8_t sreg;
  46.     unsigned long res;
  47.    
  48.     //Disable interrupts while reading tick count
  49.     sreg=SREG;
  50.     cli();
  51.    
  52.     res = gMilliSecTick;
  53.    
  54.     SREG=sreg;
  55.    
  56.     return res;
  57. }
  58.  
  59. // TODO: Insert can driver's Can_Send directly in bios interface.
  60. Can_Return_t can_send(Can_Message_t* msg) {
  61.     return Can_Send(msg);
  62. }
  63.  
  64. //---------------------------------------------------------------------------
  65. // Function definitions for the private functions
  66.  
  67. #ifdef BIOS_UART
  68. static int console_getchar(FILE *stream) {
  69.     return bios_getchar();
  70. }
  71.  
  72. static int console_putchar(char c, FILE *stream) {
  73.     bios_putchar(c);
  74.     return 0;
  75. }
  76.  
  77. static FILE bios_stdio = FDEV_SETUP_STREAM(console_putchar, console_getchar,
  78.                                          _FDEV_SETUP_RW);
  79. #endif
  80.  
  81. //---------------------------------------------------------------------------
  82. // Interrupt Service Routines
  83. // Read app_vectors.h!
  84.  
  85. ISR(TIMEBASE_VECTOR) {
  86.     TIMEBASE_COUNTER -= TIMEBASE_RELOAD;
  87.     gMilliSecTick++;
  88.     wdt_reset();
  89. }
  90.  
  91. void Can_Process(Can_Message_t* msg) {
  92.     if (!(msg->ExtendedFlag)) return;
  93.    
  94.     //applikationen ska bara ta hand om paket som inte är nmt så else:et nedan kommer om det inte är nmt enbart
  95.     if ((msg->Id & CAN_MASK_CLASS) == ((uint32_t)CAN_NMT << CAN_SHIFT_CLASS)) {
  96.         if ((msg->Id & CAN_MASK_NMT_RID) == ((uint32_t)NODE_ID << CAN_SHIFT_NMT_RID)) {
  97.             //printf("BIOS received msg!\n");
  98.             if ((msg->Id & CAN_MASK_NMT_TYPE)>>CAN_SHIFT_NMT_TYPE == CAN_NMT_RESET) {
  99.                 reset();
  100.             }
  101.             // Copy message to bios buffer if bios is done with the previous message.
  102.             // This is also a check to see if bios is still running. When app is
  103.             // started, bios_msg_full is never reset to 0 so the check fails and all
  104.             // NMT communication except reset is ignored.
  105.             if (!(bios_msg_full)) {
  106.                 memcpy(bios_msg_ptr, msg, sizeof(Can_Message_t));
  107.                 bios_msg_full = 1;
  108.             }      
  109.         } else if (bios->can_callback) {
  110.             //printf("Calling app callback.\n");
  111.             bios->can_callback(msg);
  112.         }
  113.     }
  114. }
  115.  
  116. #define BIOS_APP    1
  117. #define BIOS_NOAPP  2
  118. #define BIOS_PGM    3
  119.  
  120. int main() {
  121.     void (*app_reset)(void) = 0;
  122.     uint8_t bios_state;
  123.     uint8_t nmt_type;
  124.     uint16_t base_addr = 0;
  125.     uint16_t offset;
  126.     uint16_t addr;
  127.     uint8_t len;
  128.     uint8_t i;
  129.     uint16_t data;
  130.     Can_Message_t tx_msg;
  131.     Can_Message_t bios_msg;
  132.     bios_msg_ptr = &bios_msg;
  133.    
  134. #ifdef BIOS_UART
  135.     // Setup USART for debug channel
  136.     UART_INIT();
  137.     stdout = &bios_stdio;
  138.     stdin = &bios_stdio;
  139. #endif
  140.    
  141.     // Initialize a suitable hardware timer to create a 1KHz interrupt.
  142.     TIMEBASE_INIT();
  143.    
  144.     // Enable watchdog timer to protect against an application locking the
  145.     // node by leaving interrupts disabled.
  146.     wdt_enable(WDTO_500MS);
  147.    
  148.     // Move interrupt vectors to start of bootloader section and enable interrupts
  149.     IVSEL_REG = _BV(IVCE);
  150.     IVSEL_REG = _BV(IVSEL);
  151.     sei();
  152.    
  153.     if (Can_Init() != CAN_OK) reset();
  154.    
  155.     tx_msg.RemoteFlag = 0;
  156.     tx_msg.ExtendedFlag = 1;
  157.     tx_msg.Id = CAN_ID_NMT_BIOS_START;
  158.     tx_msg.DataLength = 3;
  159.     tx_msg.Data.words[0] = BIOS_VERSION;
  160.            
  161.     if (pgm_read_word(0) == 0xffff) {
  162.         // No application in flash
  163.         //send CAN_NMT_BIOS_START(BIOS_VERSION, 0)
  164.         tx_msg.Data.bytes[2] = 0;
  165.         bios_state = BIOS_NOAPP;
  166.     } else {
  167.         // Application exists
  168.         //send CAN_NMT_BIOS_START(BIOS_VERSION, 1)
  169.         tx_msg.Data.bytes[2] = 1;
  170.         bios_state = BIOS_APP;
  171.     }
  172.    
  173.     while (Can_Send(&tx_msg) != CAN_OK);
  174.  
  175.     tx_msg.DataLength = 2;
  176.    
  177.     // main loop
  178.     while (1) {
  179.         // Wait for message
  180.         while (!bios_msg_full);
  181.         nmt_type = (bios_msg.Id & CAN_MASK_NMT_TYPE)>>CAN_SHIFT_NMT_TYPE;
  182.        
  183.         switch (bios_state) {
  184.         case BIOS_APP:
  185.             if (nmt_type == CAN_NMT_START_APP) {
  186.                 app_reset(); // Will never return
  187.             }
  188.             // Fall through
  189.         case BIOS_NOAPP:
  190.             if (nmt_type == CAN_NMT_PGM_START) {
  191.                 // Set base address
  192.                 base_addr = bios_msg.Data.words[0];
  193.                 flash_init();
  194.                 //send CAN_NMT_PGM_ACK(offset)
  195.                 tx_msg.Id = CAN_ID_NMT_PGM_ACK;
  196.                 tx_msg.Data.words[0] = base_addr;
  197.                 bios_state = BIOS_PGM;
  198.                 while (Can_Send(&tx_msg) != CAN_OK);
  199.             }
  200.             break;
  201.         case BIOS_PGM:
  202.             if (nmt_type == CAN_NMT_PGM_DATA) {
  203.                 // Set address = base address + offset
  204.                 offset = bios_msg.Data.words[0];
  205.                 addr = base_addr + offset;
  206.                 tx_msg.Data.words[0] = offset;
  207.                 // TODO: Check (addr + dlc) valid instead
  208.                 if (addr < (uint16_t)&__bios_start) { //address valid
  209.                     //flash data at address
  210.                     len = (bios_msg.DataLength+1)/2; // Number of words in message, rounded up.
  211.                     for (i=1; i<len; i++) { // Skip first word (offset)
  212.                         data = bios_msg.Data.words[i];
  213.                         flash_write_word(addr, data);
  214.                         addr += 2;
  215.                     }
  216.                     //update crc
  217.                     //send CAN_NMT_PGM_ACK(offset)
  218.                     tx_msg.Id = CAN_ID_NMT_PGM_ACK;
  219.                 } else {
  220.                     //send CAN_NMT_PGM_NACK(offset)
  221.                     tx_msg.Id = CAN_ID_NMT_PGM_NACK;
  222.                 }
  223.             }
  224.             if (nmt_type == CAN_NMT_PGM_END) {
  225.                 flash_flush_buffer();
  226.                 //check crc
  227.                 //tx_msg.Data.words[0] = crc;
  228.                 if (1) { //crc ok
  229.                     //send CAN_NMT_PGM_ACK(crc)
  230.                     tx_msg.Id = CAN_ID_NMT_PGM_ACK;
  231.                 } else {
  232.                     //send CAN_NMT_PGM_NACK(crc)
  233.                     tx_msg.Id = CAN_ID_NMT_PGM_NACK;
  234.                 }
  235.                 bios_state = BIOS_NOAPP;
  236.             }
  237.             while (Can_Send(&tx_msg) != CAN_OK);
  238.         }
  239.  
  240.         bios_msg_full = 0; // We're done with this message, ready for the next.
  241.     }
  242.  
  243.     return 0;
  244. }
  245.