Subversion Repositories HomeAutomation

Rev

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

  1.  
  2. #include "sns_power.h"
  3.  
  4. static uint32_t volatile PreviusTimerValue, lastMeasurment;
  5.  
  6. #ifdef sns_power_10000_PULSES_PER_KWH
  7.   static uint8_t volatile tmpCounter=0;
  8. #endif
  9. static uint8_t volatile StoreInEEPROM = 0;
  10. static uint8_t sns_power_ReportInterval = (uint8_t)sns_power_SEND_PERIOD;
  11. static uint16_t volatile MeasurmentBuffer[32]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  12. static uint8_t volatile MeasurmentBufferPointer=0;
  13. static uint32_t volatile EnergyCounter=0;
  14. #if sns_power_SEND_1_MIN_AVG == 1
  15.   static uint16_t volatile avgCounter = 0;
  16. #endif
  17.  
  18. #ifdef POWER_SNS_PIN_ch2
  19.   static uint32_t volatile PreviusTimerValue_ch2, lastMeasurment_ch2;
  20.  
  21.   #ifdef sns_power_10000_PULSES_PER_KWH
  22.     static uint8_t volatile tmpCounter_ch2=0;
  23.   #endif
  24.   static uint16_t volatile MeasurmentBuffer_ch2[32]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  25.   static uint8_t volatile MeasurmentBufferPointer_ch2=0;
  26.   static uint32_t volatile EnergyCounter_ch2=0;
  27.   #if sns_power_SEND_1_MIN_AVG == 1
  28.     static uint16_t volatile avgCounter_ch2 = 0;
  29.   #endif
  30. #endif
  31. #if sns_power_USEEEPROM==1
  32.   #include "sns_power_eeprom.h"
  33.   struct eeprom_sns_power EEMEM eeprom_sns_power =
  34.   {
  35.       {
  36.           ///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.
  37.           (uint8_t)sns_power_SEND_PERIOD,   // reportInterval
  38.           0,    // EnergyCounterUpper
  39.           0,    // EnergyCounterLower
  40.           #ifdef POWER_SNS_PIN_ch2
  41.             0,  // EnergyCounterUpper_ch2
  42.             0,  // EnergyCounterLower_ch2
  43.           #endif
  44.       },
  45.       0 // crc, must be a correct value, but this will also be handled by the EEPROM module or make scripts
  46.   };
  47. #endif
  48.  
  49. #if sns_power_SEND_1_MIN_AVG == 1
  50.   void sns_power_timer_callback(uint8_t timer)
  51.   {
  52.       StdCan_Msg_t txMsg;
  53.       StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  54.       StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  55.       txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER;
  56.       txMsg.Header.ModuleId = sns_power_ID;
  57.       txMsg.Header.Command = CAN_MODULE_CMD_POWER_AVGPOWER;
  58.       txMsg.Length = 2;
  59.       cli();
  60.       txMsg.Data[0] = (uint8_t)((avgCounter>>8) & 0xff);
  61.       txMsg.Data[1] = (uint8_t)(avgCounter & 0xff);
  62.       avgCounter = 0;
  63.       sei();
  64.       while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  65.  
  66.       #ifdef POWER_SNS_PIN_ch2
  67.         txMsg.Length = 2;
  68.         txMsg.Header.ModuleId = sns_power_ID_ch2;
  69.         cli();
  70.         txMsg.Data[0] = (uint8_t)((avgCounter_ch2>>8) & 0xff);
  71.         txMsg.Data[1] = (uint8_t)(avgCounter_ch2 & 0xff);
  72.         avgCounter = 0;
  73.         sei();
  74.         while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  75.  
  76.       #endif
  77.   }
  78. #endif
  79.  
  80. void sns_power_pcint_callback(uint8_t id, uint8_t status)
  81. {
  82.     if (status == 0)
  83.     {
  84.         if (Timer_GetTicks() - PreviusTimerValue >= 16)
  85.         {
  86.             MeasurmentBufferPointer++;
  87.             if (MeasurmentBufferPointer >= 32) MeasurmentBufferPointer = 0;
  88.             lastMeasurment =  Timer_GetTicks() - PreviusTimerValue;
  89.             MeasurmentBuffer[MeasurmentBufferPointer] = (uint16_t) (lastMeasurment & 0x0000FFFF);
  90.             PreviusTimerValue = Timer_GetTicks();
  91.             #if sns_power_1000_PULSES_PER_KWH == 1
  92.                 EnergyCounter++;
  93.                 if (EnergyCounter % 1024 == 0)
  94.                     StoreInEEPROM = 1; 
  95.             #endif
  96.             #if sns_power_10000_PULSES_PER_KWH == 1
  97.                 tmpCounter++;
  98.                 #if sns_power_SEND_1_MIN_AVG == 1
  99.                 avgCounter++;
  100.                 #endif
  101.                 if(tmpCounter >= 10) {
  102.                     EnergyCounter++;
  103.                     if (EnergyCounter % 1024 == 0)
  104.                         StoreInEEPROM = 1;
  105.                     tmpCounter = 0;
  106.                 }
  107.             #endif
  108.  
  109. #ifdef sns_power_LED_PIN
  110.             gpio_toggle_pin(sns_power_LED_PIN); // toggle pin
  111. #endif
  112.         }
  113.     }
  114. }
  115.  
  116. #ifdef POWER_SNS_PIN_ch2
  117. void sns_power_pcint_callback_ch2(uint8_t id, uint8_t status)
  118. {
  119.     if (status == 0)
  120.     {
  121.         if (Timer_GetTicks() - PreviusTimerValue_ch2 >= 16)
  122.         {
  123.             MeasurmentBufferPointer_ch2++;
  124.             if (MeasurmentBufferPointer_ch2 >= 32) MeasurmentBufferPointer_ch2 = 0;
  125.             lastMeasurment_ch2 =  Timer_GetTicks() - PreviusTimerValue_ch2;
  126.             MeasurmentBuffer_ch2[MeasurmentBufferPointer_ch2] = (uint16_t) (lastMeasurment_ch2 & 0x0000FFFF);
  127.             PreviusTimerValue_ch2 = Timer_GetTicks();
  128.             #if sns_power_1000_PULSES_PER_KWH == 1
  129.                 EnergyCounter_ch2++;
  130.             #endif
  131.             #if sns_power_10000_PULSES_PER_KWH == 1
  132.                 tmpCounter_ch2++;
  133.                 #if sns_power_SEND_1_MIN_AVG == 1
  134.                 avgCounter_ch2++;
  135.                 #endif
  136.                 if(tmpCounter_ch2 >= 10) {
  137.                     EnergyCounter_ch2++;
  138.                     tmpCounter_ch2 = 0;
  139.                 }
  140.             #endif
  141. #ifdef sns_power_LED_PIN
  142.             gpio_toggle_pin(sns_power_LED_PIN); // toggle pin
  143. #endif
  144.         }
  145.     }
  146. }
  147. #endif
  148.  
  149. void sns_power_Init(void)
  150. {
  151. #if sns_power_USEEEPROM==1
  152.     if (EEDATA_OK)
  153.     {
  154.       ///TODO: Use stored data to set initial values for the module
  155.       sns_power_ReportInterval = eeprom_read_byte(EEDATA.reportInterval);
  156.       EnergyCounter = eeprom_read_word(EEDATA16.EnergyCounterLower);
  157.       EnergyCounter += (((uint32_t)(eeprom_read_word(EEDATA16.EnergyCounterUpper)))<<16);
  158.         #ifdef POWER_SNS_PIN_ch2
  159.           EnergyCounter_ch2 = eeprom_read_word(EEDATA16.EnergyCounterLower_ch2);
  160.           EnergyCounter_ch2 += (((uint32_t)(eeprom_read_word(EEDATA16.EnergyCounterUpper_ch2)))<<16);
  161.         #endif
  162.     } else
  163.     {   //The CRC of the EEPROM is not correct, store default values and update CRC
  164.       eeprom_write_byte_crc(EEDATA.reportInterval, sns_power_SEND_PERIOD, WITHOUT_CRC);
  165.       eeprom_write_word_crc(EEDATA16.EnergyCounterUpper, 0, WITHOUT_CRC);
  166.       eeprom_write_word_crc(EEDATA16.EnergyCounterLower, 0, WITHOUT_CRC);
  167.       #ifdef POWER_SNS_PIN_ch2
  168.         eeprom_write_word_crc(EEDATA16.EnergyCounterUpper_ch2, 0, WITHOUT_CRC);
  169.         eeprom_write_word_crc(EEDATA16.EnergyCounterLower_ch2, 0, WITHOUT_CRC);
  170.       #endif
  171.       EEDATA_UPDATE_CRC;
  172.       sns_power_ReportInterval = eeprom_read_byte(EEDATA.reportInterval);
  173.     }
  174. #endif  
  175.     ///Initialize hardware etc
  176.     gpio_set_in(POWER_SNS_PIN); // Set to input
  177. #if sns_power_PIN_PULLUP==1
  178.     gpio_set_pullup(POWER_SNS_PIN); // Enable pull-up
  179. #endif
  180.  
  181.     Pcint_SetCallbackPin(sns_power_PCINT, POWER_SNS_PIN, &sns_power_pcint_callback);
  182.  
  183.     MeasurmentBufferPointer = 0;
  184. #ifdef POWER_SNS_PIN_ch2
  185.     gpio_set_in(POWER_SNS_PIN_ch2); // Set to input
  186. #if sns_power_PIN_PULLUP_ch2==1
  187.     gpio_set_pullup(POWER_SNS_PIN_ch2); // Enable pull-up
  188. #endif
  189.    
  190.     Pcint_SetCallbackPin(sns_power_PCINT_ch2, POWER_SNS_PIN_ch2, &sns_power_pcint_callback_ch2);
  191.  
  192.     MeasurmentBufferPointer_ch2 = 0;
  193. #endif
  194.     Timer_SetTimeout(sns_power_SEND_TIMER, sns_power_ReportInterval*1000 , TimerTypeFreeRunning, 0);
  195. #if sns_power_SEND_1_MIN_AVG == 1
  196.     Timer_SetTimeout(sns_power_SEND_TIMER_1_MIN_AVG, 60000-10 , TimerTypeFreeRunning, &sns_power_timer_callback);
  197. #endif
  198.  
  199. #ifdef sns_power_LED_PIN
  200.     gpio_set_out(sns_power_LED_PIN);    // Set to output
  201.     gpio_clr_pin(sns_power_LED_PIN);    // clear pin
  202. #endif
  203. }
  204.  
  205. void sns_power_Process(void)
  206. {
  207.     if (StoreInEEPROM == 1)
  208.     {
  209.         StoreInEEPROM = 0;
  210.        
  211.         eeprom_write_word_crc(EEDATA16.EnergyCounterUpper, (uint16_t)((EnergyCounter>>16) & 0xffff), WITHOUT_CRC);
  212.         eeprom_write_word_crc(EEDATA16.EnergyCounterLower, (uint16_t)(EnergyCounter & 0xffff), WITH_CRC);
  213.     #ifdef POWER_SNS_PIN_ch2
  214.         eeprom_write_word_crc(EEDATA16.EnergyCounterUpper_ch2, (uint16_t)((EnergyCounter_ch2>>16) & 0xffff), WITHOUT_CRC);
  215.         eeprom_write_word_crc(EEDATA16.EnergyCounterLower_ch2, (uint16_t)(EnergyCounter_ch2 & 0xffff), WITH_CRC);
  216.     #endif
  217.     }
  218.     StdCan_Msg_t txMsg;
  219.     if (Timer_Expired(sns_power_SEND_TIMER)) {
  220.         //4 times average
  221.         /*uint32_t Avg4 = MeasurmentBuffer[MeasurmentBufferPointer] + MeasurmentBuffer[MeasurmentBufferPointer-1] + MeasurmentBuffer[MeasurmentBufferPointer-2] + MeasurmentBuffer[MeasurmentBufferPointer-3];
  222.         Avg4 = (360000/(Avg4/4));
  223.         */
  224.         //32 times average
  225.         uint32_t Avg32 = 0;
  226.         for (uint8_t i = 0; i<32;i++) {
  227.              Avg32 += MeasurmentBuffer[i];
  228.         }
  229.         Avg32 /= 32;
  230.         #if sns_power_1000_PULSES_PER_KWH == 1
  231.             Avg32 = (3600000/Avg32);
  232.         #endif
  233.         #if sns_power_10000_PULSES_PER_KWH == 1
  234.             Avg32 = (360000/Avg32);
  235.         #endif
  236.  
  237.            
  238.         StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  239.         StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  240.         txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER;
  241.         txMsg.Header.ModuleId = sns_power_ID;
  242.         txMsg.Header.Command = CAN_MODULE_CMD_PHYSICAL_ELECTRICPOWER;
  243.         txMsg.Length = 8;
  244.         #if sns_power_1000_PULSES_PER_KWH == 1
  245.             uint32_t tmp = 3600000/MeasurmentBuffer[MeasurmentBufferPointer];
  246.         #endif
  247.         #if sns_power_10000_PULSES_PER_KWH == 1
  248.             uint32_t tmp = 360000/MeasurmentBuffer[MeasurmentBufferPointer];
  249.         #endif
  250.         txMsg.Data[0] = (uint8_t)((tmp>>8) & 0xff);
  251.         txMsg.Data[1] = (uint8_t)(tmp & 0xff);
  252.         txMsg.Data[5] = (uint8_t)EnergyCounter & 0xff;
  253.         txMsg.Data[4] = (uint8_t)(EnergyCounter >> 8) & 0xff;
  254.         txMsg.Data[3] = (uint8_t)(EnergyCounter >> 16) & 0xff;
  255.         txMsg.Data[2] = (uint8_t)(EnergyCounter >> 24) & 0xff;
  256.         txMsg.Data[6] = (uint8_t)((Avg32>>8) & 0xff);
  257.         txMsg.Data[7] = (uint8_t)(Avg32 & 0xff);
  258.         while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  259.        
  260.     #ifdef POWER_SNS_PIN_ch2
  261.         uint32_t Avg32_ch2 = 0;
  262.         for (uint8_t i = 0; i<32;i++) {
  263.              Avg32_ch2 += MeasurmentBuffer_ch2[i];
  264.         }
  265.         Avg32_ch2 /= 32;
  266.         #if sns_power_1000_PULSES_PER_KWH == 1
  267.             Avg32_ch2 = (3600000/Avg32_ch2);
  268.         #endif
  269.         #if sns_power_10000_PULSES_PER_KWH == 1
  270.             Avg32_ch2 = (360000/Avg32_ch2);
  271.         #endif
  272.            
  273.         txMsg.Header.ModuleId = sns_power_ID_ch2;
  274.         #if sns_power_1000_PULSES_PER_KWH == 1
  275.             tmp = 3600000/MeasurmentBuffer_ch2[MeasurmentBufferPointer_ch2];
  276.         #endif
  277.         #if sns_power_10000_PULSES_PER_KWH == 1
  278.             tmp = 360000/MeasurmentBuffer_ch2[MeasurmentBufferPointer_ch2];
  279.         #endif
  280.         txMsg.Data[0] = (uint8_t)((tmp>>8) & 0xff);
  281.         txMsg.Data[1] = (uint8_t)(tmp & 0xff);
  282.         txMsg.Data[5] = (uint8_t)EnergyCounter_ch2 & 0xff;
  283.         txMsg.Data[4] = (uint8_t)(EnergyCounter_ch2 >> 8) & 0xff;
  284.         txMsg.Data[3] = (uint8_t)(EnergyCounter_ch2 >> 16) & 0xff;
  285.         txMsg.Data[2] = (uint8_t)(EnergyCounter_ch2 >> 24) & 0xff;
  286.         txMsg.Data[6] = (uint8_t)((Avg32_ch2>>8) & 0xff);
  287.         txMsg.Data[7] = (uint8_t)(Avg32_ch2 & 0xff);
  288.         while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  289.        
  290.     #endif
  291.        
  292.        
  293.     }
  294. }
  295.  
  296. void sns_power_HandleMessage(StdCan_Msg_t *rxMsg)
  297. {
  298.     if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_SNS &&
  299.         StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_TO_OWNER &&
  300.         rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_POWER &&
  301.         rxMsg->Header.ModuleId == sns_power_ID)
  302.     {
  303. StdCan_Msg_t txMsg;
  304.         switch (rxMsg->Header.Command)
  305.         {
  306.         case CAN_MODULE_CMD_GLOBAL_REPORT_INTERVAL:
  307.             if (rxMsg->Length > 0)
  308.             {
  309.                 sns_power_ReportInterval = rxMsg->Data[0];
  310.                 Timer_SetTimeout(sns_power_SEND_TIMER, sns_power_ReportInterval*1000 , TimerTypeFreeRunning, 0);
  311.             }
  312.             StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  313.             StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  314.             txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER;
  315.             txMsg.Header.ModuleId = sns_power_ID;
  316.             txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_REPORT_INTERVAL;
  317.             txMsg.Length = 1;
  318.             txMsg.Data[0] = sns_power_ReportInterval;
  319.             StdCan_Put(&txMsg);
  320.             break;
  321.         case CAN_MODULE_CMD_POWER_SETENERGY:
  322.             if (rxMsg->Length == 4)
  323.             {
  324.                 EnergyCounter = rxMsg->Data[3];
  325.                 EnergyCounter += ((uint32_t)rxMsg->Data[2])<<8;
  326.                 EnergyCounter += ((uint32_t)rxMsg->Data[1])<<16;
  327.                 EnergyCounter += ((uint32_t)rxMsg->Data[0])<<24;
  328.             }
  329.             StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  330.             StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  331.             txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER;
  332.             txMsg.Header.ModuleId = sns_power_ID;
  333.             txMsg.Header.Command = CAN_MODULE_CMD_POWER_SETENERGY;
  334.             txMsg.Length = 1;
  335.             txMsg.Data[3] = (uint8_t)EnergyCounter & 0xff;
  336.             txMsg.Data[2] = (uint8_t)(EnergyCounter >> 8) & 0xff;
  337.             txMsg.Data[1] = (uint8_t)(EnergyCounter >> 16) & 0xff;
  338.             txMsg.Data[0] = (uint8_t)(EnergyCounter >> 24) & 0xff;
  339.             StdCan_Put(&txMsg);
  340.            
  341.             break;
  342.         }
  343.     }
  344.    
  345. #ifdef POWER_SNS_PIN_ch2   
  346.     if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_SNS &&
  347.         StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_TO_OWNER &&
  348.         rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_POWER &&
  349.         rxMsg->Header.ModuleId == sns_power_ID_ch2)
  350.     {
  351.         StdCan_Msg_t txMsg;
  352.         switch (rxMsg->Header.Command)
  353.         {
  354.         case CAN_MODULE_CMD_GLOBAL_REPORT_INTERVAL:
  355.             if (rxMsg->Length > 0)
  356.             {
  357.                 sns_power_ReportInterval = rxMsg->Data[0];
  358.                 Timer_SetTimeout(sns_power_SEND_TIMER, sns_power_ReportInterval*1000 , TimerTypeFreeRunning, 0);
  359.             }
  360.             StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  361.             StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  362.             txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER;
  363.             txMsg.Header.ModuleId = sns_power_ID_ch2;
  364.             txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_REPORT_INTERVAL;
  365.             txMsg.Length = 1;
  366.             txMsg.Data[0] = sns_power_ReportInterval;
  367.             StdCan_Put(&txMsg);
  368.             break;
  369.         case CAN_MODULE_CMD_POWER_SETENERGY:
  370.             if (rxMsg->Length == 4)
  371.             {
  372.                 EnergyCounter_ch2 = rxMsg->Data[3];
  373.                 EnergyCounter_ch2 += ((uint32_t)rxMsg->Data[2])<<8;
  374.                 EnergyCounter_ch2 += ((uint32_t)rxMsg->Data[1])<<16;
  375.                 EnergyCounter_ch2 += ((uint32_t)rxMsg->Data[0])<<24;
  376.             }
  377.             StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  378.             StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  379.             txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER;
  380.             txMsg.Header.ModuleId = sns_power_ID_ch2;
  381.             txMsg.Header.Command = CAN_MODULE_CMD_POWER_SETENERGY;
  382.             txMsg.Length = 1;
  383.             txMsg.Data[3] = (uint8_t)EnergyCounter_ch2 & 0xff;
  384.             txMsg.Data[2] = (uint8_t)(EnergyCounter_ch2 >> 8) & 0xff;
  385.             txMsg.Data[1] = (uint8_t)(EnergyCounter_ch2 >> 16) & 0xff;
  386.             txMsg.Data[0] = (uint8_t)(EnergyCounter_ch2 >> 24) & 0xff;
  387.             StdCan_Put(&txMsg);
  388.            
  389.             break;
  390.         }
  391.     }
  392. #endif
  393.    
  394. }
  395.  
  396. void sns_power_List(uint8_t ModuleSequenceNumber)
  397. {
  398.     StdCan_Msg_t txMsg;
  399.    
  400.     StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  401.     StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  402.     txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER;
  403.     txMsg.Header.ModuleId = sns_power_ID;
  404.     txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_LIST;
  405.     txMsg.Length = 6;
  406.  
  407.     uint32_t HwId=BIOS_GetHwId();
  408.     txMsg.Data[0] = HwId&0xff;
  409.     txMsg.Data[1] = (HwId>>8)&0xff;
  410.     txMsg.Data[2] = (HwId>>16)&0xff;
  411.     txMsg.Data[3] = (HwId>>24)&0xff;
  412.    
  413.     txMsg.Data[4] = NUMBER_OF_MODULES;
  414.     txMsg.Data[5] = ModuleSequenceNumber;
  415.    
  416.     while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  417.    
  418.    
  419. #ifdef POWER_SNS_PIN_ch2   
  420.     txMsg.Header.ModuleId = sns_power_ID_ch2;
  421.     txMsg.Data[5] = ModuleSequenceNumber;
  422.     while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  423. #endif
  424. }
  425.