Subversion Repositories HomeAutomation

Rev

Rev 1978 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /* ----------------------------------------------------------------------------
  2.  * Inclusions
  3.  * --------------------------------------------------------------------------*/
  4. #include "sns_Serial.h"
  5.  
  6.  
  7. /* ----------------------------------------------------------------------------
  8.  * Definitions
  9.  * --------------------------------------------------------------------------*/
  10. #define sns_Serial_DEBUG 0
  11.  
  12. #ifndef min
  13. #define min(_a,_b)      ((_a)<(_b) ? (_a) : (_b))
  14. #endif
  15.  
  16. #ifndef max
  17. #define max(_a,_b)      ((_a)>(_b) ? (_a) : (_b))
  18. #endif
  19.  
  20. #ifndef lim
  21. #define lim(_a,_minval,_maxval)     (max(min((_a),(_maxval)),(_minval)))
  22. #endif
  23.  
  24. typedef enum {
  25.     PARITY_NONE = 0,
  26.     PARITY_EVEN = 1,
  27.     PARITY_ODD = 2,
  28. } parityMode_t;
  29.  
  30.  
  31. /* ----------------------------------------------------------------------------
  32.  * Variables
  33.  * --------------------------------------------------------------------------*/
  34.  
  35. static uint32_t baudRate = 9600;
  36. static uint16_t format = CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_RS232;
  37. static uint8_t databits = 8;
  38. static uint8_t stopbits = 1;
  39. static parityMode_t parityMode = PARITY_NONE;
  40. static uint8_t dataTimeout = 255;
  41. static uint8_t packetLength = 0;
  42.  
  43. static struct __attribute__ ((packed)) {
  44.     uint8_t prefixLength:2;
  45.     uint8_t suffixLength:2;
  46.     uint8_t prefixPattern[3];
  47.     uint8_t suffixPattern[3];
  48. } filter;
  49.  
  50. static StdCan_Msg_t msg;
  51.  
  52. #if sns_Serial_USEEEPROM==1
  53. #include "sns_Serial_eeprom.h"
  54. struct eeprom_sns_Serial EEMEM eeprom_sns_Serial =
  55. {
  56.     {
  57.         9600,   // baudRate
  58.         CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_LOOPBACK,    // format
  59.         8,      // databits
  60.         1,      // stopbits
  61.         PARITY_NONE,    // parityMode
  62.         255,    // dataTimeout
  63.         8,      // packetLength
  64.         0,      // prefixLength
  65.         0,      // suffixLength
  66.         {0,0,0},    // prefixPattern
  67.         {0,0,0},    // suffixPattern
  68.     },
  69.     0   // crc, must be a correct value, but this will also be handled by the EEPROM module or make scripts
  70. };
  71. #endif
  72.  
  73.  
  74. /* ----------------------------------------------------------------------------
  75.  * Internal Functions
  76.  * --------------------------------------------------------------------------*/
  77. static uint16_t getTimeoutValue(void)
  78. {
  79.     // configurations 0-250 translate directly to milliseconds (0 means DIRECT)
  80.     if (dataTimeout>=0 && dataTimeout<=250) {
  81.         return dataTimeout;    
  82.     }
  83.     // configurations 251..254 are baudrate-dependent
  84.     else if (dataTimeout>=251 && dataTimeout<=254) {
  85.         return (uint16_t)(baudRate/(uint32_t)1000UL*((uint32_t)dataTimeout-250UL));
  86.     }
  87.     // configuration 255 means use the compiled default value
  88.     else {
  89.         return sns_Serial_FORCE_SEND_TIME_MS;
  90.     }
  91. }
  92.  
  93.  
  94. /* ----------------------------------------------------------------------------
  95.  * Function Implementations
  96.  * --------------------------------------------------------------------------*/
  97.  
  98. uint8_t sns_Serial_setSettings(void)
  99. {
  100.     uint8_t returnval = 1;
  101.    
  102.     if (format == CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_RS232)
  103.     {
  104. #if sns_Serial_DEBUG==1
  105.         printf("RS232\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_clr_pin(sns_Serial_485_232);       // RS232 mode
  110.         gpio_set_pin(sns_Serial_RXEN);          // enable RX
  111.         gpio_set_pin(sns_Serial_ON);            // enable charge pump
  112.     }
  113.     else if (format == CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_RS485FULLDUPLEX)
  114.     {
  115. #if sns_Serial_DEBUG==1
  116.         printf("RS485FD\n");
  117. #endif
  118.         gpio_clr_pin(sns_Serial_485_CONNECT);   // disable RS485_CONNECT
  119.         gpio_clr_pin(sns_Serial_TERM_EN);       // disable termination
  120.         gpio_set_pin(sns_Serial_485_232);       // RS485 mode
  121.         gpio_set_pin(sns_Serial_RXEN);          // enable RX
  122.         gpio_set_pin(sns_Serial_TXEN);          // enable TX
  123.         gpio_set_pin(sns_Serial_ON);            // enable charge pump
  124.     }
  125.     else if (format == CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_RS485HALFDUPLEX)
  126.     {
  127. #if sns_Serial_DEBUG==1
  128.         printf("RS485HD\n");
  129. #endif
  130.         gpio_set_pin(sns_Serial_485_CONNECT);   // enable RS485_CONNECT
  131.         gpio_clr_pin(sns_Serial_TERM_EN);       // disable termination
  132.         gpio_set_pin(sns_Serial_485_232);       // RS485 mode
  133.         gpio_set_pin(sns_Serial_RXEN);          // enable RX
  134.     /* TODO shoud the TX really be enabled in half duplex? */
  135.         gpio_set_pin(sns_Serial_TXEN);          // enable TX
  136.         gpio_set_pin(sns_Serial_ON);            // enable charge pump
  137.     }
  138.     else if (format == CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_RS485HALFDUPLEXWITHTERMINATION)
  139.     {
  140. #if sns_Serial_DEBUG==1
  141.         printf("485HDT\n");
  142. #endif
  143.         gpio_set_pin(sns_Serial_485_CONNECT);   // enable RS485_CONNECT
  144.         gpio_set_pin(sns_Serial_TERM_EN);       // enable termination
  145.         gpio_set_pin(sns_Serial_485_232);       // RS485 mode
  146.     /* TODO shoud the TX really be enabled in half duplex? */
  147.         gpio_set_pin(sns_Serial_RXEN);          // enable RX
  148.         gpio_set_pin(sns_Serial_TXEN);          // enable TX
  149.         gpio_set_pin(sns_Serial_ON);            // enable charge pump
  150.     }
  151.     else if (format == CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_LOOPBACK)
  152.     {
  153. #if sns_Serial_DEBUG==1
  154.         printf("LPMODE\n");
  155. #endif
  156.         gpio_clr_pin(sns_Serial_485_CONNECT);   // disable RS485_CONNECT
  157.         gpio_clr_pin(sns_Serial_TERM_EN);       // disable termination
  158.         gpio_set_pin(sns_Serial_485_232);       // RS232 mode
  159.         gpio_set_pin(sns_Serial_RXEN);          // enable RX
  160.         gpio_set_pin(sns_Serial_TXEN);          // enable TX
  161.         gpio_clr_pin(sns_Serial_ON);            // disable charge pump (i.e. enable loopback)
  162.     }
  163.     else
  164.     {
  165.         //invalid format
  166. #if sns_Serial_DEBUG==1
  167.         printf("ERROR!\n");
  168. #endif
  169.         //return 0, not successful
  170.         returnval = 0;
  171.     }
  172.    
  173.     return returnval;
  174. }
  175.  
  176.  
  177. void sns_Serial_Init()
  178. {
  179.     /* Init filter in case eeprom not correct */
  180.     filter.prefixLength = 0;
  181.     filter.suffixLength = 0;
  182.     filter.prefixPattern[0] = 0;
  183.     filter.prefixPattern[1] = 0;
  184.     filter.prefixPattern[2] = 0;
  185.     filter.suffixPattern[0] = 0;
  186.     filter.suffixPattern[1] = 0;
  187.     filter.suffixPattern[2] = 0;
  188. #if sns_Serial_USEEEPROM==1
  189.     if (EEDATA_OK) {
  190.     //if (0) {
  191. #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)
  192.         baudRate = eeprom_read_dword(EEDATA32.baudRate);
  193. #else
  194. #warning This version of AVR-libc does not have support for eeprom read dword
  195. #endif
  196.         format = eeprom_read_word(EEDATA16.format);
  197.         databits = eeprom_read_byte(EEDATA.databits);
  198.         stopbits = eeprom_read_byte(EEDATA.stopbits);
  199.         parityMode = eeprom_read_byte(EEDATA.parityMode);
  200.         dataTimeout = eeprom_read_byte(EEDATA.dataTimeout);
  201.         packetLength = eeprom_read_byte(EEDATA.packetLength);
  202.         filter.prefixLength = lim(eeprom_read_byte(EEDATA.prefixLength), 0, 3);
  203.         filter.suffixLength = lim(eeprom_read_byte(EEDATA.suffixLength), 0, 3);
  204.         filter.prefixPattern[0] = eeprom_read_byte(EEDATA.prefixPattern[0]);
  205.         filter.prefixPattern[1] = eeprom_read_byte(EEDATA.prefixPattern[1]);
  206.         filter.prefixPattern[2] = eeprom_read_byte(EEDATA.prefixPattern[2]);
  207.         filter.suffixPattern[0] = eeprom_read_byte(EEDATA.suffixPattern[0]);
  208.         filter.suffixPattern[1] = eeprom_read_byte(EEDATA.suffixPattern[1]);
  209.         filter.suffixPattern[2] = eeprom_read_byte(EEDATA.suffixPattern[2]);
  210.     }
  211.     else {
  212.         //The CRC of the EEPROM is not correct, store default values and update CRC
  213. #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)
  214.         eeprom_write_dword_crc(EEDATA32.baudRate, 9600, WITHOUT_CRC);
  215. #else
  216. #warning This version of AVR-libc does not have support for eeprom write dword
  217. #endif
  218.         eeprom_write_word_crc(EEDATA16.format, CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_LOOPBACK, WITHOUT_CRC);
  219.         eeprom_write_byte_crc(EEDATA.databits, 8, WITHOUT_CRC);
  220.         eeprom_write_byte_crc(EEDATA.stopbits, 1, WITHOUT_CRC);
  221.         eeprom_write_byte_crc(EEDATA.parityMode, PARITY_NONE, WITHOUT_CRC);
  222.         eeprom_write_byte_crc(EEDATA.dataTimeout, 255, WITHOUT_CRC);
  223.         eeprom_write_byte_crc(EEDATA.packetLength, 8, WITHOUT_CRC);
  224.         eeprom_write_byte_crc(EEDATA.prefixLength, 0, WITHOUT_CRC);
  225.         eeprom_write_byte_crc(EEDATA.suffixLength, 0, WITHOUT_CRC);
  226.         eeprom_write_byte_crc(EEDATA.prefixPattern[0], 0, WITHOUT_CRC);
  227.         eeprom_write_byte_crc(EEDATA.prefixPattern[1], 0, WITHOUT_CRC);
  228.         eeprom_write_byte_crc(EEDATA.prefixPattern[2], 0, WITHOUT_CRC);
  229.         eeprom_write_byte_crc(EEDATA.suffixPattern[0], 0, WITHOUT_CRC);
  230.         eeprom_write_byte_crc(EEDATA.suffixPattern[1], 0, WITHOUT_CRC);
  231.         eeprom_write_byte_crc(EEDATA.suffixPattern[2], 0, WITHOUT_CRC);
  232.         EEDATA_UPDATE_CRC;
  233.     }
  234. #endif
  235.     uart_setDatabits(databits);
  236.     uart_setStopbits(stopbits);
  237.     uart_setParity(parityMode!=PARITY_NONE, parityMode==PARITY_ODD);
  238.     uart_init(UART_BAUD_SELECT(baudRate, F_CPU));
  239.    
  240.     // configure control pins to outputs
  241.     gpio_set_out(sns_Serial_RXEN);
  242.     gpio_set_out(sns_Serial_TXEN);
  243.     gpio_set_out(sns_Serial_ON);
  244.     gpio_set_out(sns_Serial_485_232);
  245.     gpio_set_out(sns_Serial_TERM_EN);
  246.     gpio_set_out(sns_Serial_485_CONNECT);
  247.  
  248.     sns_Serial_setSettings();
  249.  
  250. #if sns_Serial_DEBUG==1
  251.     printf("Serial started!\n");
  252. #endif
  253.  
  254.     msg.Length = 0; // no data so far
  255.    
  256.     //gpio_set_pin(sns_Serial_TXEN);            // enable TX
  257.     //uart_putc('7');
  258. }
  259.  
  260.  
  261. void sns_Serial_Process(void)
  262. {
  263.     StdCan_Set_class(msg.Header, CAN_MODULE_CLASS_SNS);
  264.     StdCan_Set_direction(msg.Header, DIRECTIONFLAG_TO_OWNER);
  265.     msg.Header.ModuleType = CAN_MODULE_TYPE_SNS_SERIAL;
  266.     msg.Header.ModuleId = sns_Serial_ID;
  267.     msg.Header.Command = CAN_MODULE_CMD_SERIAL_SERIALDATA;
  268.    
  269.     unsigned char status;
  270.    
  271.     do
  272.     {
  273.         // ask uart driver for more data
  274.         unsigned int data = uart_getc();
  275.         // character is contained in LSB
  276.         unsigned char c = (unsigned char)(data & 0x00FF);
  277.  
  278.         // status is contained in MSB
  279.         status = (unsigned char)((data & 0xFF00) >> 8);
  280.        
  281.         // status == 0 means we just received a new char
  282.         if (status == 0)
  283.         {
  284. #if sns_Serial_DEBUG==1
  285.             printf("RX\n");
  286. #endif
  287.             // insert it into the message
  288.             msg.Data[(uint8_t)msg.Length] = c;
  289.             msg.Length++;
  290.            
  291.             uint16_t timeout;
  292.             if ((timeout = getTimeoutValue()) != 0) {
  293.                 Timer_SetTimeout(sns_Serial_FORCE_SEND_TIMER, timeout , TimerTypeOneShot, 0);
  294.             }
  295.         }
  296.     // keep going until max data length reached, or until uart RXBUF is empty
  297.     } while (status == 0 && msg.Length < packetLength);
  298.    
  299.     // check if force send or send-frame full
  300.     if ((Timer_Expired(sns_Serial_FORCE_SEND_TIMER) && msg.Length>0) || msg.Length==packetLength || (getTimeoutValue()==0 && msg.Length>0))
  301.     {
  302.         // transmit this chunk of data (max 8 chars)
  303.         while(StdCan_Put(&msg) != StdCan_Ret_OK);
  304.         msg.Length = 0; // no data so far
  305.     }
  306. }
  307.  
  308.  
  309. void sns_Serial_HandleMessage(StdCan_Msg_t *rxMsg)
  310. {
  311.     if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_SNS &&
  312.         StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_FROM_OWNER &&
  313.         rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_SERIAL &&
  314.         rxMsg->Header.ModuleId == sns_Serial_ID)
  315.     {
  316.         switch (rxMsg->Header.Command)
  317.         {
  318.             case CAN_MODULE_CMD_SERIAL_SERIALDATA:
  319. #if sns_Serial_DEBUG==1
  320.                 printf("TX\n");
  321. #endif
  322.                 gpio_set_pin(sns_Serial_TXEN);          // enable TX
  323.                 for (uint8_t i=0; i<rxMsg->Length; i++)
  324.                 {
  325.                     uart_putc(rxMsg->Data[i]);
  326.                 }
  327.                 /* TODO Cannot disable TX yet, the data has only been placed in buffer but not sent */
  328. //              gpio_clr_pin(sns_Serial_TXEN);          // disable TX
  329.                 break;
  330.                
  331.             case CAN_MODULE_CMD_SERIAL_SERIALCONFIG:
  332.                 baudRate = 10 * (((uint32_t)rxMsg->Data[1] << 0) | ((uint32_t)rxMsg->Data[0] << 8));
  333.                 format = (uint16_t)rxMsg->Data[2];
  334.                 databits = lim(rxMsg->Data[3], 5, 9);
  335.                 stopbits = lim(rxMsg->Data[4], 1, 2);
  336.                 parityMode = lim(rxMsg->Data[5], 0, 2);
  337.                 uart_setDatabits(databits);
  338.                 uart_setStopbits(stopbits);
  339.                 uart_setParity(parityMode!=PARITY_NONE, parityMode==PARITY_ODD);
  340.                 uart_init(UART_BAUD_SELECT(baudRate, F_CPU));
  341.                
  342.                 uint8_t returnval = sns_Serial_setSettings();
  343.                
  344.                 if (returnval)
  345.                 {
  346.                 // update EEPROM data
  347. #if sns_Serial_USEEEPROM==1
  348. #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)
  349.                 eeprom_write_dword_crc(EEDATA32.baudRate, baudRate, WITHOUT_CRC);
  350. #else
  351. #warning This version of AVR-libc does not have support for eeprom read dword
  352. #endif
  353.                 eeprom_write_word_crc(EEDATA16.format, format, WITHOUT_CRC);
  354.                 eeprom_write_byte_crc(EEDATA.databits, databits, WITHOUT_CRC);
  355.                 eeprom_write_byte_crc(EEDATA.stopbits, stopbits, WITHOUT_CRC);
  356.                 eeprom_write_byte_crc(EEDATA.parityMode, parityMode, WITHOUT_CRC);
  357.                 EEDATA_UPDATE_CRC;
  358. #endif
  359.                 }
  360.                 break;
  361.                
  362.             case CAN_MODULE_CMD_SERIAL_SERIALFILTER:
  363.                 dataTimeout = rxMsg->Data[0];
  364.                 filter.prefixLength = ((rxMsg->Data[1] & 0x0F) >> 0);
  365.                 filter.suffixLength = ((rxMsg->Data[1] & 0x30) >> 4);
  366.                 packetLength = ((rxMsg->Data[1] & 0xC0) >> 6);
  367.                 filter.prefixPattern[2] = rxMsg->Data[2];
  368.                 filter.prefixPattern[1] = rxMsg->Data[3];
  369.                 filter.prefixPattern[0] = rxMsg->Data[4];
  370.                 filter.suffixPattern[2] = rxMsg->Data[5];
  371.                 filter.suffixPattern[1] = rxMsg->Data[6];
  372.                 filter.suffixPattern[0] = rxMsg->Data[7];
  373.                
  374.                 // update EEPROM data
  375.                 eeprom_write_byte_crc(EEDATA.dataTimeout, dataTimeout, WITHOUT_CRC);
  376.                 eeprom_write_byte_crc(EEDATA.packetLength, packetLength, WITHOUT_CRC);
  377.                 eeprom_write_byte_crc(EEDATA.prefixLength, filter.prefixLength, WITHOUT_CRC);
  378.                 eeprom_write_byte_crc(EEDATA.suffixLength, filter.suffixLength, WITHOUT_CRC);
  379.                 eeprom_write_byte_crc(EEDATA.prefixPattern[0], filter.prefixPattern[0], WITHOUT_CRC);
  380.                 eeprom_write_byte_crc(EEDATA.prefixPattern[1], filter.prefixPattern[1], WITHOUT_CRC);
  381.                 eeprom_write_byte_crc(EEDATA.prefixPattern[2], filter.prefixPattern[2], WITHOUT_CRC);
  382.                 eeprom_write_byte_crc(EEDATA.suffixPattern[0], filter.suffixPattern[0], WITHOUT_CRC);
  383.                 eeprom_write_byte_crc(EEDATA.suffixPattern[1], filter.suffixPattern[1], WITHOUT_CRC);
  384.                 eeprom_write_byte_crc(EEDATA.suffixPattern[2], filter.suffixPattern[2], WITHOUT_CRC);
  385.                 EEDATA_UPDATE_CRC;
  386.                
  387.                 break;
  388.         }
  389.     }
  390. }
  391.  
  392.  
  393. void sns_Serial_List(uint8_t ModuleSequenceNumber)
  394. {
  395.     StdCan_Msg_t txMsg;
  396.  
  397.     StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  398.     StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  399.     txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_SERIAL;
  400.     txMsg.Header.ModuleId = sns_Serial_ID;
  401.     txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_LIST;
  402.     txMsg.Length = 6;
  403.  
  404.     uint32_t HwId=BIOS_GetHwId();
  405.     txMsg.Data[0] = HwId&0xff;
  406.     txMsg.Data[1] = (HwId>>8)&0xff;
  407.     txMsg.Data[2] = (HwId>>16)&0xff;
  408.     txMsg.Data[3] = (HwId>>24)&0xff;
  409.  
  410.     txMsg.Data[4] = NUMBER_OF_MODULES;
  411.     txMsg.Data[5] = ModuleSequenceNumber;
  412.  
  413.     while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  414. }
  415.  
  416.