Subversion Repositories HomeAutomation

Rev

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