예제 #1
0
파일: drag.c 프로젝트: jbmulligan/quip
void _make_dragg(QSP_ARG_DECL  const char *name,Data_Obj *bm,Data_Obj *dp)
{
	Draggable *dgp;

	if( !dp_same_size(bm,dp,"make_dragg") ){
		warn("image/bitmap size mismatch");
		return;
	}
	if( OBJ_PREC(bm) != PREC_BIT ){
		sprintf(ERROR_STRING,"Object %s has precision %s, should be %s",
			OBJ_NAME(bm),PREC_NAME(OBJ_PREC_PTR(bm)),
			PREC_NAME(PREC_FOR_CODE(PREC_BIT)));
		warn(ERROR_STRING);
		return;
	}
	if( OBJ_PREC(dp) != PREC_BY && OBJ_PREC(dp) != PREC_UBY ){
		sprintf(ERROR_STRING,"Image %s (for draggable object) has %s precision, should be %s or %s",
			OBJ_NAME(dp),PREC_NAME(OBJ_PREC_PTR(dp)),
			PREC_NAME(PREC_FOR_CODE(PREC_BY)),
			PREC_NAME(PREC_FOR_CODE(PREC_UBY)) );
		warn(ERROR_STRING);
		return;
	}

	dgp = new_dragg(name);
	if( dgp == NULL ) return;

	dgp->dg_width = (int) OBJ_COLS(dp);
	dgp->dg_height = (int) OBJ_ROWS(dp);
	dgp->dg_bitmap = bm;
	dgp->dg_image = dp;
	dgp->dg_np = mk_node(dgp);
}
예제 #2
0
파일: cu2_menu.c 프로젝트: E-LLP/QuIP
static PF_COMMAND_FUNC( centroid )
{
	Data_Obj *dst1_dp;
	Data_Obj *dst2_dp;
	Data_Obj *src_dp;
	Vec_Obj_Args oargs;

	dst1_dp = PICK_OBJ("x scratch image");
	dst2_dp = PICK_OBJ("y scratch image");
	src_dp = PICK_OBJ("source image");

	if( OBJ_MACH_PREC(src_dp) != PREC_SP && OBJ_MACH_PREC(src_dp) != PREC_DP ){
		sprintf(ERROR_STRING,"Object %s (%s) must have %s or %s precision for centroid helper",
			OBJ_NAME(src_dp),PREC_NAME(OBJ_PREC_PTR(src_dp)),PREC_NAME(PREC_FOR_CODE(PREC_SP)),
			PREC_NAME(PREC_FOR_CODE(PREC_DP)));
		WARN(ERROR_STRING);
		return;
	}

	// BUG - do more checking here sizes must match, precisions must match.

	setvarg3(&oargs,dst1_dp,dst2_dp,src_dp);	/* abusing this a little */

	if( OBJ_PREC(src_dp) == PREC_SP )
		sp_cu2_centroid(&oargs);
	else if( OBJ_PREC(src_dp) == PREC_DP )
		dp_cu2_centroid(&oargs);
#ifdef CAUTIOUS
	else ERROR1("CAUTIOUS:  centroid:  unexpected source precision!?");
#endif /* CAUTIOUS */
}
예제 #3
0
파일: acquire.c 프로젝트: nasa/QuIP
void convert_polh_vector(Data_Obj *flt_dp,Data_Obj *polh_dp)
{
	uint32_t i,j;
	short *rpdp;
	float *cvt_p;
	Fmt_Pt fp1;
	int station;

	if( OBJ_PREC(flt_dp) != PREC_SP ){
		sprintf(ERROR_STRING,"convert_polh_data:  object %s has precision %s, should be %s",
				OBJ_NAME(flt_dp),PREC_NAME(OBJ_PREC_PTR(flt_dp)),PREC_NAME(prec_for_code(PREC_SP)));
		warn(ERROR_STRING);
		return;
	}
	if( OBJ_COLS(flt_dp) != OBJ_COLS(polh_dp) ){
		sprintf(ERROR_STRING,"convert_polh_data:  vectors %s (%d) and %s (%d) do not have the same number of columns",
				OBJ_NAME(flt_dp),OBJ_COLS(flt_dp),OBJ_NAME(polh_dp),OBJ_COLS(polh_dp));
		warn(ERROR_STRING);
		return;
	}
	/* BUG should make sure that tdim of flt_dp is correct! */

	/* assume that the object has already been checked for proper dim, type... */

	if( n_active_stations == 2 )
		station=0;
	else if(n_active_stations < 1 ){
		warn("format_polh_vector:  no active stations!?");
		return;
	} else
		station=curr_station_idx;

	rpdp = (short *) OBJ_DATA_PTR(polh_dp);

	for(i=0;i<OBJ_COLS(polh_dp);i++){
		Polh_Record_Format *prfp;

		cvt_p = ((float *) OBJ_DATA_PTR(flt_dp)) + i * OBJ_PXL_INC(flt_dp);

		prfp = &station_info[station].sd_multi_prf;
		format_polh_data(&fp1,rpdp,prfp);
		for(j=0;j<prfp->rf_n_data;j++){
			Polh_Output_Type type;
			type = prfp->rf_output[j];
			convert_chunk(cvt_p,&fp1,type);
			cvt_p += od_tbl[type].od_strings;	/* BUG not the right variable?... */
		}
		rpdp += prfp->rf_n_words;
		if( n_active_stations == 2 )
			station ^= 1;
	}
}
예제 #4
0
파일: acquire.c 프로젝트: nasa/QuIP
static int parse_polh_reading( QSP_ARG_DECL  Data_Obj *dp, char * s )
{
	char str[32];
	float *f_p;

#ifdef QUIP_DEBUG
if( debug & debug_polhemus ){
sprintf(ERROR_STRING,"parse_polh_reading \"%s\"",show_printable(DEFAULT_QSP_ARG  s));
advise(ERROR_STRING);
}
#endif /* QUIP_DEBUG */

	if( OBJ_PREC(dp) != PREC_SP ){
		sprintf(ERROR_STRING,"Object %s has %s precision, should be %s",
			OBJ_NAME(dp),
			PREC_NAME(OBJ_PREC_PTR(dp)),
			PREC_NAME(prec_for_code(PREC_SP)) );
		warn(ERROR_STRING);
		return(-1);
	}
	if( ! IS_CONTIGUOUS(dp) ){
		sprintf(ERROR_STRING,"Object %s should be contiguous",OBJ_NAME(dp));
		warn(ERROR_STRING);
		return(-1);
	}
	if( OBJ_N_MACH_ELTS(dp) < 6 ){
		sprintf(ERROR_STRING,"Object %s should have at least 6 elements",OBJ_NAME(dp));
		warn(ERROR_STRING);
		return(-1);
	}

	f_p = OBJ_DATA_PTR(dp);

	if( sscanf(s,"%s %f %f %f %f %f %f",str,
		f_p+0,
		f_p+1,
		f_p+2,
		f_p+3,
		f_p+4,
		f_p+5
		) != 7 ){
		sprintf(ERROR_STRING,"Error scanning polhemus data string");
		warn(ERROR_STRING);
		sprintf(ERROR_STRING,"String:  \"%s\"",show_printable(DEFAULT_QSP_ARG  s));
		advise(ERROR_STRING);
		return(-1);
	}
	return(0);
}
예제 #5
0
파일: wav.c 프로젝트: jbmulligan/quip
FIO_DP_TO_FT_FUNC(wav,Wav_Header)
{
	/* num_frame set when when write request given */

	/* BUG questionable cast */
	hd_p->wh_n_channels = (short) OBJ_COMPS(dp);
	switch( OBJ_MACH_PREC(dp) ){
		case PREC_UBY:
			hd_p->wh_bits_per_sample = 8;
			break;
		case PREC_IN:
			hd_p->wh_bits_per_sample = 16;
			break;
		default:
			sprintf(ERROR_STRING,
		"dp_to_wav:  vector %s has unsupported source precision %s",
				OBJ_NAME(dp),PREC_NAME(OBJ_MACH_PREC_PTR(dp)));
			warn(ERROR_STRING);
			return(-1);
			break;
	}
			
	hd_p->wh_datasize = OBJ_N_TYPE_ELTS(dp) * PREC_SIZE( OBJ_MACH_PREC_PTR(dp) );
	hd_p->wh_chunksize = 36 + hd_p->wh_datasize;

	/* BUG dp's don't have a way to carry around the sample rate with them??? */
	/* So we assume that the current sample rate is the one that corresponds
	 * to this object BUG
	 */
	hd_p->wh_samp_rate = (*samp_rate_func)();
	hd_p->wh_blk_align = hd_p->wh_n_channels * hd_p->wh_bits_per_sample / 8;
	hd_p->wh_bytes_per_sec = hd_p->wh_blk_align * hd_p->wh_samp_rate;

	return 0;
}
예제 #6
0
파일: glmenu.c 프로젝트: nasa/QuIP
void set_texture_image(QSP_ARG_DECL  Data_Obj *dp)
{
	int code,prec;
	/*glDepthFunc(GL_LEQUAL);
		glPixelStorei(GL_UNPACK_ALIGNMENT,1);*/

	if(OBJ_COMPS(dp)==1) code=GL_LUMINANCE;
	else if( OBJ_COMPS(dp) == 3 ) code=GL_RGB;
	else {
		sprintf(ERROR_STRING,
			"set_texture_image:  Object %s has type dimension %d, expected 1 or 3",
			OBJ_NAME(dp),OBJ_COMPS(dp));
		warn(ERROR_STRING);
		return;
	}

	if( OBJ_PREC(dp) == PREC_SP ) prec=GL_FLOAT;
	else if( OBJ_PREC(dp) == PREC_UBY ) prec=GL_UNSIGNED_BYTE;
	else {
		sprintf(ERROR_STRING,"set_texture_image:  Object %s has precision %s, expected %s or %s",
			OBJ_NAME(dp),PREC_NAME(OBJ_PREC_PTR(dp)),
			NAME_FOR_PREC_CODE(PREC_SP),NAME_FOR_PREC_CODE(PREC_UBY));
		warn(ERROR_STRING);
		return;
	}

	if( debug & gl_debug ) advise("glTexImage2D");
	glTexImage2D(GL_TEXTURE_2D, 0, OBJ_COMPS(dp), OBJ_COLS(dp),
		OBJ_ROWS(dp), 0, code, prec, OBJ_DATA_PTR(dp));

	if( debug & gl_debug ) advise("glTexParameterf (4)");
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	if( debug & gl_debug ) advise("glTexEnv");
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	/*glEnable(GL_TEXTURE_2D);
		glShadeModel(GL_FLAT);*/
}
예제 #7
0
파일: vl_menu.c 프로젝트: jbmulligan/quip
static void _vf_info(QSP_ARG_DECL  Vector_Function *vfp)
{
	int i;
	int n_printed=0;

	sprintf(msg_str,"Vector function %s:",VF_NAME(vfp));
	prt_msg(msg_str);

#define MAX_PER_LINE	4

	prt_msg_frag("\tallowable precisions:");
	for(i=0;i<N_MACHINE_PRECS;i++){
		if( VF_PRECMASK(vfp) & (1<<i) ){
			/* BUG?  is 0 a legal precision code? it is PREC_NONE... */
			sprintf(msg_str,"%s%s",
			(n_printed>=MAX_PER_LINE?",\n\t\t\t": (n_printed>0?", ":"")),
			PREC_NAME(prec_for_code(i)) );
			prt_msg_frag(msg_str);
			if( n_printed >= MAX_PER_LINE ) n_printed=0;
			n_printed++;
		}
	}
	prt_msg("");
	prt_msg_frag("\tallowable types:");
	n_printed=0;
	for(i=0;i<N_ARGSET_TYPES;i++){
		if( VF_TYPEMASK(vfp) & VL_TYPE_MASK(i) ){
			sprintf(msg_str,"%s%s",
			n_printed>0?", ":"",
			number_type_name[i]);
			prt_msg_frag(msg_str);
			n_printed++;
		}
	}
	prt_msg("");
}
예제 #8
0
파일: dumptree.c 프로젝트: jbmulligan/quip
static void _dump_node_basic(QSP_ARG_DECL  Vec_Expr_Node *enp)
{
	Tree_Code code;
	int i;
	const char *s;

	if( enp==NULL ) return;

	/* print the node "name", and a code that tells about shape knowledge */

// Temporarily print to stderr instead of stdout for debugging...
	prt_node(enp,msg_str);
	prt_msg_frag(msg_str);

	if( SHOWING_LHS_REFS ){
		sprintf(msg_str,"\t%d",VN_LHS_REFS(enp));
		prt_msg_frag(msg_str);
	}

	if( SHOWING_COST ){
		if( VN_SHAPE(enp) != NULL ){
			sprintf(msg_str,"\t%d", SHP_N_MACH_ELTS(VN_SHAPE(enp)));
		}

		prt_msg_frag(msg_str);

		sprintf(msg_str,"\t%d\t%d", VN_FLOPS(enp),VN_N_MATH(enp));
		prt_msg_frag(msg_str);
	}

	if( IS_CURDLED(enp) ){
		sprintf(msg_str,"\t%s (curdled!?)", NNAME(enp));
		prt_msg(msg_str);
		return;
	}

	sprintf(msg_str,"\t%s", NNAME(enp));
	prt_msg_frag(msg_str);

	/* print the special op-dependent args in human-readable form */

	code = VN_CODE(enp);

	if( code==T_DYN_OBJ || code == T_UNDEF || code == T_PROTO || code==T_POINTER || code==T_FUNCPTR || code==T_STR_PTR ){
		sprintf(msg_str,"\t%s",VN_STRING(enp));
		prt_msg_frag(msg_str);
		if( code == T_POINTER ){
			Identifier *idp;
			/* We don't use get_set_ptr() here because we don't want an error msg... */
			idp = id_of(VN_STRING(enp));
			if( idp != NULL && IS_POINTER(idp) && POINTER_IS_SET(idp) ){
				if( PTR_REF(ID_PTR(idp)) == NULL ){
					/* how could this ever happen??? */
					prt_msg_frag("->???");
				} else {
					Data_Obj *dp;
					dp = REF_OBJ(PTR_REF(ID_PTR(idp)));
					sprintf(msg_str,"->%s",OBJ_NAME(dp));
					prt_msg_frag(msg_str);
				}
			}
		}
	} else if( code == T_STATIC_OBJ ){
		sprintf(msg_str,"\t%s",OBJ_NAME(VN_OBJ(enp)));
		prt_msg_frag(msg_str);
#ifdef SCALARS_NOT_OBJECTS
	} else if( code == T_SCALAR_VAR ){
		sprintf(msg_str,"\t%s",VN_STRING(enp));
		prt_msg_frag(msg_str);
#endif // SCALARS_NOT_OBJECTS
	} else if ( code == T_FUNCREF ){
		Subrt *srp;
		srp=VN_SUBRT(enp);
		sprintf(msg_str,"\t%s",SR_NAME(srp));
		prt_msg_frag(msg_str);
	} else if( code == T_SIZE_FN ){
		sprintf(msg_str,"\t%s",FUNC_NAME(VN_FUNC_PTR(enp)));
		prt_msg_frag(msg_str);
	}
#ifdef NOT_YET
	else if(code == T_CALL_NATIVE ){
		// was kw_token???
		// curr_native_func_tbl...
		sprintf(msg_str,"\t%s",FUNC_NAME(VN_FUNC_PTR(enp)));
		prt_msg_frag(msg_str);
	}
#endif /* NOT_YET */
	else if(code == T_TYPECAST ){
		// BUG not how we do precision any more!!!
		//sprintf(msg_str,"  %s",NAME_FOR_PREC_CODE(VN_INTVAL(enp)));
        if( VN_SHAPE(enp) == NULL ) error1("CAUTIOUS:  null node shape for typecast node!?");
        else {
            sprintf(msg_str,"  %s",PREC_NAME(VN_PREC_PTR(enp)));
            prt_msg_frag(msg_str);
        }
    } else if( code == T_SUBRT_DECL || code == T_SCRIPT ){
		Subrt *srp;
		srp=VN_SUBRT(enp);
		sprintf(msg_str,"\t%s",SR_NAME(srp));
		prt_msg_frag(msg_str);
	} else if( code==T_DECL_STAT ){
		//sprintf(msg_str," %s",NAME_FOR_PREC_CODE(VN_INTVAL(enp)));
		sprintf(msg_str," %s",PREC_NAME(VN_DECL_PREC(enp)));
		prt_msg_frag(msg_str);
	} else if( IS_DECL(code) ){
		sprintf(msg_str," %s",VN_STRING(enp));
		prt_msg_frag(msg_str);
	} else if( code==T_ADVISE ){
		/* BUG need to elim yylex_qsp */
		s=eval_string(VN_CHILD(enp,0));
		sprintf(msg_str,"\t\"%s\"",s);
		prt_msg_frag(msg_str);
	} else if( code==T_WARN ){
		/* BUG need to elim yylex_qsp */
		s=eval_string(VN_CHILD(enp,0));
		sprintf(msg_str,"\t\"%s\"",s);
		prt_msg_frag(msg_str);
	} else if( code==T_STRING ){
		sprintf(msg_str,"\t\"%s\"",VN_STRING(enp));
		prt_msg_frag(msg_str);
	} else if( code == T_LABEL || code ==T_GO_BACK || code == T_GO_FWD ){
		sprintf(msg_str," %s",VN_STRING(enp));
		prt_msg_frag(msg_str);
	} else if( code==T_LIT_DBL ){
		sprintf(msg_str," %g",VN_DBLVAL(enp));
		prt_msg_frag(msg_str);
	} else if( code == T_MATH0_FN ){
		sprintf(msg_str," %s",FUNC_NAME(VN_FUNC_PTR(enp)));
		prt_msg_frag(msg_str);
	} else if( code == T_MATH1_FN ){
		sprintf(msg_str," %s",FUNC_NAME(VN_FUNC_PTR(enp)));
		prt_msg_frag(msg_str);
	} else if( code == T_MATH2_FN ){
		sprintf(msg_str," %s",FUNC_NAME(VN_FUNC_PTR(enp)));
		prt_msg_frag(msg_str);
	} else if (
		   code == T_MATH0_VFN
		|| code == T_MATH1_VFN
		|| code == T_MATH2_VFN
		|| code == T_MATH2_VSFN
		|| code == T_CHAR_VFN
			/* BUG? shouldn't there bre a VSFN2 ??? */
		|| code == T_VS_FUNC
		|| code == T_VV_FUNC
		){
		sprintf(msg_str," %s",VF_NAME(FIND_VEC_FUNC(VN_VFUNC_CODE(enp))));
		prt_msg_frag(msg_str);
	} else if( code==T_CALLFUNC ){
assert(VN_SUBRT(enp)!=NULL);
		sprintf(msg_str," %s", SR_NAME(VN_SUBRT(enp)));
		prt_msg_frag(msg_str);
	} else if( code==T_LIT_INT ){
		sprintf(msg_str," %"PRId64, VN_INTVAL(enp) );
		prt_msg_frag(msg_str);
	} else if( code==T_ASSIGN ){
		prt_msg_frag("\t");
	} else if( code==T_MAXVAL ){
		prt_msg_frag("\t");
	} else if( code==T_MINVAL ){
		prt_msg_frag("\t");
	} else if( code==T_RAMP ){
		prt_msg_frag("\t");
	}

	/* Now print the addresses of the child nodes */

	if( VN_CHILD(enp,0)!=NULL){
		sprintf(msg_str,"\t\tn%d",VN_SERIAL(VN_CHILD(enp,0)));
		prt_msg_frag(msg_str);
	}
	for(i=1;i<MAX_CHILDREN(enp);i++){
		if( VN_CHILD(enp,i)!=NULL){
			sprintf(msg_str,", n%d",VN_SERIAL(VN_CHILD(enp,i)));
			prt_msg_frag(msg_str);
		}
	}
	prt_msg("");

	if( SHOWING_SHAPES && VN_SHAPE(enp) != NULL ){
		prt_msg_frag("\t");
		if( OWNS_SHAPE(enp) ){
			sprintf(msg_str,"* 0x%lx  ",(u_long)VN_SHAPE(enp));
			prt_msg_frag(msg_str);
		}
		else {
			sprintf(msg_str,"@ 0x%lx  ",(u_long)VN_SHAPE(enp));
			prt_msg_frag(msg_str);
		}
		prt_msg_frag("\t");
		describe_shape(VN_SHAPE(enp));
	}

	if( SHOWING_RESOLVERS && VN_RESOLVERS(enp)!=NULL ){
		Node *np; Vec_Expr_Node *enp2;
		prt_msg("\tResolvers:");
		np=QLIST_HEAD(VN_RESOLVERS(enp));
		while(np!=NULL){
			enp2=(Vec_Expr_Node *)NODE_DATA(np);
			sprintf(msg_str,"\t\t%s",node_desc(enp2));
			prt_msg(msg_str);
			np=NODE_NEXT(np);
		}
	}
}
예제 #9
0
// This function allows us to do a different mapping of the image...
static void map_cuda_viewer(QSP_ARG_DECL  Cuda_Viewer *cvp,
				Data_Obj *img_dp, Data_Obj *coord_dp) 
{
	if( OBJ_PREC(coord_dp) != PREC_SP ){
		sprintf(ERROR_STRING,
	"map_cuda_viewer:  coord object %s must have %s precision!?",
			OBJ_NAME(coord_dp),PREC_NAME(OBJ_PREC_PTR(coord_dp)));
		WARN(ERROR_STRING);
		return;
	}
	if( ! IS_CONTIGUOUS(coord_dp) ){
		sprintf(ERROR_STRING,
	"map_cuda_viewer:  coord object %s must be contiguous!?",
			OBJ_NAME(coord_dp));
		WARN(ERROR_STRING);
		return;
	}
	if( OBJ_COMPS(coord_dp) != 2 ){
		sprintf(ERROR_STRING,
	"map_cuda_viewer:  coord object %s must have 2 components!?",
			OBJ_NAME(coord_dp));
		WARN(ERROR_STRING);
		return;
	}
	if( OBJ_COLS(coord_dp) != 2 ){
		sprintf(ERROR_STRING,
	"map_cuda_viewer:  coord object %s must have 2 columns!?",
			OBJ_NAME(coord_dp));
		WARN(ERROR_STRING);
		return;
	}
	if( OBJ_ROWS(coord_dp) != 2 ){
		sprintf(ERROR_STRING,
	"map_cuda_viewer:  coord object %s must have 2 rows!?",
			OBJ_NAME(coord_dp));
		WARN(ERROR_STRING);
		return;
	}

#ifdef HAVE_OPENGL
	float *f;

	prepare_image_for_mapping(img_dp);

	f=(float *)OBJ_DATA_PTR(coord_dp);

	glBegin(GL_QUADS);
fprintf(stderr,"first vertex at %f, %f (normally -1, -1)\n",f[0],f[1]);
	glTexCoord2f(0, 1); glVertex2f( f[0], f[1] );	// -1, -1
fprintf(stderr,"second vertex at %f, %f (normally -1,  1)\n",f[4],f[5]);
	glTexCoord2f(0, 0); glVertex2f( f[4], f[5] );	// -1,  1
fprintf(stderr,"third vertex at %f, %f (normally  1,  1)\n",f[6],f[7]);
	glTexCoord2f(1, 0); glVertex2f( f[6], f[7] );	//  1,  1
fprintf(stderr,"fourth vertex at %f, %f (normally  1, -1)\n",f[2],f[3]);
	glTexCoord2f(1, 1); glVertex2f( f[2], f[3] );	//  1, -1
	glEnd();
	glBindTexture(GL_TEXTURE_2D, 0);

	cuda_display_finish(QSP_ARG  img_dp);
#else // ! HAVE_OPENGL
	NO_OGL_MSG
#endif // ! HAVE_OPENGL
}
예제 #10
0
파일: genlock.c 프로젝트: nasa/QuIP
static void test_parport(void)
{
	int n,s;
	Data_Obj *dp;
	u_long *lp;
	FB_Info *fbip;
	pthread_attr_t attr1;
	VBoard_Info vbi1;
	PPort_Info ppti1;
	u_long l;

	pthread_attr_init(&attr1);	/* initialize to default values */
	pthread_attr_setinheritsched(&attr1,PTHREAD_INHERIT_SCHED);


	fbip = pick_fbi("frame buffer for VSYNC");
	dp = pick_obj("data vector for latencies");

	if( fbip == NULL || dp == NULL ) return;

	INSIST_RAM_OBJ(dp,"test_parport")

	if( OBJ_PREC(dp) != PREC_UDI ){
		sprintf(ERROR_STRING,"latency vector %s (%s) should have precision %s",
			OBJ_NAME(dp),PREC_NAME(OBJ_PREC_PTR(dp)),
				NAME_FOR_PREC_CODE(PREC_UDI));
		WARN(ERROR_STRING);
		return;
	}

	if( OBJ_COMPS(dp) != 2 ){
		sprintf(ERROR_STRING,"latency vector %s (%d) should have 2 components",
			OBJ_NAME(dp),OBJ_COMPS(dp));
		WARN(ERROR_STRING);
		return;
	}

	if( ! IS_CONTIGUOUS(dp) ){
		sprintf(ERROR_STRING,"latency vector %s should be contiguous",OBJ_NAME(dp));
		WARN(ERROR_STRING);
		return;
	}

	n = OBJ_N_MACH_ELTS(dp)/2;
	lp = (u_long *) OBJ_DATA_PTR(dp);

	vbi1.vbi_fbip = fbip;
	vbi1.vbi_buf = lp;
	vbi1.vbi_count = n;
	vbi1.vbi_inc = 2;
#ifdef THREAD_SAFE_QUERY
	vbi1.vbi_qsp = THIS_QSP;
#endif // THREAD_SAFE_QUERY

	lp ++;

	if( the_ppp == NULL ){
		the_ppp=open_parport(NULL);	/* use default */
		if( the_ppp == NULL ) return;
	}

	ppti1.ppti_ppp = the_ppp;
	ppti1.ppti_buf = lp;
	ppti1.ppti_count = n;
	ppti1.ppti_inc = 2;

	tvp = NULL;				/* force re-zero */

	s=read_til_transition(the_ppp,8);
	if( s==0 )
		s=read_til_transition(the_ppp,8);
	/* should now be in the one state */
	/* this is the end of the (negative) pulse */

	l = delta_usecs();	/* zero the clock */

	pthread_create(&vboard_thr,&attr1,vboard_daemon,&vbi1);
	pthread_create(&pport_thr,&attr1,pport_logger,&ppti1);

	/* should wait for threads here... */
	if( pthread_join(vboard_thr,NULL) != 0 ){
		perror("pthread_join");
		WARN("error joining video board thread");
	}
	if( pthread_join(pport_thr,NULL) != 0 ){
		perror("pthread_join");
		WARN("error joining parallel port thread");
	}
}