6 #include "configuration.h"
7 #include "gpsConversion.h"
8 #include "networkInterfaces.h"
10 #include "uplinkGateway.h"
17 #include <nmea/parser.h>
18 #include <nmea/gmath.h>
19 #include <nmea/sentence.h>
20 #include <OlsrdPudWireFormat/wireFormat.h>
26 /** The NMEA string parser */
27 static nmeaPARSER nmeaParser;
33 /** Type describing movement calculations */
34 typedef struct _MovementType {
35 TristateBoolean moving; /**< SET: we are moving */
37 TristateBoolean overThresholds; /**< SET: at least 1 threshold state is set */
38 TristateBoolean speedOverThreshold; /**< SET: speed is over threshold */
39 TristateBoolean hDistanceOverThreshold; /**< SET: horizontal distance is outside threshold */
40 TristateBoolean vDistanceOverThreshold; /**< SET: vertical distance is outside threshold */
42 TristateBoolean outside; /**< SET: at least 1 outside state is SET */
43 TristateBoolean outsideHdop; /**< SET: avg is outside lastTx HDOP */
44 TristateBoolean outsideVdop; /**< SET: avg is outside lastTx VDOP */
46 TristateBoolean inside; /**< SET: all inside states are SET */
47 TristateBoolean insideHdop; /**< SET: avg is inside lastTx HDOP */
48 TristateBoolean insideVdop; /**< SET: avg is inside lastTx VDOP */
55 /** The average position with its administration */
56 static PositionAverageList positionAverageList;
62 typedef enum _TimedTxInterface {
63 TX_INTERFACE_OLSR = 1,
64 TX_INTERFACE_UPLINK = 2
67 /** The latest position information that is transmitted */
68 static TransmitGpsInformation transmitGpsInformation;
70 /** The size of the buffer in which the OLSR and uplink messages are assembled */
71 #define TX_BUFFER_SIZE_FOR_OLSR 1024
78 Clear the MovementType
79 * @param result a pointer to the MovementType
81 static void clearMovementType(MovementType * result) {
83 result->moving = TRISTATE_BOOLEAN_UNKNOWN;
84 result->overThresholds = TRISTATE_BOOLEAN_UNKNOWN;
85 result->speedOverThreshold = TRISTATE_BOOLEAN_UNKNOWN;
86 result->hDistanceOverThreshold = TRISTATE_BOOLEAN_UNKNOWN;
87 result->vDistanceOverThreshold = TRISTATE_BOOLEAN_UNKNOWN;
88 result->outside = TRISTATE_BOOLEAN_UNKNOWN;
89 result->outsideHdop = TRISTATE_BOOLEAN_UNKNOWN;
90 result->outsideVdop = TRISTATE_BOOLEAN_UNKNOWN;
91 result->inside = TRISTATE_BOOLEAN_UNKNOWN;
92 result->insideHdop = TRISTATE_BOOLEAN_UNKNOWN;
93 result->insideVdop = TRISTATE_BOOLEAN_UNKNOWN;
97 Determine whether s position is valid.
100 a pointer to a position
106 static bool positionValid(PositionUpdateEntry * position) {
107 return (nmea_INFO_has_field(position->nmeaInfo.smask, FIX)
108 && (position->nmeaInfo.fix != NMEA_FIX_BAD));
112 Send the transmit buffer out over all designated interfaces, called as a
113 timer callback and also immediately on an external state change.
116 a bitmap defining which interfaces to send over
118 static void txToAllOlsrInterfaces(TimedTxInterface interfaces) {
119 /** txBuffer is used to concatenate the position update and cluster leader messages in */
120 unsigned char txBuffer[TX_BUFFER_SIZE_FOR_OLSR];
121 unsigned int txBufferBytesUsed = 0;
122 #define txBufferBytesFree (sizeof(txBuffer) - txBufferBytesUsed)
125 * The first message in txBuffer is an OLSR position update.
127 * The position update is always present.
129 * The second message is the cluster leader message, but only when uplink
130 * was requested and correctly configured.
133 UplinkMessage * pu_uplink = (UplinkMessage *) &txBuffer[0];
134 union olsr_message * pu = &pu_uplink->msg.olsrMessage;
135 unsigned int pu_size = 0;
136 union olsr_ip_addr gateway;
137 MovementState externalState;
140 externalState = getExternalState();
142 /* only fixup timestamp when the position is valid _and_ when the position was not updated */
143 if (positionValid(&transmitGpsInformation.txPosition) && !transmitGpsInformation.positionUpdated) {
144 nmea_time_now(&transmitGpsInformation.txPosition.nmeaInfo.utc);
147 nmeaInfo = transmitGpsInformation.txPosition.nmeaInfo;
148 transmitGpsInformation.positionUpdated = false;
149 gateway = transmitGpsInformation.txGateway;
151 /* convert nmeaINFO to wireformat olsr message */
152 txBufferBytesUsed += sizeof(UplinkHeader); /* keep before txBufferSpaceFree usage */
153 pu_size = gpsToOlsr(&nmeaInfo, pu, txBufferBytesFree,
154 ((externalState == MOVEMENT_STATE_STATIONARY) ? getUpdateIntervalStationary() : getUpdateIntervalMoving()));
155 txBufferBytesUsed += pu_size;
158 * push out to all OLSR interfaces
160 if (((interfaces & TX_INTERFACE_OLSR) != 0) && (pu_size > 0)) {
162 struct interface *ifn;
163 for (ifn = ifnet; ifn; ifn = ifn->int_next) {
164 r = net_outbuffer_push(ifn, pu, pu_size);
165 if (r != (int) pu_size) {
168 "Could not send to OLSR interface %s: %s (size=%u, r=%d)",
170 ((r == -1) ? "no buffer was found" :
171 (r == 0) ? "there was not enough room in the buffer" : "unknown reason"), pu_size, r);
175 /* loopback to tx interface when so configured */
176 if (getUseLoopback()) {
177 (void) packetReceivedFromOlsr(pu, NULL, NULL);
181 /* push out over uplink when an uplink is configured */
182 if (((interfaces & TX_INTERFACE_UPLINK) != 0) && isUplinkAddrSet()) {
183 int fd = getDownlinkSocketFd();
185 union olsr_sockaddr * uplink_addr = getUplinkAddr();
186 struct sockaddr * addr;
189 UplinkMessage * cl_uplink = (UplinkMessage *) &txBuffer[txBufferBytesUsed];
190 UplinkClusterLeader * cl = &cl_uplink->msg.clusterLeader;
191 union olsr_ip_addr * cl_originator = getClusterLeaderOriginator(olsr_cnf->ip_version, cl);
192 union olsr_ip_addr * cl_clusterLeader = getClusterLeaderClusterLeader(olsr_cnf->ip_version, cl);
194 unsigned int cl_size =
195 sizeof(UplinkClusterLeader) - sizeof(cl->leader)
196 + ((olsr_cnf->ip_version == AF_INET) ? sizeof(cl->leader.v4) :
197 sizeof(cl->leader.v6));
199 unsigned long long uplinkUpdateInterval =
200 (externalState == MOVEMENT_STATE_STATIONARY) ? getUplinkUpdateIntervalStationary() : getUplinkUpdateIntervalMoving();
202 if (uplink_addr->in.sa_family == AF_INET) {
203 addr = (struct sockaddr *)&uplink_addr->in4;
204 addrSize = sizeof(struct sockaddr_in);
206 addr = (struct sockaddr *)&uplink_addr->in6;
207 addrSize = sizeof(struct sockaddr_in6);
211 * position update message (pu)
214 /* set header fields in position update uplink message and adjust
215 * the validity time to the uplink validity time */
217 PudOlsrPositionUpdate * pu_gpsMessage = getOlsrMessagePayload(olsr_cnf->ip_version, pu);
219 setUplinkMessageType(&pu_uplink->header, POSITION);
220 setUplinkMessageLength(&pu_uplink->header, pu_size);
221 setUplinkMessageIPv6(&pu_uplink->header, (olsr_cnf->ip_version != AF_INET));
222 setUplinkMessagePadding(&pu_uplink->header, 0);
224 /* fixup validity time */
225 setValidityTime(&pu_gpsMessage->validityTime, uplinkUpdateInterval);
229 * cluster leader message (cl)
232 /* set cl_uplink header fields */
233 setUplinkMessageType(&cl_uplink->header, CLUSTERLEADER);
234 setUplinkMessageLength(&cl_uplink->header, cl_size);
235 setUplinkMessageIPv6(&cl_uplink->header, (olsr_cnf->ip_version != AF_INET));
236 setUplinkMessagePadding(&cl_uplink->header, 0);
239 setClusterLeaderVersion(cl, PUD_WIRE_FORMAT_VERSION);
240 setValidityTime(&cl->validityTime, uplinkUpdateInterval);
242 /* really need 2 memcpy's here because of olsr_cnf->ipsize */
243 memcpy(cl_originator, &olsr_cnf->main_addr, olsr_cnf->ipsize);
244 memcpy(cl_clusterLeader, &gateway, olsr_cnf->ipsize);
246 txBufferBytesUsed += sizeof(UplinkHeader);
247 txBufferBytesUsed += cl_size;
250 if (sendto(fd, &txBuffer, txBufferBytesUsed, 0, addr, addrSize) < 0) {
251 pudError(true, "Could not send to uplink (size=%u)", txBufferBytesUsed);
262 The OLSR tx timer callback
267 static void pud_olsr_tx_timer_callback(void *context __attribute__ ((unused))) {
268 txToAllOlsrInterfaces(TX_INTERFACE_OLSR);
272 The uplink timer callback
277 static void pud_uplink_timer_callback(void *context __attribute__ ((unused))) {
278 txToAllOlsrInterfaces(TX_INTERFACE_UPLINK);
282 Restart the OLSR tx timer
284 static void restartOlsrTimer(MovementState externalState) {
285 if (!restartOlsrTxTimer(
286 (externalState == MOVEMENT_STATE_STATIONARY) ? getUpdateIntervalStationary() :
287 getUpdateIntervalMoving(), &pud_olsr_tx_timer_callback)) {
288 pudError(0, "Could not restart OLSR tx timer, no periodic"
289 " position updates will be sent to the OLSR network");
294 Restart the uplink tx timer
296 static void restartUplinkTimer(MovementState externalState) {
297 if (!restartUplinkTxTimer(
298 (externalState == MOVEMENT_STATE_STATIONARY) ? getUplinkUpdateIntervalStationary() :
299 getUplinkUpdateIntervalMoving(),
300 &pud_uplink_timer_callback)) {
301 pudError(0, "Could not restart uplink timer, no periodic"
302 " position updates will be uplinked");
306 static void doImmediateTransmit(MovementState externalState) {
307 TimedTxInterface interfaces = TX_INTERFACE_OLSR; /* always send over olsr */
308 restartOlsrTimer(externalState);
310 if (isUplinkAddrSet()) {
311 interfaces |= TX_INTERFACE_UPLINK;
312 restartUplinkTimer(externalState);
315 /* do an immediate transmit */
316 txToAllOlsrInterfaces(interfaces);
320 The gateway timer callback
325 static void pud_gateway_timer_callback(void *context __attribute__ ((unused))) {
326 union olsr_ip_addr bestGateway;
327 bool externalStateChange;
328 MovementState externalState;
329 TristateBoolean movingNow = TRISTATE_BOOLEAN_UNSET;
331 getBestUplinkGateway(&bestGateway);
337 if (!ipequal(&bestGateway, &transmitGpsInformation.txGateway)) {
338 movingNow = TRISTATE_BOOLEAN_SET;
342 * State Determination
345 determineStateWithHysteresis(SUBSTATE_GATEWAY, movingNow, &externalState, &externalStateChange, NULL);
348 * Update transmitGpsInformation
351 if (movingNow == TRISTATE_BOOLEAN_SET) {
352 transmitGpsInformation.txGateway = bestGateway;
355 if (externalStateChange) {
356 doImmediateTransmit(externalState);
361 Detemine whether we are moving from the position, by comparing fields from the
362 average position against those of the last transmitted position.
364 MUST be called which the position average list locked.
369 the last transmitted position
371 the results of all movement criteria
373 static void detemineMovingFromPosition(PositionUpdateEntry * avg, PositionUpdateEntry * lastTx, MovementType * result) {
374 /* avg field presence booleans */
381 /* lastTx field presence booleans */bool lastTxHasPos;
386 /* these have defaults */
387 double dopMultiplier;
393 /* calculated values and their validity booleans */
396 double hdopDistanceForOutside;
397 double hdopDistanceForInside;
398 double vdopDistanceForOutside;
399 double vdopDistanceForInside;
401 bool hdopDistanceValid;
403 bool vdopDistanceValid;
409 * 0 0 UNKNOWN : can't determine whether we're moving
410 * 0 1 UNKNOWN : can't determine whether we're moving
411 * 1 0 UNKNOWN : can't determine whether we're moving
412 * 1 1 determine via other parameters
415 if (!positionValid(avg)) {
416 result->moving = TRISTATE_BOOLEAN_UNKNOWN;
420 /* avg is valid here */
422 if (!positionValid(lastTx)) {
423 result->moving = TRISTATE_BOOLEAN_UNKNOWN;
427 /* both avg and lastTx are valid here */
429 /* avg field presence booleans */
430 avgHasSpeed = nmea_INFO_has_field(avg->nmeaInfo.smask, SPEED);
431 avgHasPos = nmea_INFO_has_field(avg->nmeaInfo.smask, LAT)
432 && nmea_INFO_has_field(avg->nmeaInfo.smask, LON);
433 avgHasHdop = nmea_INFO_has_field(avg->nmeaInfo.smask, HDOP);
434 avgHasElv = nmea_INFO_has_field(avg->nmeaInfo.smask, ELV);
435 avgHasVdop = nmea_INFO_has_field(avg->nmeaInfo.smask, VDOP);
437 /* lastTx field presence booleans */
438 lastTxHasPos = nmea_INFO_has_field(lastTx->nmeaInfo.smask, LAT)
439 && nmea_INFO_has_field(lastTx->nmeaInfo.smask, LON);
440 lastTxHasHdop = nmea_INFO_has_field(lastTx->nmeaInfo.smask, HDOP);
441 lastTxHasElv = nmea_INFO_has_field(lastTx->nmeaInfo.smask, ELV);
442 lastTxHasVdop = nmea_INFO_has_field(lastTx->nmeaInfo.smask, VDOP);
444 /* fill in some values _or_ defaults */
445 dopMultiplier = getDopMultiplier();
446 avgHdop = avgHasHdop ? avg->nmeaInfo.HDOP : getDefaultHdop();
447 lastTxHdop = lastTxHasHdop ? lastTx->nmeaInfo.HDOP : getDefaultHdop();
448 avgVdop = avgHasVdop ? avg->nmeaInfo.VDOP : getDefaultVdop();
449 lastTxVdop = lastTxHasVdop ? lastTx->nmeaInfo.VDOP : getDefaultVdop();
456 if (avgHasPos && lastTxHasPos) {
460 avgPos.lat = nmea_degree2radian(avg->nmeaInfo.lat);
461 avgPos.lon = nmea_degree2radian(avg->nmeaInfo.lon);
463 lastTxPos.lat = nmea_degree2radian(lastTx->nmeaInfo.lat);
464 lastTxPos.lon = nmea_degree2radian(lastTx->nmeaInfo.lon);
466 hDistance = fabs(nmea_distance_ellipsoid(&avgPos, &lastTxPos, NULL, NULL));
467 hDistanceValid = true;
469 hDistanceValid = false;
473 if (avgHasHdop || lastTxHasHdop) {
474 hdopDistanceForOutside = dopMultiplier * (lastTxHdop + avgHdop);
475 hdopDistanceForInside = dopMultiplier * (lastTxHdop - avgHdop);
476 hdopDistanceValid = true;
478 hdopDistanceValid = false;
482 if (avgHasElv && lastTxHasElv) {
483 vDistance = fabs(lastTx->nmeaInfo.elv - avg->nmeaInfo.elv);
484 vDistanceValid = true;
486 vDistanceValid = false;
490 if (avgHasVdop || lastTxHasVdop) {
491 vdopDistanceForOutside = dopMultiplier * (lastTxVdop + avgVdop);
492 vdopDistanceForInside = dopMultiplier * (lastTxVdop - avgVdop);
493 vdopDistanceValid = true;
495 vdopDistanceValid = false;
499 * Moving Criteria Evaluation Start
500 * We compare the average position against the last transmitted position.
505 if (avg->nmeaInfo.speed >= getMovingSpeedThreshold()) {
506 result->speedOverThreshold = TRISTATE_BOOLEAN_SET;
508 result->speedOverThreshold = TRISTATE_BOOLEAN_UNSET;
515 * avg last hDistanceMoving
516 * 0 0 determine via other parameters
517 * 0 1 determine via other parameters
519 * 1 1 determine via distance threshold and HDOP
521 if (avgHasPos && !lastTxHasPos) {
522 result->hDistanceOverThreshold = TRISTATE_BOOLEAN_SET;
523 } else if (hDistanceValid) {
524 if (hDistance >= getMovingDistanceThreshold()) {
525 result->hDistanceOverThreshold = TRISTATE_BOOLEAN_SET;
527 result->hDistanceOverThreshold = TRISTATE_BOOLEAN_UNSET;
534 * 0 0 determine via other parameters
535 * 0 1 determine via position with HDOP (avg has default HDOP)
536 * 1 0 determine via position with HDOP (lastTx has default HDOP)
537 * 1 1 determine via position with HDOP
539 if (hdopDistanceValid) {
540 /* we are outside the HDOP when the HDOPs no longer overlap */
541 if (hDistance > hdopDistanceForOutside) {
542 result->outsideHdop = TRISTATE_BOOLEAN_SET;
544 result->outsideHdop = TRISTATE_BOOLEAN_UNSET;
547 /* we are inside the HDOP when the HDOPs fully overlap */
548 if (hDistance <= hdopDistanceForInside) {
549 result->insideHdop = TRISTATE_BOOLEAN_SET;
551 result->insideHdop = TRISTATE_BOOLEAN_UNSET;
560 * 0 0 determine via other parameters
561 * 0 1 determine via other parameters
563 * 1 1 determine via distance threshold and VDOP
565 if (avgHasElv && !lastTxHasElv) {
566 result->vDistanceOverThreshold = TRISTATE_BOOLEAN_SET;
567 } else if (vDistanceValid) {
568 if (vDistance >= getMovingDistanceThreshold()) {
569 result->vDistanceOverThreshold = TRISTATE_BOOLEAN_SET;
571 result->vDistanceOverThreshold = TRISTATE_BOOLEAN_UNSET;
575 * Elevation with VDOP
578 * 0 0 determine via other parameters
579 * 0 1 determine via elevation with VDOP (avg has default VDOP)
580 * 1 0 determine via elevation with VDOP (lastTx has default VDOP)
581 * 1 1 determine via elevation with VDOP
583 if (vdopDistanceValid) {
584 /* we are outside the VDOP when the VDOPs no longer overlap */
585 if (vDistance > vdopDistanceForOutside) {
586 result->outsideVdop = TRISTATE_BOOLEAN_SET;
588 result->outsideVdop = TRISTATE_BOOLEAN_UNSET;
591 /* we are inside the VDOP when the VDOPs fully overlap */
592 if (vDistance <= vdopDistanceForInside) {
593 result->insideVdop = TRISTATE_BOOLEAN_SET;
595 result->insideVdop = TRISTATE_BOOLEAN_UNSET;
601 * Moving Criteria Evaluation End
604 /* accumulate inside criteria */
605 if ((result->insideHdop == TRISTATE_BOOLEAN_SET) && (result->insideVdop == TRISTATE_BOOLEAN_SET)) {
606 result->inside = TRISTATE_BOOLEAN_SET;
607 } else if ((result->insideHdop == TRISTATE_BOOLEAN_UNSET) || (result->insideVdop == TRISTATE_BOOLEAN_UNSET)) {
608 result->inside = TRISTATE_BOOLEAN_UNSET;
611 /* accumulate outside criteria */
612 if ((result->outsideHdop == TRISTATE_BOOLEAN_SET) || (result->outsideVdop == TRISTATE_BOOLEAN_SET)) {
613 result->outside = TRISTATE_BOOLEAN_SET;
614 } else if ((result->outsideHdop == TRISTATE_BOOLEAN_UNSET)
615 || (result->outsideVdop == TRISTATE_BOOLEAN_UNSET)) {
616 result->outside = TRISTATE_BOOLEAN_UNSET;
619 /* accumulate threshold criteria */
620 if ((result->speedOverThreshold == TRISTATE_BOOLEAN_SET)
621 || (result->hDistanceOverThreshold == TRISTATE_BOOLEAN_SET)
622 || (result->vDistanceOverThreshold == TRISTATE_BOOLEAN_SET)) {
623 result->overThresholds = TRISTATE_BOOLEAN_SET;
624 } else if ((result->speedOverThreshold == TRISTATE_BOOLEAN_UNSET)
625 || (result->hDistanceOverThreshold == TRISTATE_BOOLEAN_UNSET)
626 || (result->vDistanceOverThreshold == TRISTATE_BOOLEAN_UNSET)) {
627 result->overThresholds = TRISTATE_BOOLEAN_UNSET;
630 /* accumulate moving criteria */
631 if ((result->overThresholds == TRISTATE_BOOLEAN_SET) || (result->outside == TRISTATE_BOOLEAN_SET)) {
632 result->moving = TRISTATE_BOOLEAN_SET;
633 } else if ((result->overThresholds == TRISTATE_BOOLEAN_UNSET)
634 && (result->outside == TRISTATE_BOOLEAN_UNSET)) {
635 result->moving = TRISTATE_BOOLEAN_UNSET;
642 Update the latest GPS information. This function is called when a packet is
643 received from a rxNonOlsr interface, containing one or more NMEA strings with
647 the receive buffer with the received NMEA string(s)
649 the number of bytes in the receive buffer
655 bool receiverUpdateGpsInformation(unsigned char * rxBuffer, size_t rxCount) {
656 static const char * rxBufferPrefix = "$GP";
657 static const size_t rxBufferPrefixLength = 3;
660 PositionUpdateEntry * incomingEntry;
661 PositionUpdateEntry * posAvgEntry;
662 MovementType movementResult;
663 bool subStateExternalStateChange;
664 bool externalStateChange;
665 bool updateTransmitGpsInformation = false;
666 PositionUpdateEntry txPosition;
667 MovementState externalState;
669 /* do not process when the message does not start with $GP */
670 if ((rxCount < rxBufferPrefixLength) || (strncmp((char *) rxBuffer,
671 rxBufferPrefix, rxBufferPrefixLength) != 0)) {
675 /* parse all NMEA strings in the rxBuffer into the incoming entry */
676 incomingEntry = getPositionAverageEntry(&positionAverageList, INCOMING);
677 nmea_zero_INFO(&incomingEntry->nmeaInfo);
678 nmea_parse(&nmeaParser, (char *) rxBuffer, rxCount,
679 &incomingEntry->nmeaInfo);
681 /* ignore when no useful information */
682 if (incomingEntry->nmeaInfo.smask == GPNON) {
687 nmea_INFO_sanitise(&incomingEntry->nmeaInfo);
689 /* we always work with latitude, longitude in degrees and DOPs in meters */
690 nmea_INFO_unit_conversion(&incomingEntry->nmeaInfo);
696 if (getInternalState(SUBSTATE_POSITION) == MOVEMENT_STATE_MOVING) {
697 /* flush average: keep only the incoming entry */
698 flushPositionAverageList(&positionAverageList);
700 addNewPositionToAverage(&positionAverageList, incomingEntry);
701 posAvgEntry = getPositionAverageEntry(&positionAverageList, AVERAGE);
707 clearMovementType(&movementResult);
709 txPosition = transmitGpsInformation.txPosition;
711 detemineMovingFromPosition(posAvgEntry, &txPosition, &movementResult);
714 * State Determination
717 determineStateWithHysteresis(SUBSTATE_POSITION, movementResult.moving, &externalState, &externalStateChange,
718 &subStateExternalStateChange);
721 * Update transmitGpsInformation
724 updateTransmitGpsInformation = subStateExternalStateChange
725 || (positionValid(posAvgEntry) && !positionValid(&txPosition))
726 || (movementResult.inside == TRISTATE_BOOLEAN_SET);
728 if ((externalState == MOVEMENT_STATE_MOVING) || updateTransmitGpsInformation) {
729 transmitGpsInformation.txPosition.nmeaInfo = posAvgEntry->nmeaInfo;
730 transmitGpsInformation.positionUpdated = true;
733 if (externalStateChange) {
734 doImmediateTransmit(externalState);
750 bool startReceiver(void) {
751 MovementState externalState;
752 char * positionFile = getPositionFile();
754 if (!nmea_parser_init(&nmeaParser)) {
755 pudError(false, "Could not initialise NMEA parser");
760 readPositionFile(positionFile, &transmitGpsInformation.txPosition.nmeaInfo);
762 nmea_zero_INFO(&transmitGpsInformation.txPosition.nmeaInfo);
764 transmitGpsInformation.txGateway = olsr_cnf->main_addr;
765 transmitGpsInformation.positionUpdated = false;
766 transmitGpsInformation.nodeId = getNodeId();
769 olsr_cnf->pud_position = &transmitGpsInformation;
771 initPositionAverageList(&positionAverageList, getAverageDepth());
773 if (!initOlsrTxTimer()) {
778 if (!initUplinkTxTimer()) {
783 if (!initGatewayTimer()) {
788 externalState = getExternalState();
789 restartOlsrTimer(externalState);
790 restartUplinkTimer(externalState);
791 if (!restartGatewayTimer(getGatewayDeterminationInterval(), &pud_gateway_timer_callback)) {
792 pudError(0, "Could not start gateway timer");
803 void stopReceiver(void) {
804 destroyGatewayTimer();
805 destroyUplinkTxTimer();
806 destroyOlsrTxTimer();
808 destroyPositionAverageList(&positionAverageList);
810 nmea_zero_INFO(&transmitGpsInformation.txPosition.nmeaInfo);
811 transmitGpsInformation.txGateway = olsr_cnf->main_addr;
812 transmitGpsInformation.positionUpdated = false;
814 nmea_parser_destroy(&nmeaParser);