4.5.8 Programming Examples |
Code samples for programmatic control of an nLight Laser.
public class NLight_Laser_Example { private const string CardIP = "192.168.1.1"; // Obviously, you should provide the real address of your card here. [Flags] private enum InputState { BppReady = 1 << 0, ExtControlReady = 1 << 1, WaterFlow = 1 << 2, Ready = 1 << 3, Error = 1 << 4, Emission = 1 << 5, FirmwareReady = 1 << 6 } private enum DeviceStateType { NoDevice, Off, Standby, Emission, Error, Fault } [Flags] private enum NLightSignalIOPin : uint { PRO_START = 1 << 7, PRO_B1 = 1 << 8, PRO_B2 = 1 << 9, PRO_B3 = 1 << 10, PRO_B4 = 1 << 11, PRO_B5 = 1 << 12, PRO_B6 = 1 << 13, PRO_B7 = 1 << 14, SYSTEM_ON = 1 << 15, ENABLE_PROFILE = 1 << 16, ARM_LASER = 1 << 18, CLEAR_ERROR = 1 << 19, ENABLE_AIMING_LASER = 1 << 20, ENABLE_EXTERNAL_CONTROL = 1 << 21, ENABLE_24V = 1 << 22, GATE_IN = 1 << 23 } private DeviceStateType DeviceState; private ClientAPI _client = new ClientAPI( CardIP ); public bool IsInitialized => DeviceState == DeviceStateType.Standby || DeviceState == DeviceStateType.Emission; public bool DisarmToOffState { get; set; } private void InitializeAdapter() { SpiConfig spiConfig = _client.Sfio.Spi.GetConfig(); spiConfig.Modules[2] = new SpiModule { Enabled = true, BitOrder = Order.MsbFirst, PreDelay = 0.5, PostDelay = 0.5, FrameDelay = 0.25, SpiSyncMode = SyncMode.SyncPerFrame, ClockPeriod = 0.125, BitsPerWord = 32, OutputSource = DataSource.Spi }; _client.Sfio.Spi.SetConfig( spiConfig ); // Enable 24V. _client.Gpio.Write( IOPort.PortD, PinAction.Set, (uint)NLightSignalIOPin.ENABLE_24V ); // Clear special functions. _client.Gpio.Write( IOPort.PortD, PinAction.Clear, (uint)( NLightSignalIOPin.ARM_LASER | NLightSignalIOPin.ENABLE_AIMING_LASER | NLightSignalIOPin.GATE_IN ) ); // Disarm the laser initially. ArmLaser( false ); } private void InitializeLaser() { UpdateDeviceState( out InputState inputState ); if ( DeviceState == DeviceStateType.NoDevice || IsInitialized ) throw new Exception( "Could not detect laser" ); bool? hasError = DeviceState == DeviceStateType.Error ? true : (bool?)null; // Wait for FIRMWARE_READY signal from laser. while ( hasError == null || hasError.Value || !inputState.HasFlag( InputState.FirmwareReady ) ) { ClearError( true ); UpdateDeviceState( out inputState ); hasError = DeviceState == DeviceStateType.Error; if ( hasError.Value || !inputState.HasFlag( InputState.FirmwareReady ) ) Thread.Sleep( TimeSpan.FromMilliseconds( 30 ) ); } // Wait for EXT_CONTROL_RDY signal from laser. hasError = null; while ( hasError == null || hasError.Value || !inputState.HasFlag( InputState.ExtControlReady ) ) { ClearError( true ); if ( hasError == null || hasError.Value ) EnableExternalControl( true ); UpdateDeviceState( out inputState ); hasError = DeviceState == DeviceStateType.Error; if ( hasError.Value || !inputState.HasFlag( InputState.ExtControlReady ) ) Thread.Sleep( TimeSpan.FromMilliseconds( 30 ) ); } // Wait for READY from laser. Min wait time is 2s. hasError = null; while ( DeviceState != DeviceStateType.Standby ) { ClearError( true ); if ( hasError == null || hasError.Value ) { EnableSystem( true ); Thread.Sleep( 2000 ); } UpdateDeviceState( out inputState ); hasError = DeviceState == DeviceStateType.Error; if ( DeviceState != DeviceStateType.Standby ) Thread.Sleep( TimeSpan.FromMilliseconds( 30 ) ); } // Set beam profile ID to 0. Otherwise, the state is undefined. hasError = null; while ( hasError == null || hasError.Value || !inputState.HasFlag( InputState.BppReady ) ) { ClearError( true ); if ( hasError == null || hasError.Value ) { ChangeBeamProfile( 0 ); Thread.Sleep( TimeSpan.FromMilliseconds( 40 ) ); } UpdateDeviceState( out inputState ); hasError = DeviceState == DeviceStateType.Error; if ( hasError.Value || !inputState.HasFlag( InputState.BppReady ) ) Thread.Sleep( TimeSpan.FromMilliseconds( 30 ) ); } } ////////////////////////////////////////////////////// // // Initialize MUST be called before any other methods. // ////////////////////////////////////////////////////// public void Initialize() { InitializeAdapter(); InitializeLaser(); } private void ClearError( bool shouldGotoOffState ) { if ( DeviceState != DeviceStateType.Error ) return; ArmLaser( false ); while ( true ) { if ( shouldGotoOffState ) { EnableSystem( false ); UpdateDeviceState( out InputState inputState ); if ( DeviceState == DeviceStateType.Off ) break; } else { _client.Gpio.Write( IOPort.PortD, PinAction.Clear, (uint)NLightSignalIOPin.CLEAR_ERROR ); Thread.Sleep( TimeSpan.FromMilliseconds( 1 ) ); _client.Gpio.Write( IOPort.PortD, PinAction.Set, (uint)NLightSignalIOPin.CLEAR_ERROR ); Thread.Sleep( TimeSpan.FromMilliseconds( 1 ) ); Thread.Sleep( TimeSpan.FromMilliseconds( 5000 ) ); UpdateDeviceState( out InputState inputState ); if ( DeviceState == DeviceStateType.Standby ) break; } Thread.Sleep( TimeSpan.FromMilliseconds( 30 ) ); } } private uint ReadInputs() { uint[] txData = { 0x03000000 }; uint[] rxData = _client.Sfio.Spi.Transceive( 2, txData, 10 ); return rxData.First(); } private void UpdateDeviceState( out InputState inputState ) { uint inputs = ReadInputs(); inputState = (InputState)inputs; // IMPORTANT: This is an assumption that there is no actual laser available. if ( ( inputs & 0xFF ) == 0xFF ) { Console.Out.WriteLine( "No laser present" ); DeviceState = DeviceStateType.NoDevice; return; } bool isExtControlReady = inputState.HasFlag( InputState.ExtControlReady ); bool isReady = inputState.HasFlag( InputState.Ready ); bool isError = inputState.HasFlag( InputState.Error ); bool isEmission = inputState.HasFlag( InputState.Emission ); bool isFirmwareReady = inputState.HasFlag( InputState.FirmwareReady ); bool isWaterFlow = inputState.HasFlag( InputState.WaterFlow ); Console.Out.WriteLine( $"Current state: {inputState}" ); if ( isError ) DeviceState = DeviceStateType.Error; else { if ( isFirmwareReady && isExtControlReady ) { if ( isReady ) DeviceState = isEmission ? DeviceStateType.Emission : DeviceStateType.Standby; else DeviceState = DeviceStateType.Off; } else DeviceState = DeviceStateType.Off; } } public void EnableSystem( bool enable ) { _client.Gpio.Write( IOPort.PortD, PinAction.Clear, (uint)NLightSignalIOPin.SYSTEM_ON ); if ( enable ) { Thread.Sleep( TimeSpan.FromMilliseconds( 1 ) ); _client.Gpio.Write( IOPort.PortD, PinAction.Set, (uint)NLightSignalIOPin.SYSTEM_ON ); } } public void ChangeBeamProfile( ushort profileID ) { (uint setMask, uint clearMask) = CalculateBeamProfileIDMasks( profileID ); _client.Gpio.Write( IOPort.PortD, PinAction.Set, setMask ); _client.Gpio.Write( IOPort.PortD, PinAction.Clear, clearMask ); _client.Gpio.Write( IOPort.PortD, PinAction.Set, (uint)NLightSignalIOPin.PRO_START ); _client.Gpio.Write( IOPort.PortD, PinAction.Clear, (uint)NLightSignalIOPin.PRO_START ); } private (uint setMask, uint clearMask) CalculateBeamProfileIDMasks( ushort profileID ) { const int localMask = ( 1 << 4 ) - 1; uint setMask = (uint)( ( profileID & localMask ) << 8 ); uint clearMask = (uint)( ( ~profileID & localMask ) << 8 ); // Clear PROFILE_EN. clearMask |= (uint)NLightSignalIOPin.ENABLE_PROFILE; // Set AFX mode. setMask |= (uint)NLightSignalIOPin.PRO_B7; return (setMask, clearMask); } public void EnableExternalControl( bool enable ) { _client.Gpio.Write( IOPort.PortD, PinAction.Set, (uint)NLightSignalIOPin.ENABLE_EXTERNAL_CONTROL ); if ( !enable ) { Thread.Sleep( TimeSpan.FromMilliseconds( 1 ) ); _client.Gpio.Write( IOPort.PortD, PinAction.Clear, (uint)NLightSignalIOPin.ENABLE_EXTERNAL_CONTROL ); } } private bool GetLaserArmed() { UpdateDeviceState( out InputState _ ); return DeviceState == DeviceStateType.Emission && _client.Laser.IsLaserArmed(); } public void ArmLaser( bool enable ) { bool isArmed = GetLaserArmed(); if ( DeviceState == DeviceStateType.NoDevice || enable && DeviceState == DeviceStateType.Emission || !enable && !isArmed && DeviceState != DeviceStateType.Error && DeviceState != DeviceStateType.Emission ) return; if ( enable ) { try { if ( DeviceState != DeviceStateType.Standby ) Initialize(); } catch ( Exception ) { // ignored } if ( DeviceState != DeviceStateType.Standby ) throw new ApplicationException( "Cannot initialize laser during arming process." ); } // Wait EMISS. Min time is 2s. UpdateDeviceState( out InputState _ ); bool? hasError = DeviceState == DeviceStateType.Error ? true : (bool?)null; while ( hasError == null || hasError.Value || enable && DeviceState != DeviceStateType.Emission || !enable && DeviceState == DeviceStateType.Emission ) { ClearError( false ); if ( hasError == null || hasError.Value ) { _client.Laser.ArmLaser( enable ); if ( enable ) Thread.Sleep( TimeSpan.FromMilliseconds( 2000 ) ); } UpdateDeviceState( out InputState _ ); hasError = DeviceState == DeviceStateType.Error; if ( hasError.Value || enable && DeviceState != DeviceStateType.Emission || !enable && DeviceState == DeviceStateType.Emission ) Thread.Sleep( TimeSpan.FromMilliseconds( 30 ) ); } if ( !enable && DisarmToOffState ) { // Wait RDY. UpdateDeviceState( out InputState inputState ); hasError = DeviceState == DeviceStateType.Error ? true : (bool?)null; while ( hasError == null || hasError.Value || inputState.HasFlag( InputState.Ready ) ) { ClearError( true ); if ( hasError == null || hasError.Value ) EnableSystem( false ); UpdateDeviceState( out inputState ); hasError = DeviceState == DeviceStateType.Error; if ( hasError.Value || inputState.HasFlag( InputState.Ready ) ) Thread.Sleep( TimeSpan.FromMilliseconds( 30 ) ); } } } }