Beispiel #1
0
        public object SendCommand(usbint_server_opcode_e opcode, usbint_server_space_e space, usbint_server_flags_e flags, [CanBeNull] params object[] args)
        {
            byte[] tBuffer = new byte[512];
            object ret     = null;

            // send directory command
            Array.Clear(tBuffer, 0, tBuffer.Length);
            tBuffer[0] = Convert.ToByte('U');
            tBuffer[1] = Convert.ToByte('S');
            tBuffer[2] = Convert.ToByte('B');
            tBuffer[3] = Convert.ToByte('A');    // directory listing
            tBuffer[4] = Convert.ToByte(opcode); // opcode
            tBuffer[5] = Convert.ToByte(space);  // space
            tBuffer[6] = Convert.ToByte(flags);  // flags

            // assign arguments
            if (space == usbint_server_space_e.FILE)
            {
                switch (opcode)
                {
                case usbint_server_opcode_e.GET:
                case usbint_server_opcode_e.PUT:
                case usbint_server_opcode_e.LS:
                case usbint_server_opcode_e.MKDIR:
                case usbint_server_opcode_e.RM:
                case usbint_server_opcode_e.MV:
                case usbint_server_opcode_e.BOOT:
                {
                    // name
                    if (!(args[0] is string))
                    {
                        throw new Exception("Command: " + opcode + " missing arg[0] string");
                    }
                    string s = (string)args[0];
                    Buffer.BlockCopy(Encoding.ASCII.GetBytes(s.ToArray()), 0, tBuffer, 256, Math.Min(255, s.Length));

                    if (opcode == usbint_server_opcode_e.MV)
                    {
                        if (!(args[1] is string))
                        {
                            throw new Exception("Command: " + opcode + " missing arg[1] string");
                        }
                        // new name
                        string n = (string)args[1];
                        Buffer.BlockCopy(Encoding.ASCII.GetBytes(n.ToArray()), 0, tBuffer, 8, n.Length);
                    }
                    else if (opcode == usbint_server_opcode_e.PUT)
                    {
                        // size
                        if (!(args[1] is uint))
                        {
                            throw new Exception("Command: " + opcode + " missing arg[1] uint");
                        }
                        uint size = (uint)args[1];
                        tBuffer[252] = Convert.ToByte((size >> 24) & 0xFF);
                        tBuffer[253] = Convert.ToByte((size >> 16) & 0xFF);
                        tBuffer[254] = Convert.ToByte((size >> 8) & 0xFF);
                        tBuffer[255] = Convert.ToByte((size >> 0) & 0xFF);
                    }

                    break;
                }

                // passthrough command
                case usbint_server_opcode_e.RESET:
                case usbint_server_opcode_e.MENU_RESET:
                case usbint_server_opcode_e.INFO:
                case usbint_server_opcode_e.STREAM:
                case usbint_server_opcode_e.POWER_CYCLE:
                    break;

                //case usbint_server_opcode_e.EXECUTE:
                //case usbint_server_opcode_e.ATOMIC:
                //case usbint_server_opcode_e.MENU_LOCK:
                //case usbint_server_opcode_e.MENU_UNLOCK:
                //case usbint_server_opcode_e.MENU_RESET:
                //case usbint_server_opcode_e.EXE:
                //case usbint_server_opcode_e.TIME:

                default:
                    throw new Exception("Unhandled Command: " + opcode + " space: " + space + " flags: " + flags);
                }
            }
            else
            {
                switch (opcode)
                {
                case usbint_server_opcode_e.GET:
                case usbint_server_opcode_e.PUT:
                {
                    // offset
                    if (!(args[0] is uint))
                    {
                        throw new Exception("Command: " + opcode + " missing arg[0] uint");
                    }
                    uint offset = (uint)args[0];
                    tBuffer[256] = Convert.ToByte((offset >> 24) & 0xFF);
                    tBuffer[257] = Convert.ToByte((offset >> 16) & 0xFF);
                    tBuffer[258] = Convert.ToByte((offset >> 8) & 0xFF);
                    tBuffer[259] = Convert.ToByte((offset >> 0) & 0xFF);

                    // size
                    if (!(args[1] is uint))
                    {
                        throw new Exception("Command: " + opcode + " missing arg[1] uint");
                    }
                    uint size = (uint)args[1];
                    tBuffer[252] = Convert.ToByte((size >> 24) & 0xFF);
                    tBuffer[253] = Convert.ToByte((size >> 16) & 0xFF);
                    tBuffer[254] = Convert.ToByte((size >> 8) & 0xFF);
                    tBuffer[255] = Convert.ToByte((size >> 0) & 0xFF);

                    break;
                }

                case usbint_server_opcode_e.VGET:
                case usbint_server_opcode_e.VPUT:
                {
                    if (args.Length == 0 || args.Length > 8)
                    {
                        throw new Exception("Command: " + opcode + " need 2 <= args <= 16 and a multiple of 2.  Format: (size0, offset0), ...");
                    }
                    uint i = 0;
                    foreach (object a in args)
                    {
                        Tuple <int, int> t      = (Tuple <int, int>)a;
                        byte             size   = Convert.ToByte(t.Item2);
                        uint             offset = Convert.ToUInt32(t.Item1);
                        tBuffer[32 + i * 4] = size;
                        tBuffer[33 + i * 4] = Convert.ToByte((offset >> 16) & 0xFF);
                        tBuffer[34 + i * 4] = Convert.ToByte((offset >> 8) & 0xFF);
                        tBuffer[35 + i * 4] = Convert.ToByte((offset >> 0) & 0xFF);
                        i++;
                    }

                    break;
                }

                // passthrough command
                case usbint_server_opcode_e.STREAM:
                case usbint_server_opcode_e.RESET:
                case usbint_server_opcode_e.MENU_RESET:
                case usbint_server_opcode_e.INFO:
                case usbint_server_opcode_e.POWER_CYCLE:
                    break;

                default:
                    throw new Exception("Unhandled Request: " + opcode + " space: " + space + " flags: " + flags);
                }
            }

            // handle 64B commands here
            int cmdSize = (opcode == usbint_server_opcode_e.VGET || opcode == usbint_server_opcode_e.VPUT) ? 64 : tBuffer.Length;

            serialPort.Write(tBuffer, 0, cmdSize);

            // read response command
            int curSize = 0;

            if ((flags & usbint_server_flags_e.NORESP) == 0)
            {
                Array.Clear(tBuffer, 0, tBuffer.Length);
                while (curSize < 512)
                {
                    curSize += serialPort.Read(tBuffer, (curSize % 512), 512 - (curSize % 512));
                }
                if (tBuffer[0] != 'U' || tBuffer[1] != 'S' || tBuffer[2] != 'B' || tBuffer[3] != 'A' || tBuffer[4] != Convert.ToByte(usbint_server_opcode_e.RESPONSE) || tBuffer[5] == 1)
                {
                    throw new Exception("Response Error Request: " + opcode + " space: " + space + " flags: " + flags + " Response: " + tBuffer[4]);
                }
            }

            // handle response
            switch (opcode)
            {
            case usbint_server_opcode_e.INFO:
            {
                List <string> sL = new List <string>();
                string        s  = Encoding.UTF8.GetString(tBuffer, 256 + 4, Array.IndexOf <byte>(tBuffer, 0, 256 + 4) - (256 + 4));
                sL.Add(s);
                int v = (tBuffer[256] << 24) | (tBuffer[257] << 16) | (tBuffer[258] << 8) | (tBuffer[259] << 0);
                s = v.ToString("X");
                sL.Add(s);
                s = Encoding.UTF8.GetString(tBuffer, 16, Array.IndexOf <byte>(tBuffer, 0, 16) - 16);
                sL.Add(s);
                byte          f     = tBuffer[6];
                List <string> sList = new List <string>();
                if ((f & 0x01) != 0)
                {
                    sList.Add("FEAT_DSPX");
                }
                if ((f & 0x02) != 0)
                {
                    sList.Add("FEAT_ST0010");
                }
                if ((f & 0x04) != 0)
                {
                    sList.Add("FEAT_SRTC");
                }
                if ((f & 0x08) != 0)
                {
                    sList.Add("FEAT_MSU1");
                }
                if ((f & 0x10) != 0)
                {
                    sList.Add("FEAT_213F");
                }
                if ((f & 0x20) != 0)
                {
                    sList.Add("FEAT_CMD_UNLOCK");
                }
                if ((f & 0x40) != 0)
                {
                    sList.Add("FEAT_USB1");
                }
                if ((f & 0x80) != 0)
                {
                    sList.Add("FEAT_DMA1");
                }
                sL.Add(string.Join("|", sList));
                ret = sL;
                break;
            }

            case usbint_server_opcode_e.LS:
            {
                int type = 0;
                List <Tuple <int, string> > list = new List <Tuple <int, string> >();
                ret = list;

                // read directory listing packets
                do
                {
                    int bytesRead = serialPort.Read(tBuffer, (curSize % 512), 512 - (curSize % 512));

                    if (bytesRead != 0)
                    {
                        curSize += bytesRead;

                        if (curSize % 512 == 0)
                        {
                            // parse strings
                            for (int i = 0; i < 512;)
                            {
                                type = tBuffer[i++];

                                if (type == 0 || type == 1)
                                {
                                    string name = "";

                                    while (tBuffer[i] != 0x0)
                                    {
                                        name += (char)tBuffer[i++];
                                    }
                                    i++;

                                    list.Add(Tuple.Create(type, name));
                                }
                                else if (type == 2 || type == 0xFF)
                                {
                                    // continued on the next packet
                                    break;
                                }
                                else
                                {
                                    throw new IndexOutOfRangeException();
                                }
                            }
                        }
                    }
                } while (type != 0xFF);

                break;
            }

            case usbint_server_opcode_e.VGET:
            case usbint_server_opcode_e.GET:
            {
                int fileSize = 0;
                fileSize |= tBuffer[252]; fileSize <<= 8;
                fileSize |= tBuffer[253]; fileSize <<= 8;
                fileSize |= tBuffer[254]; fileSize <<= 8;
                fileSize |= tBuffer[255]; fileSize <<= 0;
                ret       = fileSize;
                break;
            }
                //default: break;
            }

            return(ret);
        }
Beispiel #2
0
            /// <summary>
            /// Run is the main operation thread.
            /// </summary>
            public void Run()
            {
                var serializer = new JavaScriptSerializer();
                var md5        = MD5.Create();

                while (!_stop)
                {
                    RequestQueueElementType t = null;
                    bool done = false;
                    try
                    {
                        t = Queue.Take();
                    }
                    catch (Exception x)
                    {
                        done = true;
                    }

                    if (!done)
                    {
                        //var elem = t.Item2;
                        var elem   = t;
                        var req    = elem.Request;
                        var socket = elem.Socket;

                        OpcodeType            socketOpcode;
                        usbint_server_flags_e flags;

                        log.Info("USB Begin: " + serializer.Serialize(req));

                        try
                        {
                            socketOpcode = (OpcodeType)Enum.Parse(typeof(OpcodeType), req.Opcode);

                            // convert flags
                            flags = usbint_server_flags_e.NONE;
                            if (req.Flags != null)
                            {
                                foreach (var flag in req.Flags)
                                {
                                    flags |= (usbint_server_flags_e)Enum.Parse(typeof(usbint_server_flags_e), flag);
                                }
                            }
                        }
                        catch (Exception x)
                        {
                            log.Warn("Invalid Command Exception: " + x.Message);
                            socket.Context.WebSocket.Close(CloseStatusCode.ProtocolError, "Invalid Command Exception: " + x.Message);
                            continue;
                        }

                        try
                        {
                            // perform snes operation
                            switch (socketOpcode)
                            {
                            case OpcodeType.Boot:
                            {
                                usbint_server_opcode_e opcode = usbint_server_opcode_e.BOOT;
                                _p.SendCommand(opcode, usbint_server_space_e.FILE, flags, req.Operands[0]);
                                break;
                            }

                            case OpcodeType.Menu:
                            case OpcodeType.Reset:
                            {
                                usbint_server_opcode_e opcode = (socketOpcode == OpcodeType.Menu) ? usbint_server_opcode_e.MENU_RESET
                                                                      : usbint_server_opcode_e.RESET;
                                _p.SendCommand(opcode, usbint_server_space_e.FILE, flags);
                                break;
                            }

                            case OpcodeType.Info:
                            {
                                usbint_server_opcode_e opcode = usbint_server_opcode_e.INFO;
                                var          version          = (List <string>)_p.SendCommand(opcode, usbint_server_space_e.SNES, flags);
                                ResponseType rsp = new ResponseType();
                                rsp.Results = version;

                                socket.Queue.Add(new ResponseQueueElementType()
                                    {
                                        Response = rsp, Done = true
                                    });
                                break;
                            }

                            case OpcodeType.Stream:
                            {
                                usbint_server_opcode_e opcode = usbint_server_opcode_e.STREAM;
                                _p.SendCommand(opcode, usbint_server_space_e.MSU, flags | usbint_server_flags_e.DATA64B);

                                // generate data
                                int    readByte  = 0;
                                Byte[] tempData  = new Byte[64];
                                bool   streamEnd = false;

                                while (!streamEnd)
                                {
                                    int readSize = 64;
                                    readByte += _p.GetData(tempData, readByte, 64 - readByte);

                                    // send data
                                    if (readByte == readSize)
                                    {
                                        if ((flags & usbint_server_flags_e.STREAM_BURST) != 0)
                                        {
                                            // look for NOP to exit
                                            streamEnd = (tempData[readSize - 2] == 0xFF && tempData[readSize - 1] == 0xFF);
                                        }

                                        socket.Queue.Add(new ResponseQueueElementType()
                                            {
                                                Data = new ArraySegment <byte>(tempData, 0, readSize).ToArray(), Done = streamEnd
                                            });
                                        readByte = 0;
                                    }
                                }

                                break;
                            }

                            case OpcodeType.GetAddress:
                            {
                                // TODO: decide if we want to pack more optimally
                                int  totalSize   = 0;
                                bool sizeOperand = false;
                                // vector operands only support up to 8 tuples
                                Tuple <int, int>[] vOperands   = (req.Operands.Count <= 16) ? new Tuple <int, int> [req.Operands.Count / 2] : null;
                                string             nameOperand = "";
                                int operandNum = 0;
                                foreach (var operand in req.Operands)
                                {
                                    if (sizeOperand)
                                    {
                                        int size = int.Parse(operand, System.Globalization.NumberStyles.HexNumber);
                                        int name = int.Parse(nameOperand, System.Globalization.NumberStyles.HexNumber);
                                        totalSize += size;
                                        if (size > 255)
                                        {
                                            vOperands = null;
                                        }
                                        else if (vOperands != null)
                                        {
                                            vOperands[operandNum++] = Tuple.Create(name, size);
                                        }
                                    }
                                    else
                                    {
                                        nameOperand = operand;
                                    }
                                    sizeOperand = !sizeOperand;
                                }

                                // allocate full buffer to make indexing easier
                                // pad for max blockSize
                                Byte[] data      = new Byte[totalSize + 512];
                                int    sendCount = 0;
                                int    recvCount = 0;

                                //try {

                                for (int i = 0; i < req.Operands.Count; i += 2)
                                {
                                    var name    = req.Operands[i + 0];
                                    var sizeStr = req.Operands[i + 1];

                                    usbint_server_space_e space = (usbint_server_space_e)Enum.Parse(typeof(usbint_server_space_e), req.Space);
                                    uint address = uint.Parse(name, System.Globalization.NumberStyles.HexNumber);
                                    int  size    = (vOperands != null) ? totalSize : int.Parse(sizeStr, System.Globalization.NumberStyles.HexNumber);

                                    if (vOperands == null)
                                    {
                                        flags |= usbint_server_flags_e.NORESP /* | usbint_server_flags_e.DATA64B*/;
                                        _p.SendCommand(usbint_server_opcode_e.GET, space, flags, address, (uint)size);
                                    }
                                    else
                                    {
                                        flags |= usbint_server_flags_e.NORESP | usbint_server_flags_e.DATA64B;
                                        i      = req.Operands.Count - 2;
                                        _p.SendCommand(usbint_server_opcode_e.VGET, space, flags, vOperands);
                                    }

                                    int blockSize    = ((flags & usbint_server_flags_e.DATA64B) == 0) ? 512 : 64;
                                    int transferSize = (size + blockSize - 1) & ~(blockSize - 1);
                                    // must be ceiling of the multiple of the block size
                                    int transferCount = 0;
                                    // actual size
                                    int localRecvCount = 0;

                                    do
                                    {
                                        // fill up to one of the following conditions
                                        // 1) local operation complete
                                        // 2) MaxMessageSize data available
                                        while (transferCount < transferSize && recvCount + localRecvCount - sendCount < Constants.MaxMessageSize)
                                        {
                                            int packetOffset = localRecvCount % blockSize;
                                            int count        = _p.GetData(data, recvCount + localRecvCount, blockSize - packetOffset);  // Math.Min(readSize - readByte, Math.Min(Constants.MaxMessageSize - readOffset, blockSize - packetOffset)));
                                            if (count == 0)
                                            {
                                                continue;
                                            }
                                            transferCount += count;

                                            // if we received over the size then clamp it the size
                                            localRecvCount = Math.Min(transferCount, size);
                                        }

                                        // send message if
                                        // 1) We have no more data to send for this GET
                                        // 2) MaxMessage data available
                                        while (recvCount + localRecvCount - sendCount >= Math.Min(totalSize - sendCount, Constants.MaxMessageSize) && sendCount < totalSize)
                                        {
                                            // recalculate last data beat to send on every message
                                            int bytesToSend = Math.Min(totalSize - sendCount, Constants.MaxMessageSize);

                                            socket.Queue.Add(new ResponseQueueElementType()
                                                {
                                                    Data = (Byte[])(new ArraySegment <byte>(data, sendCount, bytesToSend).ToArray()).Clone(), Done = sendCount + bytesToSend >= totalSize
                                                });
                                            sendCount += bytesToSend;
                                        }

                                        // check if we are are done and have to send the final message
                                    } while (transferCount < transferSize);

                                    recvCount += localRecvCount;
                                }

                                log.Info("USB MD5: " + BitConverter.ToString(md5.ComputeHash(data, 0, totalSize)).Replace("-", ""));

                                break;
                            }

                            case OpcodeType.PutAddress:
                            {
                                // TODO: decide if we want to pack more optimally
                                int  totalSize   = 0;
                                bool sizeOperand = false;
                                // vector operands only support up to 8 tuples
                                Tuple <int, int>[] vOperands   = (req.Operands.Count <= 16) ? new Tuple <int, int> [req.Operands.Count / 2] : null;
                                string             nameOperand = "";
                                int operandNum = 0;
                                foreach (var operand in req.Operands)
                                {
                                    if (sizeOperand)
                                    {
                                        int size = int.Parse(operand, System.Globalization.NumberStyles.HexNumber);
                                        int name = int.Parse(nameOperand, System.Globalization.NumberStyles.HexNumber);
                                        totalSize += size;
                                        if (size > 255)
                                        {
                                            vOperands = null;
                                        }
                                        else if (vOperands != null)
                                        {
                                            vOperands[operandNum++] = Tuple.Create(name, size);
                                        }
                                    }
                                    else
                                    {
                                        nameOperand = operand;
                                    }
                                    sizeOperand = !sizeOperand;
                                }

                                // allocate full buffer to make indexing easier
                                // pad for max blockSize
                                Byte[] data      = new Byte[totalSize + 512];
                                int    sendCount = 0;
                                int    recvCount = 0;

                                for (int i = 0; i < req.Operands.Count; i += 2)
                                {
                                    var name    = req.Operands[i + 0];
                                    var sizeStr = req.Operands[i + 1];

                                    usbint_server_space_e space = (usbint_server_space_e)Enum.Parse(typeof(usbint_server_space_e), req.Space);
                                    uint address = uint.Parse(name, System.Globalization.NumberStyles.HexNumber);
                                    int  size    = (vOperands != null) ? totalSize : int.Parse(sizeStr, System.Globalization.NumberStyles.HexNumber);

                                    if (vOperands == null)
                                    {
                                        flags |= usbint_server_flags_e.NORESP /* | usbint_server_flags_e.DATA64B*/;
                                        _p.SendCommand(usbint_server_opcode_e.PUT, space, flags, address, (uint)size);
                                    }
                                    else
                                    {
                                        flags |= usbint_server_flags_e.NORESP | usbint_server_flags_e.DATA64B;
                                        i      = req.Operands.Count - 2;
                                        _p.SendCommand(usbint_server_opcode_e.VPUT, space, flags, vOperands);
                                    }

                                    int blockSize      = ((flags & usbint_server_flags_e.DATA64B) == 0) ? 512 : 64;
                                    int localSendCount = 0;

                                    do
                                    {
                                        // fill up to one of the following conditions
                                        // 1) local operation complete
                                        // 2) blockSize data available
                                        while (recvCount - (sendCount + localSendCount) < blockSize && recvCount < totalSize)
                                        {
                                            Byte[] d = null;
                                            try
                                            {
                                                d = socket.DataQueue.Take();
                                            }
                                            catch (Exception x)
                                            {
                                                continue;
                                            }
                                            Array.Copy(d, 0, data, recvCount, d.Length);
                                            recvCount += d.Length;
                                        }

                                        // send message if
                                        // 1) We haven't finished sending this particular PUT
                                        // 2) Block available
                                        bool dataDone = sendCount + blockSize >= totalSize;
                                        while (localSendCount < size && recvCount - (sendCount + localSendCount) >= Math.Min(totalSize - (sendCount + localSendCount), blockSize))
                                        {
                                            _p.SendData(new ArraySegment <Byte>(data, sendCount + localSendCount, blockSize).ToArray(), blockSize);
                                            localSendCount += blockSize;
                                        }

                                        // if we received over the size then clamp it the size
                                        localSendCount = Math.Min(localSendCount, size);
                                    } while (localSendCount < size);

                                    sendCount += localSendCount;
                                }

                                log.Info("USB MD5: " + BitConverter.ToString(md5.ComputeHash(data, 0, totalSize)).Replace("-", ""));

                                break;
                            }

                            case OpcodeType.PutIPS:
                            {
                                var name    = req.Operands[0];
                                var sizeStr = req.Operands[1];

                                usbint_server_space_e space = (usbint_server_space_e)Enum.Parse(typeof(usbint_server_space_e), req.Space);
                                int size = int.Parse(sizeStr, System.Globalization.NumberStyles.HexNumber);

                                // collect the full IPS patch
                                var data      = new Byte[size];
                                int blockSize = ((flags & usbint_server_flags_e.DATA64B) == 0) ? 512 : 64;

                                int recvCount = 0;
                                while (recvCount < size)
                                {
                                    Byte[] d = null;
                                    try
                                    {
                                        d = socket.DataQueue.Take();
                                    }
                                    catch (Exception x)
                                    {
                                        continue;
                                    }
                                    Array.Copy(d, 0, data, recvCount, d.Length);
                                    recvCount += d.Length;
                                }

                                // parse IPS
                                IPS ips = new IPS();
                                ips.Parse(data);

                                int patchNum = 0;
                                // loop through patches and send to USB
                                foreach (var patch in ips.Items)
                                {
                                    var tBuffer = new Byte[patch.data.Count + blockSize];
                                    Array.Copy(patch.data.ToArray(), 0, tBuffer, 0, patch.data.Count);

                                    var localFlags = flags | usbint_server_flags_e.NORESP /* | usbint_server_flags_e.DATA64B*/;

                                    // handle hook executables
                                    if (name == "hook" && patchNum == 0)
                                    {
                                        localFlags |= usbint_server_flags_e.CLRX;
                                    }
                                    if (name == "hook" && patchNum == ips.Items.Count - 1)
                                    {
                                        localFlags |= usbint_server_flags_e.SETX;
                                    }

                                    _p.SendCommand(usbint_server_opcode_e.PUT, space, localFlags, (uint)patch.address, (uint)patch.data.Count);

                                    int sendCount = 0;
                                    while (sendCount < patch.data.Count)
                                    {
                                        int toWriteSize = Math.Min(patch.data.Count - sendCount, Constants.MaxMessageSize);
                                        _p.SendData(new ArraySegment <Byte>(tBuffer, sendCount, blockSize).ToArray(), blockSize);
                                        sendCount += blockSize;
                                    }

                                    patchNum++;
                                }

                                break;
                            }

                            case OpcodeType.List:
                                foreach (var dir in req.Operands)
                                {
                                    usbint_server_opcode_e opcode = usbint_server_opcode_e.LS;
                                    usbint_server_space_e  space  = usbint_server_space_e.FILE;
                                    var          list             = (List <Tuple <int, string> >)_p.SendCommand(opcode, space, flags, dir);
                                    ResponseType rsp = new ResponseType();
                                    rsp.Results = new List <string>();
                                    foreach (var item in list)
                                    {
                                        rsp.Results.Add(item.Item1.ToString());
                                        rsp.Results.Add(item.Item2);
                                    }

                                    // send entire list (or last)
                                    socket.Queue.Add(new ResponseQueueElementType()
                                    {
                                        Response = rsp, Done = true
                                    });
                                }
                                break;

                            case OpcodeType.GetFile:
                            {
                                foreach (var name in req.Operands)
                                {
                                    usbint_server_opcode_e opcode = usbint_server_opcode_e.GET;
                                    usbint_server_space_e  space  = usbint_server_space_e.FILE;
                                    int    size     = (int)_p.SendCommand(opcode, space, flags, name);
                                    Byte[] tempData = new Byte[Constants.MaxMessageSize];

                                    // send back response with size
                                    ResponseType rsp = new ResponseType();
                                    rsp.Results = new List <string>();
                                    rsp.Results.Add(size.ToString("X"));
                                    socket.Queue.Add(new ResponseQueueElementType()
                                        {
                                            Response = rsp, Done = false
                                        });

                                    int blockSize = ((flags & usbint_server_flags_e.DATA64B) == 0) ? 512 : 64;
                                    int readSize  = (size + blockSize - 1) & ~(blockSize - 1);
                                    int readByte  = 0;
                                    int writeSize = size;
                                    int writeByte = 0;

                                    while (readByte < readSize)
                                    {
                                        int readOffset   = readByte % Constants.MaxMessageSize;
                                        int packetOffset = readByte % blockSize;
                                        var count        = _p.GetData(tempData, readOffset, blockSize - packetOffset);
                                        if (count == 0)
                                        {
                                            continue;
                                        }
                                        readByte += count;

                                        // send data
                                        if ((readByte == readSize || (readByte - writeByte >= Constants.MaxMessageSize)) && (writeByte < writeSize))
                                        {
                                            int toWriteSize = Math.Min(writeSize - writeByte, Constants.MaxMessageSize);
                                            writeByte += toWriteSize;
                                            socket.Queue.Add(new ResponseQueueElementType()
                                                {
                                                    Data = new ArraySegment <byte>(tempData, 0, toWriteSize).ToArray(), Done = (writeByte >= writeSize)
                                                });
                                        }
                                    }
                                }
                                break;
                            }

                            case OpcodeType.PutFile:
                                for (int i = 0; i < req.Operands.Count; i += 2)
                                {
                                    var name    = req.Operands[i + 0];
                                    var sizeStr = req.Operands[i + 1];

                                    usbint_server_space_e space = usbint_server_space_e.FILE;
                                    int size = int.Parse(sizeStr, System.Globalization.NumberStyles.HexNumber);
                                    _p.SendCommand(usbint_server_opcode_e.PUT, space, flags, name, (uint)size);

                                    // get data and write to USB
                                    int blockSize = ((flags & usbint_server_flags_e.DATA64B) == 0) ? 512 : 64;

                                    // simplify data receipt by allocating a full size buffer
                                    Byte[] receiveBuffer = new Byte[blockSize];
                                    Byte[] fileBuffer    = new Byte[size + Constants.MaxMessageSize];
                                    int    getCount      = 0;
                                    int    putCount      = 0;
                                    do
                                    {
                                        Byte[] d        = null;
                                        bool   dataDone = false;
                                        try
                                        {
                                            d = socket.DataQueue.Take();
                                        }
                                        catch (Exception x)
                                        {
                                            dataDone = true;
                                        }

                                        if (!dataDone)
                                        {
                                            Array.Copy(d, 0, fileBuffer, getCount, d.Length);
                                            getCount += d.Length;

                                            int nextCount = (getCount >= size) ? ((size + blockSize - 1) & ~(blockSize - 1)) : (getCount & ~(blockSize - 1));
                                            // send data over USB
                                            while (putCount < nextCount)
                                            {
                                                // copies for now.  Would be better to work with array segments
                                                Array.Copy(fileBuffer, putCount, receiveBuffer, 0, blockSize);
                                                putCount += blockSize;
                                                _p.SendData(receiveBuffer, blockSize);
                                            }
                                        }
                                    } while (putCount < size);
                                }
                                break;

                            case OpcodeType.Rename:
                            {
                                for (int i = 0; i < req.Operands.Count; i += 2)
                                {
                                    string name    = req.Operands[i + 0];
                                    string newName = req.Operands[i + 1];

                                    usbint_server_opcode_e opcode = usbint_server_opcode_e.MV;
                                    usbint_server_space_e  space  = usbint_server_space_e.FILE;
                                    _p.SendCommand(opcode, space, flags, name, newName);
                                }
                                break;
                            }

                            case OpcodeType.MakeDir:
                            case OpcodeType.Remove:
                            {
                                foreach (var name in req.Operands)
                                {
                                    usbint_server_opcode_e opcode = (socketOpcode == OpcodeType.MakeDir) ? usbint_server_opcode_e.MKDIR : usbint_server_opcode_e.RM;
                                    usbint_server_space_e  space  = usbint_server_space_e.FILE;
                                    _p.SendCommand(opcode, space, flags, name);
                                }
                                break;
                            }
                            }
                        }
                        catch (Exception e)
                        {
                            // TODO: close all sockets and clear queues
                            log.Error("USB Exception: " + e.Message);

                            lock (_ports)
                            {
                                var p = _ports[_p.PortName()];

                                lock (p.Clients)
                                {
                                    // close all clients
                                    try
                                    {
                                        foreach (var c in p.Clients)
                                        {
                                            c.Value.Context.WebSocket.Close();
                                        }

                                        // clear them out
                                        p.Clients.Clear();
                                    }
                                    catch (Exception x)
                                    {
                                        // Clients have been deleted
                                    }
                                }

                                // remove the port so a new one needs to be created
                                _ports.Remove(_p.PortName());
                            }

                            break;
                        }

                        log.Info("USB End: " + serializer.Serialize(req));
                    }
                }
            }