Subversion Repositories HomeAutomation

Rev

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