Subversion Repositories HomeAutomation

Rev

Rev 1910 | Go to most recent revision | 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. #if sns_Serial_USEEEPROM==1
  180.     if (EEDATA_OK) {
  181.     //if (0) {
  182. #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)
  183.         baudRate = eeprom_read_dword(EEDATA32.baudRate);
  184. #else
  185. #warning This version of AVR-libc does not have support for eeprom read dword
  186. #endif
  187.         format = eeprom_read_word(EEDATA16.format);
  188.         databits = eeprom_read_byte(EEDATA.databits);
  189.         stopbits = eeprom_read_byte(EEDATA.stopbits);
  190.         parityMode = eeprom_read_byte(EEDATA.parityMode);
  191.         dataTimeout = eeprom_read_byte(EEDATA.dataTimeout);
  192.         packetLength = eeprom_read_byte(EEDATA.packetLength);
  193.         filter.prefixLength = lim(eeprom_read_byte(EEDATA.prefixLength), 0, 3);
  194.         filter.suffixLength = lim(eeprom_read_byte(EEDATA.suffixLength), 0, 3);
  195.         filter.prefixPattern[0] = eeprom_read_byte(EEDATA.prefixPattern[0]);
  196.         filter.prefixPattern[1] = eeprom_read_byte(EEDATA.prefixPattern[1]);
  197.         filter.prefixPattern[2] = eeprom_read_byte(EEDATA.prefixPattern[2]);
  198.         filter.suffixPattern[0] = eeprom_read_byte(EEDATA.suffixPattern[0]);
  199.         filter.suffixPattern[1] = eeprom_read_byte(EEDATA.suffixPattern[1]);
  200.         filter.suffixPattern[2] = eeprom_read_byte(EEDATA.suffixPattern[2]);
  201.     }
  202.     else {
  203.         //The CRC of the EEPROM is not correct, store default values and update CRC
  204. #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)
  205.         eeprom_write_dword_crc(EEDATA32.baudRate, 9600, WITHOUT_CRC);
  206. #else
  207. #warning This version of AVR-libc does not have support for eeprom write dword
  208. #endif
  209.         eeprom_write_word_crc(EEDATA16.format, CAN_MODULE_ENUM_SERIAL_SERIALCONFIG_PHYSICALFORMAT_LOOPBACK, WITHOUT_CRC);
  210.         eeprom_write_byte_crc(EEDATA.databits, 8, WITHOUT_CRC);
  211.         eeprom_write_byte_crc(EEDATA.stopbits, 1, WITHOUT_CRC);
  212.         eeprom_write_byte_crc(EEDATA.parityMode, PARITY_NONE, WITHOUT_CRC);
  213.         eeprom_write_byte_crc(EEDATA.dataTimeout, 255, WITHOUT_CRC);
  214.         eeprom_write_byte_crc(EEDATA.packetLength, 8, WITHOUT_CRC);
  215.         eeprom_write_byte_crc(EEDATA.prefixLength, 0, WITHOUT_CRC);
  216.         eeprom_write_byte_crc(EEDATA.suffixLength, 0, WITHOUT_CRC);
  217.         eeprom_write_byte_crc(EEDATA.prefixPattern[0], 0, WITHOUT_CRC);
  218.         eeprom_write_byte_crc(EEDATA.prefixPattern[1], 0, WITHOUT_CRC);
  219.         eeprom_write_byte_crc(EEDATA.prefixPattern[2], 0, WITHOUT_CRC);
  220.         eeprom_write_byte_crc(EEDATA.suffixPattern[0], 0, WITHOUT_CRC);
  221.         eeprom_write_byte_crc(EEDATA.suffixPattern[1], 0, WITHOUT_CRC);
  222.         eeprom_write_byte_crc(EEDATA.suffixPattern[2], 0, WITHOUT_CRC);
  223.         EEDATA_UPDATE_CRC;
  224.     }
  225. #endif
  226.     uart_setDatabits(databits);
  227.     uart_setStopbits(stopbits);
  228.     uart_setParity(parityMode!=PARITY_NONE, parityMode==PARITY_ODD);
  229.     uart_init(UART_BAUD_SELECT(baudRate, F_CPU));
  230.    
  231.     // configure control pins to outputs
  232.     gpio_set_out(sns_Serial_RXEN);
  233.     gpio_set_out(sns_Serial_TXEN);
  234.     gpio_set_out(sns_Serial_ON);
  235.     gpio_set_out(sns_Serial_485_232);
  236.     gpio_set_out(sns_Serial_TERM_EN);
  237.     gpio_set_out(sns_Serial_485_CONNECT);
  238.  
  239.     sns_Serial_setSettings();
  240.  
  241. #if sns_Serial_DEBUG==1
  242.     printf("Serial started!\n");
  243. #endif
  244.  
  245.     msg.Length = 0; // no data so far
  246.    
  247.     //gpio_set_pin(sns_Serial_TXEN);            // enable TX
  248.     //uart_putc('7');
  249. }
  250.  
  251.  
  252. void sns_Serial_Process(void)
  253. {
  254.     StdCan_Set_class(msg.Header, CAN_MODULE_CLASS_SNS);
  255.     StdCan_Set_direction(msg.Header, DIRECTIONFLAG_TO_OWNER);
  256.     msg.Header.ModuleType = CAN_MODULE_TYPE_SNS_SERIAL;
  257.     msg.Header.ModuleId = sns_Serial_ID;
  258.     msg.Header.Command = CAN_MODULE_CMD_SERIAL_SERIALDATA;
  259.    
  260.     unsigned char status;
  261.    
  262.     do
  263.     {
  264.         // ask uart driver for more data
  265.         unsigned int data = uart_getc();
  266.         // character is contained in LSB
  267.         unsigned char c = (unsigned char)(data & 0x00FF);
  268.  
  269.         // status is contained in MSB
  270.         status = (unsigned char)((data & 0xFF00) >> 8);
  271.        
  272.         // status == 0 means we just received a new char
  273.         if (status == 0)
  274.         {
  275. #if sns_Serial_DEBUG==1
  276.             printf("RX\n");
  277. #endif
  278.             // insert it into the message
  279.             msg.Data[(uint8_t)msg.Length] = c;
  280.             msg.Length++;
  281.            
  282.             uint16_t timeout;
  283.             if ((timeout = getTimeoutValue()) != 0) {
  284.                 Timer_SetTimeout(sns_Serial_FORCE_SEND_TIMER, timeout , TimerTypeOneShot, 0);
  285.             }
  286.         }
  287.     // keep going until max data length reached, or until uart RXBUF is empty
  288.     } while (status == 0 && msg.Length < packetLength);
  289.    
  290.     // check if force send or send-frame full
  291.     if ((Timer_Expired(sns_Serial_FORCE_SEND_TIMER) && msg.Length>0) || msg.Length==packetLength || (getTimeoutValue()==0 && msg.Length>0))
  292.     {
  293.         // transmit this chunk of data (max 8 chars)
  294.         while(StdCan_Put(&msg) != StdCan_Ret_OK);
  295.         msg.Length = 0; // no data so far
  296.     }
  297. }
  298.  
  299.  
  300. void sns_Serial_HandleMessage(StdCan_Msg_t *rxMsg)
  301. {
  302.     if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_SNS &&
  303.         StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_FROM_OWNER &&
  304.         rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_SERIAL &&
  305.         rxMsg->Header.ModuleId == sns_Serial_ID)
  306.     {
  307.         switch (rxMsg->Header.Command)
  308.         {
  309.             case CAN_MODULE_CMD_SERIAL_SERIALDATA:
  310. #if sns_Serial_DEBUG==1
  311.                 printf("TX\n");
  312. #endif
  313.                 gpio_set_pin(sns_Serial_TXEN);          // enable TX
  314.                 for (uint8_t i=0; i<rxMsg->Length; i++)
  315.                 {
  316.                     uart_putc(rxMsg->Data[i]);
  317.                 }
  318.                 /* TODO Cannot disable TX yet, the data has only been placed in buffer but not sent */
  319. //              gpio_clr_pin(sns_Serial_TXEN);          // disable TX
  320.                 break;
  321.                
  322.             case CAN_MODULE_CMD_SERIAL_SERIALCONFIG:
  323.                 baudRate = 10 * (((uint32_t)rxMsg->Data[1] << 0) | ((uint32_t)rxMsg->Data[0] << 8));
  324.                 format = (uint16_t)rxMsg->Data[2];
  325.                 databits = lim(rxMsg->Data[3], 5, 9);
  326.                 stopbits = lim(rxMsg->Data[4], 1, 2);
  327.                 parityMode = lim(rxMsg->Data[5], 0, 2);
  328.                 uart_setDatabits(databits);
  329.                 uart_setStopbits(stopbits);
  330.                 uart_setParity(parityMode!=PARITY_NONE, parityMode==PARITY_ODD);
  331.                 uart_init(UART_BAUD_SELECT(baudRate, F_CPU));
  332.                
  333.                 uint8_t returnval = sns_Serial_setSettings();
  334.                
  335.                 if (returnval)
  336.                 {
  337.                 // update EEPROM data
  338. #if sns_Serial_USEEEPROM==1
  339. #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)
  340.                 eeprom_write_dword_crc(EEDATA32.baudRate, baudRate, WITHOUT_CRC);
  341. #else
  342. #warning This version of AVR-libc does not have support for eeprom read dword
  343. #endif
  344.                 eeprom_write_word_crc(EEDATA16.format, format, WITHOUT_CRC);
  345.                 eeprom_write_byte_crc(EEDATA.databits, databits, WITHOUT_CRC);
  346.                 eeprom_write_byte_crc(EEDATA.stopbits, stopbits, WITHOUT_CRC);
  347.                 eeprom_write_byte_crc(EEDATA.parityMode, parityMode, WITHOUT_CRC);
  348.                 EEDATA_UPDATE_CRC;
  349. #endif
  350.                 }
  351.                 break;
  352.                
  353.             case CAN_MODULE_CMD_SERIAL_SERIALFILTER:
  354.                 dataTimeout = rxMsg->Data[0];
  355.                 filter.prefixLength = ((rxMsg->Data[1] & 0x0F) >> 0);
  356.                 filter.suffixLength = ((rxMsg->Data[1] & 0x30) >> 4);
  357.                 packetLength = ((rxMsg->Data[1] & 0xC0) >> 6);
  358.                 filter.prefixPattern[2] = rxMsg->Data[2];
  359.                 filter.prefixPattern[1] = rxMsg->Data[3];
  360.                 filter.prefixPattern[0] = rxMsg->Data[4];
  361.                 filter.suffixPattern[2] = rxMsg->Data[5];
  362.                 filter.suffixPattern[1] = rxMsg->Data[6];
  363.                 filter.suffixPattern[0] = rxMsg->Data[7];
  364.                
  365.                 // update EEPROM data
  366.                 eeprom_write_byte_crc(EEDATA.dataTimeout, dataTimeout, WITHOUT_CRC);
  367.                 eeprom_write_byte_crc(EEDATA.packetLength, packetLength, WITHOUT_CRC);
  368.                 eeprom_write_byte_crc(EEDATA.prefixLength, filter.prefixLength, WITHOUT_CRC);
  369.                 eeprom_write_byte_crc(EEDATA.suffixLength, filter.suffixLength, WITHOUT_CRC);
  370.                 eeprom_write_byte_crc(EEDATA.prefixPattern[0], filter.prefixPattern[0], WITHOUT_CRC);
  371.                 eeprom_write_byte_crc(EEDATA.prefixPattern[1], filter.prefixPattern[1], WITHOUT_CRC);
  372.                 eeprom_write_byte_crc(EEDATA.prefixPattern[2], filter.prefixPattern[2], WITHOUT_CRC);
  373.                 eeprom_write_byte_crc(EEDATA.suffixPattern[0], filter.suffixPattern[0], WITHOUT_CRC);
  374.                 eeprom_write_byte_crc(EEDATA.suffixPattern[1], filter.suffixPattern[1], WITHOUT_CRC);
  375.                 eeprom_write_byte_crc(EEDATA.suffixPattern[2], filter.suffixPattern[2], WITHOUT_CRC);
  376.                 EEDATA_UPDATE_CRC;
  377.                
  378.                 break;
  379.         }
  380.     }
  381. }
  382.  
  383.  
  384. void sns_Serial_List(uint8_t ModuleSequenceNumber)
  385. {
  386.     StdCan_Msg_t txMsg;
  387.  
  388.     StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  389.     StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  390.     txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_SERIAL;
  391.     txMsg.Header.ModuleId = sns_Serial_ID;
  392.     txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_LIST;
  393.     txMsg.Length = 6;
  394.  
  395.     uint32_t HwId=BIOS_GetHwId();
  396.     txMsg.Data[0] = HwId&0xff;
  397.     txMsg.Data[1] = (HwId>>8)&0xff;
  398.     txMsg.Data[2] = (HwId>>16)&0xff;
  399.     txMsg.Data[3] = (HwId>>24)&0xff;
  400.  
  401.     txMsg.Data[4] = NUMBER_OF_MODULES;
  402.     txMsg.Data[5] = ModuleSequenceNumber;
  403.  
  404.     while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  405. }
  406.  
  407.