prepared for combined date/time types, corrected DAY type and added tests for it

This commit is contained in:
john30
2016-10-03 19:06:02 +02:00
parent e116cadf3f
commit 863d651868
3 changed files with 104 additions and 74 deletions
+82 -62
View File
@@ -281,8 +281,9 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
if (outputFormat & OF_JSON)
output << '"';
int type = (m_hasDate?2:0) | (m_hasTime?1:0);
for (size_t offset = start, i = 0; i < count; offset += incr, i++) {
if (length == 4 && i == 2 && m_isDate)
if (length == 4 && i == 2 && m_hasDate)
continue; // skip weekday in between
ch = input[baseOffset + offset];
if (hasFlag(BCD) && (hasFlag(REQ) || ch != m_replacement)) {
@@ -290,34 +291,38 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
ch = (unsigned char)((ch >> 4) * 10 + (ch & 0x0f));
}
switch (m_isDate)
switch (type)
{
case true:
if (length == 2) { // number of days since 01.01.1900
if (i == 0) {
break;
}
/*int days = last*256 + ch + 15020; // 01.01.1900
int y = days(value < 100 ? value + 2000 : value) - 1900;
int l = (last==1 || last==2) ? 1 : 0;
int mjd = 14956 + lastLast + (int)((y-l)*365.25) + (int)((last+1+l*12)*30.6001);
int daysSinceSunday = (mjd+3) % 7; // Sun=0
if ((m_dataType.flags & BCD) != 0)
output[baseOffset + offset - incr] = (unsigned char)((6+daysSinceSunday) % 7); // Sun=0x06
else
output[baseOffset + offset - incr] = (unsigned char)(daysSinceSunday==0 ? 7 : daysSinceSunday); // Sun=0x07*/
output << setw(2) << dec << setfill('0') << static_cast<unsigned>(ch) << ".";
}
case 2: // date only
if (!hasFlag(REQ) && ch == m_replacement) {
if (i + 1 != length) {
output << NULL_VALUE << ".";
break;
}
else if (last == m_replacement) {
} else if (last == m_replacement) {
if (length == 2) { // number of days since 01.01.1900
output << NULL_VALUE << ".";
}
output << NULL_VALUE;
break;
}
}
if (length == 2) { // number of days since 01.01.1900
if (i == 0) {
break;
}
int mjd = last + ch*256 + 15020; // 01.01.1900
int y = (int)((mjd-15078.2)/365.25);
int m = (int)((mjd-14956.1-(int)(y*365.25))/30.6001);
int d = mjd-14956-(int)(y*365.25)-(int)(m*30.6001);
m--;
if (m>=13) {
y++;
m -= 12;
}
output << dec << setfill('0') << setw(2) << static_cast<unsigned>(d) << "."
<< setw(2) << static_cast<unsigned>(m) << "." << static_cast<unsigned>(y + 1900);
break;
}
if (i + 1 == length)
output << (2000 + ch);
else if (ch < 1 || (i == 0 && ch > 31) || (i == 1 && ch > 12))
@@ -325,7 +330,8 @@ result_t DateTimeDataType::readSymbols(SymbolString& input, const bool isMaster,
else
output << setw(2) << dec << setfill('0') << static_cast<unsigned>(ch) << ".";
break;
case false:
case 1: // time only
if (!hasFlag(REQ) && ch == m_replacement) {
if (length == 1) { // truncated time
output << NULL_VALUE << ":" << NULL_VALUE;
@@ -392,10 +398,13 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
}
result_t result;
size_t i = 0, offset;
for (offset = start; i < count; offset += incr, i++) {
switch (m_isDate)
int type = (m_hasDate?2:0) | (m_hasTime?1:0);
bool skip = false;
for (offset = start; i < count; offset += skip?0:incr, i++) {
skip = false;
switch (type)
{
case true:
case 2: // date only
if (length == 4 && i == 2)
continue; // skip weekday in between
if (input.eof() || !getline(input, token, '.'))
@@ -408,11 +417,27 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
if (result != RESULT_OK) {
return result; // invalid date part
}
if (i + 1 == length) {
if (length == 2) { // number of days since 01.01.1900
skip = true;
if (i == 0) {
count++;
} else if (i + 1 == count) {
int y = (value < 100 ? value + 2000 : value) - 1900;
int l = last<=2 ? 1 : 0;
int mjd = 14956 + lastLast + (int)((y-l)*365.25) + (int)((last+1+l*12)*30.6001);
value = mjd - 15020; // 01.01.1900
output[baseOffset + offset] = (unsigned char)(value&0xff);
value >>= 8;
offset += incr;
skip = false;
break;
}
}
if (i + 1 == count) {
if (length == 4) {
// calculate local week day
int y = (value < 100 ? value + 2000 : value) - 1900;
int l = (last==1 || last==2) ? 1 : 0;
int l = last<=2 ? 1 : 0;
int mjd = 14956 + lastLast + (int)((y-l)*365.25) + (int)((last+1+l*12)*30.6001);
int daysSinceSunday = (mjd+3) % 7; // Sun=0
if (hasFlag(BCD))
@@ -424,21 +449,21 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
value -= 2000;
if (value > 99)
return RESULT_ERR_OUT_OF_RANGE; // invalid year
}
else if (value < 1 || (i == 0 && value > 31) || (i == 1 && value > 12))
} else if (value < 1 || (i == 0 && value > 31) || (i == 1 && value > 12)) {
return RESULT_ERR_OUT_OF_RANGE; // invalid date part
}
break;
case false:
case 1: // time only
if (input.eof() || !getline(input, token, LENGTH_SEPARATOR))
return RESULT_ERR_EOF; // incomplete
if (!hasFlag(REQ) && strcmp(token.c_str(), NULL_VALUE) == 0) {
value = m_replacement;
if (length == 1) { // truncated time
if (i == 0) {
last = value;
offset -= incr; // repeat for minutes
skip = true; // repeat for minutes
count++;
continue;
break;
}
if (last != m_replacement)
return RESULT_ERR_INVALID_NUM; // invalid truncated time minutes
@@ -452,10 +477,9 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
return RESULT_ERR_OUT_OF_RANGE; // invalid time part
if (length == 1) { // truncated time
if (i == 0) {
last = value;
offset -= incr; // repeat for minutes
skip = true; // repeat for minutes
count++;
continue;
break;
}
if ((value % m_resolution) != 0)
@@ -466,23 +490,18 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
}
break;
}
if (remainder && input.eof() && i > 0) {
if (value == 0x00) {
output[baseOffset + offset] = 0;
offset += incr;
}
break;
}
lastLast = last;
last = value;
if (hasFlag(BCD) && (hasFlag(REQ) || value != m_replacement)) {
if (value > 99)
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
value = ((value / 10) << 4) | (value % 10);
if (!skip) {
if (hasFlag(BCD) && (hasFlag(REQ) || value != m_replacement)) {
if (value > 99)
return RESULT_ERR_OUT_OF_RANGE; // invalid BCD
value = ((value / 10) << 4) | (value % 10);
}
if (value > 0xff)
return RESULT_ERR_OUT_OF_RANGE; // value out of range
output[baseOffset + offset] = (unsigned char)value;
}
if (value > 0xff)
return RESULT_ERR_OUT_OF_RANGE; // value out of range
output[baseOffset + offset] = (unsigned char)value;
}
if (!remainder && i < count)
@@ -879,19 +898,20 @@ DataTypeList::DataTypeList()
add(new StringDataType("IGN", MAX_LEN*8, IGN|ADJ, 0)); // >= 1 byte ignored data
add(new StringDataType("NTS", MAX_LEN*8, ADJ, 0)); // >= 1 byte character string filled up with 0x00 (null terminated string)
add(new StringDataType("HEX", MAX_LEN*8, ADJ, 0, true)); // >= 1 byte hex digit string, usually separated by space, e.g. 0a 1b 2c 3d
add(new DateTimeDataType("BDA", 32, BCD, 0xff, true, 0)); // date with weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday Mon=0x00 - Sun=0x06, replacement 0xff)
add(new DateTimeDataType("BDA", 24, BCD, 0xff, true, 0)); // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99, replacement 0xff)
add(new DateTimeDataType("HDA", 32, 0, 0xff, true, 0)); // date with weekday, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x1f,0x0c,WW,0x63, WW is weekday Mon=0x01 - Sun=0x07, replacement 0xff)
add(new DateTimeDataType("HDA", 24, 0, 0xff, true, 0)); // date, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x1f,0x0c,0x63, replacement 0xff)
add(new DateTimeDataType("DAY", 16, REQ, 0, true, 0)); // date, days since 01.01.1900, 01.01.1900 - 06.06.2079 (0x00,0x00 - 0xff,0xff)
add(new DateTimeDataType("BTI", 24, BCD|REV|REQ, 0, false, 0)); // time in BCD, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x59,0x59,0x23)
add(new DateTimeDataType("HTI", 24, REQ, 0, false, 0)); // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x17,0x3b,0x3b)
add(new DateTimeDataType("VTI", 24, REV, 0x63, false, 0)); // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x3b,0x3b,0x17, replacement 0x63) [Vaillant type]
add(new DateTimeDataType("BTM", 16, BCD|REV, 0xff, false, 0)); // time as hh:mm in BCD, 00:00 - 23:59 (0x00,0x00 - 0x59,0x23, replacement 0xff)
add(new DateTimeDataType("HTM", 16, REQ, 0, false, 0)); // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x17,0x3b)
add(new DateTimeDataType("VTM", 16, REV, 0xff, false, 0)); // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x3b,0x17, replacement 0xff) [Vaillant type]
add(new DateTimeDataType("TTM", 8, 0, 0x90, false, 10)); // truncated time (only multiple of 10 minutes), 00:00 - 24:00 (minutes div 10 + hour * 6 as integer)
add(new DateTimeDataType("TTH", 8, 0, 0, false, 30)); // truncated time (only multiple of 30 minutes), 00:30 - 24:00 (minutes div 30 + hour * 2 as integer)
add(new DateTimeDataType("BDA", 32, BCD, 0xff, true, false, 0)); // date with weekday in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x31,0x12,WW,0x99, WW is weekday Mon=0x00 - Sun=0x06, replacement 0xff)
add(new DateTimeDataType("BDA", 24, BCD, 0xff, true, false, 0)); // date in BCD, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x31,0x12,0x99, replacement 0xff)
add(new DateTimeDataType("HDA", 32, 0, 0xff, true, false, 0)); // date with weekday, 01.01.2000 - 31.12.2099 (0x01,0x01,WW,0x00 - 0x1f,0x0c,WW,0x63, WW is weekday Mon=0x01 - Sun=0x07, replacement 0xff)
add(new DateTimeDataType("HDA", 24, 0, 0xff, true, false, 0)); // date, 01.01.2000 - 31.12.2099 (0x01,0x01,0x00 - 0x1f,0x0c,0x63, replacement 0xff)
add(new DateTimeDataType("DAY", 16, 0, 0xff, true, false, 0)); // date, days since 01.01.1900, 01.01.1900 - 06.06.2079 (0x00,0x00 - 0xff,0xff)
add(new DateTimeDataType("BTI", 24, BCD|REV|REQ, 0, false, true, 0)); // time in BCD, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x59,0x59,0x23)
add(new DateTimeDataType("HTI", 24, REQ, 0, false, true, 0)); // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x17,0x3b,0x3b)
add(new DateTimeDataType("VTI", 24, REV, 0x63, false, true, 0)); // time, 00:00:00 - 23:59:59 (0x00,0x00,0x00 - 0x3b,0x3b,0x17, replacement 0x63) [Vaillant type]
add(new DateTimeDataType("BTM", 16, BCD|REV, 0xff, false, true, 0)); // time as hh:mm in BCD, 00:00 - 23:59 (0x00,0x00 - 0x59,0x23, replacement 0xff)
add(new DateTimeDataType("HTM", 16, REQ, 0, false, true, 0)); // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x17,0x3b)
add(new DateTimeDataType("VTM", 16, REV, 0xff, false, true, 0)); // time as hh:mm, 00:00 - 23:59 (0x00,0x00 - 0x3b,0x17, replacement 0xff) [Vaillant type]
// add(new DateTimeDataType("MIN", 16, SPE, 0xff, false, true, 0)); // time, minutes since last midnight, 00:00 - 24:00 (minutes + hour * 60 as integer)
add(new DateTimeDataType("TTM", 8, 0, 0x90, false, true, 10)); // truncated time (only multiple of 10 minutes), 00:00 - 24:00 (minutes div 10 + hour * 6 as integer)
add(new DateTimeDataType("TTH", 8, 0, 0, false, true, 30)); // truncated time (only multiple of 30 minutes), 00:00 - 24:00 (minutes div 30 + hour * 2 as integer)
add(new NumberDataType("BDY", 8, DAY, 0x07, 0, 6, 1)); // weekday, "Mon" - "Sun" (0x00 - 0x06) [eBUS type]
add(new NumberDataType("HDY", 8, DAY, 0x00, 1, 7, 1)); // weekday, "Mon" - "Sun" (0x01 - 0x07) [Vaillant type]
add(new NumberDataType("BCD", 8, BCD, 0xff, 0, 99, 1)); // unsigned decimal in BCD, 0 - 99
+17 -12
View File
@@ -100,6 +100,7 @@ static const unsigned int HCD = 0x80; //!< binary representation is hex converte
static const unsigned int EXP = 0x100; //!< exponential numeric representation
static const unsigned int DAY = 0x200; //!< forced value list defaulting to week days
static const unsigned int NUM = 0x400; //!< numeric type with base class @a NumberDataType
static const unsigned int SPE = 0x800; //!< special marker for certain types
/**
@@ -324,12 +325,13 @@ public:
* @param bitCount the number of bits (maximum length if #ADJ flag is set, must be multiple of 8 with flag #BCD).
* @param flags the combination of flags (like #BCD).
* @param replacement the replacement value.
* @param isDate true for date, false for time.
* @param hasDate true if date part is present.
* @param hasTime true if time part is present.
* @param resolution the the resolution in minutes for time types, or 1.
*/
DateTimeDataType(const string id, const unsigned char bitCount, const unsigned short flags, const unsigned int replacement,
const bool isDate, const short resolution)
: DataType(id, bitCount, flags, replacement), m_isDate(isDate), m_resolution(resolution) {}
const bool hasDate, const bool hasTime, const short resolution)
: DataType(id, bitCount, flags, replacement), m_hasDate(hasDate), m_hasTime(hasTime), m_resolution(resolution) {}
/**
* Destructor.
@@ -337,9 +339,14 @@ public:
virtual ~DateTimeDataType() {}
/**
* @return true for date, false for time.
* @return true if date part is present.
*/
bool isDate() const { return m_isDate; }
bool hasDate() const { return m_hasDate; }
/**
* @return true if time part is present.
*/
bool hasTime() const { return m_hasTime; }
/**
* @return the resolution in minutes for time types, or 1.
@@ -363,8 +370,11 @@ public:
private:
/** true for date, false for time. */
const bool m_isDate;
/** true if date part is present. */
const bool m_hasDate;
/** true if time part is present. */
const bool m_hasTime;
/** the resolution in minutes for time types, or 1. */
const short m_resolution;
@@ -555,11 +565,6 @@ public:
*/
void addCleanup(DataType* dataType) { m_cleanupTypes.push_back(dataType); }
// @copydoc
/*virtual result_t addFromFile(vector<string>::iterator& begin, const vector<string>::iterator end,
vector< vector<string> >* defaults, const string& defaultDest, const string& defaultCircuit, const string& defaultSuffix,
const string& filename, unsigned int lineNo);*/
/**
* Gets the @a DataType instance with the specified ID.
* @param id the ID string (excluding optional length suffix).
+5
View File
@@ -100,6 +100,11 @@ int main()
{"x,,hda:3", "-.-.-", "10fe070003ffffff", "00", ""},
{"x,,hda:3", "", "10fe070003200c63", "00", "rw"},
{"x,,hda,2", "", "", "", "c"},
{"x,,day", "26.10.2014","10fe070002d0a3", "00", ""},
{"x,,day", "01.01.2000","10fe070002ac8e", "00", ""},
{"x,,day", "31.12.2078","10fe07000262ff", "00", ""},
{"x,,day", "-.-.-", "10fe070002ffff", "00", ""},
{"x,,day", "", "10fe0700020000", "00", "Rw"},
{"x,,bti", "21:04:58", "10fe070003580421", "00", ""},
{"x,,bti", "00:00:00", "10fe070003000000", "00", ""},
{"x,,bti", "23:59:59", "10fe070003595923", "00", ""},