uint16 NodeEeprom::readEeprom(uint16 location) { uint16 result; bool canCacheEeprom = NodeEepromMap::canUseCache_read(location); //if we want to pull from the cache if(m_useCache && canCacheEeprom) { //attempt to read the value from the cache if(readCache(location, result)) { //the value was found in the cache, just return the result return result; } } //we didn't get a value from the cache //attempt to read the value from the device if(updateCacheFromDevice(location, canCacheEeprom)) { //successfully read from the device, the cache has been updated so read from it readCache(location, result); return result; } //we failed to read the eeprom value from the cache or the device throw Error_NodeCommunication(m_nodeAddress, "Failed to read EEPROM " + Utils::toStr(location) + " from Node " + Utils::toStr(m_nodeAddress)); }
AutoShuntCalResult WirelessNode_Impl::autoShuntCal(const ChannelMask& mask, const ShuntCalCmdInfo& commandInfo) { //verify the node supports this operation if(!features().supportsAutoShuntCal()) { throw Error_NotSupported("AutoShuntCal is not supported by this Node."); } //verify the channel mask supports this operation if(!features().supportsChannelSetting(WirelessTypes::chSetting_autoShuntCal, mask)) { throw Error_NotSupported("AutoShuntCal is not supported by the provided channel(s)."); } uint8 channel = mask.lastChEnabled(); WirelessTypes::ChannelType chType = features().channelType(channel); AutoShuntCalResult result; bool success = m_baseStation.node_autoShuntCal(m_address, commandInfo, channel, model(), chType, result); if(!success) { throw Error_NodeCommunication(m_address, "AutoShuntCal has failed."); } return result; }
AutoCalResult_shmLink WirelessNode_Impl::autoCal_shmLink() { WirelessModels::NodeModel nodeModel = features().m_nodeInfo.model(); //verify the node supports autocal if(!features().supportsAutoCal()) { throw Error_NotSupported("AutoCal is not supported by this Node."); } //verify the node is the correct model if(nodeModel != WirelessModels::node_shmLink2 && nodeModel != WirelessModels::node_shmLink2_cust1) { throw Error_NotSupported("autoCal_shmLink is not supported by this Node's model."); } //perform the autocal command by the base station AutoCalResult_shmLink result; bool success = m_baseStation.node_autocal_shm(m_address, result); if(!success) { throw Error_NodeCommunication(m_address, "AutoCal has failed."); } return result; }
void NodeEeprom::writeEeprom(uint16 location, uint16 value) { //if we want to check the cache if(m_useCache && NodeEepromMap::canUseCache_write(location)) { //attempt to read the value from the cache uint16 valInCache; if(readCache(location, valInCache)) { //if the value in the cache is the same we are trying to write if(valInCache == value) { //do not need to write anything, just return return; } } } //if we made it here, we want to actually write to the device //if the read/write version is unknown if(m_readWriteVersion == 0) { //try to determine the version of the read/write eeprom cmd if(!determineReadWriteVersion()) { //failed to get the read/write version throw Error_NodeCommunication(m_nodeAddress, "Failed to write EEPROM " + Utils::toStr(location) + " to Node " + Utils::toStr(m_nodeAddress)); } } //attempt to write the value to the Node if(m_baseStation.node_writeEeprom(m_readWriteVersion, m_nodeAddress, location, value)) { //successfully wrote to the Node, update the cache updateCache(location, value); return; } //we failed to write the value to the Node //clear the eeprom cache for this location if we have one, just to be safe clearCacheLocation(location); throw Error_NodeCommunication(m_nodeAddress, "Failed to write EEPROM " + Utils::toStr(location) + " to Node " + Utils::toStr(m_nodeAddress)); }
void WirelessNode_Impl::erase() { //call the node_erase command from the parent BaseStation bool success = m_baseStation.node_erase(protocol(), m_address); //if the erase command failed if(!success) { throw Error_NodeCommunication(m_address, "Failed to erase the Node."); } }
void WirelessNode_Impl::getDiagnosticInfo(ChannelData& result) { //verify the node supports this operation if(!features().supportsGetDiagnosticInfo()) { throw Error_NotSupported("The Get Diagnostic Info command is not supported by this Node."); } bool success = m_baseStation.node_getDiagnosticInfo(m_address, result); if(!success) { throw Error_NodeCommunication(m_address, "Get Diagnostic Info has failed."); } }
ByteStream* NodeMemory_v1::getByteStream(uint16 page) { //if the requested data is in the currently downloaded data buffer if(page == m_currentPageNumber && !m_currentData.empty()) { //just return the address of m_currentPageData return &m_currentData; } //if the requested data is in the previously downloaded data buffer if(page == m_previousPageNumber && !m_previousData.empty()) { //just return the address of m_previousPageData return &m_previousData; } //if we made it here, the page requested is data we don't already have //request the current page data ByteStream tempData; if(!m_node.getBaseStation().node_pageDownload(m_node.protocol(), m_node.nodeAddress(), page, tempData)) { //the page download failed, throw an exception throw Error_NodeCommunication(m_node.nodeAddress(), "Failed to download data from the Node."); } //if there is current data that needs move to previous data if(!m_currentData.empty()) { //copy the current data into the previous data buffer m_previousData.clear(); m_previousData = m_currentData; m_previousPageNumber = m_currentPageNumber; } //copy the data that was just read into m_currentData m_currentData = tempData; m_currentPageNumber = page; //we successfully downloaded data that is in m_currentData return &m_currentData; }
uint16 WirelessNode_Impl::getNumDatalogSessions() { if(features().datalogDownloadVersion() == 1) { return m_eepromHelper->read_numDatalogSessions(); } else { //datalog v2+ doesn't support the num datalog sessions eeprom //use the getDatalogSessionInfo command to obtain this information DatalogSessionInfoResult info; if(!m_baseStation.node_getDatalogSessionInfo(protocol(), m_address, info)) { throw Error_NodeCommunication(nodeAddress(), "Failed to get the Datalogging Session Info"); } return info.sessionCount; } }
DatalogDownloader::DatalogDownloader(const WirelessNode& node): m_node(node), m_foundFirstTrigger(false), m_outOfMemory(false), m_sweepCount(0) { //verify the node supports logged data if(!node.features().supportsLoggedData()) { throw Error_NotSupported("Logging is not supported by this Node."); } m_datalogDownloadVersion = m_node.features().datalogDownloadVersion(); if(m_datalogDownloadVersion == 1) { //get the datalogging information from the Node uint16 logPage = m_node.eepromHelper().read_logPage(); uint16 pageOffset = m_node.eepromHelper().read_logPageOffset(); //create the NodeMemory object (v1) m_nodeMemory.reset(new NodeMemory_v1(m_node, logPage, pageOffset)); } else { //get the datalogging session info DatalogSessionInfoResult dlInfo; if(!m_node.getBaseStation().node_getDatalogSessionInfo(node.protocol(), node.nodeAddress(), dlInfo)) { throw Error_NodeCommunication(m_node.nodeAddress(), "Failed to get the Datalog Session Info"); } //get the FlashInfo FlashInfo flashInfo = m_node.eepromHelper().read_flashInfo(); //create the Node Memory object (v2) m_nodeMemory.reset(new NodeMemory_v2(m_node, flashInfo, dlInfo.startAddress, dlInfo.maxLoggedBytes)); } }
AutoBalanceResult WirelessNode_Impl::autoBalance(const ChannelMask& mask, float targetPercent) { Utils::checkBounds_min(targetPercent, 0.0f); Utils::checkBounds_max(targetPercent, 100.0f); //attempt a few pings first //(legacy (v1) autobalance doesn't have a response packet, so need to check communication) uint8 retryCounter = 0; bool pingSuccess = false; while(!pingSuccess && retryCounter < 3) { pingSuccess = ping().success(); retryCounter++; } if(!pingSuccess) { throw Error_NodeCommunication(nodeAddress()); } //find the eeprom location that the autobalance will adjust //Note: this also verifies that it is supported for this mask const EepromLocation& eepromLoc = features().findEeprom(WirelessTypes::chSetting_autoBalance, mask); //currently, autobalance is always per channel, so get the channel from the mask uint8 channelNumber = mask.lastChEnabled(); AutoBalanceResult result; //perform the autobalance command with the parent base station m_baseStation.node_autoBalance(protocol(), m_address, channelNumber, targetPercent, result); //clear the cache of the hardware offset eeprom location we adjusted eeprom().clearCacheLocation(eepromLoc.location()); Utils::threadSleep(200); //if we used the legacy command, we don't get result info, need to do more work to get it if(result.m_errorCode == WirelessTypes::autobalance_legacyNone) { result.m_errorCode = WirelessTypes::autobalance_maybeInvalid; //force the read eeprom retries to a minimum of 3 uint8 startRetries = m_eepromSettings.numRetries; //when this goes out of scope, it will change back the original retries value ScopeHelper writebackRetries(std::bind(&WirelessNode_Impl::setReadWriteRetries, this, startRetries)); //if there are less than 10 retries if(startRetries < 10) { //we want to retry at least a few times setReadWriteRetries(10); } else { //don't need to write back the retries since we didn't make a change writebackRetries.cancel(); } //read the updated hardware offset from the node result.m_hardwareOffset = readEeprom(eepromLoc).as_uint16(); bool readSensorSuccess = false; uint8 readSensorTry = 0; do { //perform the read single sensor command uint16 sensorVal = 0; readSensorSuccess = m_baseStation.node_readSingleSensor(m_address, channelNumber, sensorVal); if(readSensorSuccess) { //find the max bits value of the node uint32 maxBitsVal = 0; switch(model()) { case WirelessModels::node_vLink: case WirelessModels::node_sgLink_rgd: case WirelessModels::node_shmLink: maxBitsVal = 65536; break; default: maxBitsVal = 4096; break; } //calculate and store the percent achieved result.m_percentAchieved = static_cast<float>(sensorVal) / static_cast<float>(maxBitsVal) * 100.0f; } readSensorTry++; } while(!readSensorSuccess && readSensorTry <= 3); if(readSensorSuccess) { //mark as questionable if not close enough to the target percentage if(std::abs(result.m_percentAchieved - targetPercent) > 5.0) { result.m_errorCode = WirelessTypes::autobalance_maybeInvalid; } else { result.m_errorCode = WirelessTypes::autobalance_success; } } } return result; }