Subversion Repositories HomeAutomation

Rev

Rev 1437 | Rev 1573 | 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.         eeprom_write_word_crc(EEDATA16.EnergyCounterUpper, (uint16_t)((EnergyCounter>>16) & 0xffff), WITHOUT_CRC);
  195.         eeprom_write_word_crc(EEDATA16.EnergyCounterLower, (uint16_t)(EnergyCounter & 0xffff), WITHOUT_CRC);
  196.         eeprom_write_word_crc(EEDATA16.EnergyCounterUpper_ch2, (uint16_t)((EnergyCounter_ch2>>16) & 0xffff), WITHOUT_CRC);
  197.         eeprom_write_word_crc(EEDATA16.EnergyCounterLower_ch2, (uint16_t)(EnergyCounter_ch2 & 0xffff), WITH_CRC);
  198.     }
  199.     StdCan_Msg_t txMsg;
  200.     ///TODO: Stuff that needs doing is done here
  201.     if (Timer_Expired(sns_power_SEND_TIMER)) {
  202.         //4 times average
  203.         /*uint32_t Avg4 = MeasurmentBuffer[MeasurmentBufferPointer] + MeasurmentBuffer[MeasurmentBufferPointer-1] + MeasurmentBuffer[MeasurmentBufferPointer-2] + MeasurmentBuffer[MeasurmentBufferPointer-3];
  204.         Avg4 = (360000/(Avg4/4));
  205.         */
  206.         //32 times average
  207.         uint32_t Avg32 = 0;
  208.         for (uint8_t i = 0; i<32;i++) {
  209.              Avg32 += MeasurmentBuffer[i];
  210.         }
  211.         Avg32 /= 32;
  212.         #if sns_power_1000_PULSES_PER_KWH == 1
  213.             Avg32 = (3600000/Avg32);
  214.         #endif
  215.         #if sns_power_10000_PULSES_PER_KWH == 1
  216.             Avg32 = (360000/Avg32);
  217.         #endif
  218.  
  219.            
  220.         StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS); ///TODO: Change this to the actual class type
  221.         StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  222.         txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER; ///TODO: Change this to the actual module type
  223.         txMsg.Header.ModuleId = sns_power_ID;
  224.         txMsg.Header.Command = CAN_MODULE_CMD_PHYSICAL_ELECTRICPOWER;
  225.         txMsg.Length = 8;
  226.         #if sns_power_1000_PULSES_PER_KWH == 1
  227.             uint32_t tmp = 3600000/MeasurmentBuffer[MeasurmentBufferPointer];
  228.         #endif
  229.         #if sns_power_10000_PULSES_PER_KWH == 1
  230.             uint32_t tmp = 360000/MeasurmentBuffer[MeasurmentBufferPointer];
  231.         #endif
  232.         txMsg.Data[0] = (uint8_t)((tmp>>8) & 0xff);
  233.         txMsg.Data[1] = (uint8_t)(tmp & 0xff);
  234.         txMsg.Data[5] = (uint8_t)EnergyCounter & 0xff;
  235.         txMsg.Data[4] = (uint8_t)(EnergyCounter >> 8) & 0xff;
  236.         txMsg.Data[3] = (uint8_t)(EnergyCounter >> 16) & 0xff;
  237.         txMsg.Data[2] = (uint8_t)(EnergyCounter >> 24) & 0xff;
  238.         txMsg.Data[6] = (uint8_t)((Avg32>>8) & 0xff);
  239.         txMsg.Data[7] = (uint8_t)(Avg32 & 0xff);
  240.         while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  241.        
  242.     #ifdef POWER_SNS_PIN_ch2
  243.         uint32_t Avg32_ch2 = 0;
  244.         for (uint8_t i = 0; i<32;i++) {
  245.              Avg32_ch2 += MeasurmentBuffer_ch2[i];
  246.         }
  247.         Avg32_ch2 /= 32;
  248.         #if sns_power_1000_PULSES_PER_KWH == 1
  249.             Avg32_ch2 = (3600000/Avg32_ch2);
  250.         #endif
  251.         #if sns_power_10000_PULSES_PER_KWH == 1
  252.             Avg32_ch2 = (360000/Avg32_ch2);
  253.         #endif
  254.            
  255.         txMsg.Header.ModuleId = sns_power_ID_ch2;
  256.         #if sns_power_1000_PULSES_PER_KWH == 1
  257.             tmp = 3600000/MeasurmentBuffer_ch2[MeasurmentBufferPointer_ch2];
  258.         #endif
  259.         #if sns_power_10000_PULSES_PER_KWH == 1
  260.             tmp = 360000/MeasurmentBuffer_ch2[MeasurmentBufferPointer_ch2];
  261.         #endif
  262.         txMsg.Data[0] = (uint8_t)((tmp>>8) & 0xff);
  263.         txMsg.Data[1] = (uint8_t)(tmp & 0xff);
  264.         txMsg.Data[5] = (uint8_t)EnergyCounter_ch2 & 0xff;
  265.         txMsg.Data[4] = (uint8_t)(EnergyCounter_ch2 >> 8) & 0xff;
  266.         txMsg.Data[3] = (uint8_t)(EnergyCounter_ch2 >> 16) & 0xff;
  267.         txMsg.Data[2] = (uint8_t)(EnergyCounter_ch2 >> 24) & 0xff;
  268.         txMsg.Data[6] = (uint8_t)((Avg32_ch2>>8) & 0xff);
  269.         txMsg.Data[7] = (uint8_t)(Avg32_ch2 & 0xff);
  270.         while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  271.        
  272.     #endif
  273.        
  274.        
  275.     }
  276. }
  277.  
  278. void sns_power_HandleMessage(StdCan_Msg_t *rxMsg)
  279. {
  280.     if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_SNS &&
  281.         StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_TO_OWNER &&
  282.         rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_POWER &&
  283.         rxMsg->Header.ModuleId == sns_power_ID)
  284.     {
  285. StdCan_Msg_t txMsg;
  286.         switch (rxMsg->Header.Command)
  287.         {
  288.         case CAN_MODULE_CMD_GLOBAL_REPORT_INTERVAL:
  289.             if (rxMsg->Length > 0)
  290.             {
  291.                 sns_power_ReportInterval = rxMsg->Data[0];
  292.                 Timer_SetTimeout(sns_power_SEND_TIMER, sns_power_ReportInterval*1000 , TimerTypeFreeRunning, 0);
  293.             }
  294.             StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  295.             StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  296.             txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER;
  297.             txMsg.Header.ModuleId = sns_power_ID;
  298.             txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_REPORT_INTERVAL;
  299.             txMsg.Length = 1;
  300.             txMsg.Data[0] = sns_power_ReportInterval;
  301.             StdCan_Put(&txMsg);
  302.             break;
  303.         case CAN_MODULE_CMD_POWER_SETENERGY:
  304.             if (rxMsg->Length == 4)
  305.             {
  306.                 EnergyCounter = rxMsg->Data[3];
  307.                 EnergyCounter += ((uint32_t)rxMsg->Data[2])<<8;
  308.                 EnergyCounter += ((uint32_t)rxMsg->Data[1])<<16;
  309.                 EnergyCounter += ((uint32_t)rxMsg->Data[0])<<24;
  310.             }
  311.             StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  312.             StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  313.             txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER;
  314.             txMsg.Header.ModuleId = sns_power_ID;
  315.             txMsg.Header.Command = CAN_MODULE_CMD_POWER_SETENERGY;
  316.             txMsg.Length = 1;
  317.             txMsg.Data[3] = (uint8_t)EnergyCounter & 0xff;
  318.             txMsg.Data[2] = (uint8_t)(EnergyCounter >> 8) & 0xff;
  319.             txMsg.Data[1] = (uint8_t)(EnergyCounter >> 16) & 0xff;
  320.             txMsg.Data[0] = (uint8_t)(EnergyCounter >> 24) & 0xff;
  321.             StdCan_Put(&txMsg);
  322.            
  323.             break;
  324.         }
  325.     }
  326.    
  327. #ifdef POWER_SNS_PIN_ch2   
  328.     if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_SNS &&
  329.         StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_TO_OWNER &&
  330.         rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_POWER &&
  331.         rxMsg->Header.ModuleId == sns_power_ID_ch2)
  332.     {
  333.         StdCan_Msg_t txMsg;
  334.         switch (rxMsg->Header.Command)
  335.         {
  336.         case CAN_MODULE_CMD_GLOBAL_REPORT_INTERVAL:
  337.             if (rxMsg->Length > 0)
  338.             {
  339.                 sns_power_ReportInterval = rxMsg->Data[0];
  340.                 Timer_SetTimeout(sns_power_SEND_TIMER, sns_power_ReportInterval*1000 , TimerTypeFreeRunning, 0);
  341.             }
  342.             StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  343.             StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  344.             txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER;
  345.             txMsg.Header.ModuleId = sns_power_ID_ch2;
  346.             txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_REPORT_INTERVAL;
  347.             txMsg.Length = 1;
  348.             txMsg.Data[0] = sns_power_ReportInterval;
  349.             StdCan_Put(&txMsg);
  350.             break;
  351.         case CAN_MODULE_CMD_POWER_SETENERGY:
  352.             if (rxMsg->Length == 4)
  353.             {
  354.                 EnergyCounter_ch2 = rxMsg->Data[3];
  355.                 EnergyCounter_ch2 += ((uint32_t)rxMsg->Data[2])<<8;
  356.                 EnergyCounter_ch2 += ((uint32_t)rxMsg->Data[1])<<16;
  357.                 EnergyCounter_ch2 += ((uint32_t)rxMsg->Data[0])<<24;
  358.             }
  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_POWER;
  362.             txMsg.Header.ModuleId = sns_power_ID_ch2;
  363.             txMsg.Header.Command = CAN_MODULE_CMD_POWER_SETENERGY;
  364.             txMsg.Length = 1;
  365.             txMsg.Data[3] = (uint8_t)EnergyCounter_ch2 & 0xff;
  366.             txMsg.Data[2] = (uint8_t)(EnergyCounter_ch2 >> 8) & 0xff;
  367.             txMsg.Data[1] = (uint8_t)(EnergyCounter_ch2 >> 16) & 0xff;
  368.             txMsg.Data[0] = (uint8_t)(EnergyCounter_ch2 >> 24) & 0xff;
  369.             StdCan_Put(&txMsg);
  370.            
  371.             break;
  372.         }
  373.     }
  374. #endif
  375.    
  376. }
  377.  
  378. void sns_power_List(uint8_t ModuleSequenceNumber)
  379. {
  380.     StdCan_Msg_t txMsg;
  381.    
  382.     StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS); ///TODO: Change this to the actual class type
  383.     StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  384.     txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_POWER; ///TODO: Change this to the actual module type
  385.     txMsg.Header.ModuleId = sns_power_ID;
  386.     txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_LIST;
  387.     txMsg.Length = 6;
  388.  
  389.     txMsg.Data[0] = NODE_HW_ID_BYTE0;
  390.     txMsg.Data[1] = NODE_HW_ID_BYTE1;
  391.     txMsg.Data[2] = NODE_HW_ID_BYTE2;
  392.     txMsg.Data[3] = NODE_HW_ID_BYTE3;
  393.    
  394.     txMsg.Data[4] = NUMBER_OF_MODULES;
  395.     txMsg.Data[5] = ModuleSequenceNumber;
  396.    
  397.     while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  398.    
  399.    
  400. #ifdef POWER_SNS_PIN_ch2   
  401.     txMsg.Header.ModuleId = sns_power_ID_ch2;
  402.     txMsg.Data[5] = ModuleSequenceNumber;
  403.     while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  404. #endif
  405. }
  406.