56 bHaveInitialPosition_{
false},
57 bHaveInitialVelocity_{
false},
62 dMagnitudeMetersPerSecond_{},
74 "File to write the name of the created pseudo term.");
83 for(
const auto & item : update)
85 if(item.first ==
"pseudoterminalfile")
87 sPseudoTerminalFile_ = item.second[0].asString();
91 throw makeException<ConfigureException>(
"GPSDLocation::Agent: " 92 "Unexpected configuration item %s",
101 char pzName[PATH_MAX]{};
103 if(openpty(&masterPTY_, &slavePTY_,
nullptr,
nullptr,
nullptr) == -1)
108 if(ttyname_r(slavePTY_,&pzName[1],
sizeof(pzName)-1) == -1)
115 tcgetattr(slavePTY_,&term);
121 term.c_cflag &=~ (PARENB | PARODD | CRTSCTS | CSIZE |
122 CSTOPB | PARENB | PARODD | CS8);
124 term.c_cflag |= CREAD | CLOCAL;
126 term.c_iflag &=~ (PARMRK | INPCK);
130 cfsetispeed(&term, B4800);
131 cfsetospeed(&term, B4800);
133 tcsetattr(slavePTY_,TCSANOW,&term);
138 std::ofstream ofs{sPseudoTerminalFile_.c_str(),std::ios::trunc};
140 ofs<<&pzName[1]<<std::endl;
144 std::chrono::seconds interval{1};
157 sPseudoTerminalFile_.c_str());
159 unlink(sPseudoTerminalFile_.c_str());
173 "GPSDLocation::Agent NEM: %hu processEvent Called",
182 auto iter = std::find_if(locations.begin(),
186 return p.getNEMId() == nemId_;
189 if(iter != locations.end())
191 const auto & position = iter->getPosition();
192 dLatitudeDegrees_ = position.getLatitudeDegrees();
193 dLongitudeDegrees_ = position.getLongitudeDegrees();
194 dAltitudeMeters_ = position.getAltitudeMeters();
195 bHaveInitialPosition_ =
true;
197 auto velocity = iter->getVelocity();
201 dAzimuthDegrees_ = velocity.first.getAzimuthDegrees();
202 dMagnitudeMetersPerSecond_ = velocity.first.getMagnitudeMetersPerSecond();
203 bHaveInitialVelocity_ =
true;
215 if(bHaveInitialPosition_)
217 sendSpoofedNMEA(dLatitudeDegrees_,dLongitudeDegrees_,dAltitudeMeters_);
221 "gpsdlocationaganet NEM: %hu lat: %lf lon: %lf alt:%lf",
227 if(bHaveInitialVelocity_)
229 sendSpoofedGPVTG(dAzimuthDegrees_,dMagnitudeMetersPerSecond_);
233 "gpsdlocationagent NEM: %hu azm: %lf mag: %lf",
236 dMagnitudeMetersPerSecond_);
241 void EMANE::Agents::GPSDLocation::Agent::sendSpoofedNMEA(
double dLatitude,
double dLongitude,
double dAltitude)
247 const int NUM_GSV_STRINGS = 2;
248 const int NUM_SV_PER_STRING = 4;
250 int elv[NUM_GSV_STRINGS * NUM_SV_PER_STRING] = {41, 9, 70, 35, 10, 53, 2, 48 };
251 int azm[NUM_GSV_STRINGS * NUM_SV_PER_STRING] = {104, 84, 30, 185, 297, 311, 29, 64 };
252 int snr[NUM_GSV_STRINGS * NUM_SV_PER_STRING] = {41, 51, 39, 25, 25, 21, 29, 32 };
254 char cLatitudeHemisphere = (dLatitude > 0) ?
'N' :
'S';
255 char cLongitudeHemisphere = (dLongitude > 0) ?
'E' :
'W';
267 int iLongitudeDegrees =
static_cast<int>(dLongitude);
268 int iLatitudeDegrees =
static_cast<int>(dLatitude);
270 double dLongitudeMinutes = (dLongitude - iLongitudeDegrees) * 60.0;
271 double dLatitudeMinutes = (dLatitude - iLatitudeDegrees) * 60.0;
273 int iLongitudeMinutes =
static_cast<int>(dLongitudeMinutes);
274 int iLatitudeMinutes =
static_cast<int>(dLatitudeMinutes);
277 int iNumSatellitesUsed = NUM_GSV_STRINGS * NUM_SV_PER_STRING;
280 double dHorizontalDOP = 1.1;
281 double dVerticalDOP = 1.3;
283 double dGeoidalHeight = -34.0;
285 dLongitudeMinutes -= iLongitudeMinutes;
286 dLatitudeMinutes -= iLatitudeMinutes;
288 dLongitudeMinutes *= 10000;
289 dLatitudeMinutes *= 10000;
295 snprintf(buf,
sizeof(buf),
"$GPGGA,%02d%02d%02d,%02d%02d.%04d,%c,%03d%02d.%04d,%c,%d,%02d,%.1f,%.1f,M,%.1f,M,,",
301 static_cast<int>(dLatitudeMinutes),
305 static_cast<int>(dLongitudeMinutes),
306 cLongitudeHemisphere,
314 doCheckSumNMEA(buf,
sizeof(buf));
315 write(masterPTY_,buf,strlen(buf));
319 snprintf(buf,
sizeof(buf),
"$GPRMC,%02d%02d%02d,A,%02d%02d.%04d,%c,%03d%02d.%04d,%c,000.0,000.0,%02d%02d%02d,000.0,%c",
325 static_cast<int>(dLatitudeMinutes),
329 static_cast<int>(dLongitudeMinutes),
330 cLongitudeHemisphere,
333 (tmval.tm_year + 1900) % 100,
337 doCheckSumNMEA(buf,
sizeof(buf));
338 write(masterPTY_,buf,strlen(buf));
342 snprintf(buf,
sizeof(buf),
"$GPGSA,A,3,01,02,03,04,05,06,07,08,,,,,%2.1f,%2.1f,%2.1f",
343 dDOP, dHorizontalDOP, dVerticalDOP);
345 doCheckSumNMEA(buf,
sizeof(buf));
346 write(masterPTY_,buf,strlen(buf));
349 for(
int i = 0; i < NUM_GSV_STRINGS; ++i)
351 const int a = (NUM_SV_PER_STRING * i) + 0;
352 const int b = (NUM_SV_PER_STRING * i) + 1;
353 const int c = (NUM_SV_PER_STRING * i) + 2;
354 const int d = (NUM_SV_PER_STRING * i) + 3;
357 snprintf(buf,
sizeof(buf),
"$GPGSV,%d,%d,%02d,%02d,%02d,%03d,%02d,%02d,%02d,%03d,%02d,%02d,%02d,%03d,%02d,%02d,%02d,%03d,%02d",
361 a + 1, elv[a], azm[a], snr[a],
362 b + 2, elv[b], azm[b], snr[b],
363 c + 3, elv[c], azm[c], snr[c],
364 d + 4, elv[d], azm[d], snr[d]);
366 doCheckSumNMEA(buf,
sizeof(buf));
367 write(masterPTY_,buf,strlen(buf));
371 void EMANE::Agents::GPSDLocation::Agent::sendSpoofedGPVTG(
double dAzimuth,
double dMagnitude)
375 double dMagnitudeKnots = dMagnitude * 1.94384;
376 double dMagnitudeKilometerPerHour = (dMagnitude * 3600.0) / 1000.0;
379 snprintf(buf,
sizeof(buf),
"$GPVTG,%.1f,%C,%.1f,%C,%.1f,%C,%.1f,%C",
386 dMagnitudeKilometerPerHour,
390 doCheckSumNMEA(buf,
sizeof(buf));
391 write(masterPTY_,buf,strlen(buf));
394 void EMANE::Agents::GPSDLocation::Agent::doCheckSumNMEA(
char *buf,
size_t len)
398 char chksum = buf[1];
400 for(
unsigned int i = 2; i < strlen(buf); ++i)
405 snprintf(foo,
sizeof(foo),
"*%02X\r\n", static_cast<unsigned int>(chksum));
407 strncat(buf, foo, len - strlen(buf) - 1);
std::string Serialization
The Registrar interface provides access to all of the emulator registrars.
virtual ConfigurationRegistrar & configurationRegistrar()=0
void initialize(Registrar ®istrar) override
virtual TimerEventId scheduleTimedEvent(const TimePoint &timePoint, const void *arg=nullptr, const Duration &interval=Duration::zero())=0
#define LOGGER_VERBOSE_LOGGING(logger, level, fmt, args...)
void processTimedEvent(TimerEventId eventId, const TimePoint &expireTime, const TimePoint &scheduleTime, const TimePoint &fireTime, const void *arg) override
void registerNonNumeric(const std::string &sName, const ConfigurationProperties &properties=ConfigurationProperties::NONE, const std::initializer_list< T > &values={}, const std::string &sUsage="", std::size_t minOccurs=1, std::size_t maxOccurs=1, const std::string &sRegexPattern={})
DECLARE_EVENT_AGENT(EMANE::Agents::GPSDLocation::Agent)
A location event is usd to set the position, orientation and velocity information for one or more NEM...
virtual EventRegistrar & eventRegistrar()=0
A location entry holds an NEM Id, that NEM's position information and optional orientation and veloci...
Agent(NEMId nemId, PlatformServiceProvider *pPlatformService)
void processEvent(const EventId &, const Serialization &) override
Base class for all event agents.
void configure(const ConfigurationUpdate &update) override
Component start exception is used to indicate an exception during transition to the start state...
std::vector< ConfigurationNameAnyValues > ConfigurationUpdate
Agent translating location events to NMEA gpsd messages.
virtual void registerEvent(EventId eventId)=0
Clock::time_point TimePoint
virtual bool cancelTimedEvent(TimerEventId eventId)=0
#define LOGGER_STANDARD_LOGGING(logger, level, fmt, args...)
const Locations & getLocations() const