Skip to content. | Skip to navigation

Personal tools

io.cpp

io.cpp

io.cpp

/////////////////////////////////////////////////////////////////////////////
// IO.CPP
//
//  Last updated: 03/29/2002
//
//  Part of the source code for the M3 Program
//
//  This file contains numerous low level I/O routines.
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
// SystemReset - Software based system reset function
void SystemReset()
// Perform a hardware reset on the system.
{
        outp(0x64,0xFE);
}

/////////////////////////////////////////////////////////////////////////////
// InitPorts - Function to configure the serial port parameters and install
// the serial interrupt driver
void InitPorts()
{
        //InitComPort(0,0x3F8,4,38400,"O71",1);
        // Use Com1: and Com2:
        InitComPort(0,0x3F8,4,34800,"O71",1);
#ifdef ENABLEIO
        InitComPort(1,0x2F8,3,19200,"N81",1);
#endif

}

/////////////////////////////////////////////////////////////////////////////
// RespondToHost - Transmit a string to the upstream host computer on COM1:
void RespondToHost(char *message)
// Send a message to the Host computer (upstream).
// The string "message" is transmitted.
// This routine automatically adds the correct Response and
// Address characters to the beginning of the string.
{
        char line[255]; // String buffer

        line[0] = Response;
        line[1] = Address;
        strcpy(&line[2],message);
        SerialBufPutString(Host,line);
        Log->AddX("IO(%d) [RespondToHost] Sent to host: \"%s\"",800,SHECGREEN,2,__LINE__,line);
}

/////////////////////////////////////////////////////////////////////////////
// VerifyChecksum: Verifies that the checksum in a string is correct
int VerifyChecksum(char* s)
// Returns a zero if the string's checksum is OK, and a 1 if not.
// Note that this routine expects a full message, i.e.
//  ":HdataCC" where data is the body of the message, and CC is the
//  checksum.
{
        int i,Checksum;
        char check[10];

        // Start checksum calculation with Site Utility address
        Checksum = Address;
        // Binary not all subsequent characters
        for (i=2;i<strlen(s)-2;i++)
                Checksum ^= s[i];
        // Reduce checksum to 1 byte
        Checksum &= 255;
        sprintf(check,"%02X",Checksum);
        if ((s[strlen(s)-2] == check[0]) && (s[strlen(s)-1] == check[1]))
                return(0);
        else
                return(1);
}

/////////////////////////////////////////////////////////////////////////////
// RespondToHostWithChecksum: Add a hex checksum + CR to string and send
void RespondToHostWithChecksum(char* s)
// Calculates the Shec-checksum for a string, and sends the
// string to the host computer (TCS)
{
        int i,Checksum;
        char s2[120];

        // Start checksum calculation with Vane End address
        Checksum = Address;
        // Binary not all subsequent characters
        for (i=0;i<strlen(s);i++)
                Checksum ^= s[i];
        // Reduce checksum to 1 byte
        Checksum &= 255;
        // Append checksum and a carriage return to the string given to us
        sprintf(s2,"%s%02X\r",s,Checksum);
        // Send total message to host
        RespondToHost(s2);
}

/////////////////////////////////////////////////////////////////////////////
// COMTerminal: opens a simple terminal with a com port
void COMTerminal(int Port)
// This routine acts as a simple terminal to a com port.
// It displays received characters, and transmits typed characters.
// Hitting ESC ends the terminal session.
{
        char c; // Holds received and typed characters

        CloseVideo();
        cprintf("Terminal on COM%d: (ESC to end)\r\n",Port+1);
        do
        {
                // Check for incoming serial characters
                if (SerialCharReady(Port))
                {
                        c = SerialGetChar(Port);
                        cprintf("%c",c);
                        if (c == 13)
                                cprintf("\n");
                }
                c = 0;
                // Check for outgoing characters
                if (kbhit())
                {
                        c = getch();
                        if (c != 27)
                        {
                                cprintf("%c",c);
                                if (c == '\r')
                                        cprintf("\n");
                                // Transmit the typed character
                                SerialPutChar(Port,c);
                        }
                }
        // Quit on an <ESC>
        } while (c != 27);
        InitVideo();
        InitDisplay();
}

/////////////////////////////////////////////////////////////////////////////
// InitHardwareIO - Initialize low-level I/O interfaces
void InitHardwareIO()
// Initialize the MESA analog card, digital IO card, and parallel port
{
        int i;

#ifdef ENABLEIO
        // Init digital IO card
        init_io(0x230);

        // Init analog IO card driver

  // DOS4GW real mode interrupt structure
        mesarmi = new TRMInfo;

        // Get a 256 byte buffer in low memory for MESAInfo
        AllocateDosMemory(16,&mesasegment,&mesaselector);
        MESAInfo = (TMESAInfo *)(mesasegment << 4);

        // Start conversions
        MESAInfo->FunctionNumber = 5;
        // 0: High Range (0-5V)  1: Low Range = 0-0.5V
        MESAInfo->Range = 0;
        // Call real mode interrupt
        MesaInterrupt();

        // Init parallel port
        outp(PARPORT,0xFF);
#endif

        PARVALUE = 0xFF;
        for (i=0;i<4;i++)
                AnalogHistoryCount[i] = 0;
}

/////////////////////////////////////////////////////////////////////////////
// CloseHardwareIO - Shut down all low-level I/O interfaces
void CloseHardwareIO()
// Halt analog card driver
{
#ifdef ENABLEIO
        // Stop conversions
        MESAInfo->FunctionNumber = 6;
        // 0: High Range (0-5V)  1: Low Range = 0-0.5V
        MESAInfo->Range = 0;
        // Call real mode interrupt
        MesaInterrupt();

        // Deallocate DOS memory previously allocated
        DeallocateDosMemory(mesaselector);

        delete mesarmi;
#endif

}

/////////////////////////////////////////////////////////////////////////////
// ReadAllAnalog - Query the MESA analog driver for updated values
void ReadAllAnalog()
// Read all analog channels and store in the global analog variables
{
        int i;
        int DataReady;  // Flag if new data is available
        int Channel;            // Channel of new analog data being read
        double ftemp;

#ifdef ENABLEIO
        do // Read all new data
        {
                // Check for new data
                MESAInfo->FunctionNumber = 3;
                // Call real mode interrupt
                MesaInterrupt();
                DataReady = MESAInfo->Status;
                if (DataReady)
                {
                        // Get FIFO data
                        MESAInfo->FunctionNumber = 11;
                        // Call real mode interrupt
                        MesaInterrupt();
                        Channel = MESAInfo->Channel;
                        // AnalogReadCount readings are taken and averaged before
                        // recording a new value.
                        AnalogHistory[Channel][AnalogHistoryCount[Channel]] = MESAInfo->Data;
                        AnalogHistoryCount[Channel]++;
                        if (AnalogHistoryCount[Channel] >= AnalogReadCount)
                        {
                                ftemp = 0.0;
                                for (i=0;i<AnalogReadCount;i++)
                                        ftemp += AnalogHistory[Channel][i];

//////////////////////////////////////////////////////////////////////////
// GRB 3/30/02: The Mesa returns analog values in microvolts,
// so we should divide by 1,000,000 to get volts.  We were dividing
// by 100,000.  I've left it as is for now.
//                              ftemp /= AnalogReadCount * 1000000.0;
                                ftemp /= AnalogReadCount * 100000.0;
        //                        AnalogData[Channel] = ftemp * a[Channel] + b[Channel];
        AnalogData[Channel] = ftemp;
                                AnalogHistoryCount[Channel] = 0;
                        }
                }
        } while (DataReady);
#endif

}

/////////////////////////////////////////////////////////////////////////////
// MesaInterrupt - Call the real-mode Mesa analog driver interrupt
void MesaInterrupt()
// Set the fields of MESAInfo appropriately, and call this routine.
// Results are in the MESAInfo structure.
{
        union REGS regs;

        // Call real mode interrupt
        memset(mesarmi,0,52);
        mesarmi->ECX = mesasegment;     // Segment of MESAInfo in real memory
  mesarmi->EBX = 0;                                             // Offset of MESAInfo in real memory
        regs.x.edi = (dword)mesarmi;// RMI structure for DOS4GW
        regs.w.bx = 0x61;                                               // MESA interrupt is 0x61
        regs.x.eax = 0x300;                                     // DPMI Real Mode Interrupt call
        regs.x.ecx = 0;                                                 // Don't copy any stack bytes
        int386(0x31,&regs,&regs);
}

/////////////////////////////////////////////////////////////////////////////
// SetParBit - Set a bit on the parallel port
void SetParBit(int bit)
// "bit" is from 0 to 7
{
        PARVALUE = PARVALUE | (1 << bit);
#ifdef ENABLEIO
        outp(PARPORT,PARVALUE);
#endif

}

/////////////////////////////////////////////////////////////////////////////
// ClrParBit - Clear a bit on the parallel port
void ClrParBit(int bit)
// "bit" is from 0 to 7
{
        PARVALUE = PARVALUE & (255 - (1 << bit));
#ifdef ENABLEIO
        outp(PARPORT,PARVALUE);
#endif

}

/////////////////////////////////////////////////////////////////////////////
// GetParBit - Get a bit on the parallel port
int GetParBit(int bit)
// "bit" is from 0 to 7
// Returns a 0 or 1 if bit "bit" is cleared or set on the parallel port.
// (Note that this doesn't actually read the parallel port, it just
// returns what has already been written.  There are only parallel port
// outputs in the M3 design, no inputs.
{
        return(PARVALUE & (1 << bit));
}

/////////////////////////////////////////////////////////////////////////////
// SetDigBit - Set a bit on the UIO48 digital IO card
void SetDigBit(int bit)
// "bit" is from 1 to 48
{
#ifdef ENABLEIO
        write_bit(bit,1);
#endif

}

/////////////////////////////////////////////////////////////////////////////
// Clear a bit on the UIO48 digital IO card
void ClrDigBit(int bit)
// "bit" is from 1 to 48
{
#ifdef ENABLEIO
        write_bit(bit,0);
#endif

}

/////////////////////////////////////////////////////////////////////////////
// Get a bit on the UIO48 digital IO card
int GetDigBit(int bit)
// "bit" is from 1 to 48
// Returns a 0 or 1 if bit "bit" is cleared or set
{
#ifdef ENABLEIO
        return(read_bit(bit));
#else

        return(0);
#endif

}

/////////////////////////////////////////////////////////////////////////////
// SetStepperPhase - Set a steppers motor phase before motor current-on
void SetStepperPhase(int StepBit,int DirBit,int MonBit,int MonSteps)
// StepBit,DirBit,MonBit: the digital I/O bits for Step, Direction, and
// phase for the stepper whose phase needs to be set.  MonSteps is the
// number of steps to send to the driver before enabling current to the
// motor, a number from -9 to 9
{
  int count = 0;

  // Step forward
  SetDigBit(DirBit);
  // Wait for the Moni bit to come on
  while (!GetDigBit(MonBit) && (count <= 10))
  {
    SetDigBit(StepBit);
    Delay(1);
    ClrDigBit(StepBit);
    Delay(1);
    count++;
  }

  // We don't seem to be communicating with the stepper driver
  if (!GetDigBit(MonBit))
    EDSLog.Add(1,"SetStepperPhase: %s bit not responding",DigIONames[MonBit-1]);

  // We're at the Moni-on phase, now step to our last recorded phase

  // Set direction
  if (MonSteps < 0)
    ClrDigBit(DirBit);

  // Go
  MonSteps = abs(MonSteps);
  while (MonSteps > 0)
  {
    SetDigBit(StepBit);
    Delay(1);
    ClrDigBit(StepBit);
    Delay(1);
    MonSteps--;
  }
}

/////////////////////////////////////////////////////////////////////////////
// StepperPowerOn - Turn power on to steppers after setting motor phases
int StepperPowerOn()
// Turn on power to M3 Turret, ADC Turret, and Tilt Steppers.  This routine
// sets the motor phases correctly (with current to the motors off) before
// enabling current to the motors to avoid power-on jerks.
// If StepperPowerOn returns a 1, call StepperPowerOnStage2 one second later.
{
  // Don't turn on power if power is already on.
  if (!StepperPowerFlag)
  {
    // Turn current off to the steppers we're enabling
    // Tilt Current off
    ClrParBit(0);
    // M3 Turret Current off
    ClrParBit(1);
    // ADC Turret Current off
    ClrParBit(2);
    // Power on
    ClrParBit(5);
    StepperPowerFlag = 1;
    return(1);
  }
  // Keep track of how many processes are using the stepper power
  // (ie, if the M3 Turret and Tilts are both active, and one asks
  // to turn the power off, don't, until the other has also asked
  // to turn power off.
  StepperPowerFlag++;
  return(0);
}

/////////////////////////////////////////////////////////////////////////////
// StepperPowerOnStage2 - Set motor phases
void StepperPowerOnStage2()
{
  int i;

  // Prepare to apply current to the M3 Turret
  // Set the stepper driver to the correct phase before applying current
  SetStepperPhase(MTBitStep,MTBitDir,MTBitMon,M3Turret->MonStep);
  // M3 Turret Current on
  SetParBit(1);
  // Prepare to apply current to the ADC Turret
  // Set the stepper driver to the correct phase before applying current
  SetStepperPhase(ATBitStep,ATBitDir,ATBitMon,ADCTurret->MonStep);
  // ADC Turret Current on
  SetParBit(2);
  // Prepare to apply current to the three Tilt steppers
  // Set the stepper drivers to the correct phases
  for (i=0;i<=2;i++)
    SetStepperPhase(TBitStep[i],TBitDir[i],TBitMon[i],Tilt.MonStep[i]);
  // Tilt Current On
  SetParBit(0);
}

/////////////////////////////////////////////////////////////////////////////
// StepperPowerOff - Turn off power to M3 Turret, ADC Turret, and Tilt Steppers
void StepperPowerOff(int MotionOK)
// If MotionOK = 0, power will not be turned off if M3 Turret,
// ADC Turret, or Tilts are moving.
{
  if (!MotionOK && (M3Turret->Moving || ADCTurret->Moving ||
        Tilt.Moving[0] || Tilt.Moving[1] || Tilt.Moving[2]))
    return;
  // Power off if everyone's done with stepper power
  if (StepperPowerFlag > 0)
    StepperPowerFlag--;
  if (StepperPowerFlag == 0)
    SetParBit(5);  // Power off
}

/////////////////////////////////////////////////////////////////////////////
// StepperPowerOffNow - Turn off power to M3 Turret, ADC Turret, and Tilt Steppers
void StepperPowerOffNow()
{
  // Power off regardless if anyone's using the steppers
  StepperPowerFlag = 0;
  SetParBit(5);  // Power off
}

/////////////////////////////////////////////////////////////////////////////
// ADCStepperPowerOn - Turn on power to ADC A and B after setting motor phases
int ADCStepperPowerOn()
// Turn on power to ADC Rotators.  This routine
// sets the motor phases correctly (with current to the motors off) before
// enabling current to the motors to avoid power-on jerks.
// If ADCStepperPowerOn returns a 1, call ADCStepperPowerOnStage2 one second later.
// Similar to StepperPowerOn
{
  // Don't turn on power if power is already on.
  if (!ADCStepperPowerFlag)
  {
    // Turn current off to the steppers we're enabling
    // ADC A+B current off
    ClrParBit(3);

    // ADC A+B Power on
    ClrParBit(4);
    ADCStepperPowerFlag = 1;
    return(1);
  }
  // Keep track of how many processes are using the stepper power
  // (ie, if ADCA and ADCB are both active, and one asks
  // to turn the power off, don't, until the other has also asked
  // to turn power off.
  ADCStepperPowerFlag++;
  return(0);
}

/////////////////////////////////////////////////////////////////////////////
// ADCStepperPowerOnStage2 - Set ADC A and B motor phases
void ADCStepperPowerOnStage2()
{
  int Curr;
  // Prepare to apply current to ADC A+B

  // Set the stepper driver to the correct phase before applying current
  SetStepperPhase(ADCABitStep,ADCABitDir,ADCABitMon,ADCA.MonStep);
  SetStepperPhase(ADCBBitStep,ADCBBitDir,ADCBBitMon,ADCB.MonStep);
  // ADC A+B Current on
  SetParBit(3);
}

/////////////////////////////////////////////////////////////////////////////
// ADCStepperPowerOff - Turn off power to ADC A + B
void ADCStepperPowerOff(int MotionOK)
// If MotionOK = 0, power will not be turned off if ADCA or ADCB are moving.
{
  if (!MotionOK && ((ADCA.Moving) || (ADCB.Moving)))
    return;
  // Power off if everyone's done with stepper power
  if (ADCStepperPowerFlag > 0)
    ADCStepperPowerFlag--;
  if (ADCStepperPowerFlag == 0)
    SetParBit(4);  // Power off
}

/////////////////////////////////////////////////////////////////////////////
// ADCStepperPowerOffNow - Turn off power to ADC A + B
void ADCStepperPowerOffNow()
{
  // Power off regardless if anyone's using the steppers
  SetParBit(4);
  ADCStepperPowerFlag = 0;
}

Generated by GNU Enscript 1.6.5.2.
Document Actions