Ejemplo n.º 1
0
deque<Message*> MessageMap::findAll(SymbolString& master)
{
	deque<Message*> ret;

	if (master.size() < 5)
		return ret;
	unsigned char maxIdLength = master[4];
	if (maxIdLength > m_maxIdLength)
		maxIdLength = m_maxIdLength;
	if (master.size() < 5+maxIdLength)
		return ret;

	for (int idLength = maxIdLength; ret.size()==0 && idLength >= 0; idLength--) {
		int exp = 7;
		unsigned long long key = (unsigned long long)idLength << (8 * exp + 5);
		key |= (unsigned long long)getMasterNumber(master[0]) << (8 * exp--);
		key |= (unsigned long long)master[1] << (8 * exp--);
		key |= (unsigned long long)master[2] << (8 * exp--);
		key |= (unsigned long long)master[3] << (8 * exp--);
		for (unsigned char i = 0; i < idLength; i++)
			key |= (unsigned long long)master[5 + i] << (8 * exp--);

		map<unsigned long long , vector<Message*> >::iterator it = m_messagesByKey.find(key);
		if (it != m_messagesByKey.end()) {
			Message* message = getFirstAvailable(it->second);
			if (message)
				ret.push_back(message);
		}
		if ((key & ID_SOURCE_MASK) != 0) {
			key &= ~ID_SOURCE_MASK;
			it = m_messagesByKey.find(key & ~ID_SOURCE_MASK); // try again without specific source master
			if (it != m_messagesByKey.end()) {
				Message* message = getFirstAvailable(it->second);
				if (message)
					ret.push_back(message);
			}
		}
		it = m_messagesByKey.find(key | ID_SOURCE_ACTIVE_READ); // try again with special value for active read
		if (it != m_messagesByKey.end()) {
			Message* message = getFirstAvailable(it->second);
			if (message)
				ret.push_back(message);
		}
		it = m_messagesByKey.find(key | ID_SOURCE_ACTIVE_WRITE); // try again with special value for active write
		if (it != m_messagesByKey.end()) {
			Message* message = getFirstAvailable(it->second);
			if (message)
				ret.push_back(message);
		}
	}

	return ret;
}
Ejemplo n.º 2
0
result_t SingleDataField::read(const PartType partType,
		SymbolString& data, unsigned char offset,
		unsigned int& output, const char* fieldName, signed char fieldIndex)
{
	if (partType != m_partType)
		return RESULT_EMPTY;

	switch (m_partType)
	{
	case pt_masterData:
		offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
		break;
	case pt_slaveData:
		offset++; // skip NN
		break;
	default:
		return RESULT_ERR_INVALID_PART;
	}
	bool remainder = m_length==REMAIN_LEN && m_dataType->isAdjustableLength();
	if (offset + (remainder?1:m_length) > data.size()) {
		return RESULT_ERR_INVALID_POS;
	}
	if (isIgnored() || (fieldName != NULL && (m_name != fieldName || fieldIndex > 0))) {
		return RESULT_EMPTY;
	}
	return m_dataType->readRawValue(data, offset, m_length, output);
}
Ejemplo n.º 3
0
result_t BusHandler::scanAndWait(unsigned char dstAddress, SymbolString& slave)
{
	if (!isValidAddress(dstAddress) || isMaster(dstAddress))
		return RESULT_ERR_INVALID_ADDR;
	m_seenAddresses[dstAddress] |= SCAN_INIT;
	Message* scanMessage = m_messages->getScanMessage();
	if (scanMessage==NULL) {
		return RESULT_ERR_NOTFOUND;
	}
	istringstream input;
	SymbolString master;
	result_t result = scanMessage->prepareMaster(m_ownMasterAddress, master, input, UI_FIELD_SEPARATOR, dstAddress);
	if (result==RESULT_OK) {
		result = sendAndWait(master, slave);
		if (result==RESULT_OK) {
			Message* message = m_messages->getScanMessage(dstAddress);
			if (message!=NULL && message!=scanMessage) {
				scanMessage = message;
				scanMessage->storeLastData(pt_masterData, master, 0); // update the cache, expected to work since this is a clone
			}
		}
		if (result!=RESULT_ERR_NO_SIGNAL)
			m_seenAddresses[dstAddress] |= SCAN_DONE;
	}
	if (result != RESULT_OK || slave.size() == 0) // avoid "invalid position" during decode
		return result;

	return scanMessage->storeLastData(pt_slaveData, slave, 0); // update the cache
}
Ejemplo n.º 4
0
result_t DataFieldSet::read(const PartType partType,
		SymbolString& data, unsigned char offset,
		ostringstream& output, OutputFormat outputFormat, signed char outputIndex,
		bool leadingSeparator, const char* fieldName, signed char fieldIndex)
{
	bool previousFullByteOffset = true, found = false, findFieldIndex = fieldName != NULL && fieldIndex >= 0;
	if (!m_uniqueNames && outputIndex<0)
		outputIndex = 0;
	for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
		SingleDataField* field = *it;
		if (partType != pt_any && field->getPartType() != partType) {
			if (outputIndex>=0 && !field->isIgnored())
				outputIndex++;
			continue;
		}
		if (!previousFullByteOffset && !field->hasFullByteOffset(false))
			offset--;

		result_t result = field->read(partType, data, offset, output, outputFormat, outputIndex, leadingSeparator, fieldName, fieldIndex);

		if (result < RESULT_OK)
			return result;

		offset = (unsigned char)(offset + field->getLength(partType, (unsigned char)(data.size()-offset)));
		previousFullByteOffset = field->hasFullByteOffset(true);
		if (result != RESULT_EMPTY) {
			found = true;
			leadingSeparator = true;
		}
		if (findFieldIndex && fieldName == field->getName()) {
			if (fieldIndex == 0) {
				if (!found)
					return RESULT_ERR_NOTFOUND;
				break;
			}
			fieldIndex--;
		}
		if (outputIndex>=0 && !field->isIgnored())
			outputIndex++;
	}

	if (!found) {
		return RESULT_EMPTY;
	}
	if ((outputFormat & OF_COMMENTS) && m_comment.length() > 0) {
		if (outputFormat & OF_JSON) {
			output << ",\"comment\": \"" << m_comment << '"';
		} else {
			output << " [" << m_comment << "]";
		}
	}

	return RESULT_OK;
}
Ejemplo n.º 5
0
result_t DataFieldSet::read(const PartType partType,
		SymbolString& data, unsigned char offset,
		unsigned int& output, const char* fieldName, signed char fieldIndex)
{
	bool previousFullByteOffset = true, found = false, findFieldIndex = fieldName != NULL && fieldIndex >= 0;
	for (vector<SingleDataField*>::iterator it = m_fields.begin(); it < m_fields.end(); it++) {
		SingleDataField* field = *it;
		if (partType != pt_any && field->getPartType() != partType)
			continue;

		if (!previousFullByteOffset && !field->hasFullByteOffset(false))
			offset--;

		result_t result = field->read(partType, data, offset, output, fieldName, fieldIndex);

		if (result < RESULT_OK)
			return result;

		offset = (unsigned char)(offset + field->getLength(partType, (unsigned char)(data.size()-offset)));
		previousFullByteOffset = field->hasFullByteOffset(true);
		if (result != RESULT_EMPTY) {
			found = true;
		}
		if (findFieldIndex && fieldName == field->getName()) {
			if (fieldIndex == 0) {
				if (!found)
					return RESULT_ERR_NOTFOUND;
				break;
			}
			fieldIndex--;
		}
	}

	if (!found) {
		return RESULT_EMPTY;
	}

	return RESULT_OK;
}
Ejemplo n.º 6
0
result_t SingleDataField::read(const PartType partType,
		SymbolString& data, unsigned char offset,
		ostringstream& output, OutputFormat outputFormat, signed char outputIndex,
		bool leadingSeparator, const char* fieldName, signed char fieldIndex)
{
	if (partType != m_partType) {
		return RESULT_OK;
	}
	switch (m_partType)
	{
	case pt_masterData:
		offset = (unsigned char)(offset + 5); // skip QQ ZZ PB SB NN
		break;
	case pt_slaveData:
		offset++; // skip NN
		break;
	default:
		return RESULT_ERR_INVALID_PART;
	}
	bool remainder = m_length==REMAIN_LEN && m_dataType->isAdjustableLength();
	if (offset + (remainder?1:m_length) > data.size()) {
		return RESULT_ERR_INVALID_POS;
	}
	if (isIgnored() || (fieldName != NULL && (m_name != fieldName || fieldIndex > 0))) {
		return RESULT_EMPTY;
	}

	if (outputFormat & OF_JSON) {
		if (leadingSeparator) {
			output << ",";
		}
		if (outputIndex>=0 || m_name.empty() || !(outputFormat & OF_NAMES)) {
			output << "\n    \"" << static_cast<signed int>(outputIndex<0?0:outputIndex) << "\": {\"name\": \"" << m_name << "\"" << ", \"value\": ";
		} else {
			output << "\n    \"" << m_name << "\": {\"value\": ";
		}
	} else {
		if (leadingSeparator) {
			output << UI_FIELD_SEPARATOR;
		}
		if (outputFormat & OF_NAMES) {
			output << m_name << "=";
		}
	}

	result_t result = readSymbols(data, m_partType==pt_masterData, offset, output, outputFormat);
	if (result != RESULT_OK) {
		return result;
	}
	if ((outputFormat & OF_UNITS) && m_unit.length() > 0) {
		if (outputFormat & OF_JSON) {
			output << ", \"unit\": \"" << m_unit << '"';
		} else {
			output << " " << m_unit;
		}
	}
	if ((outputFormat & OF_COMMENTS) && m_comment.length() > 0) {
		if (outputFormat & OF_JSON) {
			output << ", \"comment\": \"" << m_comment << '"';
		} else {
			output << " [" << m_comment << "]";
		}
	}
	if (outputFormat & OF_JSON) {
		output << "}";
	}
	return RESULT_OK;
}
Ejemplo n.º 7
0
result_t loadScanConfigFile(MessageMap* messages, unsigned char address, SymbolString& data, string& relativeFile)
{
	PartType partType;
	if (isMaster(address)) {
		address = (unsigned char)(data[0]+5); // slave address of sending master
		partType = pt_masterData;
		if (data.size()<5+1+5+2+2) // skip QQ ZZ PB SB NN
			return RESULT_EMPTY;
	} else {
		partType = pt_slaveData;
		if (data.size()<1+1+5+2+2) // skip NN
			return RESULT_EMPTY;
	}
	DataFieldSet* identFields = DataFieldSet::getIdentFields();
	// MANUFACTURER/ZZ. ( C.S.H., C.H., C.S., S.H., C., S., H., "" ) .*csv
	string path, prefix, ident, sw, hw; // path: cfgpath/MANUFACTURER, prefix: ZZ., ident: C[C[C[C[C]]]], sw: xxxx, hw: xxxx
	ostringstream out;
	unsigned char offset = 0;
	size_t field = 0;
	result_t result = (*identFields)[field]->read(partType, data, offset, out, 0); // manufacturer name
	if (result==RESULT_ERR_NOTFOUND)
		result = (*identFields)[field]->read(partType, data, offset, out, OF_NUMERIC); // manufacturer name
	if (result==RESULT_OK) {
		path = out.str();
		transform(path.begin(), path.end(), path.begin(), ::tolower);
		path = string(opt.configPath) + "/" + path;
		out.str("");
		out << setw(2) << hex << setfill('0') << nouppercase << static_cast<unsigned>(address) << ".";
		prefix = out.str();
		out.str("");
		out.clear();
		offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
		result = (*identFields)[field]->read(partType, data, offset, out, 0); // identification string
	}
	if (result==RESULT_OK) {
		ident = out.str();
		out.str("");
		offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
		result = (*identFields)[field]->read(partType, data, offset, out, 0); // software version number
	}
	if (result==RESULT_OK) {
		sw = out.str();
		out.str("");
		offset = (unsigned char)(offset+(*identFields)[field++]->getLength(partType));
		result = (*identFields)[field]->read(partType, data, offset, out, 0); // hardware version number
	}
	if (result!=RESULT_OK) {
		logDebug(lf_main, "load scan config files: %s", getResultCode(result));
		return result;
	}
	vector<string> files;
	bool hasTemplates = false;
	if (result==RESULT_OK) {
		hw = out.str();
		result = collectConfigFiles(path, prefix, ".csv", files, NULL, &hasTemplates);
	}
	logDebug(lf_main, "found %d matching scan config files from %s with prefix %s: %s", files.size(), path.c_str(), prefix.c_str(), getResultCode(result));
	if (result!=RESULT_OK)
		return result;
	if (files.empty())
		return RESULT_ERR_NOTFOUND;

	// complete name: cfgpath/MANUFACTURER/ZZ[.C[C[C[C[C]]]]][.SWxxxx][.HWxxxx][.*].csv
	for (string::iterator it = ident.begin(); it!=ident.end(); it++) {
		if (::isspace(*it)) {
			ident.erase(it--);
		} else {
			*it = (char)::tolower(*it);
		}
	}
	size_t prefixLen = path.length()+1+prefix.length()-1;
	size_t bestMatch = 0;
	string best;
	for (vector<string>::iterator it = files.begin(); it!=files.end(); it++) {
		string name = *it;
		name = name.substr(prefixLen, name.length()-prefixLen+1-strlen(".csv")); // .*.
		size_t match = 1;
		if (name.length()>2) { // more than just "."
			size_t pos = name.rfind(".SW"); // check for ".SWxxxx."
			if (pos!=string::npos && name.find(".", pos+1)==pos+7) {
				if (name.substr(pos+3, 4)==sw)
					match += 6;
				else {
					continue; // SW mismatch
				}
			}
			pos = name.rfind(".HW"); // check for ".HWxxxx."
			if (pos!=string::npos && name.find(".", pos+1)==pos+7) {
				if (name.substr(pos+3, 4)==hw)
					match += 6;
				else {
					continue; // HW mismatch
				}
			}
			pos = name.find(".", 1); // check for ".C[C[C[C[C]]]]."
			if (ident.length()>0 && pos!=string::npos && pos>1 && pos<=6) { // up to 5 chars between two "."s, immediately after "ZZ."
				string check = name.substr(1, pos-1);
				string remain = ident;
				bool matches = false;
				while (remain.length()>0 && remain.length()>=check.length()) {
					if (check==remain) {
						matches = true;
						break;
					}
					if (remain[remain.length()-1]!='0')
						break;
					remain.erase(remain.length()-1);
				}
				if (matches)
					match += remain.length();
				else {
					continue; // IDENT mismatch
				}
			}
		}
		if (match>=bestMatch) {
			bestMatch = match;
			best = *it;
		}
	}

	if (best.length()==0)
		return RESULT_ERR_NOTFOUND;

	// found the right file. load the templates if necessary, then load the file itself
	bool readCommon = false;
	DataFieldTemplates* templates = getTemplates(path, ".csv", hasTemplates, false, &readCommon);
	if (readCommon) {
		result = collectConfigFiles(path, "", ".csv", files);
		if (result==RESULT_OK && !files.empty()) {
			for (vector<string>::iterator it = files.begin(); it!=files.end(); it++) {
				string name = *it;
				name = name.substr(path.length()+1, name.length()-path.length()-strlen(".csv")); // *.
				if (name=="_templates.") // skip templates
					continue;
				if (name.length()<3 || name.find_first_of('.')!=2) { // different from the scheme "ZZ."
					name = *it;
					result = messages->readFromFile(name, templates);
					if (result==RESULT_OK)
						logNotice(lf_main, "read common config file %s for scan %s", name.c_str(), ident.c_str());
					else
						logError(lf_main, "error reading common config file %s for scan %s: %s", name.c_str(), ident.c_str(), getResultCode(result));
				}
			}
		}
	}
	result = messages->readFromFile(best, templates);
	if (result!=RESULT_OK) {
		logError(lf_main, "error reading config file %s for scan %s: %s", best.c_str(), ident.c_str(), getResultCode(result));
		return result;
	}
	logNotice(lf_main, "read config file %s for scan %s", best.c_str(), ident.c_str());
	result = messages->resolveConditions(false);
	if (result != RESULT_OK)
		logError(lf_main, "error resolving conditions: %s, %s", getResultCode(result), messages->getLastError().c_str());

	logNotice(lf_main, "found messages: %d (%d conditional on %d conditions, %d poll, %d update)", messages->size(), messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive());
	relativeFile = best.substr(strlen(opt.configPath)+1);
	return RESULT_OK;
}