Exemple #1
0
 private void checkBoxEnableHeadPower_CheckedChanged(object sender, EventArgs e)
 {
     if (inSetHeadPower)
     {
         return;
     }
     inSetHeadPower = true;
     if (status.Connected)
     {
         eRET rVal = PrinterInterfaceCLS.PiSetHeadPower(checkBoxEnableHeadPower.Checked ? 1 : 0);
         if (rVal != eRET.RVAL_OK)
         {
             MessageBox.Show("PiSetHeadPower failed with " + rVal.ToString() +
                             "\n\nPlease check that all PCC cards are connected and have completed initialisation",
                             Application.ProductName,
                             MessageBoxButtons.OK,
                             MessageBoxIcon.Asterisk);
             checkBoxEnableHeadPower.Checked = false;
         }
         else
         {
             // Prevent further PiSetHeadPower commands being sent until the status reports HeadPowerIdle
             checkBoxEnableHeadPower.Enabled = false;
         }
     }
     inSetHeadPower = false;
 }
Exemple #2
0
 /// <summary>
 /// Disconnect from the Meteor Printer Interface if currently connected.
 /// Should be called before the application exits.
 /// </summary>
 public void Disconnect()
 {
     if (Connected)
     {
         PrinterInterfaceCLS.PiAbort();
         WaitNotBusy();
         PrinterInterfaceCLS.PiClosePrinter();
         Connected = false;
     }
 }
Exemple #3
0
 /// <summary>
 /// Set up the printer prior to starting a print job.
 ///
 /// PiSetAndValidateParam blocks until the parameters have been successfully set (or have failed to set
 /// - e.g. if there is an out of range value).
 ///
 /// This must be used here in preference to the asynchronous method PiSetParam to guarantee that the
 /// values are set in Meteor before the print job is started.
 ///
 /// </summary>
 /// <returns>Success / failure</returns>
 private bool SetupPrinter()
 {
     if (PrinterInterfaceCLS.PiSetAndValidateParam((int)eCFGPARAM.CCP_PRINT_CLOCK_HZ, UserPrintClock) != eRET.RVAL_OK)
     {
         return(false);
     }
     if (PrinterInterfaceCLS.PiSetAndValidateParam((int)eCFGPARAM.CCP_BITS_PER_PIXEL, UserBitsPerPixel) != eRET.RVAL_OK)
     {
         return(false);
     }
     return(true);
 }
Exemple #4
0
 /// <summary>
 /// Polls the Printer Interface until it finishes the previous control command
 /// Use timeoutms to specify how long to wait in ms, default is 10000ms.
 /// For example, the Printer Interface will remain busy after a
 /// PiAbort until the abort has completed in Meteor.
 /// Note that the interface does not become busy as a result of a call to
 /// PiSendCommand.
 /// </summary>
 /// <param name="timeoutms">Timeout in milliseconds.  Defaults to ten seconds.</param>
 public bool WaitNotBusy(int timeoutms = 10000)
 {
     while (PrinterInterfaceCLS.PiIsBusy())
     {
         Thread.Sleep(100);
         if ((timeoutms -= 100) <= 0)
         {
             return(false);
         }
     }
     return(true);
 }
Exemple #5
0
 /// <summary>
 /// Abort any in-progress print job
 /// </summary>
 private void AbortPrintJob()
 {
     // No longer starting a job
     bJobStarting = false;
     bJobAborting = true;
     // Update display status and refresh, as the abort can take a few seconds
     buttonStopPrint.Enabled = false;
     buttonStopPrint.Refresh();
     textBoxStatus.Text = PRINTER_STATUS.ABORTING.ToString();
     textBoxStatus.Refresh();
     // Send the abort command to Meteor.  This will halt any in-progress
     // print, and clear out all print buffers
     PrinterInterfaceCLS.PiAbort();
     // Wait until the abort has completed
     Cursor.Current = Cursors.WaitCursor;
     status.WaitNotBusy();
     Cursor.Current = Cursors.Default;
 }
Exemple #6
0
        /// <summary>
        /// Query the head and auxiliary temperatures for the given pcc / head
        /// </summary>
        /// <param name="pccnum">pcc index (1-max)</param>
        /// <param name="hnum">head index (1-max)</param>
        /// <param name="temperature1">set with the head temperature</param>
        /// <param name="temperature2">set with the aux temperature</param>
        /// <returns>success / failure</returns>
        public bool GetHeadTemperature(int pccnum, int hnum, out int temperature1, out int temperature2)
        {
            TAppHeadStatus HeadStatus;

            if (PrinterInterfaceCLS.PiGetHeadStatus(pccnum, hnum, out HeadStatus) == eRET.RVAL_OK)
            {
                // Convert from 0.1 degrees to degrees and round
                temperature1 = (int)(((double)HeadStatus.Temperature1 / 10.0) + 0.5);
                temperature2 = (int)(((double)HeadStatus.Temperature2 / 10.0) + 0.5);
                return(true);
            }
            else
            {
                temperature1 = 0;
                temperature2 = 0;
                return(false);
            }
        }
Exemple #7
0
        /// <summary>
        /// See if we can access PrinterInterfaceCLS.  If not, look in the registry and see where Meteor
        /// is installed, add this to the path, and try again.
        /// </summary>
        static private bool DoLocatePrinterInterface()
        {
            // See if we can call into the Printer Interface.  This will drill down into the
            // underlying unmanaged PrinterInterface.dll.
            try {
                PrinterInterfaceCLS.PiGetBuildNumber();
            }

            // If both the managed (PrinterInterfaceCLS.dll) and unmanaged (PrinterInterface.dll) components
            // were found, there's nothing to do.  If just the managed component is found, we must add the
            // API folder to the environment path of the current process.
            catch (DllNotFoundException) {
                string apipath = GetMeteorAPIPath();
                if (apipath != null)
                {
                    string envpath = Environment.GetEnvironmentVariable("PATH");
                    Console.WriteLine("MeteorPath: Adding '" + apipath + "' to local environment PATH");
                    envpath = apipath + ";" + envpath;
                    Environment.SetEnvironmentVariable("PATH", envpath);

                    // Try again
                    try {
                        PrinterInterfaceCLS.PiGetBuildNumber();
                    }
                    catch (Exception e) {
                        Console.WriteLine("MeteorPath: Exception + " + e.Message);
                        return(false);
                    }
                }
                else
                {
                    Console.WriteLine("MeteorPath: Install folder not found");
                    return(false);
                }
            }

            // Unhandled exception
            catch (Exception e) {
                Console.WriteLine("MeteorPath: Exception + " + e.Message);
                return(false);
            }

            return(true);
        }
Exemple #8
0
 /// <summary>
 /// Check whether any of the PCCs in the system are in the process of turning head
 /// power on or off.  Should only be called when all required PCCs are connected.
 /// Sets the value of HeadPowerIdle.
 /// </summary>
 private void CheckHeadPowerIdle()
 {
     for (int pccNum = 1; pccNum <= PccsRequired; pccNum++)
     {
         TAppPccStatus pccStatus;
         eRET          rVal = PrinterInterfaceCLS.PiGetPccStatus(pccNum, out pccStatus);
         if (rVal != eRET.RVAL_OK)
         {
             HeadPowerIdle = false;
             return;
         }
         if ((pccStatus.bmStatusBits2 & Bmps.BMPS2_HEAD_POWER_IN_PROGRESS) != 0)
         {
             HeadPowerIdle = false;
             return;
         }
     }
     HeadPowerIdle = true;
 }
Exemple #9
0
        /// <summary>
        /// Send the print job to Meteor.  When the method returns, all print data has been
        /// sent to Meteor - however, it has not necessarily all been sent to the hardware.
        /// </summary>
        /// <returns>Success / failure</returns>
        public eRET Start()
        {
            eRET rVal;

            // Meteor command to start a print job
            int[] StartJobCmd = new int[] {
                (int)CtrlCmdIds.PCMD_STARTJOB,  // Command ID
                4,                              // Number of DWORD parameters
                jobid,                          // Job ID
                (int)eJOBTYPE.JT_PRELOAD,       // This job uses the preload data path
                (int)eRES.RES_HIGH,             // Print at full resolution
                image.GetDocWidth() + 2         // Needed for Left-To-Right printing only
            };

            // A start job command can fail if there is an existing print job
            // ready or printing in Meteor, or if a previous print job is still
            // aborting.  The sequencing of the main form's control enables should
            // guarantee that thie never happens in this application.
            if ((rVal = PrinterInterfaceCLS.PiSendCommand(StartJobCmd)) != eRET.RVAL_OK)
            {
                return(rVal);
            }
            // The start document command specifies the number of discrete copies
            // of the image which are required
            //
            int[] StartDocCmd = new int[] {
                (int)CtrlCmdIds.PCMD_STARTPDOC, // Command ID
                1,                              // DWORD parameter count
                repeatmode == (REPEAT_MODE.DISCRETE) ? copies : 1
            };
            if ((rVal = PrinterInterfaceCLS.PiSendCommand(StartDocCmd)) != eRET.RVAL_OK)
            {
                return(rVal);
            }
            // For seamless image repeats using the prelod data path, PCMD_REPEAT
            // must be sent after PCMD_STARTPDOC and before the image data.
            //
            if (copies > 1 && repeatmode == REPEAT_MODE.SEAMLESS)
            {
                int[] RepeatCmd = new int[] {
                    (int)CtrlCmdIds.PCMD_REPEAT,    // Command ID
                    1,                              // DWORD parameter cound
                    copies
                };
                if ((rVal = PrinterInterfaceCLS.PiSendCommand(RepeatCmd)) != eRET.RVAL_OK)
                {
                    return(rVal);
                }
            }
            // PCMD_BIGIMAGE must be used if the application needs to pass images
            // which exceed 60MB in size to Meteor as one buffer.  (An alternative
            // is for the application to split up the data into smaller images,
            // each of which can used PCMD_IMAGE).
            //
            // The image data is sent through the Printer Interface to the Meteor
            // Print Engine in chunks.  The application must continually call
            // PiSendCommand with the same buffer while the Print Engine
            // returns RVAL_FULL.
            //
            // Note that it is necessary to fix the location of the image command
            // in memory while carrying out this sequence, to prevent the garbage
            // collector from relocating the buffer (theoretically possible, but
            // highly unlikely) between successive PiSendCommand calls.
            //
            int[] ImageCmd = image.GetBigImageCommand(ytop, bpp);
            unsafe
            {
                fixed(int *pImageCmd = ImageCmd)
                {
                    do
                    {
                        rVal = PrinterInterfaceCLS.PiSendCommand(ImageCmd);
                    } while (rVal == eRET.RVAL_FULL);
                    if (rVal != eRET.RVAL_OK)
                    {
                        return(rVal);
                    }
                }
            }
            int[] EndDocCmd = new int[] { (int)CtrlCmdIds.PCMD_ENDDOC, 0 };
            if ((rVal = PrinterInterfaceCLS.PiSendCommand(EndDocCmd)) != eRET.RVAL_OK)
            {
                return(rVal);
            }
            int[] EndJobCmd = new int[] { (int)CtrlCmdIds.PCMD_ENDJOB, 0 };
            if ((rVal = PrinterInterfaceCLS.PiSendCommand(EndJobCmd)) != eRET.RVAL_OK)
            {
                return(rVal);
            }
            return(eRET.RVAL_OK);
        }
Exemple #10
0
        /// <summary>
        /// Called periodically to handle Meteor initialisation and status
        /// </summary>
        private void HandleMeteorStatus()
        {
            // Get the Meteor status / open a connection to Meteor if one doesn't
            // already exist
            PRINTER_STATUS Status = status.GetStatus();

            if (Status == PRINTER_STATUS.READY ||
                Status == PRINTER_STATUS.PRINTING ||
                Status == PRINTER_STATUS.DISCONNECTED)
            {
                bJobStarting = false;
            }
            else
            {
                bJobAborting = false;
            }
            latestPrinterStatus = Status;
            // Update the head/aux temperature setpoints if the values in the inteface
            // have been changed
            if (status.Connected)
            {
                if (lastSetHeadTemperature != UserHeadTemperature)
                {
                    // Set target head temperature globally (PiSetParam with pcc = 0, head = 0)
                    if (PrinterInterfaceCLS.PiSetParam((int)eCFGPARAM.CCP_HEAD_TEMP, UserHeadTemperature) == eRET.RVAL_OK)
                    {
                        lastSetHeadTemperature = UserHeadTemperature;
                    }
                }
                if (lastSetAuxTemperature != UserAuxTemperature)
                {
                    // Set target auxiliary temperature globally (PiSetParam with pcc = 0, head = 0)
                    if (PrinterInterfaceCLS.PiSetParam((int)eCFGPARAM.CCP_AUX_TEMP, UserAuxTemperature) == eRET.RVAL_OK)    // Set globally
                    {
                        lastSetAuxTemperature = UserAuxTemperature;
                    }
                }
                if (lastSupportedBppBitmask != status.SupportedBppBitmask)
                {
                    lastSupportedBppBitmask = status.SupportedBppBitmask;
                    EnableBppRadioButtons();
                }
                // Meteor will reject a PiSetHeadPower command if any of the PCCs are still in the process
                // of changing the head power status
                if (checkBoxEnableHeadPower.Enabled != status.HeadPowerIdle)
                {
                    checkBoxEnableHeadPower.Enabled = status.HeadPowerIdle;
                }
                // If the Meteor head power state is stable, check that we're displaying the correct state
                if (status.HeadPowerIdle)
                {
                    if (status.HeadPowerEnabled != checkBoxEnableHeadPower.Checked)
                    {
                        inSetHeadPower = true;
                        checkBoxEnableHeadPower.Checked = status.HeadPowerEnabled;
                        inSetHeadPower = false;
                    }
                }
            }
            else
            {
                lastSetHeadTemperature = -1;
                lastSetAuxTemperature  = -1;
            }
            // Update the enabled state of the controls to reflect the Meteor status
            EnableControls();
            // Update the status text
            if (bJobStarting)
            {
                textBoxStatus.Text = PRINTER_STATUS.LOADING.ToString();
            }
            else if (bJobAborting)
            {
                textBoxStatus.Text = PRINTER_STATUS.ABORTING.ToString();
            }
            else
            {
                textBoxStatus.Text = Status.ToString();
            }
        }
Exemple #11
0
        /// <summary>
        /// Get the status from Meteor.  Also attempts to open a connection to Meteor every
        /// 2 seconds if the application is not currently connected.
        /// </summary>
        /// <returns></returns>
        public PRINTER_STATUS GetStatus()
        {
            TAppStatus AppStatus;
            eRET       rVal;

            if (!Connected)
            {
                if (Environment.TickCount < tickLastConnectAttempt + CONNECT_INTERVAL_MS)
                {
                    return(PRINTER_STATUS.DISCONNECTED);
                }
                tickLastConnectAttempt = Environment.TickCount;

                rVal = PrinterInterfaceCLS.PiOpenPrinter();
                // RVAL_OK means the Meteor Printer Interface was successfully opened.
                //
                // RVAL_EXISTS means that the Printer Interface is already open in this
                // process.
                //
                // All other return values mean we have failed to open the printer
                // interface - the most likely reasons are either the Meteor Print Engine
                // is not running, or the Meteor Printer Interface is already open in another
                // print application.
                //
                if (rVal != eRET.RVAL_OK && rVal != eRET.RVAL_EXISTS)
                {
                    return(PRINTER_STATUS.DISCONNECTED);
                }
                Connected = true;
                // Send an abort command in case the application which previously used
                // Meteor left a print job running.  This is not done if Meteor is
                // currently initialising the hardware, as in this case it should
                // not be necessary, and can take a significant amount of time to complete.
                rVal = PrinterInterfaceCLS.PiGetPrnStatus(out AppStatus);
                if (rVal == eRET.RVAL_OK && AppStatus.PrinterState != ePRINTERSTATE.MPS_INITIALIZING)
                {
                    PrinterInterfaceCLS.PiAbort();
                }
                // Wait until the abort has completed.  While an abort is in progress
                // the printer interface is busy, and status requests will fail.
                WaitNotBusy();
            }

            // Request the Meteor printer status.  Provided the Print Engine is
            // still running, this method should never fail in a single threaded
            // printer application.  In a more complex application which uses
            // multiple threads to can communicate with the Print Engine, it
            // is possible (though rare) for the status request to time out if
            // the Printer Interface is busy servicing another request.
            //
            rVal = PrinterInterfaceCLS.PiGetPrnStatus(out AppStatus);
            if (rVal != eRET.RVAL_OK)
            {
                if (Connected)
                {
                    PrinterInterfaceCLS.PiClosePrinter();
                    Connected = false;
                }
                return(PRINTER_STATUS.DISCONNECTED);
            }

            // Store the bitmask indicating which bits-per-pixel are valid for the current head type
            SupportedBppBitmask = AppStatus.SupportedBppBitmask;

            // The Meteor Print Engine state goes into IDLE after all connecteded PCCs have finished
            // initialising.
            //
            // Here we trap the case of the Meteor configuration file listing more PCCs than are
            // currently attached.
            //
            PccsRequired = AppStatus.PccsRequired;
            if (PccsRequired != AppStatus.PccsAttached)
            {
                return(PRINTER_STATUS.WAITING_FOR_PCC);
            }
            // Protect against the application acting on a brief status transition to IDLE
            ePRINTERSTATE PrinterState = AppStatus.PrinterState;

            if (AppStatus.PrinterState == ePRINTERSTATE.MPS_IDLE)
            {
                if (idleConfCount < IDLE_CONF)
                {
                    PrinterState = LastMeteorState;
                    idleConfCount++;
                }
            }
            else
            {
                idleConfCount = 0;
            }
            // Track last known stable printer state
            LastMeteorState = PrinterState;
            // Find out whether Meteor is currently turning head power on or off
            CheckHeadPowerIdle();
            // Is at least one head powered on
            HeadPowerEnabled = (AppStatus.HeadPowerState == eHEADPOWERSTATE.HPS_HEAD);
            // Convert from the Meteor printer status into the application status
            switch (PrinterState)
            {
            // There is no hardware connected.
            case ePRINTERSTATE.MPS_DISCONNECTED:
                return(PRINTER_STATUS.WAITING_FOR_PCC);

            // The PCC hardware has connected to the Print Engine but has not yet been
            // initialised
            case ePRINTERSTATE.MPS_CONNECTED:
                return(PRINTER_STATUS.INITIALISING);

            // The Print Engine is initialised and waiting for a print job to start
            case ePRINTERSTATE.MPS_IDLE:
                return(PRINTER_STATUS.IDLE);

            // The next print job is ready to start
            case ePRINTERSTATE.MPS_READY:
                return(PRINTER_STATUS.READY);

            // Meteor is actively printing
            case ePRINTERSTATE.MPS_PRINTING:
                return(PRINTER_STATUS.PRINTING);

            // The Print Engine is downloading FPGA code to the PCCs
            case ePRINTERSTATE.MPS_INITIALIZING:
                return(PRINTER_STATUS.INITIALISING);

            // The PCC FPGA has completed programming and is starting up
            case ePRINTERSTATE.MPS_STARTUP:
                return(PRINTER_STATUS.INITIALISING);

            // Fault condition - more information can be found by looking at the
            // values in the status registers.  For the purposes of this application
            // we just report the generic error; the register values can be viewed
            // in Monitor
            case ePRINTERSTATE.MPS_FAULT:
                return(PRINTER_STATUS.ERROR);

            // Image data is being loaded
            case ePRINTERSTATE.MPS_LOADING:
                return(PRINTER_STATUS.LOADING);

            // Should never get here
            default:
                return(PRINTER_STATUS.ERROR);
            }
        }