Subversion Repositories HomeAutomation

Rev

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 chTargetState[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(uint8_t skipDiagCheck);
  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(uint8_t skipDiagCheck) {
  135.  
  136.     #if act_protectedOutput_CH_COUNT >= 1
  137.     if (chTargetState[0] == 0) {
  138.         gpio_set_statement(CH0_OFF, CH0_PIN);
  139.     }
  140.     else if (chTargetState[0] == 1) {
  141.         if (diagState == DIAG_NORMAL || skipDiagCheck) {
  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 (chTargetState[1] == 0) {
  153.         gpio_set_statement(CH1_OFF, CH1_PIN);
  154.     }
  155.     else if (chTargetState[1] == 1) {
  156.         if (diagState == DIAG_NORMAL || skipDiagCheck) {
  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 (chTargetState[2] == 0) {
  168.         gpio_set_statement(CH2_OFF, CH2_PIN);
  169.     }
  170.     else if (chTargetState[2] == 1) {
  171.         if (diagState == DIAG_NORMAL || skipDiagCheck) {
  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 (chTargetState[3] == 0) {
  183.         gpio_set_statement(CH3_OFF, CH3_PIN);
  184.     }
  185.     else if (chTargetState[3] == 1) {
  186.         if (diagState == DIAG_NORMAL || skipDiagCheck) {
  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.         readDiagPin();
  208.         updateOutput(0);
  209.         // DIAG asserted?
  210.         if (diagState == DIAG_ASSERTED) {
  211.             // if retry-timer mechanism is enabled, initiate timer
  212.             if (act_protectedOutput_RETRY_TIMER_TIME_S > 0) {
  213.                 Timer_SetTimeout(act_protectedOutput_RETRY_TIMER, act_protectedOutput_RETRY_TIMER_TIME_S*1000, TimerTypeOneShot, 0);
  214.             }
  215.             // if the retry-mechanism is disabled, change the target output state to OFF
  216.             else {
  217.                 for (uint8_t i=0; i<act_protectedOutput_CH_COUNT; i++) {
  218.                     chTargetState[i] = 0;
  219.                 }
  220. #if act_protectedOutput_EEPROM_ENABLED == 1
  221.                 // output states changed, store to EE after this timer delay
  222.                 Timer_SetTimeout(act_protectedOutput_STORE_VALUE_TIMEOUT, act_protectedOutput_STORE_VALUE_TIMEOUT_TIME_S*1000, TimerTypeOneShot, 0);
  223. #endif
  224.             }
  225.         }
  226.         // something interesting obviously happened. let's report it
  227.         diagReportPending = 1;
  228.     }
  229. }
  230.  
  231.  
  232. void act_protectedOutput_Init() {
  233.     /*
  234.      * Init target state vector, in case EEPROM is disabled
  235.      */
  236.     for (uint8_t i=0; i<act_protectedOutput_CH_COUNT; i++) {
  237.         chTargetState[i] = 0;
  238.     }
  239.  
  240.     /*
  241.      * Configure DIAG input pin
  242.      */
  243.     if (act_protectedOutput_DIAG_PIN_PULL_ENABLED) {
  244.         // if DIAG is asserted low, we need pull-up
  245.         gpio_set_statement(act_protectedOutput_DIAG_PIN_POLARITY == 0 ? 1 : 0, DIAG_PIN);
  246.     }
  247.     gpio_set_in(DIAG_PIN);
  248.     Pcint_SetCallbackPin(act_protectedOutput_DIAG_PIN_PCINT, DIAG_PIN, &pcIntCallback);
  249.    
  250.     /*
  251.      * Read EEPROM data
  252.      */
  253. #if act_protectedOutput_EEPROM_ENABLED == 1
  254.     if (EEDATA_OK) {
  255. #if act_protectedOutput_CH_COUNT >= 1
  256.       chTargetState[0] = eeprom_read_byte(EEDATA.ch0);
  257. #endif
  258. #if act_protectedOutput_CH_COUNT >= 2
  259.       chTargetState[1] = eeprom_read_byte(EEDATA.ch1);
  260. #endif
  261. #if act_protectedOutput_CH_COUNT >= 3
  262.       chTargetState[2] = eeprom_read_byte(EEDATA.ch2);
  263. #endif
  264. #if act_protectedOutput_CH_COUNT >= 4
  265.       chTargetState[3] = eeprom_read_byte(EEDATA.ch3);
  266. #endif
  267.     }
  268.     else {
  269.         //The CRC of the EEPROM is not correct, store default values and update CRC
  270. #if act_protectedOutput_CH_COUNT >= 1
  271.         eeprom_write_byte_crc(EEDATA.ch0, 0x00, WITHOUT_CRC);
  272. #endif
  273. #if act_protectedOutput_CH_COUNT >= 2
  274.         eeprom_write_byte_crc(EEDATA.ch1, 0x00, WITHOUT_CRC);
  275. #endif
  276. #if act_protectedOutput_CH_COUNT >= 3
  277.         eeprom_write_byte_crc(EEDATA.ch2, 0x00, WITHOUT_CRC);
  278. #endif
  279. #if act_protectedOutput_CH_COUNT >= 4
  280.         eeprom_write_byte_crc(EEDATA.ch3, 0x00, WITHOUT_CRC);
  281. #endif
  282.         EEDATA_UPDATE_CRC;
  283.     }
  284. #endif
  285.  
  286.     /*
  287.      * Configure OUTPUT pins
  288.      */
  289.     #if act_protectedOutput_CH_COUNT >= 1
  290.     gpio_set_statement(CH0_OFF, CH0_PIN);
  291.     gpio_set_out(act_protectedOutput_CH0);
  292.     #endif
  293.    
  294.     #if act_protectedOutput_CH_COUNT >= 2
  295.     gpio_set_statement(CH1_OFF, CH1_PIN);
  296.     gpio_set_out(act_protectedOutput_CH1);
  297.     #endif
  298.  
  299.     #if act_protectedOutput_CH_COUNT >= 3
  300.     gpio_set_statement(CH2_OFF, CH2_PIN);
  301.     gpio_set_out(act_protectedOutput_CH2);
  302.     #endif
  303.  
  304.     #if act_protectedOutput_CH_COUNT >= 4
  305.     gpio_set_statement(CH3_OFF, CH3_PIN);
  306.     gpio_set_out(act_protectedOutput_CH3);
  307.     #endif
  308.  
  309.     diagState = DIAG_NORMAL;
  310. }
  311.  
  312.  
  313. void act_protectedOutput_Process() {
  314.  
  315. #if act_protectedOutput_EEPROM_ENABLED == 1
  316.     if (Timer_Expired(act_protectedOutput_STORE_VALUE_TIMEOUT)) {
  317. #if act_protectedOutput_CH_COUNT >= 1
  318.         eeprom_write_byte_crc(EEDATA.ch0, chTargetState[0], WITHOUT_CRC);
  319. #endif
  320. #if act_protectedOutput_CH_COUNT >= 2
  321.         eeprom_write_byte_crc(EEDATA.ch1, chTargetState[1], WITHOUT_CRC);
  322. #endif
  323. #if act_protectedOutput_CH_COUNT >= 3
  324.         eeprom_write_byte_crc(EEDATA.ch2, chTargetState[2], WITHOUT_CRC);
  325. #endif
  326. #if act_protectedOutput_CH_COUNT >= 4
  327.         eeprom_write_byte_crc(EEDATA.ch3, chTargetState[3], WITHOUT_CRC);
  328. #endif
  329.         EEDATA_UPDATE_CRC;
  330.     }
  331. #endif
  332.  
  333.     // shall we retry to set target output state?
  334.     if (Timer_Expired(act_protectedOutput_RETRY_TIMER)) {
  335.         // read DIAG pin again and update outputs accordingly
  336.         readDiagPin();
  337. #if act_protectedOutput_FORCED_RETRIES == 1
  338.         // forced retry to set output states, regardless of DIAG
  339.         updateOutput(1);
  340.         // read DIAG pin again and hope we have a better flag
  341.         readDiagPin();
  342. #else
  343.         // if DIAG allows it, retry to set the output states
  344.         updateOutput(0);
  345. #endif
  346.         if (diagState == DIAG_ASSERTED) {
  347.             // if DIAG was still asserted, initiate another timer run
  348.             Timer_SetTimeout(act_protectedOutput_RETRY_TIMER, act_protectedOutput_RETRY_TIMER_TIME_S*1000, TimerTypeOneShot, 0);
  349.         }
  350.         else {
  351.             // things went back to normal. report this
  352.             diagReportPending = 1;
  353.         }
  354.     }
  355.    
  356.     // shall we report diag status to CAN?
  357.     if (diagReportPending) {
  358.         StdCan_Msg_t txMsg;
  359.         StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  360.         StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  361.         txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT;
  362.         txMsg.Header.ModuleId = act_protectedOutput_ID;
  363.         txMsg.Header.Command = CAN_MODULE_CMD_PHYSICAL_PINSTATUS;
  364.         txMsg.Length = 2;
  365.         txMsg.Data[0] = 0; //TODO: add support for more channels
  366.         // we follow the standard SNS_INPUT format, but the data corresponds to the "health" rather than physical level
  367.         if (diagState == DIAG_NORMAL) {
  368.             txMsg.Data[1] = 1;  //healthy, target output state stable
  369.         } else {
  370.             txMsg.Data[1] = 0;  //not healthy, DIAG pin ASSERTED, not in target output state
  371.         }
  372.         while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  373.         diagReportPending = 0;
  374.     }
  375. }
  376.  
  377.  
  378. void act_protectedOutput_HandleMessage(StdCan_Msg_t *rxMsg) {
  379.     if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_ACT &&
  380.         StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_TO_OWNER &&
  381.         rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT &&
  382.         rxMsg->Header.ModuleId == act_protectedOutput_ID)
  383.     {
  384.         switch (rxMsg->Header.Command) {
  385.            
  386.             case CAN_MODULE_CMD_PHYSICAL_SETPIN:
  387.                 /*
  388.                  * This message is used to activate/deactivate
  389.                  * an output channel.
  390.                  */
  391.                 if (rxMsg->Length == 2) {
  392.                     uint8_t channel = rxMsg->Data[0];
  393.                     if (channel >= 0 && channel < act_protectedOutput_CH_COUNT) {
  394.                         chTargetState[channel] = rxMsg->Data[1];
  395.                         readDiagPin();
  396. #if act_protectedOutput_FORCED_RETRIES == 1
  397.                         updateOutput(1);
  398. #else
  399.                         updateOutput(0);
  400. #endif
  401. #if act_protectedOutput_EEPROM_ENABLED == 1
  402.                         // output states changed, store to EE after this timer delay
  403.                         Timer_SetTimeout(act_protectedOutput_STORE_VALUE_TIMEOUT, act_protectedOutput_STORE_VALUE_TIMEOUT_TIME_S*1000, TimerTypeOneShot, 0);
  404. #endif
  405.                     }
  406.                     StdCan_Set_direction(rxMsg->Header, DIRECTIONFLAG_FROM_OWNER);
  407.                     rxMsg->Length = 2;
  408.                     while (StdCan_Put(rxMsg) != StdCan_Ret_OK);
  409.                 }
  410.                 break;
  411.         }
  412.     }
  413. }
  414.  
  415.  
  416. void act_protectedOutput_List(uint8_t ModuleSequenceNumber)
  417. {
  418.     StdCan_Msg_t txMsg;
  419.     StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_ACT);
  420.     StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  421.     txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_PROTECTEDOUTPUT;
  422.     txMsg.Header.ModuleId = act_protectedOutput_ID;
  423.     txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_LIST;
  424.     txMsg.Length = 6;
  425.  
  426.     txMsg.Data[0] = NODE_HW_ID_BYTE0;
  427.     txMsg.Data[1] = NODE_HW_ID_BYTE1;
  428.     txMsg.Data[2] = NODE_HW_ID_BYTE2;
  429.     txMsg.Data[3] = NODE_HW_ID_BYTE3;
  430.    
  431.     txMsg.Data[4] = NUMBER_OF_MODULES;
  432.     txMsg.Data[5] = ModuleSequenceNumber;
  433.    
  434.     while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  435. }
  436.  
  437.