예제 #1
0
 public void Request_viable_parts(VehiclePart_CHASSIS _chassis)
 {
     foreach (KeyValuePair <VehiclePart_Config, int> _PAIR in currentTask.requiredParts)
     {
         VehiclePart_Config _PART = _PAIR.Key;
         int _QUANTITY            = _PAIR.Value;
         if (_PART.partType != Vehicle_PartType.CHASSIS)
         {
             if (currentTask.requiredParts.ContainsKey(_PAIR.Key))
             {
                 if (factoryMode == FactoryMode.OOP)
                 {
                     if (_chassis.partsFitted.ContainsKey(_PART))
                     {
                         if (_chassis.partsFitted[_PART] >= _QUANTITY)
                         {
                             continue;
                         }
                     }
                 }
                 L1.Request_part(new VehiclePartRequest(_PAIR.Key, REG));
                 REG.waitingForPartType = _chassis.partsNeeded[0].partConfig;
                 if (!purgingPartsToSharedStorage)
                 {
                     REG.Change_state(StorageState.WAITING);
                 }
                 return;
             }
         }
     }
 }
예제 #2
0
        public void push(REG r)
        {
            if (sp < 1024)
            {
                switch (r)
                {
                case REG.AX:
                    stk[sp++] = ax;
                    break;

                case REG.BX:
                    stk[sp++] = bx;
                    break;

                case REG.CX:
                    stk[sp++] = cx;
                    break;

                case REG.DX:
                    stk[sp++] = dx;
                    break;;
                }
            }
            else
            {
                Interrupt(INTERRUPT.HARDWARE, 0x0C);
            }
        }
예제 #3
0
    private void Update_REG_ViableParts()
    {
        REG_viableParts = new List <VehiclePart>();
        List <VehiclePart_Config> _TASK_PARTS = currentTask.requiredParts.Keys.ToList();

        // If part is NOT a chassis and is used in the current TASK - add it to VIABLE_PARTS
        for (int _slotIndex = 0; _slotIndex < REG.lineLength; _slotIndex++)
        {
            var _PART = REG.Get_data_slot(0, _slotIndex);
            if (_PART != null)
            {
                if (_PART.partConfig.partType != Vehicle_PartType.CHASSIS)
                {
                    if (_TASK_PARTS.Contains(_PART.partConfig))
                    {
                        foreach (VehiclePart_CHASSIS _CHASSIS in REG_viableChassis)
                        {
                            if (!_CHASSIS.partsFitted.ContainsKey(_PART.partConfig))
                            {
                                REG_viableParts.Add(_PART);
                            }
                            else if (_CHASSIS.partsFitted[_PART.partConfig] < _CHASSIS.design.quantities[_PART.partConfig])
                            {
                                REG_viableParts.Add(_PART);
                            }
                        }
                    }
                }
            }
        }
    }
예제 #4
0
 public void Do_purge()
 {
     if (REG.usedSpace > 0)
     {
         REG.Dump_line();
     }
     else if (L1.usedSpace > 0)
     {
         Factory.INSTANCE.L3.Await_purged_data();
         L1.Dump_first_line_with_data();
     }
     else if (L2.usedSpace > 0)
     {
         Factory.INSTANCE.L3.Await_purged_data();
         L2.Dump_first_line_with_data();
         if (L2.usedSpace == 0)
         {
             // purge complete
             // reset all workshops - start searching fresh for parts
             foreach (var _WORKSHOP in Factory.INSTANCE.workshops)
             {
                 _WORKSHOP.Clear_all_requests_then_idle();
             }
         }
     }
     if (REG.currentState == StorageState.IDLE &&
         L1.currentState == StorageState.IDLE &&
         L2.currentState == StorageState.IDLE
         )
     {
         Cancel_purge();
     }
 }
예제 #5
0
        public DecoderOutput[] Process(Dictionary <string, Array> inputWaveforms, Dictionary <string, object> parameters, double samplePeriod)
        {
            DecoderOutput[] i2cStream = (DecoderOutput[])inputWaveforms["I2C"];

            List <DecoderOutput> decoderOutputList = new List <DecoderOutput>();

            int  startIndex         = 0;
            bool i2cSequenceStarted = false;
            bool fpgaAddressed      = false;
            int  targetRegister     = -1;

            for (int i = 0; i < i2cStream.Length; i++)
            {
                DecoderOutput currentData = i2cStream[i];

                if ((!i2cSequenceStarted) && (currentData.Text == "S"))
                {
                    i2cSequenceStarted = true;
                    fpgaAddressed      = false;
                    startIndex         = currentData.StartIndex;
                    targetRegister     = -1;
                    continue;
                }

                if (i2cSequenceStarted)
                {
                    if (currentData is DecoderOutputValue <byte> ) //check for values only, not events
                    {
                        byte rawValue = (currentData as DecoderOutputValue <byte>).Value;
                        if (!fpgaAddressed)
                        {
                            fpgaAddressed = true;
                        }
                        else if (targetRegister < 0)
                        {
                            targetRegister = (int)rawValue;
                        }
                        else //3rd byte: regsiter value
                        {
                            REG    fpgaRegister = (REG)targetRegister;
                            string toPrint      = "FPGA: Set register " + fpgaRegister.ToString() + " to " + rawValue.ToString() + " (0x" + rawValue.ToString("X").PadLeft(2, '0') + ")";
                            decoderOutputList.Add(new DecoderOutputEvent(startIndex, currentData.EndIndex, DecoderOutputColor.Blue, toPrint));

                            //terminate this transmission
                            i2cSequenceStarted = false;
                        }
                    }
                    else
                    {
                        //if any event other than ACK is encountered during I2C transmission
                        if (currentData.Text != "ACK")
                        {
                            i2cSequenceStarted = false;
                        }
                    }
                }
            }

            return(decoderOutputList.ToArray());
        }
예제 #6
0
        public void div(REG r, int val)
        {
            if (val == 0)
            {
                Interrupt(INTERRUPT.HARDWARE, 0x00);
            }
            switch (r)
            {
            case REG.AX:
                ax /= val;
                break;

            case REG.BX:
                bx /= val;
                break;

            case REG.CX:
                cx /= val;
                break;

            case REG.DX:
                dx /= val;
                break;
            }
        }
예제 #7
0
        public float GetYOffset(AnalogChannel channel)
        {
            REG  r          = (channel == AnalogChannel.ChA) ? REG.CHA_YOFFSET_VOLTAGE : REG.CHB_YOFFSET_VOLTAGE;
            byte offsetByte = FpgaSettingsMemory[r].GetByte();

            return(ConvertYOffsetByteToVoltage(channel, offsetByte));
        }
예제 #8
0
        public void SetYOffsetByte(AnalogChannel channel, byte offset)
        {
            REG r = channel == AnalogChannel.ChA ? REG.CHA_YOFFSET_VOLTAGE : REG.CHB_YOFFSET_VOLTAGE;

            Logger.Debug("Set Y offset for channel " + channel + " to " + offset + " (int value)");
            FpgaSettingsMemory[r].Set(offset);
        }
예제 #9
0
        public void pop(REG r)
        {
            if (sp < 0)
            {
                Interrupt(INTERRUPT.HARDWARE, 0x0C);
            }
            switch (r)
            {
            case REG.AX:
                ax = stk[--sp];
                break;

            case REG.BX:
                bx = stk[--sp];
                break;

            case REG.CX:
                cx = stk[--sp];
                break;

            case REG.DX:
                dx = stk[--sp];
                break;
            }
        }
예제 #10
0
 public void Purge_parts_to_shared_storage()
 {
     purgingPartsToSharedStorage = true;
     Debug.Log("PURGE WORKSHOP: " + workshopIndex);
     Factory.INSTANCE.L3.Await_purged_data();
     L2.Await_purged_data();
     L1.Await_purged_data();
     REG.Await_purged_data();
 }
예제 #11
0
    public void Clear_all_requests_then_idle()
    {
        L2.Clear_all_requests();
        L1.Clear_all_requests();
        REG.Clear_all_requests();

        REG.Change_state(StorageState.IDLE);
        L1.Change_state(StorageState.IDLE);
        L2.Change_state(StorageState.IDLE);
    }
예제 #12
0
 public HMIViewModel()
 {
     Vanne_Pushed = new Command(Vanne_pushed);
     Messaging.Messenger.Default.Register <object>(this, receivedMessage);
     for (int n = 0; n < 6; n++)
     {
         TOR.Add(new VanneTOR());
     }
     REG.Add(new VanneREG());
     //Excel();
 }
예제 #13
0
        //reg: 要读的寄存器, num: 要读的WORD数, val: 传递的参数)
        public void Send_03(REG Register, byte Number, uint val)
        {
            const Int32 MODBUS_SEND_03_NUM = 10;
            UInt16      crc_val;

            modbus_send_data[0] = 0x01;
            modbus_send_data[1] = 0x03;
            modbus_send_data[2] = (byte)Register;
            modbus_send_data[3] = Number;
            modbus_send_data[4] = (byte)((val & 0xFF000000) >> 24);
            modbus_send_data[5] = (byte)((val & 0x00FF0000) >> 16);
            modbus_send_data[6] = (byte)((val & 0x0000FF00) >> 8);
            modbus_send_data[7] = (byte)((val & 0x000000FF) >> 0);
            crc_val             = Func.Get_CRC(modbus_send_data, 8);
            modbus_send_data[8] = (byte)((crc_val & 0xFF00) >> 8);
            modbus_send_data[9] = (byte)((crc_val & 0x00FF) >> 0);

            try
            {
                is_busy = true;
                modbus_respone_timeout = 0;

                com.Write(modbus_send_data, 0, MODBUS_SEND_03_NUM);

                Console.Write("PC->MCU:");
                for (int v = 0; v < MODBUS_SEND_03_NUM; v++)
                {
                    Console.Write(" {0:X}", modbus_send_data[v]);
                }
                Console.Write("\r\n\r\n");

                if (echo_en == true)
                {
                    String SerialIn = "";
                    SerialIn += "Send: ";
                    for (uint i = 0; i < MODBUS_SEND_03_NUM; i++)
                    {
                        SerialIn += "0x";
                        SerialIn += Func.GetHexHighLow(modbus_send_data[i], 0);
                        SerialIn += Func.GetHexHighLow(modbus_send_data[i], 1) + " ";
                    }
                    queue_message.Enqueue(SerialIn);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "提示");
            }
        }
예제 #14
0
    void Remove_completed_chassis()
    {
        foreach (VehiclePart_CHASSIS _CHASSIS in REG_viableChassis)
        {
            if (_CHASSIS.vehicleIsComplete)
            {
                int indexOfCompletedChassis = REG.storageLines[0].slots.IndexOf(_CHASSIS);
                REG.Clear_slot(0, indexOfCompletedChassis);
                Factory.INSTANCE.VehicleComplete(_CHASSIS);
                completedVehicles++;

                _CHASSIS.transform.position = transform.position + new Vector3(completedVehicles % 10, 0f, -1 - Mathf.FloorToInt(completedVehicles / 10));
            }
        }
    }
예제 #15
0
    private void Push_nonViable_parts_to_shared_storage()
    {
        if (REG.Contains_nonViablePart(currentTaskPart))
        {
            REG.Dump_first_nonViable_part(currentTaskPart);
        }

        else if (L1.Contains_nonViablePart(currentTaskPart))
        {
            L1.Dump_first_nonViable_part(currentTaskPart);
        }

        else if (L2.Contains_nonViablePart(currentTaskPart))
        {
            L2.Dump_first_nonViable_part(currentTaskPart);
        }
    }
예제 #16
0
    private void Push_nonViable_chassis_to_shared_storage()
    {
        if (REG.Has_nonViable_chassis(CurrentChassisRequest))
        {
            REG.Dump_first_nonViable_chassis(CurrentChassisRequest);
        }

        else if (L1.Has_nonViable_chassis(CurrentChassisRequest))
        {
            L1.Dump_first_nonViable_chassis(CurrentChassisRequest);
        }

        else if (L2.Has_nonViable_chassis(CurrentChassisRequest))
        {
            L2.Dump_first_nonViable_chassis(CurrentChassisRequest);
        }
    }
예제 #17
0
        /// <summary>
        /// Sets vertical offset of a channel
        /// </summary>
        /// <param name="channel">0 or 1 (channel A or B)</param>
        /// <param name="offset">Vertical offset in Volt</param>
        public void SetYOffset(AnalogChannel channel, float offset)
        {
            yOffset[channel] = offset;
            if (!Connected)
            {
                return;
            }
            //FIXME: convert offset to byte value
            REG r = (channel == AnalogChannel.ChA) ? REG.CHA_YOFFSET_VOLTAGE : REG.CHB_YOFFSET_VOLTAGE;

            //Logger.Debug("Set Y-offset for channel " + channel + " to " + offset + "V");
            //Offset: 0V --> 150 - swing +-0.9V

            //Let ADC output of 127 be the zero point of the Yoffset
            double[] c         = channelSettings[channel].coefficients;
            int      offsetInt = (int)(-(ProbeScaleHostToScope(channel, offset) + c[2] + c[0] * 127) / c[1]);

            FpgaSettingsMemory[r].Set((byte)Math.Max(yOffsetMin, Math.Min(yOffsetMax, -(ProbeScaleHostToScope(channel, offset) + c[2] + c[0] * 127) / c[1])));
            //Logger.Debug(String.Format("Yoffset Ch {0} set to {1} V = byteval {2}", channel, GetYOffset(channel), FpgaSettingsMemory[r].GetByte()));
        }
예제 #18
0
 void Attach_parts()
 {
     for (int _slotIndex = 0; _slotIndex < REG.lineLength; _slotIndex++)
     {
         var _PART = REG.storageLines[0].slots[_slotIndex];
         if (REG_viableParts.Contains(_PART))
         {
             for (int _chassisIndex = 0; _chassisIndex < REG_viableChassis.Count; _chassisIndex++)
             {
                 if (REG_viableChassis[_chassisIndex].AttachPart(_PART.partConfig, _PART.gameObject))
                 {
                     _PART.ClearDestination();
                     REG_viableParts.Remove(_PART);
                     Factory.INSTANCE.PartAttached(_PART.partConfig, this);
                     REG.Clear_slot(0, _slotIndex);
                     break;
                 }
             }
         }
     }
 }
예제 #19
0
        public void mul(REG r, int val)
        {
            switch (r)
            {
            case REG.AX:
                ax *= val;
                break;

            case REG.BX:
                bx *= val;
                break;

            case REG.CX:
                cx *= val;
                break;

            case REG.DX:
                dx *= val;
                break;
            }
        }
예제 #20
0
        public void sub(REG r, int val)
        {
            switch (r)
            {
            case REG.AX:
                ax -= val;
                break;

            case REG.BX:
                bx -= val;
                break;

            case REG.CX:
                cx -= val;
                break;

            case REG.DX:
                dx -= val;
                break;
            }
        }
예제 #21
0
        public void add(REG r, int val)
        {
            switch (r)
            {
            case REG.AX:
                ax += val;
                break;

            case REG.BX:
                bx += val;
                break;

            case REG.CX:
                cx += val;
                break;

            case REG.DX:
                dx += val;
                break;
            }
        }
예제 #22
0
        public void mov(REG r, int val)
        {
            switch (r)
            {
            case REG.AX:
                ax = val;
                break;

            case REG.BX:
                bx = val;
                break;

            case REG.CX:
                cx = val;
                break;

            case REG.DX:
                dx = val;
                break;
            }
        }
예제 #23
0
        internal byte GetRegister(REG r)
        {
            int offset = 0;

            if (!SmartScope.AcquisitionRegisters.Contains(r))
            {
                if (!SmartScope.DumpRegisters.Contains(r))
                {
                    throw new Exception("Register " + r.ToString("G") + " not part of header");
                }
                else
                {
                    offset = SmartScope.AcquisitionRegisters.Length + Array.IndexOf(SmartScope.DumpRegisters, r);
                };
            }
            else
            {
                offset = Array.IndexOf(SmartScope.AcquisitionRegisters, r);
            }

            return(raw[offset]);
        }
예제 #24
0
        /// <summary>
        /// Sets vertical offset of a channel
        /// </summary>
        /// <param name="channel">0 or 1 (channel A or B)</param>
        /// <param name="offset">Vertical offset in Volt</param>
        public void SetYOffset(AnalogChannel channel, float offset)
        {
            yOffset[channel] = offset;
            if (!Connected)
            {
                return;
            }
            //FIXME: convert offset to byte value
            REG r = (channel == AnalogChannel.ChA) ? REG.CHA_YOFFSET_VOLTAGE : REG.CHB_YOFFSET_VOLTAGE;

            //Logger.Debug("Set Y-offset for channel " + channel + " to " + offset + "V");
            //Offset: 0V --> 150 - swing +-0.9V

            //Let ADC output of 127 be the zero point of the Yoffset
            double[] c = channelSettings[channel].coefficients;

            FpgaSettingsMemory[r].Set((byte)Math.Max(yOffsetMin, Math.Min(yOffsetMax, -(ProbeScaleHostToScope(channel, offset) + c[2] + c[0] * 127) / c[1])));
            yOffset[channel] = GetYOffset(channel);
            if (channel == triggerValue.channel && triggerValue.mode != TriggerMode.Digital)
            {
                TriggerValue = this.triggerValue;
            }
        }
예제 #25
0
        /// <summary>
        /// Sets vertical offset of a channel
        /// </summary>
        /// <param name="channel">0 or 1 (channel A or B)</param>
        /// <param name="offset">Vertical offset in Volt</param>
        public void SetYOffset(AnalogChannel channel, float offset)
        {
            yOffset[channel] = offset;
            if (!Connected)
            {
                return;
            }
            //FIXME: convert offset to byte value
            REG r = (channel == AnalogChannel.ChA) ? REG.CHA_YOFFSET_VOLTAGE : REG.CHB_YOFFSET_VOLTAGE;

            //Logger.Debug("Set Y-offset for channel " + channel + " to " + offset + "V");
            //Offset: 0V --> 150 - swing +-0.9V

            //Let ADC output of 127 be the zero point of the Yoffset
            double[] c = channelSettings[channel].coefficients;

            FpgaSettingsMemory[r].Set((byte)Math.Max(yOffsetMin, Math.Min(yOffsetMax, -(channel.UserToRaw(offset + channel.Probe.Offset) + c[2] + c[0] * 127) / c[1]))); //probe offset needs to be taken into account here, because entire class uses the 'GUI' values == the values measured in the probe's unit. Only when settings div/mult or offset, these are translated to the real voltage.
            yOffset[channel] = GetYOffset(channel);
            if (channel == triggerValue.channel && triggerValue.mode != TriggerMode.Digital)
            {
                TriggerValue = this.triggerValue;
            }
        }
예제 #26
0
 public static extern int RegQueryValueEx(IntPtr hKey, string valueName, int reserved, ref REG type, System.Text.StringBuilder data, ref int dataSize);
        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            if (CurrentUser.type != 0)
            {
                if (Login.Text != "")
                {
                    if (Password.Password != "" && Password.Password.Length >= 5)
                    {
                        CurrentUser.name     = Login.Text;
                        CurrentUser.password = Password.Password;
                        reg = new REG();

                        if (CurrentUser.type == 2)
                        {
                            var r = from o in org where o.orgname == Login.Text select o.Idorg;
                            if (r.Max() == null)
                            {
                                reg.Login    = Login.Text;
                                reg.Password = Password.Password;
                                Treg.InsertOnSubmit(reg);
                                NewOrg       = new org();
                                NewOrg.Idorg = (from o in org select o.Idorg).Max() + 1;
                                if (NewOrg.Idorg == null)
                                {
                                    NewOrg.Idorg = 1;
                                }
                                NewOrg.orgname = Login.Text;
                                org.InsertOnSubmit(NewOrg);
                                try
                                {
                                    db.SubmitChanges();
                                    MessageBox.Show("Компания зарегистрирована!\nВаш логин: " + reg.Login + "\nВаш пароль: " + reg.Password);
                                    CurrentUser.flag = false;
                                }
                                catch (Exception)
                                {
                                    MessageBox.Show("Ошибка регистрации!");
                                }
                                finally
                                {
                                    ch?.Invoke(this, new EventArgs());
                                    if (CurrentUser.flag == false)
                                    {
                                        this.Close();
                                    }
                                    this.Close();
                                }
                            }
                            else
                            {
                                MessageBox.Show("Компания уже зарегистрирована.");
                            }
                        }
                        if (CurrentUser.type == 1)
                        {
                            var r = from a in Treg where a.Login == Login.Text select a.Login;
                            if (r.Max() == null)
                            {
                                reg.Login    = Login.Text;
                                reg.Password = Password.Password;
                                Treg.InsertOnSubmit(reg);
                                try
                                {
                                    db.SubmitChanges();
                                    MessageBox.Show("Вы успешно зарегистрированы!\nВаш логин: " + reg.Login + "\nВаш пароль: " + reg.Password);
                                    CurrentUser.flag = false;
                                }
                                catch (Exception)
                                {
                                    MessageBox.Show("Ошибка регистрации!");
                                }
                                finally
                                {
                                    ch?.Invoke(this, new EventArgs());
                                    if (CurrentUser.flag == false)
                                    {
                                        this.Close();
                                    }
                                    this.Close();
                                }
                            }
                            else
                            {
                                MessageBox.Show("Пользователь с таким именем уже есть.");
                            }
                        }
                    }
                    else
                    {
                        MessageBox.Show("Введите корректный пароль (не менее 5 символов)");
                    }
                }
                else
                {
                    MessageBox.Show("Введите логин");
                }
            }
            else
            {
                MessageBox.Show("Кто же вы?");
            }
        }
 public ByteRegister this[REG r]
 {
     get { return(this[(uint)r]); }
     set { this[(uint)r] = value; }
 }
예제 #29
0
        internal byte GetRegister(REG r)
        {
            int offset = 0;
            if (!SmartScope.AcquisitionRegisters.Contains(r))
            {
                if (!SmartScope.DumpRegisters.Contains(r))
                    throw new Exception("Register " + r.ToString("G") + " not part of header");
                else
                    offset = SmartScope.AcquisitionRegisters.Length + Array.IndexOf(SmartScope.DumpRegisters, r); ;
            }
            else
            {
                offset = Array.IndexOf(SmartScope.AcquisitionRegisters, r);
            }

            return raw[offset];
        }
예제 #30
0
 public static extern int RegQueryValueEx(IntPtr hKey, string valueName, int reserved, ref REG type, System.Text.StringBuilder data, ref int dataSize);
 public ByteRegister this[REG r]
 {
     get { return this[(uint)r]; }
     set { this[(uint)r] = value; }
 }
 public static unsafe byte GetRegister(this SmartScopeHeader hdr, REG r)
 {
     return(hdr.regs[Constants.HDR_REGS[r]]);
 }
예제 #33
0
    // - - - - - - - - - - - - - - - - - PERFORM WORKSHOP TASK
    void Perform_task()
    {
        if (purgingPartsToSharedStorage)
        {
            Do_purge();
            return;
        }

        CurrentChassisRequest = new VehicleChassiRequest(
            currentTask.design.chassisType.partConfig,
            currentTask.design.chassisType.partConfig.partVersion,
            currentTask.requiredParts,
            REG,
            factoryMode);

        if (
            REG.currentState == StorageState.IDLE ||
            (REG.currentState == StorageState.WAITING && L1.currentState == StorageState.IDLE))
        {
            if (REG.currentState == StorageState.IDLE && L1.currentState == StorageState.WAITING)
            {
                L1.Clear_all_requests();
                L1.Change_state(StorageState.IDLE);
            }
            if (L2.currentState == StorageState.WAITING && Factory.INSTANCE.L3.currentState == StorageState.IDLE)
            {
                L2.Clear_all_requests();
                L2.Change_state(StorageState.IDLE);
            }
            // REG is able to request
            REG_viableChassis = Get_chassis(REG);

            if (REG_viableChassis.Count > 0)
            {
                // HAS CHASSIS
                Update_REG_ViableParts();

                if (REG_viableParts.Count > 0)
                {
                    // HAS PARTS
                    Attach_parts();
                    Remove_completed_chassis();
                }
                else
                {
                    // NO PARTS
                    bool REG_IS_FULL = REG.freeSpace == 0;
                    switch (factoryMode)
                    {
                    case FactoryMode.OOP:

                        if (REG_IS_FULL)
                        {
                            REG.Dump_from_line_exceptType(0, Vehicle_PartType.CHASSIS, 1);
                        }
                        else
                        {
                            Request_viable_parts(REG_viableChassis[0]);
                        }

                        break;

                    case FactoryMode.DOD:

                        if (REG_IS_FULL)
                        {
                            REG.Dump_nonViable_chassis(CurrentChassisRequest, 0);
                        }
                        else
                        {
                            Request_currentTask_part(REG);
                        }
                        break;
                    }
                }
            }
            else
            { // NO CHASSIS
                if (REG.freeSpace > 0)
                {
                    REG.waitingForPartType = CurrentChassisRequest.part;
                    REG.Change_state(StorageState.WAITING);
                    L1.Request_chassis(CurrentChassisRequest);
                }
                else
                { // NO ROOM, DUMP
                    REG.Dump_from_line_exceptType(0, Vehicle_PartType.CHASSIS, 1);
                }
            }
        }

        if (factoryMode == FactoryMode.DOD)
        {
            Push_nonViable_chassis_to_shared_storage();
            Push_nonViable_parts_to_shared_storage();

            // if we're waiting for occupied parts, try to purge nonViable parts
            if (REG.currentState == StorageState.WAITING &&
                L1.currentState == StorageState.WAITING &&
                L2.currentState == StorageState.WAITING
                )
            {
                REG.Change_state(StorageState.IDLE);
                L1.Change_state(StorageState.IDLE);
                L2.Change_state(StorageState.IDLE);
            }

            if (L2.currentState == StorageState.IDLE)
            {
                Request_currentTask_part(L2);
            }
        }
    }