#include "../ioaddr.c" /*definitions for using the smc800-card This card uses 74HC574 as puffer/latches, and a gal, which is addressable in an easy way. The generally latched settings for the halfstep-values uses only 6bit, and 4 bits for steering. ##############################################*/ /*halfstep signals smc800 with gal-addressing*/ #define SMCHSTEP1 0x27 #define SMCHSTEP2 0x2d #define SMCHSTEP3 0x1c #define SMCHSTEP4 0x0d #define SMCHSTEP5 0x03 #define SMCHSTEP6 0x09 #define SMCHSTEP7 0x38 #define SMCHSTEP8 0x29 /* here the values for the smc-halfstepaddressing hex 0x27 dec 39 bin 00100111 ( bit 7,6,5,4,3,2,1,0 ) hex 0x2d dec 45 bin 00101101 hex 0x1c dec 28 bin 00011100 hex 0x0d dec 13 bin 00001101 hex 0x03 dec 3 bin 00000011 hex 0x09 dec 9 bin 00001001 hex 0x38 dec 56 bin 00111000 hex 0x29 dec 41 bin 00101001 the addressing for the smc800 gal ist to set bit 7,and 6 to 00 for X=az 01 for y=alt 10 for z=fr */ /*standby signals smc800 with gal-addressing (20percent max-current) currently we do not use it, but it makes sense for further using less power. */ #define SMCSSTEP1 0x37 #define SMCSSTEP2 0x36 #define SMCSSTEP3 0x1e #define SMCSSTEP4 0x16 #define SMCSSTEP5 0x13 #define SMCSSTEP6 0x12 #define SMCSSTEP7 0x3a #define SMCSSTEP8 0x32 /* hex 0x37 dec 55 bin 00110111 hex 0x36 dec 54 bin 00110110 hex 0x1e dec 30 bin 00011110 hex 0x16 dec 22 bin 00010110 hex 0x13 dec 19 bin 00010011 hex 0x12 dec 18 bin 00010010 hex 0x3a dec 58 bin 00111010 hex 0x32 dec 50 bin 00110010 */ #define SMCPENUP 0x9b #define SMCPENDOWN 0x87 /* The pen-up/down functionality of the card is currently not used, but we show, if we can implement it. hex 0x9b dec 155 bin 10011011 hex 0x87 dec 135 bin 10000111 */ /*definitions for raw-parallel-using ######################################*/ /*halfstep signals are low-active when using raw parallelsignals. these are the preferred version, because we can puffer the signals with Inverters 7404 .., and using a lot of accessible ready-boards. */ #define PHSTEP1 14 #define PHSTEP2 10 #define PHSTEP3 11 #define PHSTEP4 9 #define PHSTEP5 13 #define PHSTEP6 5 #define PHSTEP7 7 #define PHSTEP8 6 /* bin: -- all signals are low-active --- this means a 0 is on, a 1 is off. bit 0, and bit 2 are the first winding bit 1, and bit 3 the second. ( bit 3,2,1,0 for az, and fr, bit 7,6,5,4 for alt ). hstep 1 1110 ( full w1 ) hstep 2 1010 ( half w1,w1 ) hstep 3 1011 ( full w2 ) hstep 4 1001 ( half w1,w2 ) hstep 5 1101 ( full w2 ) hstep 6 0101 ( half w2,w2 ) hstep 7 0111 ( full w2 ) hstep 8 0110 ( half w2,w1 ) */ /* for the fr-drive we must lookf for the inverted pins C0,C1,C3 (Bit 0,1,3) only bit 2 is normally 1=high. */ #define PFRHSTEP1 5 #define PFRHSTEP2 1 #define PFRHSTEP3 0 #define PFRHSTEP4 2 #define PFRHSTEP5 6 #define PFRHSTEP6 14 #define PFRHSTEP7 12 #define PFRHSTEP8 13 /* The inverted signals for the Controloutputs of the paralleport C0,C1,C3 will be correct automatically. */ /* DATAS #############################################*/ unsigned char rawazalthsteps[9] = {PHSTEP1,PHSTEP2,PHSTEP3,PHSTEP4,PHSTEP5,PHSTEP6,PHSTEP7,PHSTEP8 , 0}; unsigned char rawfrhsteps[9] = {PFRHSTEP1,PFRHSTEP2,PFRHSTEP3,PFRHSTEP4,PFRHSTEP5,PFRHSTEP6,PFRHSTEP7,PFRHSTEP8 , 0}; unsigned char smchsteps[9] = {SMCHSTEP1,SMCHSTEP2,SMCHSTEP3,SMCHSTEP4,SMCHSTEP5,SMCHSTEP6,SMCHSTEP7,SMCHSTEP8,0 }; /*we implement it for further standby settings - currently not used*/ unsigned char smcssteps[9] = {SMCSSTEP1,SMCSSTEP2,SMCSSTEP3,SMCSSTEP4,SMCSSTEP5,SMCSSTEP6,SMCSSTEP7,SMCSSTEP8,0 }; unsigned char * azhstepsptr = &rawazalthsteps[0]; unsigned char * althstepsptr = &rawazalthsteps[0]; unsigned char * frhstepsptr = &rawfrhsteps[0]; int azhstepoffset = 0; int althstepoffset = 0; int frhstepoffset = 0; unsigned char azaltprevval = 0xff; pthread_t parallelthread; pthread_attr_t parallelthread_attr; struct sched_param parallelsched; int parconnection = 0; /* datas for running the parallelportmachine */ /*########################################## */ int pmc_az_motor = 0; int pmc_alt_motor = 0; int pmc_fr_motor = 0; int pmc_az_dir = 0; int pmc_alt_dir = 0; int pmc_fr_dir = 0; double pmc_az_pos = 0.0; double pmc_alt_pos = 0.0; double pmc_fr_pos = 0.0; double pmc_az_evt = 0.0; double pmc_alt_evt = 0.0; double pmc_fr_evt = 0.0; long pmc_az_speed = 0; long pmc_alt_speed = 0; long pmc_fr_speed = 0; long pmc_az_speedct = 0; long pmc_alt_speedct = 0; long pmc_fr_speedct = 0; long pmc_speed_ct = 0; int parsubtype = IF_PARALLELSUBRAW; /* This is called once a time parallellloop is started, and every time encoders are set to active, when not active before*/ void par_init_encoders( void ) { /* unsigned char val; if(encoder.type == PARALLELENCODER){ val = read_parallelencoders(); } else { if(encoder.type == JOYSTICKENCODER){ val = read_joystickencoders(); } else { return; } } encoders_calculate( val, -1, -1 ); */ } /* read the ports, and updates encoder.azpulse, and encoder.altpulse */ int par_encoderread( double azhs, double alths ) { /* unsigned char val; if(encoder.type == PARALLELENCODER){ val = read_parallelencoders(); } else { if(encoder.type == JOYSTICKENCODER){ val = read_joystickencoders(); } else { return(1); } } return(encoders_calculate( val, azhs, alths )); */ return(1); } void parhstepout( int az, int azleft, int alt, int altdown, int fr, int frleft ) { unsigned char azstep,altstep,frstep,azaltstep; azstep = 0; altstep = 0; frstep = 0; azaltstep = 0; if(az){ if(azleft){ if( azhstepoffset < 0 ){ azhstepoffset = 7; } else { if( azhstepoffset > 7 ){ azhstepoffset = 7; } } } else { if(azhstepoffset > 7 ){ azhstepoffset = 0; } else { if(azhstepoffset < 0 ){ azhstepoffset = 0; } } } azstep = azhstepsptr[azhstepoffset]; if(azleft){ azhstepoffset--; } else { azhstepoffset++; } } if(alt){ if(altdown){ if( althstepoffset < 0 ){ althstepoffset = 7; } else { if( althstepoffset > 7 ){ althstepoffset = 7; } } } else { if(althstepoffset > 7 ){ althstepoffset = 0; } else { if(althstepoffset < 0 ){ althstepoffset = 0; } } } altstep = althstepsptr[althstepoffset]; if(altdown){ althstepoffset--; } else { althstepoffset++; } } if(fr){ if(frleft){ if( frhstepoffset < 0 ){ frhstepoffset = 7; } else { if( frhstepoffset > 7 ){ frhstepoffset = 7; } } } else { if(frhstepoffset > 7 ){ frhstepoffset = 0; } else { if(frhstepoffset < 0 ){ frhstepoffset = 0; } } } frstep = frhstepsptr[frhstepoffset]; if(frleft){ frhstepoffset--; } else { frhstepoffset++; } } if(parsubtype == IF_PARALLELSUBSMC ){ if(azstep){ write_port( azstep, parallelport ); /* i don't know if we really use the waiting, but perhaps in the future, we have software with nanoseconds-working :-) */ // ctrif_waitmicrosecs( 1 ); /*latch it*/ write_port( 1, parallelport + 2 ); write_port( 0, parallelport + 2); } if(altstep){ write_port( altstep + 64, parallelport ); // ctrif_waitmicrosecs( 1 ); write_port( 1, parallelport + 2 ); write_port( 0, parallelport + 2); } if(frstep){ write_port( frstep + 128, parallelport ); // ctrif_waitmicrosecs( 1 ); write_port( 1, parallelport + 2 ); write_port( 0, parallelport + 2); } } else { azaltstep = azaltprevval; if(azstep){ azstep = azstep & 0x0f; azaltstep = azaltstep & 0xf0; azaltstep = azaltstep | azstep; } if(altstep){ altstep = altstep << 4; altstep = altstep & 0xf0; azaltstep = azaltstep & 0x0f; azaltstep = azaltstep | altstep; } if( azstep || altstep ){ /* do out azaltstep*/ write_port( azaltstep , parallelport ); azaltprevval = azaltstep; } if(frstep){ frstep = frstep & 0x0f; /* do out frstep*/ write_port( frstep , parallelport + 2 ); } } /*set current position, and stop if target reached for GOTO */ if(azstep){ if(azleft){ pmc_az_pos = pmc_az_pos - 1.0; if( pmc_az_pos < 0.0 ){ pmc_az_pos = elctr.hs_az360; } } else { pmc_az_pos = pmc_az_pos + 1.0; if( pmc_az_pos > elctr.hs_az360 ){ pmc_az_pos = 0.0; } } if( az == MGOTO ){ pmc_az_evt = pmc_az_evt - 1.0; if( pmc_az_evt <= 0.0 ){ pmc_az_motor = MNORUN; } } /* if(! par_encoderread( pmc_az_pos, -1)){ pmc_az_pos = encoder.correctazhs; } */ } if(altstep){ if(altdown){ pmc_alt_pos = pmc_alt_pos - 1.0; if( pmc_alt_pos < elctr.hs_altlb ){ pmc_alt_motor = MNORUN; } } else { pmc_alt_pos = pmc_alt_pos + 1.0; if(pmc_alt_pos > elctr.hs_altub ) { pmc_alt_motor = MNORUN; } } if( alt == MGOTO ){ pmc_alt_evt = pmc_alt_evt - 1.0; if( pmc_alt_evt <= 0.0 ){ pmc_alt_motor = MNORUN; } } /* if(! par_encoderread( -1, pmc_alt_pos )){ pmc_alt_pos = encoder.correctalths; } */ } if(frstep){ if(frleft){ pmc_fr_pos = pmc_fr_pos - 1.0; if( pmc_fr_pos < 0.0 ){ pmc_fr_pos = elctr.hs_fr360; } } else { pmc_fr_pos = pmc_fr_pos + 1.0; if( pmc_fr_pos > elctr.hs_fr360 ){ pmc_fr_pos = 0.0; } } } } /* #### threaded loop - machinesimulation ############################## ##################################################################### */ void parallelloop ( char *data ) { int azm,altm,frm; /* par_init_encoders(); encoders_reset(0,0); */ parconnection = 1; while( parconnection ) { if( ( elctr.motorrun == MGOTO ) && ( pmc_az_motor == MNORUN ) && ( pmc_alt_motor == MNORUN ) ){ elctr.motorrun = MNORUN; } ctrif_waitmicrosecs( pmc_speed_ct ); azm = MNORUN; altm = MNORUN; frm = MNORUN; if( ( pmc_az_motor != MNORUN ) && ( elctr.motorrun == pmc_az_motor ) ) { pmc_az_speedct++; if(pmc_az_speedct >= pmc_az_speed){ pmc_az_speedct = 0; azm = pmc_az_motor; } } if( ( pmc_alt_motor != MNORUN ) && ( elctr.motorrun == pmc_alt_motor ) ) { pmc_alt_speedct++; if(pmc_alt_speedct >= pmc_alt_speed){ pmc_alt_speedct = 0; altm = pmc_alt_motor; } } if( ( pmc_fr_motor != MNORUN ) && ( elctr.motorrun == pmc_fr_motor ) ){ pmc_fr_speedct++; if(pmc_fr_speedct >= pmc_fr_speed ) { pmc_fr_speedct = 0; frm = pmc_fr_motor; } } if( ( ! azm ) && ( ! altm ) && ( ! frm ) ) { continue; } parhstepout( azm, pmc_az_dir, altm, pmc_alt_dir, frm, pmc_fr_dir ); } parconnection = 0; } /* #### HIGH LEVEL INTERFACECALLS ####################################### ###################################################################### */ int par_openConnection( void ) { if(parconnection){ return(1); } /* is set by default if(parsubtype == IF_PARALLELSUBRAW ){ azhstepsptr = &rawazalthsteps[0]; althstepsptr = &rawazalthsteps[0]; frhstepsptr = &rawfrhsteps[0]; } */ if(parsubtype == IF_PARALLELSUBSMC ){ azhstepsptr = &smchsteps[0]; althstepsptr = &smchsteps[0]; frhstepsptr = &smchsteps[0]; } pmc_az_motor = MNORUN; pmc_alt_motor = MNORUN; pmc_fr_motor = MNORUN; azaltprevval = 0xff; write_port( 1, azaltprevval ); write_port( 1, 0x04 ); /* Be aware, don't do this currently - its very dangerous. If you will use parallelport, you must start program as root, to get permissions for this port. So, there are non-blocked operations i've currently not sorted out. If you use this commented code, - the complete system will be hang-up. You only can restart computer. So - be warned !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! I' will try to make this operation to a real-time operation, so i've set this code for reminding. Currently we have to start program as root, with a high nicevalue. If there are problems with not proper running motors, we have to start program with sudo nice -20 eltel. if( elctr.uid == 0 ){ parallelsched.sched_priority = 0; if( pthread_attr_init( ¶llelthread_attr ) != 0 ){ return( 0 ); } if( pthread_attr_setschedpolicy( ¶llelthread_attr, SCHED_RR ) != 0 ){ return( 0 ); } if( pthread_attr_setschedparam( ¶llelthread_attr, ¶llelsched ) != 0 ){ return( 0 ); } if( pthread_create( ¶llelthread, ¶llelthread_attr , (void *)¶llelloop, NULL ) != 0 ){ return( 0 ); } } else { if( pthread_create( ¶llelthread, NULL , (void *)¶llelloop, NULL ) != 0 ){ return( 0 ); } } */ /* Currently we have to start program with a higher nice value as root. So we create a normal thread. With a upper 200 Mhz Machine, this will currently useable, but not the last word. */ if( pthread_create( ¶llelthread, NULL , (void *)¶llelloop, NULL ) != 0 ){ return( 0 ); } return(1); } int par_closeConnection( void ) { pmc_az_motor = MNORUN; pmc_alt_motor = MNORUN; pmc_fr_motor = MNORUN; parconnection = 0; return(1); } int par_stopMotors( void ) { if( ! parconnection ) { return(0); } pmc_az_motor = MNORUN; pmc_alt_motor = MNORUN; pmc_fr_motor = MNORUN; return(1); } double par_getCurrentAzKoor(void) { if( ! parconnection ) { return(-1.0); } return( makeAbsoluteDouble( pmc_az_pos ) ); } double par_getCurrentAltKoor(void) { if( ! parconnection ) { return(-1.0); } return(makeAbsoluteDouble( pmc_alt_pos ) ); } double par_getCurrentFrKoor(void) { if( ! parconnection ) { return(-1.0); } return(makeAbsoluteDouble( pmc_fr_pos ) ); } int par_CorrectionMode( int spd, double azsp, int azdir, double altsp, int altdir, double frsp, int frdir ) { if( ! parconnection ) { return(0); } pmc_az_motor = MNORUN; pmc_alt_motor = MNORUN; pmc_fr_motor = MNORUN; pmc_az_dir = 0; pmc_alt_dir = 0; pmc_fr_dir = 0; if(spd == SPEED_SLOW){ pmc_speed_ct = (long)makeAbsoluteDouble(elctr.timerintct_correction); } if(spd == SPEED_FAST){ pmc_speed_ct = (long)makeAbsoluteDouble(elctr.timerintct_goto); } if(azsp >= 0.0 ){ pmc_az_speed = (long)makeAbsoluteDouble(azsp); pmc_az_speedct = 0; pmc_az_dir = azdir; elctr.azleft = azdir; pmc_az_motor = MCORRECTION; } if(altsp >= 0.0 ){ pmc_alt_speed = (long)makeAbsoluteDouble(altsp); pmc_alt_speedct = 0; pmc_alt_dir = altdir; elctr.altdown = altdir; pmc_alt_motor = MCORRECTION; } if(frsp > 0.0 ){ pmc_fr_speed = (long)makeAbsoluteDouble(frsp); pmc_fr_speedct = 0; pmc_fr_dir = frdir; pmc_fr_motor = MCORRECTION; } return(1); } int par_Goto( double azhs , double alths ) { double curaz,curalt; double newaz,newalt; double azevt,altevt; if( ! parconnection ) { return(0); } pmc_az_motor = MNORUN; pmc_alt_motor = MNORUN; pmc_fr_motor = MNORUN; pmc_az_dir = 0; pmc_alt_dir = 0; pmc_fr_dir = 0; pmc_speed_ct = (long)makeAbsoluteDouble(elctr.timerintct_goto); pmc_az_speed = (long)makeAbsoluteDouble(elctr.az_gotospeed); pmc_alt_speed = (long)makeAbsoluteDouble(elctr.alt_gotospeed); pmc_az_speedct = 0; pmc_alt_speedct = 0; curaz = pmc_az_pos; curalt = pmc_alt_pos; newaz = makeAbsoluteDouble( azhs ); newalt = makeAbsoluteDouble( alths ); if( curaz != newaz ){ if(newaz > elctr.hs_az360){ return(0); } elctr.azleft = 0; pmc_az_motor = MGOTO; if( ( curaz >= 0 ) && ( curaz < elctr.hs_az180 ) ){ //scope is current between 0 and 180 degrees if( ( newaz >= 0 ) && ( newaz < elctr.hs_az180 ) ){ //new azval is in the same sector if(newaz < curaz){ pmc_az_dir = 1; // turn left azevt = curaz - newaz; elctr.azleft = 1; } else { // turn right azevt = newaz - curaz; } } else { //new azval is in the opposite sector //normally turn right azevt = newaz - curaz; if( ( curaz < elctr.hs_az90) && ( newaz >= elctr.hs_az270 ) ){ //scope is current between 0 and 90 degrees //and new az also north pmc_az_dir = 1; // turn left azevt = ( elctr.hs_az360 - newaz ) + curaz; elctr.azleft = 1; } } } else { // scope is cuurrent between 180 and 360 degrees if( ( newaz >= elctr.hs_az180 ) && ( newaz <= elctr.hs_az360 ) ){ //new azval is in the same sector if(newaz < curaz){ pmc_az_dir = 1; // turn left azevt = curaz - newaz; elctr.azleft = 1; } else { //turn right azevt = newaz - curaz; } } else { // new azval is in the opposite sector if( ( curaz >= elctr.hs_az270 ) && ( newaz < elctr.hs_az90 ) ){ //scope is current between 270 and 360 degrees //and new az also north // turn right azevt = ( elctr.hs_az360 - curaz ) + newaz; } else { //normally turn left pmc_az_dir = 1; azevt = curaz - newaz; elctr.azleft = 1; } } } } if(curalt != newalt ) { if(newalt <= elctr.hs_altlb){ return(0); } if(newalt >= elctr.hs_altub){ return(0); } elctr.altdown = 0; pmc_alt_motor = MGOTO; if( newalt < curalt ){ //turn down pmc_alt_dir = 1; altevt = curalt - newalt; elctr.altdown = 1; } else { //turn up altevt = newalt - curalt; } } pmc_az_evt = azevt; pmc_alt_evt = altevt; return(1); } int par_ResetKoors( double azhs, double alths ) { if( ! parconnection ) { return(0); } pmc_az_pos = makeAbsoluteDouble( azhs ); pmc_alt_pos = makeAbsoluteDouble( alths ); return(1); } /* makes one step per motor ( az, alt, fr - set to 1 what you use, otherwise 0) to direction ( azleft, frleft 0 = right, 1 = left, altdown 0 = up, 1 = down ) function gets new halfstepvalues for az,alt, if answer if set to 1, and sets *azhs,*alths to this. In mostly case when using az,alt this should be use in every case, for knowing if step is ready done. For only using fr, this makes mostly no sense. ms is a little timer in microsecs. Sometimes we need a little wait after doing halfsteps, for beeing sure, steps are ready. ( Escpecially for parallel interface ). */ int par_Step( int answer, int az, int azleft, int alt, int altdown, int fr, int frleft, double * azhs, double * alths, long ms ) { int azm,altm,frm; if( ! parconnection ) { return(0); } pmc_az_motor = MNORUN; pmc_alt_motor = MNORUN; pmc_fr_motor = MNORUN; azm = MNORUN; altm = MNORUN; frm = MNORUN; if(az){ elctr.azleft = 0; if(azleft){ elctr.azleft = 1; } azm = MCORRECTION; } if(alt){ elctr.altdown = 0; if(altdown){ elctr.altdown = 1; } altm = MCORRECTION; } if(fr){ frm = MCORRECTION; } if( azm || altm || frm ) { parhstepout( azm, azleft, altm, altdown, frm, frleft ); /* A minimum wait we must install, for the case we do more then one step. Here we have no timeing as in the goto, correction thread. If we do not wait this minimum time, a direct following next step will be handled before the previous is done ready. */ if(ms > 0 ){ ctrif_waitmicrosecs( ms ); } if(answer){ *azhs = pmc_az_pos; *alths = pmc_alt_pos; } pmc_az_motor = MNORUN; pmc_alt_motor = MNORUN; pmc_fr_motor = MNORUN; } return(1); }