void Slave::HandleWriteTimeDate(HeaderReadIterator& arHWI) { if (!mIIN.GetNeedTime()) { LOG_BLOCK(LEV_WARNING, "Master is attempting to write time but slave is not requesting time sync"); return; } ObjectReadIterator obj = arHWI.BeginRead(); if (obj.Count() != 1) { mRspIIN.SetParameterError(true); return; } millis_t val = Group50Var1::Inst()->mTime.Get(*obj); mpTime->SetTime(val); mIIN.SetNeedTime(false); if(mpLogger->IsEnabled(LEV_EVENT)) { LogEntry le(LEV_EVENT, mpLogger->GetName(), LOCATION, "Time synchronized with master", TIME_SYNC_UPDATED); le.AddValue("MILLISEC_SINCE_EPOCH", val); mpLogger->Log(le); } }
void Slave::HandleWriteIIN(HeaderReadIterator& arHdr) { for (ObjectReadIterator obj = arHdr.BeginRead(); !obj.IsEnd(); ++obj) { switch (obj->Index()) { case IINI_DEVICE_RESTART: { bool value = Group80Var1::Inst()->Read(*obj, obj->Start(), obj->Index()); if (!value) { mIIN.SetDeviceRestart(false); } else { mRspIIN.SetParameterError(true); ERROR_BLOCK(LEV_WARNING, "", SERR_INVALID_IIN_WRITE); } break; } case IINI_NEED_TIME: mpTimeTimer->Cancel(); mpTimeTimer = NULL; mIIN.SetNeedTime(false); LOG_BLOCK(LEV_INFO, "Master forced clear time needed flag"); break; default: mRspIIN.SetParameterError(true); ERROR_BLOCK(LEV_WARNING, "", SERR_INVALID_IIN_WRITE); break; } } }
void ResponseLoader::ReadVto(HeaderReadIterator& arIter, SizeByVariationObject* apObj) { /* Get an iterator to the object data */ ObjectReadIterator objIter = arIter.BeginRead(); /* Copy the object data to a VtoData instance */ VtoData data; data.Copy(*objIter, arIter->GetVariation()); /* Determine the Virtual Terminal port/channel number */ size_t index = objIter->Index(); if(index > std::numeric_limits<boost::uint8_t>::max()) { LOG_BLOCK(LEV_WARNING, "Ignoring VTO index that exceeds bit width of uint8_t: " << index); } else { boost::uint8_t channel = static_cast<boost::uint8_t>(index); Transaction t(mpVtoReader); this->mpVtoReader->Update(data, channel); } }
void Slave::HandleOperate(const APDU& arRequest, SequenceInfo aSeqInfo) { if (aSeqInfo == SI_PREV && mLastRequest == arRequest) { return; } mResponse.Set(FC_RESPONSE); for (HeaderReadIterator hdr = arRequest.BeginRead(); !hdr.IsEnd(); ++hdr) { ObjectReadIterator i = hdr.BeginRead(); switch (MACRO_DNP_RADIX(hdr->GetGroup(), hdr->GetVariation())) { case (MACRO_DNP_RADIX(12, 1)): this->RespondToCommands<BinaryOutput>(Group12Var1::Inst(), i, boost::bind(&Slave::Operate<BinaryOutput>, this, _1, _2, false, hdr.info(), aSeqInfo, arRequest.GetControl().SEQ)); break; case (MACRO_DNP_RADIX(41, 1)): this->RespondToCommands<Setpoint>(Group41Var1::Inst(), i, boost::bind(&Slave::Operate<Setpoint>, this, _1, _2, false, hdr.info(), aSeqInfo, arRequest.GetControl().SEQ)); break; case (MACRO_DNP_RADIX(41, 2)): this->RespondToCommands<Setpoint>(Group41Var2::Inst(), i, boost::bind(&Slave::Operate<Setpoint>, this, _1, _2, false, hdr.info(), aSeqInfo, arRequest.GetControl().SEQ)); break; case (MACRO_DNP_RADIX(41, 3)): this->RespondToCommands<Setpoint>(Group41Var3::Inst(), i, boost::bind(&Slave::Operate<Setpoint>, this, _1, _2, false, hdr.info(), aSeqInfo, arRequest.GetControl().SEQ)); break; case (MACRO_DNP_RADIX(41, 4)): this->RespondToCommands<Setpoint>(Group41Var4::Inst(), i, boost::bind(&Slave::Operate<Setpoint>, this, _1, _2, false, hdr.info(), aSeqInfo, arRequest.GetControl().SEQ)); break; default: mRspIIN.SetFuncNotSupported(true); ERROR_BLOCK(LEV_WARNING, "Object/Function mismatch", SERR_OBJ_FUNC_MISMATCH); break; } } }
void Slave::HandleWriteVto(HeaderReadIterator& arHdr) { Transaction tr(mVtoReader); for (ObjectReadIterator obj = arHdr.BeginRead(); !obj.IsEnd(); ++obj) { size_t index = obj->Index(); if(index > std::numeric_limits<boost::uint8_t>::max()) { LOG_BLOCK(LEV_WARNING, "Ignoring VTO index that exceeds bit width of uint8_t: " << index); } else { /* * Pass the data to the vto reader */ boost::uint8_t channel = static_cast<boost::uint8_t>(index); VtoData vto(arHdr->GetVariation()); Group112Var0::Inst()->Read(*obj, arHdr->GetVariation(), vto.mpData); mVtoReader.Update(vto, channel); } } }
TaskResult TimeSync::_OnFinalResponse(const APDU& arAPDU) { if(mDelay < 0) { ptime now = mpTimeSrc->GetUTC(); HeaderReadIterator hri = arAPDU.BeginRead(); if(hri.Count() != 1) { LOG_BLOCK(LEV_WARNING, "DelayMeas response w/ unexcpected header count"); return TR_FAIL; } if(!hri->GetBaseObject()->Equals(Group52Var2::Inst())) { LOG_BLOCK(LEV_WARNING, "DelayMeas response w/ unexpected object: " << hri->GetBaseObject()->Name()); return TR_FAIL; } ObjectReadIterator ori = hri.BeginRead(); if(ori.Count() != 1) { LOG_BLOCK(LEV_WARNING, "DelayMeas got more than 1 object in response"); return TR_FAIL; } millis_t send_rcv_time = (now - mStart).total_milliseconds(); millis_t rtu_turn_around = Group52Var2::Inst()->mTime.Get(*ori); // The later shouldn't happen, but could cause a negative delay which would // result in a weird time setting mDelay = (send_rcv_time >= rtu_turn_around) ? (send_rcv_time - rtu_turn_around)/2 : 0; return TR_CONTINUE; } else { return TR_SUCCESS; } }