Subversion Repositories HomeAutomation

Rev

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

  1.  
  2. #include "sns_Serial.h"
  3.  
  4. #ifdef sns_Serial_USEEEPROM
  5. #include "sns_Serial_eeprom.h"
  6. struct eeprom_sns_Serial EEMEM eeprom_sns_Serial =
  7. {
  8.     {
  9.         ///TODO: Define initialization values on the EEPROM variables here, this will generate a *.eep file that can be used to store this values to the node, can in future be done with a EEPROM module and the make-scrips. Write the values in the exact same order as the struct is defined in the *.h file.
  10.         0xAB,   // x
  11.         0x1234  // y
  12.     },
  13.     0   // crc, must be a correct value, but this will also be handled by the EEPROM module or make scripts
  14. };
  15. #endif
  16.  
  17. // internal variables
  18. static uint32_t baudRate = 9600;
  19. static uint16_t format = CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_LOOPBACK;
  20. static uint8_t databits = 8;
  21. static uint8_t stopbits = 1;
  22.  
  23. static enum {
  24.     PARITY_NONE = 0,
  25.     PARITY_EVEN = 1,
  26.     PARITY_ODD = 2,
  27. } parityMode;
  28.  
  29. // prepare a new message, in case new data is available
  30. static StdCan_Msg_t msg;
  31.  
  32. #define sns_Serial_DEBUG 0
  33.  
  34.  
  35. #ifndef min
  36. #define min(_a,_b)      ((_a)<(_b) ? (_a) : (_b))
  37. #endif
  38.  
  39. #ifndef max
  40. #define max(_a,_b)      ((_a)>(_b) ? (_a) : (_b))
  41. #endif
  42.  
  43. #ifndef lim
  44. #define lim(_a,_minval,_maxval)     (max(min((_a),(_maxval)),(_minval)))
  45. #endif
  46.  
  47.  
  48.  
  49. uint8_t sns_Serial_setSettings(void)
  50. {
  51.     uint8_t returnval = 1;
  52.    
  53.     if (format == CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_RS232)
  54.     {
  55. #if sns_Serial_DEBUG==1
  56.         printf("RS232\n");
  57. #endif
  58.         gpio_clr_pin(sns_Serial_485_CONNECT);   // disable RS485_CONNECT
  59.         gpio_clr_pin(sns_Serial_TERM_EN);       // disable termination
  60.         gpio_clr_pin(sns_Serial_485_232);       // RS232 mode
  61.         gpio_set_pin(sns_Serial_RXEN);          // enable RX
  62.         gpio_set_pin(sns_Serial_ON);            // enable charge pump
  63.     }
  64.     else if (format == CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_RS485FULLDUPLEX)
  65.     {
  66. #if sns_Serial_DEBUG==1
  67.         printf("RS485FD\n");
  68. #endif
  69.         gpio_clr_pin(sns_Serial_485_CONNECT);   // disable RS485_CONNECT
  70.         gpio_clr_pin(sns_Serial_TERM_EN);       // disable termination
  71.         gpio_set_pin(sns_Serial_485_232);       // RS485 mode
  72.         gpio_set_pin(sns_Serial_RXEN);          // enable RX
  73.         gpio_set_pin(sns_Serial_TXEN);          // enable TX
  74.         gpio_set_pin(sns_Serial_ON);            // enable charge pump
  75.     }
  76.     else if (format == CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_RS485HALFDUPLEX)
  77.     {
  78. #if sns_Serial_DEBUG==1
  79.         printf("RS485HD\n");
  80. #endif
  81.         gpio_set_pin(sns_Serial_485_CONNECT);   // enable RS485_CONNECT
  82.         gpio_clr_pin(sns_Serial_TERM_EN);       // disable termination
  83.         gpio_set_pin(sns_Serial_485_232);       // RS485 mode
  84.         gpio_set_pin(sns_Serial_RXEN);          // enable RX
  85.     /* TODO shoud the TX really be enabled in half duplex? */
  86.         gpio_set_pin(sns_Serial_TXEN);          // enable TX
  87.         gpio_set_pin(sns_Serial_ON);            // enable charge pump
  88.     }
  89.     else if (format == CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_RS485HALFDUPLEXWITHTERMINATION)
  90.     {
  91. #if sns_Serial_DEBUG==1
  92.         printf("485HDT\n");
  93. #endif
  94.         gpio_set_pin(sns_Serial_485_CONNECT);   // enable RS485_CONNECT
  95.         gpio_set_pin(sns_Serial_TERM_EN);       // enable termination
  96.         gpio_set_pin(sns_Serial_485_232);       // RS485 mode
  97.     /* TODO shoud the TX really be enabled in half duplex? */
  98.         gpio_set_pin(sns_Serial_RXEN);          // enable RX
  99.         gpio_set_pin(sns_Serial_TXEN);          // enable TX
  100.         gpio_set_pin(sns_Serial_ON);            // enable charge pump
  101.     }
  102.     else if (format == CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_LOOPBACK)
  103.     {
  104. #if sns_Serial_DEBUG==1
  105.         printf("LPMODE\n");
  106. #endif
  107.         gpio_clr_pin(sns_Serial_485_CONNECT);   // disable RS485_CONNECT
  108.         gpio_clr_pin(sns_Serial_TERM_EN);       // disable termination
  109.         gpio_set_pin(sns_Serial_485_232);       // RS232 mode
  110.         gpio_set_pin(sns_Serial_RXEN);          // enable RX
  111.         gpio_set_pin(sns_Serial_TXEN);          // enable TX
  112.         gpio_clr_pin(sns_Serial_ON);            // disable charge pump (i.e. enable loopback)
  113.     }
  114.     else
  115.     {
  116.         //invalid format
  117. #if sns_Serial_DEBUG==1
  118.         printf("ERROR!\n");
  119. #endif
  120.         //return 0, not successful
  121.         returnval = 0;
  122.     }
  123.    
  124.     return returnval;
  125. }
  126.  
  127. void sns_Serial_Init(void)
  128. {
  129. #ifdef sns_Serial_USEEEPROM
  130.     if (EEDATA_OK) {
  131. #if ((__AVR_LIBC_MAJOR__ == 1  && __AVR_LIBC_MINOR__ == 6 && __AVR_LIBC_REVISION__ >=2)||(__AVR_LIBC_MAJOR__ == 1  && __AVR_LIBC_MINOR__ > 6)||__AVR_LIBC_MAJOR__ > 1)
  132.         baudRate = eeprom_read_dword(EEDATA32.baudRate);
  133. #else
  134. #warning This version of AVR-libc does not have support for eeprom read dword
  135. #endif
  136.         format = eeprom_read_word(EEDATA16.format);
  137.         databits = eeprom_read_byte(EEDATA.databits);
  138.         stopbits = eeprom_read_byte(EEDATA.stopbits);
  139.         parityMode = eeprom_read_byte(EEDATA.parityMode);
  140.     }
  141.     else {
  142.         //The CRC of the EEPROM is not correct, store default values and update CRC
  143. #if ((__AVR_LIBC_MAJOR__ == 1  && __AVR_LIBC_MINOR__ == 6 && __AVR_LIBC_REVISION__ >=2)||(__AVR_LIBC_MAJOR__ == 1  && __AVR_LIBC_MINOR__ > 6)||__AVR_LIBC_MAJOR__ > 1)
  144.         eeprom_write_dword_crc(EEDATA32.baudRate, 9600, WITHOUT_CRC);
  145. #else
  146. #warning This version of AVR-libc does not have support for eeprom write dword
  147. #endif
  148.         eeprom_write_word_crc(EEDATA16.format, CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_LOOPBACK, WITHOUT_CRC);
  149.         eeprom_write_byte_crc(EEDATA.databits, 8, WITHOUT_CRC);
  150.         eeprom_write_byte_crc(EEDATA.stopbits, 1, WITHOUT_CRC);
  151.         eeprom_write_byte_crc(EEDATA.parityMode, PARITY_NONE, WITHOUT_CRC);
  152.         EEDATA_UPDATE_CRC;
  153.     }
  154. #endif
  155.     uart_setDatabits(databits);
  156.     uart_setStopbits(stopbits);
  157.     uart_setParity(parityMode!=PARITY_NONE, parityMode==PARITY_ODD);
  158.     // default baudrate
  159.     uart_init(UART_BAUD_SELECT(baudRate, F_CPU));
  160.    
  161.     // configure control pins to outputs
  162.     gpio_set_out(sns_Serial_RXEN);
  163.     gpio_set_out(sns_Serial_TXEN);
  164.     gpio_set_out(sns_Serial_ON);
  165.     gpio_set_out(sns_Serial_485_232);
  166.     gpio_set_out(sns_Serial_TERM_EN);
  167.     gpio_set_out(sns_Serial_485_CONNECT);
  168.  
  169.     sns_Serial_setSettings();
  170.  
  171. #if sns_Serial_DEBUG==1
  172.     printf("Serial started!\n");
  173. #endif
  174.  
  175.     msg.Length = 0; // no data so far
  176. }
  177.  
  178. void sns_Serial_Process(void)
  179. {
  180.     StdCan_Set_class(msg.Header, CAN_MODULE_CLASS_SNS);
  181.     StdCan_Set_direction(msg.Header, DIRECTIONFLAG_TO_OWNER);
  182.     msg.Header.ModuleType = CAN_MODULE_TYPE_SNS_SERIAL;
  183.     msg.Header.ModuleId = sns_Serial_ID;
  184.     msg.Header.Command = CAN_MODULE_CMD_SERIAL_SERIALDATA;
  185.    
  186.     unsigned char status;
  187.    
  188.     do
  189.     {
  190.         // ask uart driver for more data
  191.         unsigned int data = uart_getc();
  192.         // character is contained in LSB
  193.         unsigned char c = (unsigned char)(data & 0x00FF);
  194.         // status is contained in MSB
  195.         status = (unsigned char)((data & 0xFF00) >> 8);
  196.        
  197.         // status == 0 means we just received a new char
  198.         if (status == 0)
  199.         {
  200. #if sns_Serial_DEBUG==1
  201.             printf("RX\n");
  202. #endif
  203.             // insert it into the message
  204.             msg.Data[(uint8_t)msg.Length] = c;
  205.             msg.Length++;
  206.            
  207. #if sns_Serial_FORCE_SEND_TIME_MS > 0
  208.             Timer_SetTimeout(sns_Serial_FORCE_SEND_TIMER, sns_Serial_FORCE_SEND_TIME_MS , TimerTypeOneShot, 0);
  209. #endif
  210.         }
  211.     // keep going until max data length reached, or until uart RXBUF is empty
  212.     } while (status == 0 && msg.Length < 8);
  213.    
  214.     // check if force send or send-frame full
  215.     if ((Timer_Expired(sns_Serial_FORCE_SEND_TIMER) && msg.Length>0) || msg.Length == 8 || (sns_Serial_FORCE_SEND_TIME_MS == 0 && msg.Length>0))
  216.     {
  217.         // transmit this chunk of data (max 8 chars)
  218.         while(StdCan_Put(&msg) != StdCan_Ret_OK);
  219.         msg.Length = 0; // no data so far
  220.     }
  221. }
  222.  
  223. void sns_Serial_HandleMessage(StdCan_Msg_t *rxMsg)
  224. {
  225.     if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_SNS &&
  226.         StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_FROM_OWNER &&
  227.         rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_SERIAL &&
  228.         rxMsg->Header.ModuleId == sns_Serial_ID)
  229.     {
  230.         switch (rxMsg->Header.Command)
  231.         {
  232.             case CAN_MODULE_CMD_SERIAL_SERIALDATA:
  233. #if sns_Serial_DEBUG==1
  234.                 printf("TX\n");
  235. #endif
  236.                 gpio_set_pin(sns_Serial_TXEN);          // enable TX
  237.                 for (uint8_t i=0; i<rxMsg->Length; i++)
  238.                 {
  239.                     uart_putc(rxMsg->Data[i]);
  240.                 }
  241.                 /* TODO Cannot disable TX yet, the data has only been placed in buffer but not sent */
  242. //              gpio_clr_pin(sns_Serial_TXEN);          // disable TX
  243.                 break;
  244.                
  245.             case CAN_MODULE_CMD_SERIAL_SERIALCONFIG:
  246.                 baudRate = 10 * (((uint32_t)rxMsg->Data[1] << 0) | ((uint32_t)rxMsg->Data[0] << 8));
  247.                 format = (uint16_t)rxMsg->Data[2];
  248.                 databits = lim(rxMsg->Data[3], 5, 9);
  249.                 stopbits = lim(rxMsg->Data[4], 1, 2);
  250.                 parityMode = lim(rxMsg->Data[5], 0, 2);
  251.                 uart_setDatabits(databits);
  252.                 uart_setStopbits(stopbits);
  253.                 uart_setParity(parityMode!=PARITY_NONE, parityMode==PARITY_ODD);
  254.                 uart_init(UART_BAUD_SELECT(baudRate, F_CPU));
  255.                 printf("D:%d, S:%d, P:%d\n", databits, stopbits, parityMode);
  256.                
  257.                 uint8_t returnval = sns_Serial_setSettings();
  258.                
  259.                 if (returnval)
  260.                 {
  261.                 // update EEPROM data
  262. #ifdef sns_Serial_USEEEPROM
  263. #if ((__AVR_LIBC_MAJOR__ == 1  && __AVR_LIBC_MINOR__ == 6 && __AVR_LIBC_REVISION__ >=2)||(__AVR_LIBC_MAJOR__ == 1  && __AVR_LIBC_MINOR__ > 6)||__AVR_LIBC_MAJOR__ > 1)
  264.                 eeprom_write_dword_crc(EEDATA32.baudRate, baudRate, WITHOUT_CRC);
  265. #else
  266. #warning This version of AVR-libc does not have support for eeprom read dword
  267. #endif
  268.                 eeprom_write_word_crc(EEDATA16.format, format, WITHOUT_CRC);
  269.                 eeprom_write_byte_crc(EEDATA.databits, databits, WITHOUT_CRC);
  270.                 eeprom_write_byte_crc(EEDATA.stopbits, stopbits, WITHOUT_CRC);
  271.                 eeprom_write_byte_crc(EEDATA.parityMode, parityMode, WITHOUT_CRC);
  272.                 EEDATA_UPDATE_CRC;
  273. #endif
  274.                 }
  275.                 break;
  276.         }
  277.     }
  278. }
  279.  
  280. void sns_Serial_List(uint8_t ModuleSequenceNumber)
  281. {
  282.     StdCan_Msg_t txMsg;
  283.  
  284.     StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  285.     StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  286.     txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_SERIAL;
  287.     txMsg.Header.ModuleId = sns_Serial_ID;
  288.     txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_LIST;
  289.     txMsg.Length = 6;
  290.  
  291.     txMsg.Data[0] = NODE_HW_ID_BYTE0;
  292.     txMsg.Data[1] = NODE_HW_ID_BYTE1;
  293.     txMsg.Data[2] = NODE_HW_ID_BYTE2;
  294.     txMsg.Data[3] = NODE_HW_ID_BYTE3;
  295.  
  296.     txMsg.Data[4] = NUMBER_OF_MODULES;
  297.     txMsg.Data[5] = ModuleSequenceNumber;
  298.  
  299.     while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  300. }
  301.  
  302.