aboutsummaryrefslogtreecommitdiff
//<>< (C) 2016 C. N. Lohr, MOSTLY Under MIT/x11 License.
//
#include "survive_internal.h"
#include <assert.h>
#include <math.h> /* for sqrt */
#include <stdint.h>
#include <string.h>

#define PULSELENGTH_MIN_SYNC 2200
#define TIMECENTER_TICKS     (48000000/240)
#define PULSEDIST_MAX_TICKS  500000
#define PULSE_IN_CLEAR_TIME  35000
#define PULSE_MAX_FOR_SWEEP   1800
#define PULSE_SYNCTIME_OFFSET 20000 //unused?
#define PULSE_SYNCTIME_SLACK  5000

static int32_t decode_acode(uint32_t length, int32_t main_divisor) {
	//+50 adds a small offset and seems to help always get it right.
	// Check the +50 in the future to see how well this works on a variety of hardware.
	if (!main_divisor)
		return -1;

	int32_t acode = (length + main_divisor + 50) / (main_divisor * 2);
	if (acode & 1)
		return -1;

	int32_t rtn = (acode >> 1) - 6;
	if (rtn > 7 || rtn < 0) {
		return -1;
	}
	return rtn;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////The charles disambiguator.  Don't use this, mostly here for
/// debugging.///////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static void HandleOOTX(SurviveContext *ctx, SurviveObject *so) {
	int32_t main_divisor = so->timebase_hz / 384000; // 125 @ 48 MHz.

	int32_t acode_array[2] = {decode_acode(so->last_sync_length[0], main_divisor),
							  decode_acode(so->last_sync_length[1], main_divisor)};

	int32_t delta1 = so->last_sync_time[0] - so->recent_sync_time;
	int32_t delta2 = so->last_sync_time[1] - so->last_sync_time[0];

	// printf( "%p %p %d %d %d  %p\n", ctx, so, so->last_sync_time[0], acode_array, so->last_sync_length[0],
	// ctx->lightproc );
	if (acode_array[0] >= 0)
		ctx->lightproc(so, -1, acode_array[0], delta1, so->last_sync_time[0], so->last_sync_length[0], 0);
	if (acode_array[1] >= 0)
		ctx->lightproc(so, -2, acode_array[1], delta2, so->last_sync_time[1], so->last_sync_length[1], 1);

	so->recent_sync_time = so->last_sync_time[1];

	so->did_handle_ootx = 1;
}

// This is the disambiguator function, for taking light timing and figuring out place-in-sweep for a given photodiode.
void DisambiguatorCharles(SurviveObject *so, LightcapElement *le) {
	SurviveContext *ctx = so->ctx;
	//	static int32_t last;
	//	printf( "%d %lu %d %d\n", le->timestamp-last, le->timestamp, le->length, le->sensor_id );
	//	last = le->timestamp;
	// printf( "LE%3d%6d%12d\n", le->sensor_id, le->length, le->timestamp );

	// int32_t deltat = (uint32_t)le->timestamp - (uint32_t)so->last_master_time;

	if (le->sensor_id > SENSORS_PER_OBJECT) {
		return;
	}

	so->tsl = le->timestamp;
	if (le->length < 20)
		return; /// Assuming 20 is an okay value for here.

	// The sync pulse finder is taking Charles's old disambiguator code and mixing it with a more linear
	// version of Julian Picht's disambiguator, available in 488c5e9.  Removed afterwards into this
	// unified driver.
	int ssn = so->sync_set_number; // lighthouse number
	if (ssn < 0)
		ssn = 0;
#ifdef DEBUG
	if (ssn >= NUM_LIGHTHOUSES) {
		SV_INFO("ALGORITHMIC WARNING: ssn exceeds NUM_LIGHTHOUSES");
	}
#endif
	int last_sync_time = so->last_sync_time[ssn];
	int last_sync_length = so->last_sync_length[ssn];
	int32_t delta = le->timestamp - last_sync_time; // Handle time wrapping (be sure to be int32)

	if (delta < -PULSEDIST_MAX_TICKS || delta > PULSEDIST_MAX_TICKS) {
		// Reset pulse, etc.
		so->sync_set_number = -1;
		delta = PULSEDIST_MAX_TICKS;
		//		return; //if we don't know what lighthouse this is we don't care to do much else
	}

	if (le->length > PULSELENGTH_MIN_SYNC) // Pulse longer indicates a sync pulse.
	{
		int is_new_pulse = delta > PULSELENGTH_MIN_SYNC /*1500*/ + last_sync_length;

		if (is_new_pulse) {
			int is_master_sync_pulse = delta > PULSE_IN_CLEAR_TIME /*40000*/;
			int is_pulse_from_same_lh_as_last_sweep;
			int tp = delta % (TIMECENTER_TICKS * 2);
			is_pulse_from_same_lh_as_last_sweep = tp < PULSE_SYNCTIME_SLACK && tp > -PULSE_SYNCTIME_SLACK;

			if (!so->did_handle_ootx) {
				HandleOOTX(ctx, so);
			}
			if (!is_master_sync_pulse) {
				so->did_handle_ootx = 0;
			}

			if (is_master_sync_pulse) // Could also be called by slave if no master was seen.
			{
				ssn = so->sync_set_number = is_pulse_from_same_lh_as_last_sweep
												? (so->sync_set_number)
												: 0; // If repeated lighthouse, just back off one.
				if (ssn < 0) {
					SV_INFO("SEVERE WARNING: Pulse codes for tracking not able to be backed out.\n");
					ssn = 0;
				}
				if (ssn != 0) {
					// If it's the slave that is repeated, be sure to zero out its sync info.
					so->last_sync_length[0] = 0;
				} else {
					so->last_sync_length[1] = 0;
				}
				so->last_sync_time[ssn] = le->timestamp;
				so->last_sync_length[ssn] = le->length;
			} else if (so->sync_set_number == -1) {
				// Do nothing.
			} else {
				ssn = ++so->sync_set_number;

				if (so->sync_set_number >= NUM_LIGHTHOUSES) {
					SV_INFO("Warning.  Received an extra, unassociated sync pulse.");
					ssn = so->sync_set_number = -1;
				} else {
					so->last_sync_time[ssn] = le->timestamp;
					so->last_sync_length[ssn] = le->length;
				}
			}
		} else {
			// Find the longest pulse.
			if (le->length > last_sync_length) {
				if (so->last_sync_time[ssn] > le->timestamp) {
					so->last_sync_time[ssn] = le->timestamp;
					so->last_sync_length[ssn] = le->length;
				}
			}
		}

#if 0
		//Extra tidbit for storing length-of-sync-pulses, if you want to try to use this to determine AoI or distance to LH.
		//We don't actually use this anywhere, and I doubt we ever will?  Though, it could be useful at a later time to improve tracking.
		{
			int32_t main_divisor = so->timebase_hz / 384000; //125 @ 48 MHz.
			int base_station = is_new_pulse;
			printf( "%s %d %d %d\n", so->codename, le->sensor_id, so->sync_set_number, le->length ); //XXX sync_set_number is wrong here.
			ctx->lightproc( so, le->sensor_id, -3 - so->sync_set_number, 0, le->timestamp, le->length, base_station); //XXX sync_set_number is wrong here.
		}
#endif
	}

	// Any else- statements below here are

	// See if this is a valid actual pulse.
	else if (le->length < PULSE_MAX_FOR_SWEEP && delta > PULSE_IN_CLEAR_TIME && ssn >= 0) {
		int32_t tpco = so->last_sync_length[0];

#if NUM_LIGHTHOUSES != 2
#error You are going to have to fix the code around here to allow for something other than two base stations.
#endif

		// Adding length
		// Long pulse-code from IR flood.
		// Make sure it fits nicely into a divisible-by-500 time.

		int32_t main_divisor = so->timebase_hz / 384000; // 125 @ 48 MHz.
		int acode = decode_acode(so->last_sync_length[0], main_divisor);

		// If acode isn't right; don't even think of emitting an event
		if (acode >= 0) {
			int whichlh = (acode >> 2);
			assert(whichlh <= 1);
			int32_t dl = so->last_sync_time[whichlh];

			if (!so->did_handle_ootx)
				HandleOOTX(ctx, so);

			int32_t offset_from = le->timestamp - dl + le->length / 2;

			// Make sure pulse is in valid window
			if (offset_from < TIMECENTER_TICKS * 2 - PULSE_IN_CLEAR_TIME &&
				offset_from > PULSE_IN_CLEAR_TIME) {
				ctx->lightproc(so, le->sensor_id, acode, offset_from, le->timestamp, le->length, whichlh);
			}
		}
	} else {
		// printf( "FAIL %d   %d - %d = %d\n", le->length, so->last_photo_time, le->timestamp, so->last_photo_time -
		// le->timestamp );
		// Runt pulse, or no sync pulses available.
	}
}

REGISTER_LINKTIME(DisambiguatorCharles);