Subversion Repositories HomeAutomation

Rev

Rev 2183 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1.  
  2. #include "sns_water.h"
  3.  
  4. static uint8_t volatile sns_water_status = LOW;
  5. static uint8_t sns_water_ReportInterval = (uint8_t)sns_water_SEND_PERIOD_S;
  6. static uint32_t volatile sns_water_TickCnt=0;
  7. static uint32_t volatile sns_water_TimePrevTick;
  8. static uint32_t volatile sns_water_Buffer[4]= {0x0000ffff,0x0000ffff,0x0000ffff,0x0000ffff};
  9. static uint8_t volatile sns_water_BufPointer=0;
  10. static uint32_t volatile sns_water_StoreCnt=0;
  11.  
  12. StdCan_Msg_t txMsg;
  13.  
  14. #if sns_water_UL_PER_TICK % 1000UL == 0
  15. #define sns_water_CONVERT_DIVIDEND  (sns_water_UL_PER_TICK/1000UL)
  16. #define sns_water_CONVERT_DIVISOR   1UL
  17. #elif sns_water_UL_PER_TICK % 100UL == 0
  18. #define sns_water_CONVERT_DIVIDEND  (sns_water_UL_PER_TICK/100UL)
  19. #define sns_water_CONVERT_DIVISOR   10UL
  20. #elif sns_water_UL_PER_TICK % 10UL == 0
  21. #define sns_water_CONVERT_DIVIDEND  (sns_water_UL_PER_TICK/10UL)
  22. #define sns_water_CONVERT_DIVISOR   100UL
  23. #else
  24. #error Could not find a suitable conversion, report this error to get help on how to solve it
  25. #endif
  26.  
  27. #if sns_water_USEEEPROM==1
  28. #include "sns_water_eeprom.h"
  29. struct eeprom_sns_water EEMEM eeprom_sns_water =
  30. {
  31.     {
  32.           (uint8_t)sns_water_SEND_PERIOD_S, // reportInterval
  33.           0,    // VolumeCounterUpper
  34.           0     // VolumeCounterLower
  35.     },
  36.     0   // crc, must be a correct value, but this will also be handled by the EEPROM module or make scripts
  37. };
  38. #endif
  39.  
  40. void sns_water_Init(void)
  41. {
  42. #if sns_water_USEEEPROM==1
  43.     if (EEDATA_OK)
  44.     {  // Use stored data to set initial values for the module
  45.       sns_water_ReportInterval = eeprom_read_byte(EEDATA.reportInterval);
  46.       sns_water_TickCnt = eeprom_read_word(EEDATA16.VolumeCounterLower);
  47.       sns_water_TickCnt += (((uint32_t)(eeprom_read_word(EEDATA16.VolumeCounterUpper)))<<16);
  48.     } else
  49.     {   //The CRC of the EEPROM is not correct, store default values and update CRC
  50.       eeprom_write_byte_crc(EEDATA.reportInterval, sns_water_SEND_PERIOD_S, WITHOUT_CRC);
  51.       eeprom_write_word_crc(EEDATA16.VolumeCounterUpper, 0, WITHOUT_CRC);
  52.       eeprom_write_word_crc(EEDATA16.VolumeCounterLower, 0, WITHOUT_CRC);
  53.       EEDATA_UPDATE_CRC;
  54.     }
  55. #endif
  56.  
  57.     ADC_Init();
  58.     sns_water_TimePrevTick = Timer_GetTicks();
  59.     Timer_SetTimeout(sns_water_ADPOLL_TIMER, sns_water_ADPOLL_PERIOD_MS, TimerTypeFreeRunning, 0);
  60.     Timer_SetTimeout(sns_water_SEND_TIMER, sns_water_SEND_PERIOD_S*1000, TimerTypeFreeRunning, 0);
  61.  
  62.     uint16_t ADvalue = ADC_Get(sns_water_AD_CHANNEL);
  63.     if (ADvalue > (sns_water_HIGH_THRESHOLD_MV*1024UL/5000UL))
  64.     {
  65.         sns_water_status = HIGH;
  66.     }
  67.  
  68.     StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  69.     StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  70.     txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_WATER;
  71.     txMsg.Header.ModuleId = sns_water_ID;
  72.     txMsg.Header.Command = CAN_MODULE_CMD_PHYSICAL_FLOW;
  73.     txMsg.Length = 6;
  74. }
  75.  
  76. void sns_water_Process(void)
  77. {
  78.     /*
  79.     Notes
  80.     maybe its better to skip the poll timer and always poll when in process
  81.     */
  82.     uint8_t oldstatus = sns_water_status;
  83.     if (Timer_Expired(sns_water_ADPOLL_TIMER))
  84.     {
  85.         uint16_t ADvalue = ADC_Get(sns_water_AD_CHANNEL);
  86.         if (sns_water_status == LOW && ADvalue > (sns_water_HIGH_THRESHOLD_MV*1024UL/5000UL))
  87.         {
  88.             sns_water_status = HIGH;
  89.         }
  90.         else if (sns_water_status == HIGH && ADvalue < (sns_water_LOW_THRESHOLD_MV*1024UL/5000UL))
  91.         {
  92.             sns_water_status = LOW;
  93.         }
  94.     }
  95.  
  96.     /* If status changed == one tick */
  97.     if (oldstatus != sns_water_status)
  98.     {
  99.         sns_water_TickCnt += 1;
  100.  
  101.         sns_water_Buffer[sns_water_BufPointer] = Timer_GetTicks() - sns_water_TimePrevTick;
  102.         if (sns_water_BufPointer++ == 4)
  103.         {
  104.             sns_water_BufPointer = 0;
  105.         }
  106.  
  107.         sns_water_TimePrevTick = Timer_GetTicks();
  108.  
  109. #if sns_water_USEEEPROM==1
  110.         if ((sns_water_TickCnt % 1024) == 0)
  111.         {
  112.             eeprom_write_word_crc(EEDATA16.VolumeCounterUpper, (uint16_t)((sns_water_TickCnt>>16) & 0xffff), WITHOUT_CRC);
  113.             eeprom_write_word_crc(EEDATA16.VolumeCounterLower, (uint16_t)(sns_water_TickCnt & 0xffff), WITH_CRC);
  114.         }
  115. #endif
  116.     }
  117.  
  118.     if (Timer_Expired(sns_water_SEND_TIMER))
  119.     {
  120.         uint32_t flow4 = 0;
  121.         for (uint8_t i = 0; i<4;i++) {
  122.              flow4 += sns_water_Buffer[i];
  123.         }
  124.         flow4 = flow4/4;
  125.         /* The flow is ml per tick / time between ticks */
  126.         flow4 = sns_water_UL_PER_TICK/flow4;
  127.        
  128.         uint32_t waterVolume = (uint64_t)sns_water_TickCnt*sns_water_CONVERT_DIVIDEND/sns_water_CONVERT_DIVISOR;
  129.  
  130.         txMsg.Data[0] = (flow4>>8) & 0xff;
  131.         txMsg.Data[1] = flow4 & 0xff;
  132.         txMsg.Data[5] = waterVolume & 0xff;
  133.         txMsg.Data[4] = (waterVolume >> 8) & 0xff;
  134.         txMsg.Data[3] = (waterVolume >> 16) & 0xff;
  135.         txMsg.Data[2] = (waterVolume >> 24) & 0xff;
  136. #if CAN_PRINTF==1
  137.         txMsg.Data[5] = (uint8_t)sns_water_TickCnt & 0xff;
  138.         txMsg.Data[4] = (uint8_t)(sns_water_TickCnt >> 8) & 0xff;
  139.         txMsg.Data[3] = (uint8_t)(sns_water_TickCnt >> 16) & 0xff;
  140.         txMsg.Data[2] = (uint8_t)(sns_water_TickCnt >> 24) & 0xff;
  141. #endif
  142.         while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  143.  
  144.         /* TODO How to handle no flow? (means no ticks, no new time-diffs) */
  145.         /* This solution starts to fill buffer with older values if ticks come in slower than we send out data */
  146.         if (Timer_GetTicks() - sns_water_TimePrevTick > sns_water_SEND_PERIOD_S*1000)
  147.         {
  148.             sns_water_Buffer[sns_water_BufPointer] = Timer_GetTicks() - sns_water_TimePrevTick;
  149.             if (sns_water_BufPointer++ == 4)
  150.             {
  151.                 sns_water_BufPointer = 0;
  152.             }
  153.         }
  154.     }
  155. }
  156.  
  157. void sns_water_HandleMessage(StdCan_Msg_t *rxMsg)
  158. {
  159.     if (    StdCan_Ret_class(rxMsg->Header) == CAN_MODULE_CLASS_SNS &&
  160.         StdCan_Ret_direction(rxMsg->Header) == DIRECTIONFLAG_TO_OWNER &&
  161.         rxMsg->Header.ModuleType == CAN_MODULE_TYPE_SNS_WATER &&
  162.         rxMsg->Header.ModuleId == sns_water_ID)
  163.     {
  164.         StdCan_Msg_t txMsg2;
  165.         switch (rxMsg->Header.Command)
  166.         {
  167.         case CAN_MODULE_CMD_GLOBAL_REPORT_INTERVAL:
  168.             if (rxMsg->Length > 0)
  169.             {
  170.                 sns_water_ReportInterval = rxMsg->Data[0];
  171.                 Timer_SetTimeout(sns_water_SEND_TIMER, sns_water_ReportInterval*1000 , TimerTypeFreeRunning, 0);
  172. #if sns_water_USEEEPROM==1
  173.                 // this did not work
  174.                 //eeprom_write_byte_crc(EEDATA.reportInterval, sns_water_ReportInterval, WITH_CRC);
  175. #endif
  176.             }
  177.             StdCan_Set_class(txMsg2.Header, CAN_MODULE_CLASS_SNS);
  178.             StdCan_Set_direction(txMsg2.Header, DIRECTIONFLAG_FROM_OWNER);
  179.             txMsg2.Header.ModuleType = CAN_MODULE_TYPE_SNS_WATER;
  180.             txMsg2.Header.ModuleId = sns_water_ID;
  181.             txMsg2.Header.Command = CAN_MODULE_CMD_GLOBAL_REPORT_INTERVAL;
  182.             txMsg2.Length = 1;
  183.             txMsg2.Data[0] = sns_water_ReportInterval;
  184.             StdCan_Put(&txMsg2);
  185.             break;
  186.         case CAN_MODULE_CMD_WATER_SETVOLUME:
  187.             if (rxMsg->Length == 4)
  188.             {
  189.                 sns_water_TickCnt = (rxMsg->Data[3]);
  190.                 sns_water_TickCnt += ((uint32_t)rxMsg->Data[2]<<8);
  191.                 sns_water_TickCnt += ((uint32_t)rxMsg->Data[1]<<16);
  192.                 sns_water_TickCnt += ((uint32_t)rxMsg->Data[0]<<24);
  193.                 /* Volume sent was in Liters */
  194.                 sns_water_TickCnt = sns_water_TickCnt*(1000000/sns_water_UL_PER_TICK);
  195.             }
  196.             StdCan_Set_class(txMsg2.Header, CAN_MODULE_CLASS_SNS);
  197.             StdCan_Set_direction(txMsg2.Header, DIRECTIONFLAG_FROM_OWNER);
  198.             txMsg2.Header.ModuleType = CAN_MODULE_TYPE_SNS_WATER;
  199.             txMsg2.Header.ModuleId = sns_water_ID;
  200.             txMsg2.Header.Command = CAN_MODULE_CMD_WATER_SETVOLUME;
  201.             txMsg2.Length = 4;
  202.             uint32_t dataToSend = sns_water_TickCnt;
  203.             dataToSend = (uint64_t)dataToSend*sns_water_UL_PER_TICK/1000000UL;
  204.             txMsg2.Data[3] = ((uint32_t)dataToSend) & 0xff;
  205.             txMsg2.Data[2] = (((uint32_t)dataToSend) >> 8) & 0xff;
  206.             txMsg2.Data[1] = (((uint32_t)dataToSend) >> 16) & 0xff;
  207.             txMsg2.Data[0] = (((uint32_t)dataToSend) >> 24) & 0xff;
  208.             StdCan_Put(&txMsg2);
  209.            
  210.             break;
  211.         }
  212.     }
  213. }
  214.  
  215. void sns_water_List(uint8_t ModuleSequenceNumber)
  216. {
  217.     StdCan_Msg_t txMsg;
  218.  
  219.     StdCan_Set_class(txMsg.Header, CAN_MODULE_CLASS_SNS);
  220.     StdCan_Set_direction(txMsg.Header, DIRECTIONFLAG_FROM_OWNER);
  221.     txMsg.Header.ModuleType = CAN_MODULE_TYPE_SNS_WATER;
  222.     txMsg.Header.ModuleId = sns_water_ID;
  223.     txMsg.Header.Command = CAN_MODULE_CMD_GLOBAL_LIST;
  224.     txMsg.Length = 6;
  225.  
  226.     uint32_t HwId=BIOS_GetHwId();
  227.     txMsg.Data[0] = HwId&0xff;
  228.     txMsg.Data[1] = (HwId>>8)&0xff;
  229.     txMsg.Data[2] = (HwId>>16)&0xff;
  230.     txMsg.Data[3] = (HwId>>24)&0xff;
  231.  
  232.     txMsg.Data[4] = NUMBER_OF_MODULES;
  233.     txMsg.Data[5] = ModuleSequenceNumber;
  234.  
  235.     while (StdCan_Put(&txMsg) != StdCan_Ret_OK);
  236. }
  237.