This gives us a better chance of the response fitting in a single
write() call (if it doesn't, it's going to get truncated, because
the internal webserver is really simple)
The old logic had a number of problems, including:
* sending heartbeats on all service types if any type needed
a heartbeat
* sending a heartbeat multiple times a second if there was a
service type that was idle but didn't generate traffic when
an empty message was sent (e.g. FATSV)
Rewrite it all so that heartbeats are explicitly tracked and handled
per service type, rather than by sending a dummy message.
Also switch to mode A/C messages for the beast/raw heartbeat, as
it's a bit more compact and less likely to mess with Mode S state
(an all-zeros Mode S message actually looks valid)
Notice synthetic mlat messages by looking for messages with a magic
timestamp value. If they arrive, tag the derived data as mlat-derived.
Don't include mlat-derived output in FATSV output to avoid loops.
In particular, not guarding in flushWrites() meant that we
could end up trying to write to an uninitialized writer
(where writer->service == c->service == NULL) and crashing.
The DF17/18 values are generally more trustworthy as they have full
CRC coverage. Errors in the CRC bits of a DF0/4/16/20 message can
result in the contained altitude being attributed to the wrong aircraft.
This lets different things dynamically create the services they need,
and sorts out the horrible hacks that view1090 used to make outgoing
connections. Now you can explicitly create a service and tell it to make
an outgoing connection.
This means that view1090 can now just set all the ports to zero (to disable
the listeners), do a normal net init, then explicitly construct the beast
input service without a listener and tell it to make a connection as needed.
This affected Beast input/output, and AVR output in --mlat mode.
Works on a little-endian host, should work on a big-endian host but
I don't have one to test with.
Probably fixes#44.
Magnitude conversion now happens immediately when sample data is
received, so there is no risk of newly received data clobbering old
data under CPU overload.
This would mangle messages if the first byte of a message ended up
as the last byte returned by a read() call - it would read beyond
the end of the buffer, decide the message was damaged, and then run
off into the message data looking for a new delimiter. Sometimes
that would work (only dropping one message), but sometimes it would
run into data that happened to look like a message start but
actually wasn't, and then try to interpret that, leading to completely
bogus message data being read.
Fixes#29.