//<>< (C) 2016 C. N. Lohr, MOSTLY Under MIT/x11 License. // #include "survive_internal.h" #include #include /* for sqrt */ #include #include #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);