Subversion Repositories HomeAutomation

Rev

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

  1. /*-----------------------------------------------------------------------------
  2.  * Includes
  3.  *---------------------------------------------------------------------------*/
  4. #include "act_protectedOutput.h"
  5.  
  6.  
  7. /*-----------------------------------------------------------------------------
  8.  * Defines
  9.  *---------------------------------------------------------------------------*/
  10.  
  11. // make sure all config params are present
  12.  
  13. #ifndef act_protectedOutput_CH_COUNT
  14. #error Config value missing: "act_protectedOutput_CH_COUNT"
  15. #endif
  16.  
  17. #ifndef act_protectedOutput_EEPROM_ENABLED
  18. #error Config value missing: "act_protectedOutput_EEPROM_ENABLED"
  19. #endif
  20.  
  21. #if act_protectedOutput_CH_COUNT >= 1
  22. #ifndef act_protectedOutput_CH0
  23. #error Config value missing: "act_protectedOutput_CH0"
  24. #endif
  25. #ifndef act_protectedOutput_CH0_POLARITY
  26. #error Config value missing: "act_protectedOutput_CH0_POLARITY"
  27. #endif
  28. #endif
  29.  
  30. #if act_protectedOutput_CH_COUNT >= 2
  31. #ifndef act_protectedOutput_CH1
  32. #error Config value missing: "act_protectedOutput_CH1"
  33. #endif
  34. #ifndef act_protectedOutput_CH1_POLARITY
  35. #error Config value missing: "act_protectedOutput_CH1_POLARITY"
  36. #endif
  37. #endif
  38.  
  39. #if act_protectedOutput_CH_COUNT >= 3
  40. #ifndef act_protectedOutput_CH2
  41. #error Config value missing: "act_protectedOutput_CH2"
  42. #endif
  43. #ifndef act_protectedOutput_CH2_POLARITY
  44. #error Config value missing: "act_protectedOutput_CH2_POLARITY"
  45. #endif
  46. #endif
  47.  
  48. #if act_protectedOutput_CH_COUNT >= 4
  49. #ifndef act_protectedOutput_CH3
  50. #error Config value missing: "act_protectedOutput_CH3"
  51. #endif
  52. #ifndef act_protectedOutput_CH3_POLARITY
  53. #error Config value missing: "act_protectedOutput_CH3_POLARITY"
  54. #endif
  55. #endif
  56.  
  57. #if act_protectedOutput_CH_COUNT >= 5
  58. #error Config value out of range: "act_protectedOutput_CH_COUNT"
  59. #endif
  60.  
  61. #define CH0_ON      (act_protectedOutput_CH0_POLARITY)
  62. #define CH0_OFF     (1 - CH0_ON)
  63. #define CH0_PIN     act_protectedOutput_CH0
  64.  
  65. #define CH1_ON      (act_protectedOutput_CH1_POLARITY)
  66. #define CH1_OFF     (1 - CH1_ON)
  67. #define CH1_PIN     act_protectedOutput_CH1
  68.  
  69. #define CH2_ON      (act_protectedOutput_CH2_POLARITY)
  70. #define CH2_OFF     (1 - CH2_ON)
  71. #define CH2_PIN     act_protectedOutput_CH2
  72.  
  73. #define CH3_ON      (act_protectedOutput_CH3_POLARITY)
  74. #define CH3_OFF     (1 - CH3_ON)
  75. #define CH3_PIN     act_protectedOutput_CH3
  76.  
  77. #define DIAG_ASSERTED   (act_protectedOutput_DIAG_PIN_POLARITY)
  78. #define DIAG_NORMAL     (1 - DIAG_ASSERTED)
  79. #define DIAG_PIN        act_protectedOutput_DIAG_PIN
  80.  
  81.  
  82. /*-----------------------------------------------------------------------------
  83.  * Types
  84.  *---------------------------------------------------------------------------*/
  85.  
  86.  
  87. #if act_protectedOutput_EEPROM_ENABLED == 1
  88. #include "act_protectedOutput_eeprom.h"
  89. struct eeprom_act_protectedOutput EEMEM eeprom_act_protectedOutput =
  90. {
  91.     {
  92.         ///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.
  93. #if act_protectedOutput_CH_COUNT >= 1
  94.         0x00,
  95. #endif
  96. #if act_protectedOutput_CH_COUNT >= 2
  97.         0x00,
  98. #endif
  99. #if act_protectedOutput_CH_COUNT >= 3
  100.         0x00,
  101. #endif
  102. #if act_protectedOutput_CH_COUNT >= 4
  103.         0x00,
  104. #endif
  105.     },
  106.     0   // crc, must be a correct value, but this will also be handled by the EEPROM module or make scripts
  107. };
  108. #endif
  109.  
  110.  
  111. /*-----------------------------------------------------------------------------
  112.  * Variables
  113.  *---------------------------------------------------------------------------*/
  114.  
  115. static uint8_t outputStateTarget[act_protectedOutput_CH_COUNT];
  116. static uint8_t diagState = DIAG_NORMAL;
  117.  
  118. // is there a recent status change that we should report via CAN?
  119. static uint8_t diagReportPending = 0;
  120.  
  121.  
  122. /*-----------------------------------------------------------------------------
  123.  * Internal Function Prototypes
  124.  *---------------------------------------------------------------------------*/
  125. static void updateOutput(void);
  126. static void readDiagPin(void);
  127. static void pcIntCallback(uint8_t id, uint8_t status);
  128.  
  129.  
  130. /*-----------------------------------------------------------------------------
  131.  * Function Implementations
  132.  *---------------------------------------------------------------------------*/
  133.  
  134. static void updateOutput() {
  135.  
  136.     #if act_protectedOutput_CH_COUNT >= 1
  137.     if (outputStateTarget[0] == 0) {
  138.         gpio_set_statement(CH0_OFF, CH0_PIN);
  139.     }
  140.     else if (outputStateTarget[0] == 1) {
  141.         if (diagState == DIAG_NORMAL) {
  142.             gpio_set_statement(CH0_ON, CH0_PIN);
  143.         }
  144.         else {
  145.             // DIAG override, we cannot set ON state right now
  146.             gpio_set_statement(CH0_OFF, CH0_PIN);
  147.         }
  148.     }
  149.     #endif
  150.  
  151.     #if act_protectedOutput_CH_COUNT >= 2
  152.     if (outputStateTarget[1] == 0) {
  153.         gpio_set_statement(CH1_OFF, CH1_PIN);
  154.     }
  155.     else if (outputStateTarget[1] == 1) {
  156.         if (diagState == DIAG_NORMAL) {
  157.             gpio_set_statement(CH1_ON, CH1_PIN);
  158.         }
  159.         else {
  160.             // DIAG override, we cannot set ON state right now
  161.             gpio_set_statement(CH1_OFF, CH1_PIN);
  162.         }
  163.     }
  164.     #endif
  165.  
  166.     #if act_protectedOutput_CH_COUNT >= 3
  167.     if (outputStateTarget[2] == 0) {
  168.         gpio_set_statement(CH2_OFF, CH2_PIN);
  169.     }
  170.     else if (outputStateTarget[2] == 1) {
  171.         if (diagState == DIAG_NORMAL) {
  172.             gpio_set_statement(CH2_ON, CH2_PIN);
  173.         }
  174.         else {
  175.             // DIAG override, we cannot set ON state right now
  176.             gpio_set_statement(CH2_OFF, CH2_PIN);
  177.         }
  178.     }
  179.     #endif
  180.  
  181.     #if act_protectedOutput_CH_COUNT >= 4
  182.     if (outputStateTarget[3] == 0) {
  183.         gpio_set_statement(CH3_OFF, CH3_PIN);
  184.     }
  185.     else if (outputStateTarget[3] == 1) {
  186.         if (diagState == DIAG_NORMAL) {
  187.             gpio_set_statement(CH3_ON, CH3_PIN);
  188.         }
  189.         else {
  190.             // DIAG override, we cannot set ON state right now
  191.             gpio_set_statement(CH3_OFF, CH3_PIN);
  192.         }
  193.     }
  194.     #endif
  195. }
  196.  
  197.  
  198. static void readDiagPin() {
  199.     diagState = gpio_get_state(DIAG_PIN);
  200. }
  201.  
  202.  
  203. static void pcIntCallback(uint8_t id, uint8_t status) {
  204.     // new state of the DIAG pin?
  205.     if (id == act_protectedOutput_DIAG_PIN_PCINT) {
  206.         diagState = status;
  207.         updateOutput();
  208.         // DIAG asserted?
  209.         if (diagState == DIAG_ASSERTED) {
  210.             // if retry-timer mechanism is enabled, initiate timer
  211.             if (act_protectedOutput_RETRY_TIMER_TIME_S > 0) {
  212.                 Timer_SetTimeout(act_protectedOutput_RETRY_TIMER, act_protectedOutput_RETRY_TIMER_TIME_S*1000, TimerTypeOneShot, 0);
  213.             }
  214.             // if the retry-mechanism is disabled, change the target output state to OFF
  215.             else {
  216.                 for (uint8_t i=0; i<act_protectedOutput_CH_COUNT; i++) {
  217.                     outputStateTarget[i] = 0;
  218.                 }
  219.             }
  220.         }
  221.         // something interesting obviously happened. let's report it
  222.         diagReportPending = 1;
  223.     }
  224. }
  225.  
  226.  
  227. void act_protectedOutput_Init() {
  228.     /*
  229.      * Init target state vector, in case EEPROM is disabled
  230.      */
  231.     for (uint8_t i=0; i<act_protectedOutput_CH_COUNT; i++) {
  232.         outputStateTarget[i] = 0;
  233.     }
  234.  
  235.     /*
  236.      * Configure DIAG input pin
  237.      */
  238.     if (act_protectedOutput_DIAG_PIN_PULL_ENABLED) {
  239.         // if DIAG is asserted low, we need pull-up
  240.         gpio_set_statement(act_protectedOutput_DIAG_PIN_POLARITY == 0 ? 1 : 0, DIAG_PIN);
  241.     }
  242.     gpio_set_in(DIAG_PIN);
  243.     Pcint_SetCallbackPin(act_protectedOutput_DIAG_PIN_PCINT, DIAG_PIN, &pcIntCallback);
  244.    
  245.     /*
  246.      * Read EEPROM data
  247.      */
  248. #if act_protectedOutput_EEPROM_ENABLED == 1
  249.     if (EEDATA_OK) {
  250. #if act_protectedOutput_CH_COUNT >= 1
  251.       outputStateTarget[0] = eeprom_read_byte(EEDATA.ch0);
  252. #endif
  253. #if act_protectedOutput_CH_COUNT >= 2
  254.       outputStateTarget[1] = eeprom_read_byte(EEDATA.ch1);
  255. #endif
  256. #if act_protectedOutput_CH_COUNT >= 3
  257.       outputStateTarget[2] = eeprom_read_byte(EEDATA.ch2);
  258. #endif
  259. #if act_protectedOutput_CH_COUNT >= 4
  260.       outputStateTarget[3] = eeprom_read_byte(EEDATA.ch3);
  261. #endif
  262.     }
  263.     else {
  264.         //The CRC of the EEPROM is not correct, store default values and update CRC
  265. #if act_protectedOutput_CH_COUNT >= 1
  266.         eeprom_write_byte_crc(EEDATA.ch0, 0x00, WITHOUT_CRC);
  267. #endif
  268. #if act_protectedOutput_CH_COUNT >= 2
  269.         eeprom_write_byte_crc(EEDATA.ch1, 0x00, WITHOUT_CRC);
  270. #endif
  271. #if act_protectedOutput_CH_COUNT >= 3
  272.         eeprom_write_byte_crc(EEDATA.ch2, 0x00, WITHOUT_CRC);
  273. #endif
  274. #if act_protectedOutput_CH_COUNT >= 4
  275.         eeprom_write_byte_crc(EEDATA.ch3, 0x00, WITHOUT_CRC);
  276. #endif
  277.         EEDATA_UPDATE_CRC;
  278.     }
  279. #endif
  280.  
  281.     /*
  282.      * Configure OUTPUT pins
  283.      */
  284.     #if act_protectedOutput_CH_COUNT >= 1
  285.     gpio_set_statement(CH0_OFF, CH0_PIN);
  286.     gpio_set_out(act_protectedOutput_CH0);
  287.     #endif
  288.    
  289.     #if act_protectedOutput_CH_COUNT >= 2
  290.     gpio_set_statement(CH1_OFF, CH1_PIN);
  291.     gpio_set_out(act_protectedOutput_CH1);
  292.     #endif
  293.  
  294.     #if act_protectedOutput_CH_COUNT >= 3
  295.     gpio_set_statement(CH2_OFF, CH2_PIN);
  296.     gpio_set_out(act_protectedOutput_CH2);
  297.     #endif
  298.  
  299.     #if act_protectedOutput_CH_COUNT >= 4
  300.     gpio_set_statement(CH3_OFF, CH3_PIN);
  301.     gpio_set_out(act_protectedOutput_CH3);
  302.     #endif
  303.  
  304.     diagState = DIAG_NORMAL;
  305. }
  306.  
  307.  
  308. void act_protectedOutput_Process() {
  309.  
  310. #if act_protectedOutput_EEPROM_ENABLED == 1
  311.     if (Timer_Expired(act_protectedOutput_STORE_VALUE_TIMEOUT)) {
  312. #if act_protectedOutput_CH_COUNT >= 1
  313.         eeprom_write_byte_crc(EEDATA.ch0, outputStateTarget[0], WITHOUT_CRC);
  314. #endif
  315. #if act_protectedOutput_CH_COUNT >= 2
  316.         eeprom_write_byte_crc(EEDATA.ch1, outputStateTarget[1], WITHOUT_CRC);
  317. #endif
  318. #if act_protectedOutput_CH_COUNT >= 3
  319.         eeprom_write_byte_crc(EEDATA.ch2, outputStateTarget[2], WITHOUT_CRC);
  320. #endif
  321. #if act_protectedOutput_CH_COUNT >= 4
  322.         eeprom_write_byte_crc(EEDATA.ch3, outputStateTarget[3], WITHOUT_CRC);
  323. #endif
  324.         EEDATA_UPDATE_CRC;
  325.     }
  326. #endif
  327.  
  328.     // shall we retry to set target output state?
  329.     if (Timer_Expired(act_protectedOutput_RETRY_TIMER)) {
  330.         // read DIAG pin again and update outputs accordingly
  331.         readDiagPin();
  332.         updateOutput();
  333.         if (diagState == DIAG_ASSERTED) {
  334.             // if DIAG was still asserted, initiate another timer run
  335.             Timer_SetTimeout(act_protectedOutput_RETRY_TIMER, act_protectedOutput_RETRY_TIMER_TIME_S*1000, TimerTypeOneShot, 0);
  336.         }
  337.         else {
  338.             // things went back to normal. report this
  339.             diagReportPending = 1;
  340.         }
  341.     }
  342.    
  343.     // shall we report diag status to CAN?
  344.     if (diagReportPending) {
  345.         StdCan_Msg_t txMsg;
  346.         StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  347.         StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  348.         txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT;
  349.         txMsg.Header.ModuleId = act_protectedOutput_ID;
  350.         txMsg.Header.Command = CAN_MODULE_CMD_PHYSICAL_PINSTATUS;
  351.         txMsg.Length = 2;
  352.         txMsg.Data[0] = 0; //TODO: add support for more channels
  353.         // we follow the standard SNS_INPUT format, but the data corresponds to the "health" rather than physical level
  354.         if (diagState == DIAG_NORMAL) {
  355.             txMsg.Data[1] = 1;  //healthy, target output state stable
  356.         } else {
  357.             txMsg.Data[1] = 0;  //not healthy, DIAG pin ASSERTED, not in target output state
  358.         }
  359.         while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  360.         diagReportPending = 0;
  361.     }
  362. }
  363.  
  364.  
  365. void act_protectedOutput_HandleMessage(StdCan_Msg_t *rxMsg) {
  366.     if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_ACT &&
  367.         StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_TO_OWNER &&
  368.         rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT &&
  369.         rxMsg->Header.ModuleId == act_protectedOutput_ID)
  370.     {
  371.         switch (rxMsg->Header.Command) {
  372.            
  373.             case CAN_MODULE_CMD_PHYSICAL_SETPIN:
  374.                 /*
  375.                  * This message is used to activate/deactivate
  376.                  * an output channel.
  377.                  */
  378.                 if (rxMsg->Length == 2) {
  379.                     uint8_t channel = rxMsg->Data[0];
  380.                     if (channel >= 0 && channel < act_protectedOutput_CH_COUNT) {
  381.                         outputStateTarget[channel] = rxMsg->Data[1];
  382.                         readDiagPin();
  383.                         updateOutput();
  384. #if act_protectedOutput_EEPROM_ENABLED == 1
  385.                         // output states changed, store to EE after thie timer delay
  386.                         Timer_SetTimeout(act_protectedOutput_STORE_VALUE_TIMEOUT, act_protectedOutput_STORE_VALUE_TIMEOUT_TIME_S*1000, TimerTypeOneShot, 0);
  387. #endif
  388.                     }              
  389.                     StdCan_Set_direction(rxMsg->Header, DIRECTIONFLAG_FROM_OWNER);
  390.                     rxMsg->Length = 2;
  391.                     while (StdCan_Put(rxMsg) != StdCan_Ret_OK);
  392.                 }
  393.                 break;
  394.         }
  395.     }
  396. }
  397.  
  398.  
  399. void act_protectedOutput_List(uint8_t ModuleSequenceNumber)
  400. {
  401.     StdCan_Msg_t txMsg;
  402.     StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_ACT);
  403.     StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  404.     txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT;
  405.     txMsg.Header.ModuleId = act_protectedOutput_ID;
  406.     txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_LIST;
  407.     txMsg.Length = 6;
  408.  
  409.     txMsg.Data[0] = NODE_HW_ID_BYTE0;
  410.     txMsg.Data[1] = NODE_HW_ID_BYTE1;
  411.     txMsg.Data[2] = NODE_HW_ID_BYTE2;
  412.     txMsg.Data[3] = NODE_HW_ID_BYTE3;
  413.    
  414.     txMsg.Data[4] = NUMBER_OF_MODULES;
  415.     txMsg.Data[5] = ModuleSequenceNumber;
  416.    
  417.     while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  418. }
  419.  
  420.