Example #1
0
	int zp_ClusterNode::run()
	{
		if (bTermSet==true)
		{
			//qDebug()<<QString("%1(%2) Node Martked Deleted, return.").arg((unsigned int)this).arg(ref());
			return 0;
		}
		int nCurrSz = -1;
		int nMessage = m_nMessageBlockSize;
		while (--nMessage>=0 && nCurrSz!=0  )
		{
			QByteArray block;
			m_mutex_rawData.lock();
			if (m_list_RawData.size())
				block =  *m_list_RawData.begin();
			m_mutex_rawData.unlock();
			if (block.isEmpty()==false && block.isNull()==false)
			{
				m_currentReadOffset = filter_message(block,m_currentReadOffset);
				if (m_currentReadOffset >= block.size())
				{
					m_mutex_rawData.lock();
					if (m_list_RawData.empty()==false)
						m_list_RawData.pop_front();
					else
						assert(false);
					m_currentReadOffset = 0;
					m_mutex_rawData.unlock();
				}
			}
			else
			{
				m_mutex_rawData.lock();
				//pop empty cabs
				if (m_list_RawData.empty()==false)
					m_list_RawData.pop_front();
				m_mutex_rawData.unlock();
			}
			m_mutex_rawData.lock();
			nCurrSz = m_list_RawData.size();
			m_mutex_rawData.unlock();
		}
		m_mutex_rawData.lock();
		nCurrSz = m_list_RawData.size();
		m_mutex_rawData.unlock();
		if (nCurrSz==0)
			return 0;
		return -1;
	}
Example #2
0
static void get_messages_listing_resp(const char **reply, void *user_data)
{
	struct session *session = user_data;
	struct request *request = session->request;
	struct messages_message *msg_data;

	DBG("reply %p", reply);

	if (reply == NULL)
		goto done;

	if (session->aborted)
		goto aborted;

	msg_data = pull_message_data(reply);

	request->size++;

	if (!msg_data->read)
			request->new_message = TRUE;

	if (request->count == TRUE) {
		free_msg_data(msg_data);
		return;
	}

	if (request->size > request->offset && filter_message(msg_data,
							request->filter))
		request->cb.messages_list(session, -EAGAIN, 1,
						request->new_message, msg_data,
						request->user_data);

	free_msg_data(msg_data);
	return;

done:
	request->cb.messages_list(session, 0, request->size,
						request->new_message, NULL,
						request->user_data);

aborted:
	g_free(request->filter->period_begin);
	g_free(request->filter->period_end);
	g_free(request->filter->originator);
	g_free(request->filter->recipient);
	g_free(request->filter);

	g_free(request);
}
/*
 * Some notes on this format, as it is poorly documented by Kinetic:
 *
 * The stream can start at an arbitrary point, the first byte might be mid-packet.
 * You need to look for a DLE STX to synchronize with the stream.
 * This implementation does that in the Python code to keep this bit simpler; the
 * C code assumes it is always given bytes starting at the start of a packet.
 *
 * You might get arbitrary packet types e.g. AIS interleaved with Mode S messages.
 * This implementation doesn't try to interpret them at all, it just reads all
 * data until DLE ETX regardless of type and skips those types it doesn't
 * understand.
 *
 * The Mode S CRC values are not the raw bytes from the message; they are the
 * residual CRC value after XORing the raw bytes with the calculated CRC over
 * the body of the message. That is, a DF17 message with a correct CRC will have
 * zeros in the CRC bytes; a DF11 with correct CRC will have the IID in the CRC
 * bytes; messages that use Address/Parity will have the address in the CRC bytes.
 * To recover the original message, calculate the CRC and XOR it back into the CRC
 * bytes. Andrew Whewell says this is probably controlled by a Basestation setting.
 *
 * The timestamps are measured at the _end_ of the frame, not at the start.
 * As frames are variable length, if you want a timestamp anchored to the
 * start of the frame (as dump1090 / Beast do), you have to compensate for
 * the frame length.
 */
static PyObject *feed_sbs(modesreader *self, Py_buffer *buffer, int max_messages)
{
    PyObject *rv = NULL;
    uint8_t *buffer_start, *p, *eod;
    int message_count = 0;
    PyObject *message_tuple = NULL;
    PyObject **messages = NULL;
    int error_pending = 0;

    buffer_start = buffer->buf;

    if (max_messages <= 0) {
        /* allocate the maximum size we might need, given a minimal encoding of:
         *   <DLE> <STX> <0x09> <n/a> <3 bytes timestamp> <2 bytes message> <DLE> <ETX> <2 bytes CRC> = 13 bytes total
         */
        max_messages = buffer->len / 13 + 1;
    }

    messages = calloc(max_messages, sizeof(PyObject*));
    if (!messages) {
        PyErr_NoMemory();
        goto out;
    }

    /* parse messages */
    p = buffer_start;
    eod = buffer_start + buffer->len;
    while (p+13 <= eod && message_count < max_messages) {
        int message_len = -1;
        uint64_t timestamp;
        /* largest message we care about is:
         *  type      1 byte   0x05 = ADS-B
         *  spare     1 byte
         *  timestamp 3 bytes
         *  data      14 bytes
         *      total 19 bytes
         */
        uint8_t data[19];
        uint8_t *m;
        int i;
        uint8_t type;
        uint32_t crc;
        PyObject *message;

        if (p[0] != 0x10 || p[1] != 0x02) {
            error_pending = 1;
            if (message_count > 0)
                goto nomoredata;
            PyErr_Format(PyExc_ValueError, "Lost sync with input stream: expected DLE STX at offset %d but found 0x%02x 0x%02x instead", (int) (p - buffer_start), (int)p[0], (int)p[1]);
            goto out;
        }

        /* scan for DLE ETX, copy data */
        m = p + 2;
        i = 0;
        while (m < eod) {
            if (*m == 0x10) {
                /* DLE <something> */

                if ((m+1) >= eod)
                    goto nomoredata;

                if (m[1] == 0x03) {
                    /* DLE ETX */
                    break;
                }

                if (m[1] != 0x10) {
                    /* DLE <something we don't understand> */
                    error_pending = 1;
                    if (message_count > 0)
                        goto nomoredata;
                    PyErr_Format(PyExc_ValueError, "Lost sync with input stream: unexpected DLE 0x%02x at offset %d", (int) (m - buffer_start), (int)m[1]);
                    goto out;
                }

                /* DLE DLE */
                ++m;
            }

            if (i < 19)
                data[i++] = *m;

            ++m;
        }

        /* now pointing at DLE of DLE ETX */
        m += 2;

        /* first CRC byte */
        if (m >= eod)
            goto nomoredata;
        if (*m++ == 0x10) {
            if (m >= eod)
                goto nomoredata;
            if (m[0] != 0x10) {
                error_pending = 1;
                if (message_count > 0)
                    goto nomoredata;
                PyErr_Format(PyExc_ValueError, "Lost sync with input stream: unexpected DLE 0x%02x at offset %d", (int) (m - buffer_start), (int)*m);
                goto out;
            }
            ++m;
        }

        /* second CRC byte */
        if (m >= eod)
            goto nomoredata;
        if (*m++ == 0x10) {
            if (m >= eod)
                goto nomoredata;
            if (m[0] != 0x10) {
                error_pending = 1;
                if (message_count > 0)
                    goto nomoredata;
                PyErr_Format(PyExc_ValueError, "Lost sync with input stream: unexpected DLE 0x%02x at offset %d", (int) (m - buffer_start), (int)*m);
                goto out;
            }
            ++m;
        }

        /* try to make sense of the message */
        type = data[0];
        switch (type) {
        case 0x01:
            /* ADS-B or TIS-B */
            message_len = 14;
            break;

        case 0x05:
            /* Mode S, long */
            message_len = 14;
            break;

        case 0x07:
            /* Mode S, short */
            message_len = 7;
            break;

        case 0x09:
            /* Mode A/C */
            message_len = 2;
            break;

        default:
            /* something else, skip it */
            p = m;
            continue;
        }

        if ((5 + message_len) > i) {
            /* not enough data */
            p = m;
            continue;
        }

        /* regenerate message CRC */
        crc = modescrc_buffer_crc(&data[5], message_len - 3);
        data[5 + message_len - 3] ^= crc >> 16;
        data[5 + message_len - 2] ^= crc >> 8;
        data[5 + message_len - 1] ^= crc;

        /* little-endian, apparently */
        timestamp = (data[4] << 16) | (data[3] << 8) | (data[2]);

        /* Baseless speculation! Let's assume that it's like the Radarcape
         * and measures at the end of the frame.
         *
         * It's easier to add to the timestamp than subtract from it, so
         * add on enough of an offset so that the timestamps we report are
         * consistently (start of frame + 112us) regardless of the actual
         * frame length.
         */
        timestamp = (timestamp + ((14-message_len) * 160)) & 0xFFFFFF;

        /* we don't use timestamp_update or timestamp_check here because SBS is "special" */

        /* The SBS timestamp is only 24 bits wide; at 20MHz this overflows more than once
         * a second (about every 839ms). To get a useful timestamp for mlat synchronization,
         * we have to widen the timestamp.
         *
         * It wasn't reliable to do this based on the system clock, there are enough
         * unpredictable delays between the SBS and mlat-client that it didn't work well.
         * Instead, we assume that we will be receiving at least one message per 839ms.
         * so if we ever see a timestamp that has gone backwards, it must be due to
         * exactly one overflow of the timestamp counter.
         *
         * This is usually true in cases where we see enough traffic for mlat/sync. When it
         * isn't true, you will get synchronization jumps that are a multiple of 839ms.
         */

        /* merge in top bits of the current widened counter */
        timestamp = timestamp | (self->last_timestamp & 0xFFFFFFFFFF000000ULL);

        /* check for rollover, if it happened then increase the widened part */
        if (timestamp < self->last_timestamp)
            timestamp += (1 << 24);

        self->last_timestamp = timestamp;

        /* decode it */
        if (! (message = modesmessage_from_buffer(timestamp, 0, &data[5], message_len)))
            goto out;

        /* apply filters, update seen-set */
        ++self->received_messages;
        int wanted = filter_message(self, message);
        if (wanted < 0)
            goto out;
        else if (wanted)
            messages[message_count++] = message;
        else {
            ++self->suppressed_messages;
            Py_DECREF(message);
        }

        p = m;
    }

 nomoredata:
    if (! (message_tuple = PyTuple_New(message_count)))
        goto out;

    while (--message_count >= 0) {
        PyTuple_SET_ITEM(message_tuple, message_count, messages[message_count]); /* steals ref */
    }

    rv = Py_BuildValue("(l,N,N)", (long) (p - buffer_start), message_tuple, PyBool_FromLong(error_pending));

 out:
    while (--message_count >= 0) {
        Py_XDECREF(messages[message_count]);
    }
    free(messages);
    return rv;
}
/* feed implementation for Beast-format data (including Radarcape) */
static PyObject *feed_beast(modesreader *self, Py_buffer *buffer, int max_messages)
{
    PyObject *rv = NULL;
    uint8_t *buffer_start, *p, *eod;
    int message_count = 0;
    PyObject *message_tuple = NULL;
    PyObject **messages = NULL;
    int error_pending = 0;

    buffer_start = buffer->buf;

    if (max_messages <= 0) {
        /* allocate the maximum size we might need, given a minimal encoding of:
         *   <1A> <'1'> <6 bytes timestamp> <1 byte signal> <2 bytes message> = 11 bytes total
         */
        max_messages = buffer->len / 11 + 2;
    }

    messages = calloc(max_messages, sizeof(PyObject*));
    if (!messages) {
        PyErr_NoMemory();
        goto out;
    }

    /* parse messages */
    p = buffer_start;
    eod = buffer_start + buffer->len;
    while (p+2 <= eod && message_count+2 < max_messages) {
        int message_len = -1;
        uint64_t timestamp;
        uint8_t signal;
        uint8_t data[14];
        uint8_t *m, *eom;
        int i;
        uint8_t type;
        PyObject *message;
        int wanted;

        if (p[0] != 0x1a) {
            error_pending = 1;
            if (message_count > 0)
                goto nomoredata;
            PyErr_Format(PyExc_ValueError, "Lost sync with input stream: expected a 0x1A marker at offset %d but found 0x%02x instead", (int) (p - buffer_start), (int)p[0]);
            goto out;
        }

        type = p[1];
        switch (type) {
        case '1': message_len = 2; break; /* mode A/C */
        case '2': message_len = 7; break; /* mode S short */
        case '3': message_len = 14; break; /* mode S long */
        case '4': message_len = 14; break; /* radarcape status message */
        default:
            error_pending = 1;
            if (message_count > 0)
                goto nomoredata;
            PyErr_Format(PyExc_ValueError, "Lost sync with input stream: unexpected message type 0x%02x after 0x1A marker at offset %d", (int)p[1], (int) (p - buffer_start));
            goto out;
        }

        m = p + 2;
        eom = m + 7 + message_len;
        if (eom > eod)
            break;

#define ADVANCE \
        do {                                                            \
            if (*m++ == 0x1a) {                                         \
                if (m < eod && *m != 0x1a) {                            \
                    error_pending = 1;                                  \
                    if (message_count > 0)                              \
                        goto nomoredata;                                \
                    PyErr_SetString(PyExc_ValueError, "Lost sync with input stream: expected 0x1A after 0x1A escape"); \
                    goto out;                                           \
                }                                                       \
                ++m, ++eom;                                             \
                if (eom > eod)                                          \
                    goto nomoredata;                                    \
            }                                                           \
        } while(0)

        /* timestamp, 6 bytes */
        timestamp = *m;
        ADVANCE;
        timestamp = (timestamp << 8) | *m;
        ADVANCE;
        timestamp = (timestamp << 8) | *m;
        ADVANCE;
        timestamp = (timestamp << 8) | *m;
        ADVANCE;
        timestamp = (timestamp << 8) | *m;
        ADVANCE;
        timestamp = (timestamp << 8) | *m;
        ADVANCE;

        /* signal, 1 byte */
        signal = *m;
        ADVANCE;

        /* message, N bytes */
        for (i = 0; i < message_len; ++i) {
            data[i] = *m;
            ADVANCE;
        }

        /* do some filtering */

        if (type == '4') {
            /* radarcape-style status message, use this to switch our decoder type */

            self->radarcape_utc_bugfix = (data[2] & 0x80) == 0x80;

            if (self->allow_mode_change) {
                decoder_mode newmode;
                if (data[0] & 0x10) {
                    /* radarcape in GPS timestamp mode */
                    if ((data[2] & 0x20) == 0x20) {
                        newmode = DECODER_RADARCAPE_EMULATED;
                    } else {
                        newmode = DECODER_RADARCAPE;
                    }
                } else {
                    /* radarcape in 12MHz timestamp mode */
                    newmode = DECODER_BEAST;
                }

                /* handle mode changes by inserting an event message */
                if (newmode != self->decoder_mode) {
                    set_decoder_mode(self, newmode);
                    if (self->want_events) {
                        if (! (messages[message_count++] = make_mode_change_event(self)))
                        goto out;
                    }
                }
            }
        }

        if (self->decoder_mode == DECODER_BEAST) {
            /* 12MHz mode */

            /* check for very out of range value
             * (dump1090 can hold messages for up to 60 seconds! so be conservative here)
             * also work around dump1090-mutability issue #47 which can send very stale Mode A/C messages
             */
            if (self->want_events && type != '1' && !timestamp_check(self, timestamp)) {
                if (! (messages[message_count++] = make_timestamp_jump_event(self, timestamp)))
                    goto out;
            }
        } else {
            /* gps mode */

            /* adjust timestamp so that it is a contiguous nanoseconds-since-
             * midnight value, rather than the raw form which skips values once
             * a second
             */
            uint64_t nanos = timestamp & 0x00003FFFFFFF;
            uint64_t secs = timestamp >> 30;

            if (!self->radarcape_utc_bugfix) {
                /* fix up the timestamp so it is UTC, not 1 second ahead */
                --secs;
            }

            timestamp = nanos + secs * 1000000000;

            /* adjust for the timestamp being at the _end_ of the frame;
             * we don't really care about getting a particular starting point
             * (that's just a fixed offset), so long as it is _the same in
             * every frame_.
             *
             * (but don't do this for status messages as they have a timestamp
             * as at the start of the message, which is basically the time of
             * the PPS)
             */
            if (type != '4') {
                uint64_t adjust = (8000 + message_len * 8000); /* each byte takes 8us to transmit, plus 8us preamble */
                if (adjust <= timestamp) {
                    timestamp = timestamp - adjust;
                } else {
                    /* wrap it to the previous day */
                    timestamp = timestamp + 86400 * 1000000000ULL - adjust;
                }
            }

            /* check for end of day rollover */
            if (self->want_events && self->last_timestamp >= (86340 * 1000000000ULL) && timestamp <= (60 * 1000000000ULL)) {
                if (! (messages[message_count++] = make_epoch_rollover_event(self, timestamp)))
                    goto out;
            } else if (self->want_events && type != '1' && !timestamp_check(self, timestamp)) {
                if (! (messages[message_count++] = make_timestamp_jump_event(self, timestamp)))
                    goto out;
            }
        }

        if (type != '1') {
            timestamp_update(self, timestamp);
        }

        if (type == '4') {
            /* radarcape-style status message, emit the status event if wanted */
            if (self->want_events) {
                if (! (messages[message_count++] = make_radarcape_status_event(self, timestamp, data)))
                    goto out;
            }

            /* don't try to process this as a Mode S message */
            p = m;
            continue;
        }

        /* it's a Mode A/C or Mode S message, parse it */
        if (! (message = modesmessage_from_buffer(timestamp, signal, data, message_len)))
            goto out;

        /* apply filters, update seen-set */
        ++self->received_messages;
        wanted = filter_message(self, message);
        if (wanted < 0)
            goto out;
        else if (wanted)
            messages[message_count++] = message;
        else {
            ++self->suppressed_messages;
            Py_DECREF(message);
        }

        p = m;
    }

 nomoredata:
    if (! (message_tuple = PyTuple_New(message_count)))
        goto out;

    while (--message_count >= 0) {
        PyTuple_SET_ITEM(message_tuple, message_count, messages[message_count]); /* steals ref */
    }

    rv = Py_BuildValue("(l,N,N)", (long) (p - buffer_start), message_tuple, PyBool_FromLong(error_pending));

 out:
    while (--message_count >= 0) {
        Py_XDECREF(messages[message_count]);
    }
    free(messages);
    return rv;
}
static PyObject *feed_avr(modesreader *self, Py_buffer *buffer, int max_messages)
{
    PyObject *rv = NULL;
    uint8_t *buffer_start, *p, *eod;
    int message_count = 0;
    PyObject *message_tuple = NULL;
    PyObject **messages = NULL;
    int error_pending = 0;

    buffer_start = buffer->buf;

    if (max_messages <= 0) {
        /* allocate the maximum size we might need, given a minimal encoding of:
         *   '*' <2 bytes message> ';' LF
         */
        max_messages = buffer->len / 5 + 1;
    }

    messages = calloc(max_messages, sizeof(PyObject*));
    if (!messages) {
        PyErr_NoMemory();
        goto out;
    }

    p = buffer_start;
    eod = buffer_start + buffer->len;
    while (p+17 <= eod && message_count+1 < max_messages) {
        int message_len = -1;
        uint64_t timestamp;
        uint8_t data[14];
        uint8_t message_format;
        int i;
        uint8_t *m;
        PyObject *message;

        message_format = p[0];
        if (message_format != '@' &&
            message_format != '%' &&
            message_format != '<' &&
            message_format != '*' &&
            message_format != ':') {
            error_pending = 1;
            if (message_count > 0)
                goto nomoredata;
            PyErr_Format(PyExc_ValueError, "Lost sync with input stream: expected '@'/'%%'/'<'/'*'/':' at offset %d but found 0x%02x instead",
                         (int) (p - buffer_start), (int)p[0]);
            goto out;
        }

        m = p + 1;
        if (message_format == '@' ||
            message_format == '%' ||
            message_format == '<') {
            /* read 6 bytes of timestamp */
            timestamp = 0;
            for (i = 0; i < 12; ++i, ++m) {
                int c;

                if (m >= eod) {
                    goto nomoredata;
                }

                timestamp <<= 4;
                c = hexvalue(*m);
                if (c >= 0) {
                    timestamp |= c;
                } else {
                    error_pending = 1;
                    if (message_count > 0)
                        goto nomoredata;
                    PyErr_Format(PyExc_ValueError, "Lost sync with input stream: expected a hex digit at offset %d but found 0x%02x instead",
                                 (int) (m - buffer_start), (int)*m);
                    goto out;
                }
            }
        } else {
            /* AVR format with no timestamp */
            timestamp = 0;
        }

        if (message_format == '<') {
            /* in format '<', skip 1 byte of signal */
            m += 2;
            if (m >= eod)
                goto nomoredata;
        }

        /* read 2-14 bytes of data */
        message_len = 0;
        while (message_len < 14) {
            int c0, c1;

            if (m+1 >= eod) {
                goto nomoredata;
            }

            if (m[0] == ';') {
                break; /* end of message marker */
            } else {
                c0 = hexvalue(m[0]);
                if (c0 < 0) {
                    error_pending = 1;
                    if (message_count > 0)
                        goto nomoredata;

                    PyErr_Format(PyExc_ValueError, "Lost sync with input stream: expected a hex digit at offset %d but found 0x%02x instead",
                                 (int) (m - buffer_start), (int)m[0]);
                    goto out;
                }
            }

            c1 = hexvalue(m[1]);
            if (c1 < 0) {
                error_pending = 1;
                if (message_count > 0)
                    goto nomoredata;

                PyErr_Format(PyExc_ValueError, "Lost sync with input stream: expected a hex digit at offset %d but found 0x%02x instead",
                             (int) (m - buffer_start), (int)m[1]);
                goto out;
            }

            if (message_len < 14) {
                data[message_len] = (c0 << 4) | c1;
            }
            ++message_len;
            m += 2;
        }

        /* consume ';' */
        if (m >= eod)
            goto nomoredata;
        if (*m != ';') {
            error_pending = 1;
            if (message_count > 0)
                goto nomoredata;

            PyErr_Format(PyExc_ValueError, "Lost sync with input stream: expected ';' at offset %d but found 0x%02x instead",
                         (int) (m - buffer_start), (int)*m);
            goto out;
        }

        /* CR LF, LF CR, LF all seen! ugh. */

        /* skip until CR or LF */
        while (m < eod && *m != '\r' && *m != '\n')
            ++m;

        /* consume however many CRs and LFs */
        while (m < eod && (*m == '\r' || *m == '\n'))
            ++m;

        /* check length */
        if (message_len != 2 && message_len != 7 && message_len != 14) {
            error_pending = 1;
            if (message_count > 0)
                goto nomoredata;

            PyErr_Format(PyExc_ValueError, "Lost sync with input stream: unexpected %d-byte message starting at offset %d",
                         message_len, (int) (p - buffer_start));
            goto out;
        }

        /* check for very out of range value
         * (dump1090 can hold messages for up to 60 seconds! so be conservative here)
         * also work around dump1090-mutability issue #47 which can send very stale Mode A/C messages
         */
        if (self->want_events && message_len != 2 && !timestamp_check(self, timestamp)) {
            if (! (messages[message_count++] = make_timestamp_jump_event(self, timestamp)))
                goto out;
        }

        timestamp_update(self, timestamp);

        /* decode it */
        if (! (message = modesmessage_from_buffer(timestamp, 0, data, message_len)))
            goto out;

        /* apply filters, update seen-set */
        ++self->received_messages;
        int wanted = filter_message(self, message);
        if (wanted < 0)
            goto out;
        else if (wanted)
            messages[message_count++] = message;
        else {
            ++self->suppressed_messages;
            Py_DECREF(message);
        }

        /* next message */
        p = m;
    }

 nomoredata:
    if (! (message_tuple = PyTuple_New(message_count)))
        goto out;

    while (--message_count >= 0) {
        PyTuple_SET_ITEM(message_tuple, message_count, messages[message_count]); /* steals ref */
    }

    rv = Py_BuildValue("(l,N,N)", (long) (p - buffer_start), message_tuple, PyBool_FromLong(error_pending));

 out:
    while (--message_count >= 0) {
        Py_XDECREF(messages[message_count]);
    }
    free(messages);
    return rv;
}