// // $Source: /Project/dcrsi/240/rcs/tape_mngr.cc,v $ // $Revision: 1.2 $ // $Date: 1997/11/22 00:23:47 $ // $Author: kdh $ // $State: Exp $ // $Locker: kdh $ // // // tape_mngr.cc // /* Tape Manager -- - monitors tape postion and motion */ #include #include #include #include "gen.h" #include "regdefs.h" #include "bit_id.h" #include "hardware.h" const int TACH_TIME_SIZE = 64; const float PULSE_LENGTH = 0.09948377, IDLER_RADIUS = 0.2375, I_SIZE = 0.418879, R_SIZE = 0.0490874, PI = 3.1415927, RMIN = 0.8025, RMAX = 2.5475, THICKNESS = 0.00086, HUB = 0.64400625, HARD_EOT = 0.86857, RAMP_DOWN = 56.0, MIN_PLAY_SP = 4.9, MAX_PLAY_SP = 5.4; typedef struct { int time; int count; } reel_sample; enum reel_state { r_init, r_reset, r_slow, r_fast, r_prepos, r_flywheel, r_transition }; class reel_estimate { public: void begin (int slow); void clear (void); int update_reel (reel_types reel, float mt, int time0, int time1); reel_estimate (void); private: float fsize; float im[3][3],k[3][2]; float theta [3],old_theta[3]; float p [3][3],op [3][3]; float err_knob; float last_length[2]; float last_radius[2]; }; int Incr_tach_offset; int Idler_adjust; int Supply_reel; int Tach_box; int Takeup_reel; int Tape_motion; int Idebug2; int Tdebug1; int Tdebug2; int Tdebug3; int Tdebug4; int Tidler; int Tsupply; int Ttakeup; int begin_time; int test_pos; unsigned char Force_flywheel; unsigned char Idler_debug; unsigned char No_estimate; unsigned char Su_prepos; unsigned char Tach_debug; unsigned char Tach_int_fault; unsigned char Tach_prepos; unsigned char Tu_prepos; unsigned char su_check; unsigned char tu_check; float Fdebug1; float Fdebug2; float Fdebug3; float Fdebug4; float Idebug1; float Idebug3; float Max_takeup; float Pack_length[2]; float Pack_radius[2]; float Ref_length[2]; float Ref_radius[2]; float Stop_radius[2]; float Tach_radius[2]; float Thickness; float Tspeed; float Sdebug1; float Sdebug2; float hold_speed; reel_state Tach_state; static float est_idler_radius, hold_length [2], hold_thickness, idler_interval, idler_speed, idler_sum, k2[2], k2_array[2][8], k2_sum [2], last_k2 [2], last_speed, last_thickness, ref_thickness, rspeed, speed, tacceleration, tot_idler; static int first_sample [2], hold_idler, hold_index_in [2], hold_index_out [2], hold_supply, hold_takeup, idler_depth, idler_time_array [TACH_TIME_SIZE], idler_time_in, idler_time_out, k2_disable, k2_in[2], k_cnt[2], k_lim[2], k_max[2], last_cap_lock, last_condition, last_idler, last_supply, last_takeup, last_tidler, last_tsupply, last_ttakeup, local_err, min_pos, old_idler_time, position_track, r_cnt[2], r_offset[2], reel_time_in [2], reel_time_out [2], ref_footage, ref_time, speed_count, speed_locked, su_hold, tu_hold; static unsigned char idler_prepos, new_estimate, old_idler_int, slow_mode, speed_switch, switch_delay, su_distance, suspect_tape, tach_is, tach_pend, tach_prepos_rdy, tu_distance, was_locked; static report_status_message status_msg; static reel_sample reel_time_array [2][TACH_TIME_SIZE]; extern char Abort, Broken_tape, Cap_ovr_fault; extern int Report_debug [], Footage_total, Stop_start_time, Start_start_time, Ms_clock; extern unsigned char Tach_override, Tach_dir, Tach_init; extern eq_parm_t Eq_parms; extern transport_state_type Transport_state; extern states Target_state, Current_state; extern oai_states Oai_state; extern play_states Oai_play_ss; extern record_states Oai_rec_ss; extern "C" { void int_disable (void); void int_enable (void); void clear_tachs (void); void new_tach_count (unsigned char direction, unsigned char idler_stat, unsigned char idler_count, unsigned char reel_stat, unsigned char takeup_count, unsigned char supply_count, unsigned char tu_except, unsigned char su_except, int idler_int, int takeup_int, int supply_int); void new_reel_time(int rl,int ms_time,unsigned char int_time,unsigned char ip); void new_idler_time (int ms_time, unsigned char int_time, unsigned char ip); void int_loger (int err,int tid); } extern void post_status (report_status_message &status_msg, int task_id, int display_request); extern int current_track (void); void track_position (void); void update_position (void); float estimated_tape_speed () { if (speed_locked) { if (Tach_state == r_slow) return (rspeed); else return (idler_speed); } else return(Tspeed); } // new_reel_time is called by either the supply tach or takeup tach interrupt // service routine to post a new interrupt time stamp to the circular queue // the parameters are the caller, supply/takeup. the millisecond counter value // the 4 Mhz millisecond interrupt timer count value and the timer interrupt // pending status register value void new_reel_time (int rl,int ms_time,unsigned char int_time, unsigned char ip) { int tmp; int_disable (); if (ip & 0x10) { ms_time++; if (int_time == 1) int_time = 250; } if (!Broken_tape) { tmp = (reel_time_in [rl] + 1) % TACH_TIME_SIZE; if (tmp == reel_time_out[rl]) loger (0,999); else { reel_time_array [rl][tmp].time = ms_time; reel_time_array [rl][tmp].count = int_time; if (!Tach_prepos) reel_time_in [rl] = tmp; } } int_enable (); if ((r_offset [su_reel]) || (r_offset [tu_reel])) idler_depth = 0; } // new_idler_time is called by the idler tach interrupt service routine to // post a new interrupt time interval to the circular queue // the parameters are the millisecond counter value, the 4 Mhz millisecond // interrupt timer count value and the timer interrupt pending status register void new_idler_time (int ms_time, unsigned char int_time, unsigned char ip) { int time, itime, tmp; time = ms_time - old_idler_time; old_idler_time = ms_time; if (ip & 0x10) { time++; old_idler_time++; if (int_time < 5) int_time = 250 - int_time + 1; } itime = old_idler_int - (250 - int_time); old_idler_int = 250 - int_time; if (itime < 0) { itime += 250; time -= 1; } time = (time * 250) + itime; tmp = (idler_time_in + 1) % TACH_TIME_SIZE; if (!Broken_tape) { if (tmp == idler_time_out) loger (0,999); else { if (!idler_prepos) { idler_time_array [tmp] = time; if (!Tach_prepos) idler_time_in = tmp; } else { idler_depth = 0; idler_speed = 5.2774; idler_prepos = 0; Tach_override = 0; } } } } // new_tach_count is called by the tach timer isr. The values passed are the // 'current' tach count positions. the interrupt statuses and the intervening // interrupt counts. It is called each 100 ms. void new_tach_count (unsigned char direction, unsigned char idler_stat, unsigned char idler_count, unsigned char reel_stat, unsigned char takeup_count, unsigned char supply_count, unsigned char tu_except, unsigned char su_except, int idler_int, int takeup_int, int supply_int) { int idler_size, reel_size, save_idler, save_supply, save_takeup; save_idler = 0; save_supply = 0; save_takeup = 0; if (slow_mode) { idler_size = 5; reel_size = 8; } else { idler_size = 60; reel_size = 128; } if (idler_stat & 0x20) { idler_int++; save_idler++; if (idler_count == 1) idler_count = idler_size; } idler_count = (idler_size - idler_count); if (reel_stat & 0x01) { supply_int++; save_supply++; if (supply_count < 4) supply_count = reel_size - supply_count + 1; } if (reel_stat & 0x20) { takeup_int++; save_takeup++; if (takeup_count < 4) takeup_count = reel_size - takeup_count + 1; } if ((!(Tach_init || speed_switch)) ||(Broken_tape)) { Tidler = (((idler_int - hold_idler) * idler_size) + idler_count)-last_idler; if (su_except) supply_count = (su_except - supply_count); else supply_count = (reel_size - supply_count); Tsupply = (((supply_int - hold_supply) * reel_size) + supply_count) - last_supply; if (tu_except) takeup_count = (tu_except - takeup_count); else takeup_count = (reel_size - takeup_count); Ttakeup = (((takeup_int - hold_takeup) * reel_size) + takeup_count) - last_takeup; last_idler = idler_count; last_supply = supply_count; last_takeup = takeup_count; } else { Tidler = last_tidler; Tsupply = last_tsupply; Ttakeup = last_ttakeup; if (Tach_init) { last_idler = 0; last_supply = 0; last_takeup = 0; save_idler = 0; save_supply = 0; save_takeup = 0; Tach_init = 0; switch_delay = 2; } else { save_idler = 0; save_supply = 0; save_takeup = 0; last_idler = 0; last_supply = 0; last_takeup = 0; speed_switch--; switch_delay = 2; } } Tach_dir = direction; hold_idler = save_idler; hold_supply = save_supply; hold_takeup = save_takeup; } // update_idler_speed checks for update tach time data for the idler tach isr // the time intervals are used to estimate the current idler speed. void update_idler_speed (void) { int i,j; j = 0; while (idler_time_in != idler_time_out) { j = 1; i = (idler_time_out == TACH_TIME_SIZE-1) ? 0 : idler_time_out+1; idler_time_out = i; i = idler_time_array [i]; idler_interval = (((float)i * 4.0) / 1000.0); if (idler_interval > 0.0) { if ((Tach_state == r_slow)||(Tach_state == r_fast)||(Tach_state == r_transition)) { if (!idler_depth) idler_sum = 0.0; if (idler_depth < 100) { idler_sum += idler_interval; idler_depth++; } else idler_sum = 0.99*idler_sum + idler_interval; if ((slow_mode) && (idler_depth > 3) && ((Tach_state == r_transition) || (r_offset [su_reel]) || (r_offset [tu_reel])) && ((idler_speed < MIN_PLAY_SP) || (idler_speed > MAX_PLAY_SP))) { idler_sum = idler_interval; idler_depth = 1; } } else { idler_sum = idler_interval; idler_depth = 1; } idler_speed = (4.0*2.0*PI*est_idler_radius)/((idler_sum / 1000.0)/(float)idler_depth); if (slow_mode) idler_speed /= 12.0; } else { idler_speed = 0.0; idler_depth = 0; } } if ((Idler_debug) && (j)) { Idebug1 = idler_interval; Idebug2 = idler_depth; Idebug3 = idler_speed; post_status (status_msg, TAPE_MNGR_TID, 95); } } // the reel estimate class is used to implement the Kalman filter optimization // algorithm. begin is called to initialize each instance of the algorithm // which is run only at constant speed. begin is called to start // the kalman filter. The parameter is the speed mode which determines the // interrupt timing rates. void reel_estimate::begin (int slow) { int_disable (); begin_time = Ms_clock; if (slow) fsize = 16.0; else fsize = 1.0; HpIPRA = 0xDE; speed_switch = 1; if (slow_mode != slow) { idler_time_out = idler_time_in; reset_bit (IDLER_CNTL); reset_bit (TU_CNTL); reset_bit (SU_CNTL); if (slow) { IDLER_TACH = 5; TU_TACH = 8; SU_TACH = 8; LpTBDR = 50; } else { IDLER_TACH = 60; TU_TACH = 128; SU_TACH = 128; LpTBDR = 50; } LpIPRB = 0xDF; set_bit (IDLER_CNTL); set_bit (TU_CNTL); set_bit (SU_CNTL); } slow_mode = slow; int_enable (); min_pos = test_pos; r_offset [su_reel] = 0; r_offset [tu_reel] = 0; r_cnt [su_reel] = 0; r_cnt [tu_reel] = 0; k_cnt [su_reel] = 0; k_cnt [tu_reel] = 0; k_lim [su_reel] = 0; k_lim [tu_reel] = 0; k2_sum [su_reel] = 0.0; k2_sum [tu_reel] = 0.0; k2_in [su_reel] = 0; k2_in [tu_reel] = 0; reel_time_out [su_reel] = reel_time_in [su_reel]; reel_time_out [tu_reel] = reel_time_in [tu_reel]; first_sample [su_reel] = 2; first_sample [tu_reel] = 2; last_thickness = ref_thickness; last_cap_lock = 0; if (Tspeed >= 15.0) { old_theta [0] = ((Pack_radius [0] * 2000.0 * PI) / Tspeed) / fsize; old_theta [1] = ((Pack_radius [1] * 2000.0 * PI) / Tspeed) / fsize; } else { old_theta [0] = ((Pack_radius [0] * 2000.0 * PI) / 5.2774) / fsize; old_theta [1] = ((Pack_radius [1] * 2000.0 * PI) / 5.2774) / fsize; } old_theta [2] = ref_thickness / fsize; memset (op,0,sizeof(op)); op [0][0] = (old_theta[0] * old_theta [0]) / 12.0; op [1][1] = (old_theta[1] * old_theta [1]) / 12.0; op [2][2] = (((0.00086-0.00074)*(0.00084-0.00074))/2.0*fsize); if (fsize > 1.0) err_knob=(float)(local_err)/100.0; else err_knob=(float)(local_err)/100.0 * 10.0; } // clear is the master initialization for the reel_estimate class. This // function is called once for each new cassette. void reel_estimate::clear (void) { Pack_length[su_reel] = 1000.0; Pack_length[tu_reel] = 1000.0; Pack_radius[su_reel] = (RMAX+RMIN)/2.0; Pack_radius[tu_reel] = (RMAX+RMIN)/2.0; Tach_radius[su_reel] = (RMAX+RMIN)/2.0; Tach_radius[tu_reel] = (RMAX+RMIN)/2.0; Ref_length[su_reel] = 1000.0; Ref_length[tu_reel] = 1000.0; Ref_radius[su_reel] = (RMAX+RMIN)/2.0; Ref_radius[tu_reel] = (RMAX+RMIN)/2.0; ref_footage = Footage_total; ref_time = Ms_clock; ref_thickness = 0.00082; last_thickness = ref_thickness; last_length[su_reel] = 1000.0; last_length[tu_reel] = 1000.0; last_radius[su_reel] = (RMAX-RMIN)/2.0; last_radius[tu_reel] = (RMAX-RMIN)/2.0; k2_sum [0] = 0.0; k2_sum [1] = 0.0; k_cnt [0] = 0; k_cnt [1] = 0; k_max [0] = 0; k_max [1] = 0; k_lim [0] = 0; k_lim [1] = 0; reset_bit (IDLER_CNTL); reset_bit (TU_CNTL); reset_bit (SU_CNTL); slow_mode = 1; SU_TACH = 8; TU_TACH = 8; IDLER_TACH = 5; set_bit (IDLER_CNTL); set_bit (TU_CNTL); set_bit (SU_CNTL); No_estimate = 1; est_idler_radius = IDLER_RADIUS; new_estimate = 1; Max_takeup = RMIN; } // Power on constructor once per session (redundant) reel_estimate::reel_estimate (void) { clear (); begin (1); } // reel_estimate is the actual kalman filter optimization. The Kalman filter // is used to implement a real time recursive linear reqression by least squares // the relationship of interest is the change in rotation period as a function // of tape thickness. it is organized to reduce the number of floating point // operations required. The algorithm update the current best quess for // hub radiuses, the thickness and the linear length on each reel. int reel_estimate::update_reel(reel_types reel,float mt,int time0,int time1) { int i, pos, rl, rn; float sp, f, cn, rf, rr, l, m; sp = rspeed / 1000.0; if (!Tach_dir) sp = -sp; rn = (int)reel; rl = !rn; rf = (float)(rl - 1); rr = (float)(rn - 1); cn = (rf-rr) * ((2.0 * PI / fsize) / sp) * (float)(r_cnt[rl] + 1); f = 1.0/((op[rl][rl] + cn*op[2][rl])+(op[rl][2]+cn*op[2][2]) * cn + err_knob); k [0][rl] = f*(op[0][rl] + op[0][2]*cn); k [1][rl] = f*(op[1][rl] + op[1][2]*cn); k [2][rl] = f*(op[2][rl] + op[2][2]*cn); f = mt - (old_theta[rl] + old_theta[2]*cn); theta [0] = old_theta[0] + f*k[0][rl]; theta [1] = old_theta[1] + f*k[1][rl]; theta [2] = old_theta[2] + f*k[2][rl]; im[0][0] = 1.0 + rf * k[0][0]; im[0][1] = rr * k[0][1]; im[0][2] = -k[0][rl] * cn; im[1][0] = rf * k[1][0]; im[1][1] = 1.0 + rr * k[1][1]; im[1][2] = -k[1][rl]* cn; im[2][0] = rf * k[2][0]; im[2][1] = rr * k[2][1]; im[2][2] = 1.0 - k[2][rl] * cn; p[rn][0] = op[rn][0] + im[rn][rl] * op[rl][0] + im[rn][2] * op[2][0]; p[rn][1] = op[rn][1] + im[rn][rl] * op[rl][1] + im[rn][2] * op[2][1]; p[rn][2] = op[rn][2] + im[rn][rl] * op[rl][2] + im[rn][2] * op[2][2]; p[rl][0] = im[rl][rl] * op[rl][0] + im[rl][2] * op[2][0]; p[rl][1] = im[rl][rl] * op[rl][1] + im[rl][2] * op[2][1]; p[rl][2] = im[rl][rl] * op[rl][2] + im[rl][2] * op[2][2]; p[2][0] = im[2][rl] * op[rl][0] + im[2][2] * op[2][0]; p[2][1] = im[2][rl] * op[rl][1] + im[2][2] * op[2][1]; p[2][2] = im[2][rl] * op[rl][2] + im[2][2] * op[2][2]; hold_thickness = theta[2]*fsize; f = (theta[rl] + cn * theta[2]) * (sp / (PI * 2.0)) * fsize; last_length[rn] = ((f * f) - (HUB)) / ((12.0 / PI) * ref_thickness); last_radius[rn] = (sp < 0) ? -f : f; k2[0] = fabs (k[2][0]); k2[1] = fabs (k[2][1]); if (((r_cnt [rl] > min_pos) && (r_cnt [rn] > min_pos / 2))) // || (k_max [rl] < r_cnt[rl])) { pos = 1; ref_time = Ms_clock; l = (rf-rr) * (sp * (float)(ref_time - time0) / 12.0); Pack_length [rn] = last_length[rn] + l; Pack_radius[rn]=last_radius[rn]+(l*ref_thickness)/(2.0*PI*Pack_radius[rn]); if (time1 > 0) { m = (rr-rf) * (sp * (float)(ref_time - time1) / 12.0); Pack_length [rl] = last_length[rl] + m; Pack_radius[rl]= last_radius[rl]+(m*ref_thickness)/(2.0*PI*Pack_radius[rl]); } else pos = 0; } else pos = 0; memcpy (op,p,sizeof(p)); memcpy (old_theta,theta,sizeof(theta)); r_cnt [rl]++; if (k_cnt [rl] < 8) { k2_array [rl][k2_in[rl]++] = k2[rl] - last_k2[rl]; if (k2_in[rl] > 7) k2_in[rl] = 0; k_cnt [rl]++; } else { k2_array [rl][k2_in[rl]++] = k2[rl] - last_k2[rl]; if (k2_in[rl] > 7) k2_in[rl] = 0; k2_sum[rl] = 0.0; for (i=0;i<8;i++) k2_sum [rl] += k2_array [rl][i]; } if (k2_sum [rl] > 1.0) { k_cnt[rl] = 0; k2_sum [rl] = 0.0; } if (!k2_disable) { if (((k2_sum [rl] < 0.0) && (k2 [rl] < last_k2 [rl])) && (k_cnt [rl] > 7) && ((hold_thickness > 0.00074) && (hold_thickness < 0.00088))) { if (fsize == 16.0) k_lim [rl]++; else k_lim [rl] += 4; if ((k_lim [rl] > k_max [rl]) || (k_lim [rl] > 1000)) { k_max [rl] = k_lim [rl]; last_thickness = hold_thickness; } } last_k2 [rl] = k2 [rl]; } else last_thickness = hold_thickness; return (pos); } // begin_tach_prepos is called by the OAI interrupt service routine // to initiate the preposition request. Should be called just before // pulsing preposition request void begin_tach_prepos (void) { int_disable (); Tach_prepos = 1; tach_prepos_rdy = 0; Tach_override = 1; HpTACR = 0; HpTBCR = 0; su_hold = SU_TACH; tu_hold = TU_TACH; TU_TACH = 100; SU_TACH = 100; hold_index_in [su_reel] = reel_time_in [su_reel]; hold_index_in [tu_reel] = reel_time_in [tu_reel]; hold_index_out [su_reel] = reel_time_out [su_reel]; hold_index_out [tu_reel] = reel_time_out [tu_reel]; reel_time_out [su_reel] = reel_time_in [su_reel]; reel_time_out [tu_reel] = reel_time_in [tu_reel]; tach_pend = HpIPRA; tach_is = HpISRA; HpIERA &= 0xDE; HpIERA |= 0x21; HpIPRA = 0xDE; HpTACR = 8; HpTBCR = 8; int_enable (); } // called by preposition ready interrupt to handshake with tape // manager that the preposition ready has been received void tape_prepos_rdy (void) { tach_prepos_rdy = 1; } // end_tach_prepos is called by the hfull routine to initiate the preplay void end_tach_prepos (void) { int s, t, x; if (Transport_state != play_state) return; int_disable (); Tach_prepos = 0; reset_bit (SU_CNTL); su_distance = SU_TACH; reset_bit (TU_CNTL); tu_distance = TU_TACH; x = ((100 - su_distance) & 255) + Incr_tach_offset - (8 - su_hold); r_offset [su_reel] = (x / 8); if ((tach_pend & 1) || (tach_is & 1)) r_offset [su_reel]--; if (hold_index_in[su_reel] != hold_index_out[su_reel]) r_offset [su_reel]--; s = x % 8; if (!s) r_offset [su_reel]++; s += 8; x = ((100 - tu_distance) & 255) + Incr_tach_offset - (8 - tu_hold); r_offset [tu_reel] = (x / 8); if ((tach_pend & 32) || (tach_is & 32)) r_offset [tu_reel]--; if (hold_index_in[tu_reel] != hold_index_out[tu_reel]) r_offset [tu_reel]--; t = x % 8; if (!t) r_offset [tu_reel]++; t += 8; SU_TACH = s; TU_TACH = t; IDLER_TACH = 5; idler_prepos = 1; Su_prepos = s; Tu_prepos = t; idler_speed = 0.0; idler_depth = 0; hold_idler = 0; hold_supply = 0; hold_takeup = 0; Tach_init = 1; track_position (); HpIPRA = 0xDE; set_bit (SU_CNTL); set_bit (TU_CNTL); int_enable (); } void abort_tach_prepos (void) { reset_bit (SU_CNTL); reset_bit (TU_CNTL); TU_TACH = 8; SU_TACH = 8; IDLER_TACH = 5; set_bit (SU_CNTL); set_bit (TU_CNTL); Tach_prepos = 0; Tach_override = 0; last_tidler = 0; last_tsupply = 0; last_ttakeup = 0; idler_speed = 0.0; idler_depth = 0; r_offset [su_reel] = 0; r_offset [tu_reel] = 0; Tach_init = 1; suspect_tape = 0; } // extract period polls the circular reel time stamp buffer for the // most recent time stamps float extract_period (reel_types rl,int &rltime, int &rntime) { float rev; int i, j, k; rev = 0.0; while (reel_time_in [rl] != reel_time_out [rl]) { if (!Tach_prepos) { int_disable (); i = (reel_time_out [rl] == TACH_TIME_SIZE-1) ? 0 : reel_time_out [rl] + 1; int_enable (); reel_time_out [rl] = i; j = (i) ? i - 1 : TACH_TIME_SIZE-1; if ((!first_sample [rl]) && (speed_locked || r_offset[rl])) { rltime = reel_time_array [rl][i].time; rev = (float)(rltime - reel_time_array [rl][j].time); k = reel_time_array [rl][j].count - reel_time_array [rl][i].count; rev += (0.004 * (float)k); rntime = reel_time_array [!rl][reel_time_out [!rl]].time; } else if (speed_locked) first_sample[rl]--; } } return (rev); } // track_position is called in lieu of update_position. When the position // is not calculateable it is extrapolated from it's last known position // based on the footage count value void track_position (void) { float tmp; tmp = (float)(Footage_total - ref_footage) * PULSE_LENGTH; Pack_length [0] = Ref_length [0] + (tmp / 12.0); Pack_length [1] = Ref_length [1] - (tmp / 12.0); Pack_radius [0] = sqrt (((PI* Ref_radius [0] * Ref_radius[0]) + (tmp * ref_thickness)) / PI); Pack_radius [1] = sqrt (((PI* Ref_radius [1] * Ref_radius[1]) - (tmp * ref_thickness)) / PI); hold_length [0] = Pack_length [0]; hold_length [1] = Pack_length [1]; Thickness = ref_thickness; position_track = 1; } // update_position is called to update the 'current' reel position information // potentially this is called each 100 ms while the tape speed is constant void update_position (void) { float tmp; if (position_track) { tmp = (float)(Footage_total - ref_footage) * PULSE_LENGTH; Fdebug3 = (Ref_length [tu_reel] + (tmp / 12.0)) - Pack_length [tu_reel]; Fdebug4 = (Ref_length [su_reel] - (tmp / 12.0)) - Pack_length [su_reel]; } ref_footage = Footage_total; Ref_length [tu_reel] = Pack_length [tu_reel]; Ref_length [su_reel] = Pack_length [su_reel]; Ref_radius [tu_reel] = Pack_radius [tu_reel]; Ref_radius [su_reel] = Pack_radius [su_reel]; if (last_thickness < 0.00074) ref_thickness = 0.00074; else if (last_thickness > 0.00088) ref_thickness = 0.00088; else ref_thickness = last_thickness; Thickness = ref_thickness; position_track = 0; hold_length [tu_reel] = Pack_length [tu_reel]; hold_length [su_reel] = Pack_length [su_reel]; if (((r_cnt [tu_reel] > 5) && (r_cnt [su_reel] > 5)) && (idler_depth > 50) && (new_estimate)) { new_estimate = 0; if (No_estimate) { if ((idler_speed > 5.1) && (idler_speed < 5.4)) est_idler_radius = (5.2774 / idler_speed) * IDLER_RADIUS; No_estimate = 0; } } if (Pack_length [tu_reel] > Max_takeup) Max_takeup = Pack_length [tu_reel]; } void update_tach_position (void) { float x; was_locked = speed_locked; speed_locked = 0; if (Tidler > 1) { speed = 10.0*((float)Tidler * PULSE_LENGTH); tacceleration = (speed - last_speed); } else { Stop_start_time = Ms_clock; speed = 0.0; tacceleration = 0.0; if ((Transport_state == stop_pending)&&(last_tidler == 0.0)) Transport_state = stop_state; } x = fabs (tacceleration); if ((((x < 1.8) && (slow_mode)) || ((x < 2.0) && (!slow_mode))) && (Tidler > 2) && (fabs (Tspeed) > 1.0)) { if (speed_count < 30.0) { tot_idler += (float)Tidler; speed_count++; if (((speed_count>1)&&(slow_mode))||((speed_count > 2)&&(!slow_mode))) speed_locked = 1; } else { speed_locked = 1; tot_idler = tot_idler*(29.0/30.0) + (float)Tidler; } Tspeed = tot_idler * PULSE_LENGTH; Tspeed /= (float)speed_count; Tspeed *= 10.0; speed = Tspeed; } else { Tspeed = (Tidler > 2) ? last_speed : speed; speed_count = 0; speed_locked = 0; tot_idler = 0.0; } if (speed_locked && !was_locked) { if (Transport_state == shuttle_pending) { Transport_state = shuttle_state; Start_start_time = Ms_clock; } else if (Transport_state == play_pending) { Transport_state = play_state; Start_start_time = Ms_clock; } else if ((Transport_state != play_state) && (Transport_state != shuttle_state)) ; } last_speed = speed; x = (float)Tidler * I_SIZE; if (Tsupply > 0) Tach_radius [su_reel] = (IDLER_RADIUS * x) / ((float)Tsupply * R_SIZE); if (Ttakeup > 0) Tach_radius [tu_reel] = (IDLER_RADIUS * x) / ((float)Ttakeup * R_SIZE); if ((Tspeed > 1.0)&&(Tidler > 0)) { Supply_reel = (600 * Tsupply) / Tidler; Takeup_reel = (600 * Ttakeup) / Tidler; } } void update_stop_estimate(float sp) { float delta_s; delta_s = 0.0; switch (Transport_state) { case stop_state: delta_s = 0.0; break; case stop_pending: if ((Stop_start_time - Ms_clock) > 0) delta_s = (sp * (Stop_start_time - Ms_clock)) / 2000.0; else delta_s = 0.0; break; case shuttle_state: delta_s = (idler_speed * 1.317) / 2.0; break; case play_state: delta_s = (idler_speed * 0.04) / 2.0; break; case play_pending: case shuttle_pending: if ((Start_start_time - Ms_clock) > 0) delta_s = (sp * (Start_start_time - Ms_clock)) / 2000.0; else delta_s = 0.0; break; default: break; } if (!Tach_dir) delta_s = -delta_s; Stop_radius [tu_reel] = sqrt (((PI* Pack_radius [tu_reel] * Pack_radius[tu_reel]) + (delta_s * Thickness)) / PI); Stop_radius [su_reel] = sqrt (((PI* Pack_radius [su_reel] * Pack_radius[su_reel]) - (delta_s * Thickness)) / PI); } int arrest_tape(int condition) { int done, msg, error, timeout; if ((suspect_tape && (condition < 4)) || (suspect_tape > 2)) { DspReg |= 8; loger (condition,991); Broken_tape = 1; Abort = 1; timeout = 0; done = 0; if (!disable (nREELRWD, error)) loger (TAPE_MNGR_TID, error); if (!disable (nREELFWD, error)) loger (TAPE_MNGR_TID, error); if (!disable (nREEL_EN, error)) loger (TAPE_MNGR_TID, error); if (!disable (nCPSTNFD, error)) loger (TAPE_MNGR_TID, error); if (!disable (PRE, error)) loger (TAPE_MNGR_TID, error); if (!enable (BrakeEnbl, error)) loger (TAPE_MNGR_TID, error); while ((timeout < FIVE_SECONDS) && (!done)) { ScAccept (Tach_box, error ,msg); if ((Tidler == 0) && (Tsupply == 0) && (Ttakeup == 0)) { Transport_state = stop_state; if (!disable (CSL, error)) loger (TAPE_MNGR_TID, error); done = 1; } ScTdelay (MSEC_100); timeout += MSEC_100; } if (!done) { if (!disable (nREELACT, error)) loger (TAPE_MNGR_TID, error); timeout = 0; done = 0; while ((timeout < THREE_SECONDS) && (!done)) { ScAccept (Tach_box, error ,msg); if ((Tidler == 0) && (Tsupply == 0) && (Ttakeup == 0)) { Transport_state = stop_state; if (!disable (CSL, error)) loger (TAPE_MNGR_TID, error); done = 1; } ScTdelay (MSEC_100); timeout += MSEC_100; } } suspect_tape = 0; } if (condition != last_condition) suspect_tape = 0; last_condition = condition; return(condition); } void police_tape (void) { int cur_status; cur_status = -1; if (nCSI && nCSLD) { if (!switch_delay) { DspReg &= 0xfb; if (!Tach_override) { switch (Transport_state) { case stop_state: if (Tsupply + Ttakeup > 30) cur_status = arrest_tape (9); break; case play_pending: case play_state: if (!nCGDD) if (Tidler < 2) if (!Tach_override) cur_status = arrest_tape (8); case stop_pending: case shuttle_pending: case shuttle_state: if (abs(Tidler - last_tidler) > 45) cur_status = arrest_tape (0); if (abs(Tsupply - last_tsupply) > 45) cur_status = arrest_tape (1); if (abs(Ttakeup - last_ttakeup) > 45) cur_status = arrest_tape (2); if (Tidler < 2) { if ((Tsupply + Ttakeup) > 30) cur_status = arrest_tape (3); } else if ((Ms_clock - Start_start_time) > 100) { if (Tsupply > 6) if (Ttakeup < 1) cur_status = arrest_tape (4); if (Ttakeup > 6) if (Tsupply < 1) cur_status = arrest_tape (5); } if (((Tsupply+Ttakeup) > 400) || (Tidler > 120)) cur_status = arrest_tape (13); break; default: break; } last_tidler = Tidler; last_tsupply = Tsupply; last_ttakeup = Ttakeup; } else if ((Tach_prepos) && (!tach_prepos_rdy)) { if (Tach_int_fault) { suspect_tape = 3; cur_status = arrest_tape (6); } if (abs(Tidler - last_tidler) > 90) cur_status = arrest_tape (10); if (abs(Tsupply - last_tsupply) > 200) cur_status = arrest_tape (11); if (abs(Ttakeup - last_ttakeup) > 200) cur_status = arrest_tape (12); if (((Tsupply+Ttakeup) > 500) || (Tidler > 120)) cur_status = arrest_tape (14); last_tidler = 0; last_tsupply = 0; last_ttakeup = 0; } else if (Tach_prepos) { if ((Tidler > 3) || (Tsupply + Ttakeup > 25)) cur_status = arrest_tape (7); last_tidler = Tidler; last_tsupply = Tsupply; last_ttakeup = Ttakeup; } DspReg |= 4; } else { last_tidler = Tidler; last_tsupply = Tsupply; last_ttakeup = Ttakeup; switch_delay--; } if (cur_status >= 0) suspect_tape++; else suspect_tape = 0; } } void post_debug (reel_types rl, float time, int flag) { if (Tach_debug) { if (rl == su_reel) { Fdebug1 = time; Tdebug1 = flag; Tdebug3 = r_cnt [!rl]; Sdebug1 = rspeed; post_status (status_msg, TAPE_MNGR_TID, 93); } else { Fdebug2 = time; Tdebug2 = flag; Tdebug4 = r_cnt [!rl]; Sdebug2 = rspeed; post_status (status_msg, TAPE_MNGR_TID, 94); } } } void tape_mngr (void) { int err, su_time, tu_time, msg; reel_estimate *pack_estimate; float tu_rev, su_rev; reel_state hold_state; unsigned char tach_timer_check, su_update, tu_update; Incr_tach_offset = -1; Idler_adjust = 1; test_pos = 28; speed_count = 0; speed_locked = 0; idler_depth = 0; tot_idler = 0.0; idler_speed = 0.0; Tach_state = r_init; local_err = 50; speed = 0.0; tach_timer_check = 0; last_speed = 0.0; while (1) { if (ScPend (Tach_box, err ,msg, MSEC_50)) { if (msg == 1) { tach_timer_check = 0; update_tach_position (); police_tape (); } else if (msg == 2) { if ((Transport_state == play_pending) || (Transport_state == shuttle_pending)) { if (Start_start_time - Ms_clock > 5) Stop_start_time = Ms_clock + ((Start_start_time - Ms_clock) / 2); else if (Transport_state == shuttle_pending) Stop_start_time = Ms_clock + 1317; else Stop_start_time = Ms_clock + 40; } else if (Transport_state == shuttle_state) Stop_start_time = Ms_clock + 1317; else if (Transport_state == play_state) Stop_start_time = Ms_clock + 40; Start_start_time = Ms_clock; Transport_state = stop_pending; } else if (msg == 3) { Start_start_time = Ms_clock + 1317 * 2; Transport_state = play_pending; Stop_start_time = Ms_clock; } else if (msg == 4) { Start_start_time = Ms_clock + 40; Transport_state = shuttle_pending; Stop_start_time = Ms_clock; } } else tach_timer_check++; update_idler_speed (); rspeed = idler_speed; hold_speed = idler_speed; if (((Tach_state == r_slow) && (Transport_state == play_state)) && ((Oai_state == oai_play) && ((Oai_play_ss == pss_steady_play) ||(Oai_play_ss ==pss_disengage) ||(Oai_play_ss ==pss_wait_disengage) ||(Oai_play_ss == pss_preposition))||(Oai_state == oai_record))) { if (current_track () >= 0) { if (last_cap_lock) rspeed = 5.2774; last_cap_lock++; } else last_cap_lock = 0; } else { if (last_cap_lock > 3) rspeed = 5.2774; last_cap_lock = 0; } if ((Oai_state == oai_play) && (Oai_play_ss == pss_steady_play)) if (!last_cap_lock) if (idler_depth < 20) rspeed = 5.2774; do { su_rev = extract_period (su_reel, su_time, tu_time); tu_rev = extract_period (tu_reel, tu_time, su_time); switch (Tach_state) { case r_init: pack_estimate = new reel_estimate; Tach_state = r_flywheel; break; case r_reset: pack_estimate->clear (); Tach_state = r_flywheel; break; case r_flywheel: if ((speed_locked) && (Tape_motion) && (!Force_flywheel) && (Eq_parms.mode == hold_m)) { if (Tspeed >= 15.0) { if (slow_mode) pack_estimate->begin (0); hold_state = r_fast; } else if (Tspeed < 15.0) { if ((!slow_mode)||(r_offset [su_reel]) || (r_offset [tu_reel])) pack_estimate->begin (1); hold_state = r_slow; } Tach_state = r_transition; } else if (Tspeed < 8.0) { if (No_estimate) { Pack_radius [su_reel] = Tach_radius [su_reel]; Pack_radius [tu_reel] = Tach_radius [tu_reel]; } if (!slow_mode) pack_estimate->begin (1); } else if (Tspeed >= 15.0) { if (slow_mode) pack_estimate->begin (0); } track_position (); break; case r_transition: track_position (); if (!speed_locked) { pack_estimate->begin(1); Tach_state = r_flywheel; } if ((speed_locked) && ((idler_speed > (Tspeed*0.9)) && (idler_speed < (Tspeed*1.1)))) { if ((Tspeed >= 15.0) && (slow_mode)) pack_estimate->begin (0); else if ((idler_speed > (5.2774*.9)) && (idler_speed < (5.2774*1.1)) && (!slow_mode)) pack_estimate->begin (1); if ((idler_depth > 8)||(!slow_mode)) Tach_state = hold_state; } else if ((Tspeed >= 15.0) && (slow_mode)) pack_estimate->begin (0); else if (!slow_mode) pack_estimate->begin (1); break; case r_fast: if ((speed_locked) && (idler_speed >= 8.0) &&(Transport_state == shuttle_state)) { if ((su_rev > 10.0) && (su_rev < 225.0)) { post_debug (su_reel, su_rev, 2); su_update = pack_estimate->update_reel (su_reel, su_rev, su_time, tu_time); Thickness = ref_thickness; } else if (su_rev != 0.0) { Tach_state = r_flywheel; pack_estimate->begin (1); } else su_update = 0; if ((tu_rev > 10.0) && (tu_rev < 225.0)) { post_debug (tu_reel, tu_rev, 2); tu_update = pack_estimate->update_reel (tu_reel, tu_rev, tu_time, su_time); Thickness = ref_thickness; } else if (tu_rev != 0.0) { Tach_state = r_flywheel; pack_estimate->begin (1); } else tu_update = 0; if ((speed_locked) && (Tach_state == r_fast) && (!first_sample [su_reel]) && (!first_sample [tu_reel])) { if (((new_estimate) && (su_update) && (tu_update)) || ((!new_estimate) && ((su_update) || (tu_update)))) update_position (); else track_position (); } else track_position (); } else { Thickness = ref_thickness; Tach_state = r_flywheel; if (Tspeed < 8.0) pack_estimate->begin (1); else pack_estimate->begin (0); } break; case r_slow: if ((speed_locked || (r_offset[su_reel] || r_offset[tu_reel])) && (rspeed > MIN_PLAY_SP) && (rspeed < MAX_PLAY_SP) && (Transport_state == play_state)) { if ((r_offset[su_reel])&&(su_rev != 0.0)) { r_offset[su_reel]--; post_debug (su_reel, su_rev, 1); su_time = 0; tu_time = 0; } else if ((su_rev > 40.0) && (su_rev < 390.0)) { if (Tach_prepos) Transport_state = play_state; post_debug (su_reel, su_rev, 0); su_update = pack_estimate->update_reel (su_reel, su_rev, su_time, tu_time); Thickness = ref_thickness; } else if (su_rev != 0.0) { if (!Tach_override) { pack_estimate->begin (1); Tach_state = r_flywheel; } } else su_update = 0; if ((r_offset[tu_reel])&&(tu_rev != 0.0)) { r_offset[tu_reel]--; post_debug (tu_reel, tu_rev, 1); su_time = 0; tu_time = 0; } else if ((tu_rev > 40.0) && (tu_rev < 390.0)) { if (Tach_prepos) Transport_state = play_state; post_debug (tu_reel, tu_rev, 0); tu_update = pack_estimate->update_reel (tu_reel, tu_rev, tu_time, su_time); Thickness = ref_thickness; } else if (tu_rev != 0.0) { if (!Tach_override) { Tach_state = r_flywheel; pack_estimate->begin (1); } } else tu_update = 0; if ((speed_locked) && (Tach_state == r_slow) && (!first_sample [su_reel]) && (!first_sample [tu_reel])) { if (((new_estimate) && (su_update) && (tu_update)) || ((!new_estimate) && ((su_update) || (tu_update)))) update_position (); else track_position (); } else track_position (); } else { if (((su_rev != 0.0) && (r_offset[su_reel])) || ((tu_rev != 0.0) && (r_offset[tu_reel]))) { if ((r_offset[su_reel]) && (su_rev != 0.0)) { // idler_depth = 0; r_offset [su_reel]--; post_debug (su_reel, su_rev, 2); } if ((r_offset[tu_reel]) && (tu_rev != 0.0)) { // idler_depth = 0; r_offset [tu_reel]--; post_debug (tu_reel, tu_rev, 2); } } else if (((su_rev != 0.0) || (tu_rev != 0.0)) || (Transport_state != play_state)) if (!Tach_override) { if (Tspeed > 8.0) pack_estimate->begin (0); else pack_estimate->begin (1); Thickness = ref_thickness; Tach_state = r_flywheel; } track_position (); } case r_prepos: break; default: break; } } while ((su_rev != 0.0) && (tu_rev != 0.0)); update_stop_estimate (rspeed); } }