?? emeter-multirate.c
字號(hào):
//--------------------------------------------------------------------------
//
// Software for MSP430 based e-meters.
//
// You may not use the Program in non-TI devices.
//
// File: emeter-multirate.c
//
// Steve Underwood <steve-underwood@ti.com>
// Texas Instruments Hong Kong Ltd.
//
// $Id: emeter-multirate.c,v 1.3 2005/12/20 10:17:57 a0754793 Exp $
//
/*! \file emeter-multirate.h */
//
//--------------------------------------------------------------------------
//
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#if !defined(__MSP430__)
#include <stdio.h>
#endif
#include <io.h>
#include <emeter-toolkit.h>
#include "emeter.h"
#include "emeter-structs.h"
#include "emeter-multirate.h"
#if MULTI_RATE_SUPPORT
uint8_t tariff_flags;
eeprom_history_t current_history;
uint8_t current_history_dirty;
/*! The current slot number in the usage history table */
uint8_t current_history_slot;
/*! The tariff type of the current day */
uint8_t current_day_type;
uint8_t current_tariff = 0xFF;
eeprom_daily_peak_t daily_peak;
uint8_t daily_peak_slot;
/*! The current slot in the five minute usage table. */
uint8_t current_five_minute_slot;
/*! This table is 30 minutes long, in 5 minute chunks. Usage is accumulated in
5 minute chunks, to the centre of the 30 minute period of peak usage may be
assessed to 5 minute accuracy. */
uint16_t five_minute_usages[6];
/* Add a one byte sumcheck to the passed message, in the byte after the message */
void add_sumcheck(void *buf, int len)
{
uint8_t *s;
int sum;
sum = 0;
s = (uint8_t *) buf;
while (--len > 0)
sum += *s++;
*s = 0xFF - sum;
}
/* Check the passed message, which must include a one byte sumcheck, is OK */
int test_sumcheck(const void *buf, int len)
{
const uint8_t *s;
int sum;
sum = 0;
s = (uint8_t *) buf;
while (len-- > 0)
sum += *s++;
return ((sum & 0xFF) == 0xFF);
}
void multirate_energy_pulse(void)
{
five_minute_usages[current_five_minute_slot]++;
if (++current_history.energy_lo == 0)
++current_history.energy_hi;
current_history_dirty = TRUE;
}
int find_next_cutoff_date(void)
{
int year;
int month;
int day;
int best_year;
int best_month;
int best_day;
int best_slot;
int i;
eeprom_cutoff_date_t cutoff_date;
/* We need to find the smallest date which is greater than the current date */
inhibit_rtc_updates();
year = rtc.year;
month = rtc.month;
day = rtc.day;
enable_rtc_updates();
best_year = 99;
best_month = 12;
best_day = 31;
best_slot = -1;
for (i = 0; i < MULTIRATE_MAX_CUTOFF_DATES; i++)
{
iicEEPROM_read(EEPROM_START_CUTOFF_DATES + i*sizeof(eeprom_cutoff_date_t), (void *) &cutoff_date, sizeof(cutoff_date));
if (year < cutoff_date.year
||
(year == cutoff_date.year
&&
(month < cutoff_date.month
||
(month == cutoff_date.month && day < cutoff_date.day))))
{
if (best_year > cutoff_date.year
||
(best_year == cutoff_date.year
&&
(best_month > cutoff_date.month
||
(best_month == cutoff_date.month && best_day > cutoff_date.day))))
{
/* This is earlier, so use it */
best_slot = i;
best_year = cutoff_date.year;
best_month = cutoff_date.month;
best_day = cutoff_date.day;
}
}
}
return best_slot;
}
int find_previous_cutoff_date(void)
{
int year;
int month;
int day;
int best_year;
int best_month;
int best_day;
int best_slot;
int i;
eeprom_cutoff_date_t cutoff_date;
/* We need to find the largest date which is less than the current date */
inhibit_rtc_updates();
year = rtc.year;
month = rtc.month;
day = rtc.day;
enable_rtc_updates();
best_year = 0;
best_month = 0;
best_day = 0;
best_slot = -1;
for (i = 0; i < MULTIRATE_MAX_CUTOFF_DATES; i++)
{
iicEEPROM_read(EEPROM_START_CUTOFF_DATES + i*sizeof(eeprom_cutoff_date_t), (void *) &cutoff_date, sizeof(cutoff_date));
if (year > cutoff_date.year
||
(year == cutoff_date.year
&&
(month > cutoff_date.month
||
(month == cutoff_date.month && day >= cutoff_date.day))))
{
if (best_year < cutoff_date.year
||
(best_year == cutoff_date.year
&&
(best_month < cutoff_date.month
||
(best_month == cutoff_date.month && best_day < cutoff_date.day))))
{
/* This is later, so use it */
best_slot = i;
best_year = cutoff_date.year;
best_month = cutoff_date.month;
best_day = cutoff_date.day;
}
}
}
return best_slot;
}
void new_tariff_day(void)
{
int i;
uint8_t day_type;
int year;
int month;
int day;
int wday;
eeprom_holiday_t holiday;
eeprom_cutoff_date_t cutoff_date;
/* Should be called when the day changes and at reset, to work out
today's type */
inhibit_rtc_updates();
year = rtc.year;
month = rtc.month;
day = rtc.day;
enable_rtc_updates();
for (i = 0; i < MULTIRATE_MAX_HOLIDAYS; i++)
{
iicEEPROM_read(EEPROM_START_HOLIDAYS + i*sizeof(eeprom_holiday_t), (void *) &holiday, sizeof(holiday));
if (year == holiday.year
&&
month == holiday.month
&&
day == holiday.day)
{
/* Its a holiday */
current_day_type = holiday.day_type;
return;
}
}
/* Not a holiday. Just use the regular weekday pattern */
wday = weekday();
iicEEPROM_read(EEPROM_START_WEEKDAYS + (wday >> 1), (void *) &day_type, sizeof(day_type));
current_day_type = ((wday & 1) ? (day_type >> 4) : day_type) & 0x0F;
/* TODO: what if the real peak were a little before midnight */
iicEEPROM_write(EEPROM_START_PEAKS + daily_peak_slot*sizeof(eeprom_daily_peak_t), (void *) &daily_peak, sizeof(daily_peak));
if (++daily_peak_slot >= MULTIRATE_MAX_DAILY_PEAKS)
daily_peak_slot = 0;
daily_peak.usage = 0;
daily_peak.hour = 0;
daily_peak.minute = 0;
/* Check if we have reached a billing cutoff point */
iicEEPROM_read(EEPROM_START_CUTOFF_DATES + current_history_slot*sizeof(eeprom_cutoff_date_t), (void *) &cutoff_date, sizeof(cutoff_date));
if (year > cutoff_date.year
||
(year == cutoff_date.year
&&
(month > cutoff_date.month
||
(month == cutoff_date.month && day > cutoff_date.day))))
{
/* Its a cutoff point - find the next cutoff point, and start using the
history slot specified for it. */
/* If we didn't find a suitable slot, we continue accumulating where we
are. At least that way we are gathering all the usage. */
if ((i = find_next_cutoff_date()) >= 0)
current_history_slot = i;
}
}
void new_tariff_minute(void)
{
int i;
int n;
int hour;
int minute;
eeprom_day_schedule_timeslot_t tariff;
uint32_t energy;
inhibit_rtc_updates();
hour = rtc.hour;
minute = rtc.minute;
enable_rtc_updates();
/* Default to the first timeslot */
iicEEPROM_read(EEPROM_START_DAY_SCHEDULES + current_day_type*MULTIRATE_DAY_SCHEDULE_TIMESLOTS*sizeof(eeprom_day_schedule_timeslot_t), (void *) &tariff, sizeof(tariff));
n = tariff.tariff;
for (i = 1; i < MULTIRATE_DAY_SCHEDULE_TIMESLOTS; i++)
{
iicEEPROM_read(EEPROM_START_DAY_SCHEDULES + (current_day_type*MULTIRATE_DAY_SCHEDULE_TIMESLOTS + i)*sizeof(eeprom_day_schedule_timeslot_t), (void *) &tariff, sizeof(tariff));
if (tariff.tariff)
{
if (tariff.start_hour > hour
||
(tariff.start_hour == hour && tariff.start_minute > minute))
{
n = tariff.tariff;
break;
}
}
}
if (n != current_tariff)
{
/* Save current tariff values, and load the new set */
write_history_slot(current_history_slot, current_tariff);
read_history_slot(current_history_slot, n);
current_tariff = n;
}
if (rtc.minute%5 == 0)
{
/* Deal with the time and size of the daily peak demand */
energy = 0;
for (i = 0; i < 6; i++)
energy += five_minute_usages[i];
if (energy > daily_peak.usage)
{
daily_peak.usage = energy;
daily_peak.hour = rtc.hour;
daily_peak.minute = rtc.minute;
}
five_minute_usages[current_five_minute_slot] = 0;
if (++current_five_minute_slot >= 6)
current_five_minute_slot = 0;
}
current_tariff = n;
}
int read_history_slot(int slot, int tariff)
{
int i;
int pos;
eeprom_history_t history[3];
int ok[3];
if (!current_history_dirty)
return 0;
current_history_dirty = FALSE;
pos = (slot*MULTIRATE_DAY_SCHEDULES + tariff)*sizeof(eeprom_history_t);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -