Subversion Repositories HomeAutomation

Rev

Rev 1572 | Rev 1978 | 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. #ifdef sns_power_USEEEPROM
  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); ///TODO: Change this to the actual class type
  54.       StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  55.       txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER; ///TODO: Change this to the actual module type
  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.     }
  110. }
  111.  
  112. #ifdef POWER_SNS_PIN_ch2
  113. void sns_power_pcint_callback_ch2(uint8_t id, uint8_t status)
  114. {
  115.     if (status == 0)
  116.     {
  117.         if (Timer_GetTicks() - PreviusTimerValue_ch2 >= 16)
  118.         {
  119.             MeasurmentBufferPointer_ch2++;
  120.             if (MeasurmentBufferPointer_ch2 >= 32) MeasurmentBufferPointer_ch2 = 0;
  121.             lastMeasurment_ch2 =  Timer_GetTicks() - PreviusTimerValue_ch2;
  122.             MeasurmentBuffer_ch2[MeasurmentBufferPointer_ch2] = (uint16_t) (lastMeasurment_ch2 & 0x0000FFFF);
  123.             PreviusTimerValue_ch2 = Timer_GetTicks();
  124.             #if sns_power_1000_PULSES_PER_KWH == 1
  125.                 EnergyCounter_ch2++;
  126.             #endif
  127.             #if sns_power_10000_PULSES_PER_KWH == 1
  128.                 tmpCounter_ch2++;
  129.                 #if sns_power_SEND_1_MIN_AVG == 1
  130.                 avgCounter_ch2++;
  131.                 #endif
  132.                 if(tmpCounter_ch2 >= 10) {
  133.                     EnergyCounter_ch2++;
  134.                     tmpCounter_ch2 = 0;
  135.                 }
  136.             #endif
  137.         }
  138.     }
  139. }
  140. #endif
  141.  
  142. void sns_power_Init(void)
  143. {
  144. #ifdef sns_power_USEEEPROM
  145.     if (EEDATA_OK)
  146.     {
  147.       ///TODO: Use stored data to set initial values for the module
  148.       sns_power_ReportInterval = eeprom_read_byte(EEDATA.reportInterval);
  149.       EnergyCounter = eeprom_read_word(EEDATA16.EnergyCounterLower);
  150.       EnergyCounter += (((uint32_t)(eeprom_read_word(EEDATA16.EnergyCounterUpper)))<<16);
  151.         #ifdef POWER_SNS_PIN_ch2
  152.           EnergyCounter_ch2 = eeprom_read_word(EEDATA16.EnergyCounterLower_ch2);
  153.           EnergyCounter_ch2 += (((uint32_t)(eeprom_read_word(EEDATA16.EnergyCounterUpper_ch2)))<<16);
  154.         #endif
  155.     } else
  156.     {   //The CRC of the EEPROM is not correct, store default values and update CRC
  157.       eeprom_write_byte_crc(EEDATA.reportInterval, sns_power_SEND_PERIOD, WITHOUT_CRC);
  158.       eeprom_write_word_crc(EEDATA16.EnergyCounterUpper, 0, WITHOUT_CRC);
  159.       eeprom_write_word_crc(EEDATA16.EnergyCounterLower, 0, WITHOUT_CRC);
  160.       #ifdef POWER_SNS_PIN_ch2
  161.         eeprom_write_word_crc(EEDATA16.EnergyCounterUpper_ch2, 0, WITHOUT_CRC);
  162.         eeprom_write_word_crc(EEDATA16.EnergyCounterLower_ch2, 0, WITHOUT_CRC);
  163.       #endif
  164.       EEDATA_UPDATE_CRC;
  165.       sns_power_ReportInterval = eeprom_read_byte(EEDATA.reportInterval);
  166.     }
  167. #endif  
  168.     ///Initialize hardware etc
  169.     gpio_set_in(POWER_SNS_PIN); // Set to input
  170.     gpio_set_pin(POWER_SNS_PIN);    // Enable pull-up
  171.    
  172.     Pcint_SetCallbackPin(sns_power_PCINT, POWER_SNS_PIN, &sns_power_pcint_callback);
  173.  
  174.     MeasurmentBufferPointer = 0;
  175. #ifdef POWER_SNS_PIN_ch2
  176.     gpio_set_in(POWER_SNS_PIN_ch2); // Set to input
  177.     gpio_set_pin(POWER_SNS_PIN_ch2);    // Enable pull-up
  178.    
  179.     Pcint_SetCallbackPin(sns_power_PCINT_ch2, POWER_SNS_PIN_ch2, &sns_power_pcint_callback_ch2);
  180.  
  181.     MeasurmentBufferPointer_ch2 = 0;
  182. #endif
  183.     Timer_SetTimeout(sns_power_SEND_TIMER, sns_power_ReportInterval*1000 , TimerTypeFreeRunning, 0);
  184. #if sns_power_SEND_1_MIN_AVG == 1
  185.     Timer_SetTimeout(sns_power_SEND_TIMER_1_MIN_AVG, 60000-10 , TimerTypeFreeRunning, &sns_power_timer_callback);
  186. #endif
  187. }
  188.  
  189. void sns_power_Process(void)
  190. {
  191.     if (StoreInEEPROM == 1)
  192.     {
  193.         StoreInEEPROM = 0;
  194.        
  195.         eeprom_write_word_crc(EEDATA16.EnergyCounterUpper, (uint16_t)((EnergyCounter>>16) & 0xffff), WITHOUT_CRC);
  196.         eeprom_write_word_crc(EEDATA16.EnergyCounterLower, (uint16_t)(EnergyCounter & 0xffff), WITH_CRC);
  197.     #ifdef POWER_SNS_PIN_ch2
  198.         eeprom_write_word_crc(EEDATA16.EnergyCounterUpper_ch2, (uint16_t)((EnergyCounter_ch2>>16) & 0xffff), WITHOUT_CRC);
  199.         eeprom_write_word_crc(EEDATA16.EnergyCounterLower_ch2, (uint16_t)(EnergyCounter_ch2 & 0xffff), WITH_CRC);
  200.     #endif
  201.     }
  202.     StdCan_Msg_t txMsg;
  203.     ///TODO: Stuff that needs doing is done here
  204.     if (Timer_Expired(sns_power_SEND_TIMER)) {
  205.         //4 times average
  206.         /*uint32_t Avg4 = MeasurmentBuffer[MeasurmentBufferPointer] + MeasurmentBuffer[MeasurmentBufferPointer-1] + MeasurmentBuffer[MeasurmentBufferPointer-2] + MeasurmentBuffer[MeasurmentBufferPointer-3];
  207.         Avg4 = (360000/(Avg4/4));
  208.         */
  209.         //32 times average
  210.         uint32_t Avg32 = 0;
  211.         for (uint8_t i = 0; i<32;i++) {
  212.              Avg32 += MeasurmentBuffer[i];
  213.         }
  214.         Avg32 /= 32;
  215.         #if sns_power_1000_PULSES_PER_KWH == 1
  216.             Avg32 = (3600000/Avg32);
  217.         #endif
  218.         #if sns_power_10000_PULSES_PER_KWH == 1
  219.             Avg32 = (360000/Avg32);
  220.         #endif
  221.  
  222.            
  223.         StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS); ///TODO: Change this to the actual class type
  224.         StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  225.         txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER; ///TODO: Change this to the actual module type
  226.         txMsg.Header.ModuleId = sns_power_ID;
  227.         txMsg.Header.Command = CAN_MODULE_CMD_PHYSICAL_ELECTRICPOWER;
  228.         txMsg.Length = 8;
  229.         #if sns_power_1000_PULSES_PER_KWH == 1
  230.             uint32_t tmp = 3600000/MeasurmentBuffer[MeasurmentBufferPointer];
  231.         #endif
  232.         #if sns_power_10000_PULSES_PER_KWH == 1
  233.             uint32_t tmp = 360000/MeasurmentBuffer[MeasurmentBufferPointer];
  234.         #endif
  235.         txMsg.Data[0] = (uint8_t)((tmp>>8) & 0xff);
  236.         txMsg.Data[1] = (uint8_t)(tmp & 0xff);
  237.         txMsg.Data[5] = (uint8_t)EnergyCounter & 0xff;
  238.         txMsg.Data[4] = (uint8_t)(EnergyCounter >> 8) & 0xff;
  239.         txMsg.Data[3] = (uint8_t)(EnergyCounter >> 16) & 0xff;
  240.         txMsg.Data[2] = (uint8_t)(EnergyCounter >> 24) & 0xff;
  241.         txMsg.Data[6] = (uint8_t)((Avg32>>8) & 0xff);
  242.         txMsg.Data[7] = (uint8_t)(Avg32 & 0xff);
  243.         while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  244.        
  245.     #ifdef POWER_SNS_PIN_ch2
  246.         uint32_t Avg32_ch2 = 0;
  247.         for (uint8_t i = 0; i<32;i++) {
  248.              Avg32_ch2 += MeasurmentBuffer_ch2[i];
  249.         }
  250.         Avg32_ch2 /= 32;
  251.         #if sns_power_1000_PULSES_PER_KWH == 1
  252.             Avg32_ch2 = (3600000/Avg32_ch2);
  253.         #endif
  254.         #if sns_power_10000_PULSES_PER_KWH == 1
  255.             Avg32_ch2 = (360000/Avg32_ch2);
  256.         #endif
  257.            
  258.         txMsg.Header.ModuleId = sns_power_ID_ch2;
  259.         #if sns_power_1000_PULSES_PER_KWH == 1
  260.             tmp = 3600000/MeasurmentBuffer_ch2[MeasurmentBufferPointer_ch2];
  261.         #endif
  262.         #if sns_power_10000_PULSES_PER_KWH == 1
  263.             tmp = 360000/MeasurmentBuffer_ch2[MeasurmentBufferPointer_ch2];
  264.         #endif
  265.         txMsg.Data[0] = (uint8_t)((tmp>>8) & 0xff);
  266.         txMsg.Data[1] = (uint8_t)(tmp & 0xff);
  267.         txMsg.Data[5] = (uint8_t)EnergyCounter_ch2 & 0xff;
  268.         txMsg.Data[4] = (uint8_t)(EnergyCounter_ch2 >> 8) & 0xff;
  269.         txMsg.Data[3] = (uint8_t)(EnergyCounter_ch2 >> 16) & 0xff;
  270.         txMsg.Data[2] = (uint8_t)(EnergyCounter_ch2 >> 24) & 0xff;
  271.         txMsg.Data[6] = (uint8_t)((Avg32_ch2>>8) & 0xff);
  272.         txMsg.Data[7] = (uint8_t)(Avg32_ch2 & 0xff);
  273.         while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  274.        
  275.     #endif
  276.        
  277.        
  278.     }
  279. }
  280.  
  281. void sns_power_HandleMessage(StdCan_Msg_t *rxMsg)
  282. {
  283.     if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_SNS &&
  284.         StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_TO_OWNER &&
  285.         rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_POWER &&
  286.         rxMsg->Header.ModuleId == sns_power_ID)
  287.     {
  288. StdCan_Msg_t txMsg;
  289.         switch (rxMsg->Header.Command)
  290.         {
  291.         case CAN_MODULE_CMD_GLOBAL_REPORT_INTERVAL:
  292.             if (rxMsg->Length > 0)
  293.             {
  294.                 sns_power_ReportInterval = rxMsg->Data[0];
  295.                 Timer_SetTimeout(sns_power_SEND_TIMER, sns_power_ReportInterval*1000 , TimerTypeFreeRunning, 0);
  296.             }
  297.             StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  298.             StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  299.             txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER;
  300.             txMsg.Header.ModuleId = sns_power_ID;
  301.             txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_REPORT_INTERVAL;
  302.             txMsg.Length = 1;
  303.             txMsg.Data[0] = sns_power_ReportInterval;
  304.             StdCan_Put(&txMsg);
  305.             break;
  306.         case CAN_MODULE_CMD_POWER_SETENERGY:
  307.             if (rxMsg->Length == 4)
  308.             {
  309.                 EnergyCounter = rxMsg->Data[3];
  310.                 EnergyCounter += ((uint32_t)rxMsg->Data[2])<<8;
  311.                 EnergyCounter += ((uint32_t)rxMsg->Data[1])<<16;
  312.                 EnergyCounter += ((uint32_t)rxMsg->Data[0])<<24;
  313.             }
  314.             StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  315.             StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  316.             txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER;
  317.             txMsg.Header.ModuleId = sns_power_ID;
  318.             txMsg.Header.Command = CAN_MODULE_CMD_POWER_SETENERGY;
  319.             txMsg.Length = 1;
  320.             txMsg.Data[3] = (uint8_t)EnergyCounter & 0xff;
  321.             txMsg.Data[2] = (uint8_t)(EnergyCounter >> 8) & 0xff;
  322.             txMsg.Data[1] = (uint8_t)(EnergyCounter >> 16) & 0xff;
  323.             txMsg.Data[0] = (uint8_t)(EnergyCounter >> 24) & 0xff;
  324.             StdCan_Put(&txMsg);
  325.            
  326.             break;
  327.         }
  328.     }
  329.    
  330. #ifdef POWER_SNS_PIN_ch2   
  331.     if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_SNS &&
  332.         StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_TO_OWNER &&
  333.         rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_POWER &&
  334.         rxMsg->Header.ModuleId == sns_power_ID_ch2)
  335.     {
  336.         StdCan_Msg_t txMsg;
  337.         switch (rxMsg->Header.Command)
  338.         {
  339.         case CAN_MODULE_CMD_GLOBAL_REPORT_INTERVAL:
  340.             if (rxMsg->Length > 0)
  341.             {
  342.                 sns_power_ReportInterval = rxMsg->Data[0];
  343.                 Timer_SetTimeout(sns_power_SEND_TIMER, sns_power_ReportInterval*1000 , TimerTypeFreeRunning, 0);
  344.             }
  345.             StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  346.             StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  347.             txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER;
  348.             txMsg.Header.ModuleId = sns_power_ID_ch2;
  349.             txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_REPORT_INTERVAL;
  350.             txMsg.Length = 1;
  351.             txMsg.Data[0] = sns_power_ReportInterval;
  352.             StdCan_Put(&txMsg);
  353.             break;
  354.         case CAN_MODULE_CMD_POWER_SETENERGY:
  355.             if (rxMsg->Length == 4)
  356.             {
  357.                 EnergyCounter_ch2 = rxMsg->Data[3];
  358.                 EnergyCounter_ch2 += ((uint32_t)rxMsg->Data[2])<<8;
  359.                 EnergyCounter_ch2 += ((uint32_t)rxMsg->Data[1])<<16;
  360.                 EnergyCounter_ch2 += ((uint32_t)rxMsg->Data[0])<<24;
  361.             }
  362.             StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  363.             StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  364.             txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER;
  365.             txMsg.Header.ModuleId = sns_power_ID_ch2;
  366.             txMsg.Header.Command = CAN_MODULE_CMD_POWER_SETENERGY;
  367.             txMsg.Length = 1;
  368.             txMsg.Data[3] = (uint8_t)EnergyCounter_ch2 & 0xff;
  369.             txMsg.Data[2] = (uint8_t)(EnergyCounter_ch2 >> 8) & 0xff;
  370.             txMsg.Data[1] = (uint8_t)(EnergyCounter_ch2 >> 16) & 0xff;
  371.             txMsg.Data[0] = (uint8_t)(EnergyCounter_ch2 >> 24) & 0xff;
  372.             StdCan_Put(&txMsg);
  373.            
  374.             break;
  375.         }
  376.     }
  377. #endif
  378.    
  379. }
  380.  
  381. void sns_power_List(uint8_t ModuleSequenceNumber)
  382. {
  383.     StdCan_Msg_t txMsg;
  384.    
  385.     StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS); ///TODO: Change this to the actual class type
  386.     StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  387.     txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER; ///TODO: Change this to the actual module type
  388.     txMsg.Header.ModuleId = sns_power_ID;
  389.     txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_LIST;
  390.     txMsg.Length = 6;
  391.  
  392.     txMsg.Data[0] = NODE_HW_ID_BYTE0;
  393.     txMsg.Data[1] = NODE_HW_ID_BYTE1;
  394.     txMsg.Data[2] = NODE_HW_ID_BYTE2;
  395.     txMsg.Data[3] = NODE_HW_ID_BYTE3;
  396.    
  397.     txMsg.Data[4] = NUMBER_OF_MODULES;
  398.     txMsg.Data[5] = ModuleSequenceNumber;
  399.    
  400.     while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  401.    
  402.    
  403. #ifdef POWER_SNS_PIN_ch2   
  404.     txMsg.Header.ModuleId = sns_power_ID_ch2;
  405.     txMsg.Data[5] = ModuleSequenceNumber;
  406.     while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  407. #endif
  408. }
  409.